#include #include #include #include "../rw.h" #include "dff.h" void ParseSection(clump *clp, rwheader *sec, int par, FILE *dff); void ReadMaterialEffects(clump *clp, rwheader *rwh, int par, FILE *dff); void ReadSection(clump *clp, rwheader *rwh, FILE *dff); void ReadStruct(clump *clp, rwheader *rwh, int par, FILE *dff); void ReadFrame(clump *clp, rwheader *rwh, FILE *dff); int clumpc = 0;; int oc, fc, gc; /* Checks if two vertices are the same and returns 1 if so, * otherwise 0. */ int IsSameVert(float *vert0, float *vert1) { if (vert0[X] == vert1[X] && vert0[Y] == vert1[Y] && vert0[Z] == vert1[Z]) { return 1; } else return 0; } void ReadMaterialEffects(clump *clp, rwheader *rwh, int par, FILE *dff) { int type; rwheader texh; fread(&type, 4, 1, dff); /* Only type 2 contains useful information */ if (type != 2) return; clp->geo[clp->gc].mat[clp->geo[clp->gc].mc].hasreflection = 1; fseek(dff, 16, SEEK_CUR); /* Read Texture - missing */ texh = ReadHeader(dff); ReadSection(clp, &texh, dff); fseek(dff, 4, SEEK_CUR); } void ReadSection(clump *clp, rwheader *rwh, FILE *dff) { rwheader child; int secend; secend = rwh->size + ftell(dff); while (secend > ftell(dff)) { child = ReadHeader(dff); ParseSection(clp, &child, rwh->type, dff); } } /* Reads a struct section. */ void ReadStruct(clump *clp, rwheader *rwh, int par, FILE *dff) { int i, j; float temp; atomic *atm; geometry *geo; material *mat; texture *tex; switch(par) { case CLUMP: fread(&clp->objcount, 4, 1, dff); clp->atm = (atomic *) malloc(clp->objcount*sizeof(atomic)); /* Unknown, not used in GTA: III */ if (rwh->version != 0x310) fseek(dff, 8, SEEK_CUR); break; case FRAMELIST: /* Read Rotation Martrix, position and parentframe */ fread(&clp->frmcount, 4, 1, dff); clp->frm = (frame *) malloc(clp->frmcount*sizeof(frame)); for (i = 0; i < clp->frmcount; i++) { int j, k; /* initialize matrices to 0 */ for (j = 0; j < 4; j++) for (k = 0; k < 4; k++) { clp->frm[i].rotmatrix[j][k] = 0; } clp->frm[i].rotmatrix[3][3] = 1; /* read rotational matrix */ for (j = 0; j < 3; j++) for (k = 0; k < 3; k++) { fread(&temp, 4, 1, dff); clp->frm[i].rotmatrix[j][k] = temp; } /* read position */ fread(&temp, 4, 1, dff); clp->frm[i].positionv[0] = temp; fread(&temp, 4, 1, dff); clp->frm[i].positionv[1] = temp; fread(&temp, 4, 1, dff); clp->frm[i].positionv[2] = temp; /* read parent frame */ fread(&clp->frm[i].parent, 4, 1, dff); fread(&clp->frm[i].unknown, 4, 1, dff); clp->frm[i].name = 0; } break; case GEOMETRYLIST: fread(&clp->geocount, 4, 1, dff); clp->geo = (geometry *) malloc(clp->geocount*sizeof(geometry)); break; case GEOMETRY: geo = &clp->geo[clp->gc]; /* Initialize material counter */ clp->geo[clp->gc].mc = 0; fread(&geo->flags, 2, 1, dff); fread(&geo->uvsets, 1, 1, dff); geo->newuvsets = geo->uvsets; if (geo->uvsets > 2) { printf("Cannot handle more than 2 UV sets!\n"); exit(3); } /* Set number of UV sets according to flags */ if (geo->uvsets == 0 && (geo->flags & HASMULUV || geo->flags & HASUV)) geo->newuvsets = 1; geo->isps2 = getc(dff); fread(&geo->facec, 4, 1, dff); fread(&geo->vertexc, 4, 1, dff); fread(&geo->framec, 4, 1, dff); if (rwh->version == 0x0C02FFFF || rwh->version == 0x310) { fread(&geo->ambient, 4, 1, dff); fread(&geo->diffuse, 4, 1, dff); fread(&geo->specular, 4, 1, dff); } if (!geo->isps2) { geo->vertices = malloc(geo->vertexc*4); geo->uv[0] = malloc(geo->vertexc*4); geo->uv[1] = malloc(geo->vertexc*4); geo->vc = malloc(geo->vertexc*4); geo->normals = malloc(geo->vertexc*4); /* If prelit flag is set, read vertex colors */ for (i = 0; i < geo->vertexc; i++) { geo->vc[i] = (unsigned char *) malloc(1*4); memset(geo->vc[i], 0, 4); if ((geo->flags & HASVCOLORS) != 0) { fread(geo->vc[i], 1, 4, dff); } } /* Read UV Coordinates */ for (j = 0; j < geo->newuvsets; j++) for (i = 0; i < geo->vertexc; i++) { geo->uv[j][i] = malloc(2*4); fread(geo->uv[j][i], 4, 2, dff); } /* Read faces */ geo->faces = (unsigned short **) malloc(geo->facec*4); for (i = 0; i < geo->facec; i++) { geo->faces[i] = (unsigned short *) malloc(2*4); if (!geo->isps2) fread(geo->faces[i], 2, 4, dff); } } fread(&geo->bs, 4, 4, dff); fread(&geo->bspos, 4, 1, dff); fread(&geo->bsnor, 4, 1, dff); if (geo->isps2 == 0) { /* Read vertices */ for (i = 0; i < geo->vertexc; i++) { geo->vertices[i] = (float *) malloc(3*4); fread(geo->vertices[i], 4, 3, dff); } /* If normals flag is set, read normals */ for (i = 0; i < geo->vertexc; i++) { geo->normals[i] = (float *) malloc(3*4); memset(geo->normals[i], 0, 3*4); if ((geo->flags & HASNORMALS) != 0) { fread(geo->normals[i], 4, 3, dff); } } } break; case MATERIALLIST: geo = &clp->geo[clp->gc]; fread(&geo->matcount, 4, 1, dff); geo->mat = (material *) malloc(geo->matcount*sizeof(material)); fseek(dff, 4*geo->matcount, SEEK_CUR); /* unknown */ break; case MATERIAL: geo = &clp->geo[clp->gc]; mat = &geo->mat[geo->mc]; fseek(dff, 4, SEEK_CUR); /* unknown */ fread(&mat->color, 1, 4, dff); fseek(dff, 4, SEEK_CUR); /* unknown */ fread(&mat->hastexture, 1, 4, dff); fseek(dff, 12, SEEK_CUR); /* unknown */ mat->texread = 0; mat->hasreflection = 0; break; case TEXTURE: geo = &clp->geo[clp->gc]; mat = &geo->mat[geo->mc]; tex = &mat->tex; /* If texture is already read, read reflection texture instead */ if (mat->texread || !mat->hastexture) tex = &mat->reflection; fread(&tex->filterflags, 2, 1, dff); fread(&tex->unknown, 2, 1, dff); /* Texture name */ *rwh = ReadHeader(dff); /* String */ tex->tex = malloc(rwh->size+1); fread(tex->tex, rwh->size, 1, dff); tex->tex[rwh->size] = '\0'; /* Alpha texture name */ *rwh = ReadHeader(dff); /* String */ tex->alpha = malloc(rwh->size+1); fread(tex->alpha, rwh->size, 1, dff); tex->alpha[rwh->size] ='\0'; /* no matter if diffuse or reflection texture was just read */ mat->texread = 1; break; case ATOMIC: atm = &clp->atm[clp->oc]; fread(&atm->frameindex, 4, 1, dff); fread(&atm->geometryindex, 4, 1, dff); fread(&atm->unknown0, 4, 1, dff); fread(&atm->unknown1, 4, 1, dff); break; default: break; } } void ReadFrame(clump *clp, rwheader *rwh, FILE *dff) { clp->frm[fc].name = (char *) malloc(rwh->size+1); fread(clp->frm[fc].name, rwh->size, 1, dff); clp->frm[fc].name[rwh->size] = '\0'; clp->frm[fc].display = 1; #ifdef ASK fprintf(stderr, "Shall object %s be displayed?\n", clp->frm[fc].name); scanf("%d", &clp->frm[fc].display); getchar(); #endif } /* Main function for reading dffs. */ void ReadClump(clump *clp, int start, FILE *dff) { rwheader rwh; /* Initialize object, frame, and geometry counter */ oc = 0; fc = 0; gc = 0; fseek(dff, start, 0); rwh = ReadHeader(dff); while (rwh.type != 0) { ParseSection(clp, &rwh, 0, dff); rwh = ReadHeader(dff); } clumpc = 0; } /* Decides which function to call depending on the section type. */ void ParseSection(clump *clp, rwheader *sec, int par, FILE *dff) { switch (sec->type) { case CLUMP: if (clumpc < 1) { ReadSection(clp, sec, dff); clumpc++; } else { return; } break; case STRUCT: ReadStruct(clp, sec, par, dff); break; case EXTENSION: ReadSection(clp, sec, dff); break; case FRAMELIST: ReadSection(clp, sec, dff); break; case FRAME: ReadFrame(clp, sec, dff); fc++; break; case GEOMETRYLIST: ReadSection(clp, sec, dff); break; case GEOMETRY: ReadSection(clp, sec, dff); clp->gc++; break; case MATERIALLIST: ReadSection(clp, sec, dff); break; case MATERIAL: ReadSection(clp, sec, dff); clp->geo[clp->gc].mc++; break; case TEXTURE: ReadSection(clp, sec, dff); break; case ATOMIC: ReadSection(clp, sec, dff); oc++; break; case BINMESH: ReadBinMesh(&clp->geo[gc], dff); break; case NATIVEDATA: /* The San Andreas Native Data section is actually * a special case of the VC section. * This test does not always do the right thing, * San Andreas weapons for example have the Vice City format */ if (sec->version == 0x1803FFFF) { fprintf(stderr, "SA not supported yet\n"); exit(2); ReadNativeDataSAPS2(&clp->geo[gc], dff); } else { ReadNativeDataVCPS2(&clp->geo[gc], dff); } break; case MATERIALEFFECTS: ReadMaterialEffects(clp, sec, par, dff); break; case SKIN: case MORPH: case PARTICLES: case SKYMIPMAP: case RIGHTTORENDER: case HANIM: case REFLECTIONMAT: case SPECULARMAT: case MESHEXTENSION: case COLLISIONMODEL: case NIGHTVERTEXCOLOR: case ADCPLG: /* Skip section */ fseek(dff, sec->size, SEEK_CUR); break; default: fprintf(stderr, "Error: Unknown section: %X at %lX\n", sec->type, ftell(dff)); exit(2); break; } } void DestroyDff(Dff *dff) { clump *clp; int i, j, k; /* Free Atomics */ free(clp->atm); /* Free Frames */ for (i = 0; i < clp->frmcount; i++) { free(clp->frm[i].name); } free(clp->frm); /* Free Geometries */ for (i = 0; i < clp->geocount; i++) { /* Free Materials */ for (j = 0; j < clp->geo[i].matcount; j++) { /* Free Textures */ if (clp->geo[i].mat[j].hastexture) { free(clp->geo[i].mat[j].tex.tex); free(clp->geo[i].mat[j].tex.alpha); } if (clp->geo[i].mat[j].hasreflection) { free(clp->geo[i].mat[j].reflection.tex); free(clp->geo[i].mat[j].reflection.alpha); } } free(clp->geo[i].mat); for (j = 0; j < clp->geo[i].vertexc; j++) { free(clp->geo[i].vertices[j]); for (k = 0; k < clp->geo[i].newuvsets; k++) free(clp->geo[i].uv[k][j]); free(clp->geo[i].vc[j]); free(clp->geo[i].normals[j]); } for (j = 0; j < clp->geo[i].facec; j++) { free(clp->geo[i].faces[j]); } free(clp->geo[i].vertices); free(clp->geo[i].uv[0]); free(clp->geo[i].uv[1]); free(clp->geo[i].vc); free(clp->geo[i].normals); free(clp->geo[i].faces); /* Free Splits */ for (j = 0; j < clp->geo[i].splitcount; j++) { int temp; free(clp->geo[i].splt[j].indices); if (clp->geo[i].normaltype == 1) temp = clp->geo[i].splt[j].indexcount - 2; else if (clp->geo[i].normaltype == 2) temp = clp->geo[i].splt[j].indexcount / 3; else temp = 0; for (k = 0; k < temp; k++) free(clp->geo[i].splt[j].normals[k]); if (temp != 0) free(clp->geo[i].splt[j].normals); } free(clp->geo[i].splt); } free(clp->geo); }