// Converts GEOMETRY.BIN files from Need For Speed Underground into Wavefront OBJ #include <stdio.h>#include <stdlib.h>#include <string.h> #define DWORD_ALIGN(n) ((n) + 3) & ~3 typedef unsigned char u8;typedef unsigned int u32; typedef struct { u8 *data; int size;} Buffer; typedef struct { u32 unk1[9]; u32 n_faces; u32 unk2[3]; u32 n_points; u32 unk3[3];} Header; typedef struct { float x, y, z; float unk[4]; float u, v;} Point; typedef struct { short a, b, c;} Mapping; int write_obj(FILE *f, int vert_off, Buffer *header, Buffer *verts, Buffer *map) { if (!f || !header || !verts || !map || !header->data || !verts->data || !map->data) return -1; if (header->size < sizeof(Header)) return -2; Header *hdr = (Header*)(header->data + header->size - sizeof(Header)); int point_block = DWORD_ALIGN(hdr->n_points * sizeof(Point)); if (verts->size < point_block) return -3; int map_block = DWORD_ALIGN(hdr->n_faces * sizeof(Mapping)); if (map->size < map_block) return -4; Point *points = (Point*)(verts->data + verts->size - point_block); Mapping *faces = (Mapping*)(map->data + map->size - map_block); fprintf(f, "o Mesh.%d\n", vert_off); for (int i = 0; i < hdr->n_points; i++) fprintf(f, "v %g %g %g\n", points[i].x, points[i].y, points[i].z); for (int i = 0; i < hdr->n_points; i++) fprintf(f, "vt %g %g\n", points[i].u, points[i].v); fprintf(f, "s off\n"); for (int i = 0; i < hdr->n_faces; i++) { int a = faces[i].a + vert_off, b = faces[i].b + vert_off, c = faces[i].c + vert_off; fprintf(f, "f %d/%d %d/%d %d/%d\n", a, a, b, b, c, c); } return hdr->n_points;} inline void set_buffer(Buffer *b, u32 *file) { b->data = (u8*)&file[2]; b->size = file[1];} int main(int argc, char **argv) { if (argc != 3) { printf("Invalid arguments\n" "Usage: %s <input geometry bin> <output obj>\n", argv[0]); return 1; } FILE *f = fopen(argv[1], "rb"); if (!f) { printf("Could not open %s\n", argv[1]); return 2; } fseek(f, 0, SEEK_END); int sz = ftell(f); rewind(f); if (sz < 1) { printf("%s is empty\n", argv[1]); return 3; } u8 *buf = malloc(sz); fread(buf, 1, sz, f); fclose(f); f = fopen(argv[2], "w"); u32 off = 0; u32 parent_off = 0, parent_type = 0; Buffer header = {0}; Buffer points = {0}; Buffer faces = {0}; int vert_off = 1; while (off < sz) { off += 8; u32 *p = (u32*)(buf + off - 8); if (*p & 0x80000000) { parent_off = off - 8; parent_type = *p; header.data = points.data = faces.data = NULL; continue; } else off += p[1]; if (parent_type == 0x80134100) { switch (*p) { case 0x00134900: set_buffer(&header, p); break; case 0x00134B01: set_buffer(&points, p); break; case 0x00134B03: set_buffer(&faces, p); break; } if (header.data && points.data && faces.data) { int res = write_obj(f, vert_off, &header, &points, &faces); if (res < 0) printf("write_obj at %s.%#x failed (%d)\n", argv[1], parent_off, res); else vert_off += res; header.data = points.data = faces.data = NULL; } } } fclose(f); free(buf); return 0;}