#include #include #include #include "../rw.h" #include "dff.h" int fc, gc, oc; /* frame, geometry and object counter */ int mc; /* material counter */ DFF * dffread(FILE *fdff, int start, int end) { DFF *dff; dff = newdff(); fseek(fdff, start, SEEK_SET); while (ftell(fdff) < end) { dff->clp = realloc(dff->clp, (dff->nclump+1)*sizeof(_clump)); readclump(fdff, &dff->clp[dff->nclump]); dff->nclump++; } return dff; } DFF * newdff() { DFF *dff; dff = malloc(sizeof(DFF)); dff->clp = NULL; dff->nclump = 0; return dff; } /* Initialize clump and read subsections */ void readclump(FILE *fdff, _clump *clp) { rwheader rwh; int end; fc = gc = oc = 0; ReadRwHeader(fdff, &rwh); end = rwh.size + ftell(fdff); clp->natomic = 0; clp->nframe = 0; clp->ngeometry = 0; clp->atm = NULL; clp->frm = NULL; clp->geo = NULL; while (ftell(fdff) < end) { ReadRwHeader(fdff, &rwh); parsesection(clp, &rwh, CLUMP, fdff); } /* dumpclump(clp); */ } /* Read subsections until we've reached the end */ void readsection(_clump *clp, rwheader *rwh, FILE *dff) { rwheader child; int end; end = rwh->size + ftell(dff); while (ftell(dff) < end) { ReadRwHeader(dff, &child); parsesection(clp, &child, rwh->type, dff); } } void readframe(_frame *frm, int size, FILE *dff) { frm->name = malloc(size+1); fread(frm->name, 1, size, dff); frm->name[size] = '\0'; } /* Read Material effects, may not be good but works. * More research on the format is needed here. */ void readmatfx(_clump *clp, rwheader *rwh, int parent, FILE *dff) { int type; rwheader texh; fread(&type, 4, 1, dff); /* Only type 2 contains useful information */ if (type != 2) return; clp->geo[gc].mat[mc].hasref = 1; fseek(dff, 16, SEEK_CUR); /* Now we've reached the reflection texture */ ReadRwHeader(dff, &texh); readsection(clp, &texh, dff); fseek(dff, 4, SEEK_CUR); } /* Call funtions according to the section type */ void parsesection(_clump *clp, rwheader *rwh, int parent, FILE *dff) { int i; _split *split; _geometry *geo; switch (rwh->type) { case STRUCT: readstruct(clp, rwh, parent, dff); break; case FRAME: readframe(&clp->frm[fc], rwh->size, dff); fc++; break; case GEOMETRY: readsection(clp, rwh, dff); gc++; break; case MATERIAL: readsection(clp, rwh, dff); mc++; break; case ATOMIC: readsection(clp, rwh, dff); oc++; break; case BINMESH: geo = &clp->geo[gc]; fread(&geo->facetype, 4, 1, dff); fread(&geo->nsplit, 4, 1, dff); fread(&geo->nindex, 4, 1, dff); geo->split = malloc(geo->nsplit * sizeof(_split)); for (i = 0; i < geo->nsplit; i++) { split = &geo->split[i]; fread(&split->nindex, 4, 1, dff); fread(&split->matindex, 4, 1, dff); if (!geo->isps2) { split->indices = malloc(split->nindex * sizeof(int)); fread(split->indices, 4, split->nindex, dff); } } break; case MATERIALLIST: case EXTENSION: case FRAMELIST: case GEOMETRYLIST: case TEXTURE: readsection(clp, rwh, dff); break; case NATIVEDATA: fprintf(stderr, "Sorry, only pc supported yet\n"); exit(-1); default: fseek(dff, rwh->size, SEEK_CUR); } } /* Read a struct according to the parent's section type */ void readstruct(_clump *clp, rwheader *rwh, int parent, FILE *dff) { int i; _frame *fp; _geometry *geo; _material *mat; _texture *tex; _atomic *atm; /* printf("Found STRUCT %#X at %lX\n", parent, ftell(dff)); */ switch (parent) { case CLUMP: fread(&clp->natomic, 4, 1, dff); if (rwh->version != GTA3_1 && rwh->version != GTA3_2) fseek(dff, 8, SEEK_CUR); /* printf("natomic: %d\n", clp->natomic); */ clp->atm = malloc(clp->natomic * sizeof(_atomic)); break; case FRAMELIST: fread(&clp->nframe, 4, 1, dff); clp->frm = malloc(clp->nframe * sizeof(_frame)); for (i = 0 ; i < clp->nframe; i++) { fp = &clp->frm[i]; fread(fp->rotmatrix, 4, 3 * 3, dff); fread(fp->posv, 4, 3, dff); fread(&fp->parent, 4, 1, dff); fread(&fp->unknown, 4, 1, dff); } break; case GEOMETRYLIST: fread(&clp->ngeometry, 4, 1, dff); clp->geo = malloc(clp->ngeometry * sizeof(_geometry)); break; case GEOMETRY: geo = &clp->geo[gc]; mc = 0; fread(&geo->flags, 2, 1, dff); geo->nuv = getc(dff); if (geo->nuv == 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 == GTA3_1 || rwh->version == GTA3_2 || rwh->version == VCPS2) { fread(&geo->ambient, 4, 1, dff); fread(&geo->diffuse, 4, 1, dff); fread(&geo->specular, 4, 1, dff); } geo->vc = NULL; geo->uv = NULL; geo->face = NULL; geo->vertex = NULL; geo->normal = NULL; if (!geo->isps2) { /* Read vertex colors if any */ if ((geo->flags & HASVCOLORS) != 0) { /* not perfect V */ geo->vc = malloc(geo->vertexc * 4); fread(geo->vc, 4, geo->vertexc, dff); } /* Read UV coordinates if any */ if ((geo->flags & HASUV) != 0) { /* not perfect V */ geo->uv = malloc(geo->vertexc * 2 * 4); fread(geo->uv, 2 * 4, geo->vertexc, dff); } /* Read face data */ geo->face = malloc(geo->facec * 4 * 2); fread(geo->face, 4 * 2, geo->facec, dff); } fread(geo->bs, 4, 4, dff); fread(&geo->bspos, 4, 1, dff); fread(&geo->bsnor, 4, 1, dff); if (!geo->isps2) { /* Read vertices */ geo->vertex = malloc(geo->vertexc * 3 * 4); fread(geo->vertex, 3 * 4, geo->vertexc, dff); /* Read normals if any */ if ((geo->flags & HASNORMALS) != 0) { /* not perfect V */ geo->normal = malloc(geo->vertexc * 3 * 4); fread(geo->normal, 3 * 4, geo->vertexc, dff); } } break; case MATERIALLIST: geo = &clp->geo[gc]; fread(&geo->nmaterial, 4, 1, dff); geo->mat = malloc(geo->nmaterial * sizeof(_material)); fseek(dff, 4 * geo->nmaterial, SEEK_CUR); /* unknown */ break; case MATERIAL: mat = &clp->geo[gc].mat[mc]; fread(&mat->unknown0, 4, 1, dff); fread(&mat->color, 1, 4, dff); fread(&mat->unknown1, 4, 1, dff); fread(&mat->hastex, 4, 1, dff); fread(&mat->unknown2, 4, 1, dff); fread(&mat->unknown3, 4, 1, dff); fread(&mat->unknown4, 4, 1, dff); mat->texread = 0; mat->hasref = 0; break; case TEXTURE: mat = &clp->geo[gc].mat[mc]; tex = &mat->tex; /* If the texture has already been read, or there has been * no texture, read reflection. */ if (mat->texread || !mat->hastex) tex = &mat->reflection; fread(&tex->filterflags, 2, 1, dff); fread(&tex->unknown, 2, 1, dff); /* texture name */ ReadRwHeader(dff, rwh); tex->tex = malloc(rwh->size+1); fread(tex->tex, rwh->size, 1, dff); tex->tex[rwh->size] = '\0'; /* alpha name */ ReadRwHeader(dff, rwh); tex->alpha = malloc(rwh->size+1); fread(tex->alpha, rwh->size, 1, dff); tex->alpha[rwh->size] = '\0'; mat->texread = 1; break; case ATOMIC: atm = &clp->atm[oc]; fread(&atm->frmindex, 4, 1, dff); fread(&atm->geoindex, 4, 1, dff); fread(&atm->unknown0, 4, 1, dff); fread(&atm->unknown1, 4, 1, dff); break; default: fseek(dff, rwh->size, SEEK_CUR); } /* printf("STRUCT end at %lX\n", ftell(dff)); */ } void dumpclump(_clump *clp) { int i; printf("\n\n\nCLUMP dump:"); printf("\n\nFRAME names:\n------------\n"); for (i = 0; i < clp->nframe; i++) printf("%s\n", clp->frm[i].name); printf("\n\nGEOMETRY:\n---------\n"); for (i = 0; i < clp->ngeometry; i++) { printf("isps2? %d\n", clp->geo[i].isps2); printf("%f %f\n", clp->geo[i].uv[0][0], clp->geo[i].uv[0][1]); printf("%f %f %f\n", clp->geo[i].vertex[0][0], clp->geo[i].vertex[0][1], clp->geo[i].vertex[0][2]); } }