#include #include typedef struct atomic { unsigned int frameindex; unsigned int geometryindex; } atomic; typedef struct split { unsigned int indexcount; unsigned int matindex; unsigned int *indices; /* not used */ /* Vice City Stuff */ int splitpartcount; int *spltvc; float ***vertices; float ***uv; unsigned char ***vc; unsigned char ***normals; } split; typedef struct texture { unsigned short filterflags; char *tex; char *alpha; } texture; typedef struct material { char color[4]; unsigned int texcount; texture *tex; } material; typedef struct geometry { unsigned short flags; unsigned short nuv; unsigned int facec; unsigned int vertexc; unsigned int framec; float ambient; float diffuse; float specular; unsigned char **vcolors; float **uvcoords; unsigned short **faces; float **vertices; float **normals; unsigned int matcount; material *mat; unsigned int bmfacetype; unsigned int bmsplitcount; unsigned int bmindexcount; split *splt; /* Probably noy used */ int nextgeo; int facecnt, vertexcnt, splitcount, indexcount; short vflag; } geometry; typedef struct frame { float rotmatrix[3] [3]; float pos[3]; int parent; char *name; int display; } frame; typedef struct clump { unsigned int objcount; atomic *atm; unsigned int frmcount; frame *frm; unsigned int geocount; geometry *geo; } clump; typedef struct rwheader { unsigned int type; unsigned int size; unsigned int version; } rwheader; typedef struct coordinate { float x; float y; float z; } coordinate; rwheader skipheader(FILE *rw) { rwheader rwh; fread(&rwh, 4, 3, rw); return rwh; } int issamevert(float *vert0, float *vert1) { if (vert0[0] == vert1[0] && vert0[1] == vert1[1] && vert0[2] == vert1[2]) { return 1; } else return 0; } void gettotalpos(frame *frm, int i, coordinate *bias) { if (frm[i].parent == -1) { bias->x += frm[i].pos[0]; bias->y += frm[i].pos[1]; bias->z += frm[i].pos[2]; return; } bias->x += frm[i].pos[0]; bias->y += frm[i].pos[1]; bias->z += frm[i].pos[2]; gettotalpos(frm, frm[i].parent, bias); } int main(int argc, char *argv[]) { int i, j, k, l, m, n, faceinc; int splitend; int isnotactor; int end; int islast; rwheader rwh; int rwvers; FILE *dff, *obj, *log; clump clp; geometry geo; coordinate bias; int subsecthdr; /* Used for VC */ int geocnt; int blocksize, nextblock, unk; short comp_vert[4]; /* Used for SA */ if (argc < 3) { printf("Usage: %s dff obj\n", argv[0]); exit(1); } if ((dff = fopen(argv[1], "rb")) == NULL) { printf("Couldn't open file: %s\n", argv[1]); exit(1); } if ((obj = fopen(argv[2], "wb")) == NULL) { printf("Couldn't open file: %s\n", argv[2]); exit(1); } if ((log = fopen("log.txt", "wb")) == NULL) { printf("Couldn't open file: %s\n", argv[2]); exit(1); } rwh = skipheader(dff); /* Clump */ rwvers = rwh.version; skipheader(dff); /* Struct */ fread(&clp.objcount, 4, 1, dff); if (rwvers != 0x310) fseek(dff, 8, SEEK_CUR); /**/ /* Frames */ /**/ skipheader(dff); /* Frame List */ skipheader(dff); /* Frame data */ /* Read Rotation Martrix, position and parentframt */ fread(&clp.frmcount, 4, 1, dff); clp.frm = (frame *) malloc(clp.frmcount*sizeof(frame)); for (i = 0; i < clp.frmcount; i++) { /* Read Struct */ fread(&clp.frm[i].rotmatrix, 4, 9, dff); fread(&clp.frm[i].pos, 4, 3, dff); fread(&clp.frm[i].parent, 4, 1, dff); fseek(dff, 4, SEEK_CUR); } /* Read names */ for (i = 0; i < clp.frmcount; i++) { rwh = skipheader(dff); j = rwh.size + ftell(dff); rwh = skipheader(dff); if (rwh.type == 0x11E) { fseek(dff, rwh.size, SEEK_CUR); rwh = skipheader(dff); } clp.frm[i].name = (char *) malloc(rwh.size+1); fread(clp.frm[i].name, rwh.size, 1, dff); clp.frm[i].name[rwh.size] = '\0'; fseek(dff, j, 0); /* Skip hanim PLG if there is one */ //printf("Should object %s be displayed?\n", clp.frm[i].name); //scanf("%d", &clp.frm[i].display); //getchar(); } /* Frame data end */ /**/ /* Geometry */ /**/ skipheader(dff); skipheader(dff); fread(&clp.geocount, 4, 1, dff); clp.geo = (geometry *) malloc(clp.geocount*sizeof(geometry)); for (j = 0; j < clp.geocount; j++) { rwh = skipheader(dff); clp.geo[j].nextgeo = rwh.size + ftell(dff); /* geometry struct - nearly empty in ps2 version */ skipheader(dff); fread(&clp.geo[j].flags, 2, 1, dff); fread(&clp.geo[j].nuv, 2, 1, dff); fread(&clp.geo[j].facec, 4, 1, dff); fread(&clp.geo[j].vertexc, 4, 1, dff); fread(&clp.geo[j].framec, 4, 1, dff); if ((rwvers == 0x0C02FFF || rwvers == 0x310) == 0) { fread(&clp.geo[j].ambient, 4, 1, dff); fread(&clp.geo[j].diffuse, 4, 1, dff); fread(&clp.geo[j].specular, 4, 1, dff); } fseek(dff, 24, SEEK_CUR); /* skip bounding sphere */ /* Material List */ skipheader(dff); skipheader(dff); /* Struct */ fread(&clp.geo[j].matcount, 4, 1, dff); fseek(dff, 4*clp.geo[j].matcount, SEEK_CUR); clp.geo[j].mat = (material *) malloc(clp.geo[j].matcount*sizeof(material)); /* Loop through Materials */ for (k = 0; k < clp.geo[j].matcount; k++) { skipheader(dff); skipheader(dff); fseek(dff, 4, SEEK_CUR); fread(&clp.geo[j].mat[k].color, 1, 4, dff); fseek(dff, 4, SEEK_CUR); fread(&clp.geo[j].mat[k].texcount, 1, 4, dff); clp.geo[j].mat[k].tex = (texture *) malloc(clp.geo[j].mat[k].texcount*sizeof(texture)); fseek(dff, 12, SEEK_CUR); /* Loop through Textures */ for (l = 0; l < clp.geo[j].mat[k].texcount; l++) { rwh = skipheader(dff); skipheader(dff); fread(&clp.geo[j].mat[k].tex[l].filterflags, 2, 1, dff); fseek(dff, 2, SEEK_CUR); rwh = skipheader(dff); clp.geo[j].mat[k].tex[l].tex = (char *) malloc(rwh.size+1); fread(clp.geo[j].mat[k].tex[l].tex, rwh.size, 1, dff); clp.geo[j].mat[k].tex[l].tex[rwh.size] = '\0'; rwh = skipheader(dff); clp.geo[j].mat[k].tex[l].alpha = (char *) malloc(rwh.size+1); fread(clp.geo[j].mat[k].tex[l].alpha, rwh.size, 1, dff); clp.geo[j].mat[k].tex[l].alpha[rwh.size] ='\0'; rwh = skipheader(dff); fseek(dff, rwh.size, SEEK_CUR); } rwh = skipheader(dff); fseek(dff, rwh.size, SEEK_CUR); } rwh = skipheader(dff); end = rwh.size + ftell(dff); /* Bin Mesh PLG */ skipheader(dff); fread(&clp.geo[j].bmfacetype, 4, 1, dff); fread(&clp.geo[j].bmsplitcount, 4, 1, dff); fread(&clp.geo[j].bmindexcount, 4, 1, dff); clp.geo[j].splt = (split *) malloc(clp.geo[j].bmsplitcount*sizeof(split)); /* Loop through Splits, no Indices like PC, only vertexcount and material */ for (i = 0; i < clp.geo[j].bmsplitcount; i++) { fread(&clp.geo[j].splt[i].indexcount, 4, 1, dff); fread(&clp.geo[j].splt[i].matindex, 4, 1, dff); } /* Native Data PLG */ rwh = skipheader(dff); skipheader(dff); /* Struct - broken header */ /**/ /* Native Data PLG Struct */ /**/ fprintf(log, "Native Data Struct: %X\n", ftell(dff)); fseek(dff, 4, SEEK_CUR); /* Skip 40 00 00 00 */ fprintf(log, "%d\n", clp.geo[j].bmsplitcount); for (i = 0; i < clp.geo[j].bmsplitcount; i++) { fread(&blocksize, 4, 1, dff); /* splitsize */ nextblock = blocksize + ftell(dff) + 4; fread(&isnotactor, 4, 1, dff); if (isnotactor) fseek(dff, 16, SEEK_CUR); clp.geo[j].splt[i].vertices = (float ***) malloc(4); clp.geo[j].splt[i].uv = (float ***) malloc(4); clp.geo[j].splt[i].vc = (unsigned char ***) malloc(4); clp.geo[j].splt[i].normals = (unsigned char ***) malloc(4); clp.geo[j].splt[i].spltvc = (int *) malloc(4); /* loop through splitparts */ for (l = 0, islast = 0; !islast; l++) { clp.geo[j].splt[i].vertices = (float ***) realloc(clp.geo[j].splt[i].vertices, (l+1)*4); clp.geo[j].splt[i].uv = (float ***) realloc(clp.geo[j].splt[i].uv, (l+1)*4); clp.geo[j].splt[i].vc = (unsigned char ***) realloc(clp.geo[j].splt[i].vc, (l+1)*4); clp.geo[j].splt[i].normals = (unsigned char ***) realloc(clp.geo[j].splt[i].normals, (l+1)*4); clp.geo[j].splt[i].spltvc = (int *) realloc(clp.geo[j].splt[i].spltvc, (l+1)*4); if (!isnotactor) /* is actor */ fseek(dff, 48, SEEK_CUR); /* */ /* Vertices */ /* */ /* get vertexcount in format: 00 80 vertexcount 68 */ fprintf(log, "Vertexheader at: %X\n", ftell(dff)); fseek(dff, 12, SEEK_CUR); fread(&subsecthdr, 4, 1, dff); if ((subsecthdr & 0xff00ffff) != 0x68008000) { printf("Vertexsection expected, exiting\n"); exit(1); } clp.geo[j].splt[i].spltvc[l] = (subsecthdr & 0x00ff0000) >> 16; /* read Vertices */ clp.geo[j].splt[i].vertices[l] = (float **) malloc(clp.geo[j].splt[i].spltvc[l]*4); for (k = 0; k < clp.geo[j].splt[i].spltvc[l]; k++) { clp.geo[j].splt[i].vertices[l] [k] = (float *) malloc(12); fread(&clp.geo[j].splt[i].vertices[l] [k] [0], 4, 1, dff); fread(&clp.geo[j].splt[i].vertices[l] [k] [1], 4, 1, dff); fread(&clp.geo[j].splt[i].vertices[l] [k] [2], 4, 1, dff); } if ((clp.geo[j].splt[i].spltvc[l]*12 % 16) != 0) fseek(dff, 16 - (clp.geo[j].splt[i].spltvc[l]*12 % 16), SEEK_CUR); /* skip padding */ /* */ /* UV Coordinates */ /* */ /* get vertexcount in format: 01 80 vertexcount 64 */ fprintf(log, "UV header at: %X\n", ftell(dff)); fseek(dff, 12, SEEK_CUR); fread(&subsecthdr, 4, 1, dff); if ((subsecthdr & 0xff00ffff) != 0x64008001) { printf("UVsection expected, exiting\n"); exit(1); } clp.geo[j].splt[i].spltvc[l] = (subsecthdr & 0x00ff0000) >> 16; /* read UV Coordinates - possibly incorrect*/ clp.geo[j].splt[i].uv[l] = (float **) malloc(clp.geo[j].splt[i].spltvc[l]*4); for (k = 0; k < clp.geo[j].splt[i].spltvc[l]; k++) { clp.geo[j].splt[i].uv[l] [k] = (float *) malloc(8); fread(&clp.geo[j].splt[i].uv[l] [k] [0], 4, 1, dff); fread(&clp.geo[j].splt[i].uv[l] [k] [1], 4, 1, dff); } if ((clp.geo[j].splt[i].spltvc[l]*8 % 16) != 0) fseek(dff, 16 - (clp.geo[j].splt[i].spltvc[l]*8 % 16), SEEK_CUR); /* skip padding */ /* */ /* Vertexcolors */ /* */ /* get vertexcount in format: 02 C0 vertexcount 6E */ fprintf(log, "Vertexcolor header at: %X\n", ftell(dff)); fseek(dff, 12, SEEK_CUR); fread(&subsecthdr, 4, 1, dff); if ((subsecthdr & 0xff00ffff) != 0x6E00C002) { printf("Vertexcolorsection expected, exiting\n"); exit(1); } clp.geo[j].splt[i].spltvc[l] = (subsecthdr & 0x00ff0000) >> 16; /* read Vertexcolors */ clp.geo[j].splt[i].vc[l] = (unsigned char **) malloc(clp.geo[j].splt[i].spltvc[l]*4); for (k = 0; k < clp.geo[j].splt[i].spltvc[l]; k++) { clp.geo[j].splt[i].vc[l] [k] = (unsigned char *) malloc(4); fread(&clp.geo[j].splt[i].vc[l] [k] [0], 1, 4, dff); } if ((clp.geo[j].splt[i].spltvc[l]*4 % 16) != 0) fseek(dff, 16 - (clp.geo[j].splt[i].spltvc[l]*4 % 16), SEEK_CUR); /* skip padding */ /* */ /* Normals */ /* */ /* get vertexcount in format: 03 80 vertexcount 6A */ fprintf(log, "Normal header at:%X\n", ftell(dff)); fseek(dff, 12, SEEK_CUR); fread(&subsecthdr, 4, 1, dff); if ((subsecthdr & 0xff00ffff) != 0x6A008003) { printf("Normalsection expected, exiting\n"); exit(1); } clp.geo[j].splt[i].spltvc[l] = (subsecthdr & 0x00ff0000) >> 16; /* read Normals */ clp.geo[j].splt[i].normals[l] = (unsigned char **) malloc(clp.geo[j].splt[i].spltvc[l]*4); for (k = 0; k < clp.geo[j].splt[i].spltvc[l]; k++) { clp.geo[j].splt[i].normals[l] [k] = (unsigned char *) malloc(3); fread(&clp.geo[j].splt[i].normals[l] [k] [0], 1, 3, dff); } fprintf(log, "%X\n", clp.geo[j].splt[i].spltvc[l]); if ((clp.geo[j].splt[i].spltvc[l]*3 % 16) != 0) fseek(dff, 16 - (clp.geo[j].splt[i].spltvc[l]*3 % 16), SEEK_CUR); /* skip padding */ /* skip end of splitpart, but read, if this splitpart was the last */ fseek(dff, 8, SEEK_CUR); fread(&islast, 4, 1, dff); if (islast == 0x11000000) islast = 1; else islast = 0; fseek(dff, 4, SEEK_CUR); fprintf(log, "Split end: %d\n\n", islast); } clp.geo[j].splt[i].splitpartcount = l; /* remember splitpartcount */ fseek(dff, nextblock, 0); /* Jump to next Split and skip unknowns */ } fseek(dff, clp.geo[j].nextgeo, 0); /* Jump to next Geometry */ } clp.atm = (atomic *) malloc(clp.objcount*sizeof(atomic)); /* Loop through Atomics */ for (i = 0; i < clp.objcount; i++) { rwh = skipheader(dff); skipheader(dff); fread(&clp.atm[i].frameindex, 4, 1, dff); fread(&clp.atm[i].geometryindex, 4, 1, dff); fseek(dff, rwh.size-20, SEEK_CUR); } /* Write the obj File */ faceinc = 0; /* Used to increment Face indices for each splitpart and split */ bias.x = 0; bias.y = 0; bias.z = 0; for (m = 0; m < clp.objcount; m++) { k = clp.atm[m].geometryindex; n = clp.atm[m].frameindex; //if (clp.frm[n].display == 0) // continue; gettotalpos(clp.frm, n, &bias); fprintf(obj, "g %s\n", clp.frm[n].name); for (i = 0; i < clp.geo[k].bmsplitcount; i++) { for (l = 0; l < clp.geo[k].splt[i].splitpartcount; l++) { /* print out every vertex */ for (j = 0; j < clp.geo[k].splt[i].spltvc[l]; j++) { fprintf(obj, "v %f %f %f\n", clp.geo[k].splt[i].vertices[l] [j] [0] + bias.x, clp.geo[k].splt[i].vertices[l] [j] [1] + bias.y, clp.geo[k].splt[i].vertices[l] [j] [2] + bias.z); } for (j = 0; j < clp.geo[k].splt[i].spltvc[l]; j++) { fprintf(obj, "vt %f %f\n", (clp.geo[k].splt[i].uv[l] [j] [0]) * -1, clp.geo[k].splt[i].vertices[l] [j] [1]); } for (j = 0; j < clp.geo[k].splt[i].spltvc[l]; j++) { fprintf(obj, "vn %f %f %f\n", (float) clp.geo[k].splt[i].normals[l] [j] [0] / 127, (float) clp.geo[k].splt[i].normals[l] [j] [1] / 127, (float) clp.geo[k].splt[i].normals[l] [j] [2]/ 127); } /* print out every face */ for (j = 2; j < clp.geo[k].splt[i].spltvc[l]; j++) { /* check if vertexstrip ends to begin new one */ if (issamevert(clp.geo[k].splt[i].vertices[l] [j-2], clp.geo[k].splt[i].vertices[l] [j]) || issamevert(clp.geo[k].splt[i].vertices[l] [j-2], clp.geo[k].splt[i].vertices[l] [j-1]) || issamevert(clp.geo[k].splt[i].vertices[l] [j-1], clp.geo[k].splt[i].vertices[l] [j])) { continue; } if ((j % 2) == 0) fprintf(obj, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", j-1+faceinc, j-1+faceinc, j-1+faceinc, j+faceinc, j+faceinc, j+faceinc, j+1+faceinc, j+1+faceinc, j+1+faceinc); else fprintf(obj, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", j+1+faceinc, j+1+faceinc, j+1+faceinc, j+faceinc, j+faceinc, j+faceinc, j-1+faceinc, j-1+faceinc, j-1+faceinc); } faceinc += clp.geo[k].splt[i].spltvc[l]; } } bias.x = 0; bias.y = 0; bias.z = 0; } return 0; }