#include #include #include #include #include #include #include #include "bsp.h" #include "pbsp.h" #include "../qcommon/sparc.h" #define SWAP16(x) \ big_endian ? \ ((short)( ( ((x) & 0xff00) >> 8 ) + ( ((x) & 0xff) << 8 ) )) \ : \ x; #define SWAP32(x) \ big_endian ? \ ((int)( ( ((x) & 0xff000000) >> 24) \ + ( ((x) & 0x00ff0000) >> 8 ) \ + ( ((x) & 0x0000ff00) << 8 ) \ + ( ((x) & 0x000000ff) << 24 ) )) \ : \ x; static float SWAPF(float x, bool big_endian) { int temp = SWAP32(*(int*)&x); return *(float*)&temp; } #define CHECKED_READ(BUFFER, SIZE, OFFSET) \ if (fseek(in, OFFSET, SEEK_SET) < 0 || \ !fread(BUFFER, SIZE, 1, in)) \ { \ fprintf(stderr, "Error reading BSP.\n"); \ assert(false); \ exit(-1); \ } #define CHECKED_WRITE(NAME, BUFFER, SIZE) \ { \ char fullname[256]; \ sprintf(fullname, "%s\\%s.%s", \ path, NAME, big_endian ? "mbe" : "mle"); \ FILE* out = fopen(fullname, "wb"); \ if (!out) \ { \ fprintf(stderr, "Error opening %s.\n", fullname); \ assert(false); \ exit(-1); \ } \ if (!fwrite(BUFFER, SIZE, 1, out)) \ { \ fprintf(stderr, "Error writing %s.\n", fullname); \ assert(false); \ exit(-1); \ } \ fclose(out); \ } static void convert_fogs(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(pdfog_t); if (num == 0) { return; } pdfog_t* fogs = new pdfog_t[num]; CHECKED_READ(fogs, lump.filelen, lump.fileofs); for (int i = 0; i < num; ++i) { fogs[i].brushNum = SWAP32(fogs[i].brushNum); fogs[i].visibleSide = SWAP32(fogs[i].visibleSide); } CHECKED_WRITE("fogs", fogs, lump.filelen); delete [] fogs; } static void convert_brushes(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dbrush_t); dbrush_t* in_brushes = new dbrush_t[num]; CHECKED_READ(in_brushes, lump.filelen, lump.fileofs); pdbrush_t* out_brushes = new pdbrush_t[num]; for (int i = 0; i < num; ++i) { assert(in_brushes[i].numSides >= 0 && in_brushes[i].numSides < 256); assert(in_brushes[i].shaderNum >= 0 && in_brushes[i].shaderNum < 65536); out_brushes[i].firstSide = SWAP32(in_brushes[i].firstSide); out_brushes[i].numSides = in_brushes[i].numSides; out_brushes[i].shaderNum = SWAP16((unsigned short)in_brushes[i].shaderNum); } int size = num * sizeof(pdbrush_t); CHECKED_WRITE("brushes", out_brushes, size); delete [] out_brushes; delete [] in_brushes; } static void convert_brushsides(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dbrushside_t); dbrushside_t* in_brushesides = new dbrushside_t[num]; CHECKED_READ(in_brushesides, lump.filelen, lump.fileofs); pdbrushside_t* out_brushesides = new pdbrushside_t[num]; for (int i = 0; i < num; ++i) { assert(in_brushesides[i].shaderNum >= 0 && in_brushesides[i].shaderNum < 256); out_brushesides[i].planeNum = SWAP32(in_brushesides[i].planeNum); out_brushesides[i].shaderNum = in_brushesides[i].shaderNum; } int size = num * sizeof(pdbrushside_t); CHECKED_WRITE("brushsides", out_brushesides, size); delete [] out_brushesides; delete [] in_brushesides; } static void convert_leafsurfaces(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(int); int* leafsurfaces = new int[num]; CHECKED_READ(leafsurfaces, lump.filelen, lump.fileofs); for (int i = 0; i < num; ++i) { leafsurfaces[i] = SWAP32(leafsurfaces[i]); } CHECKED_WRITE("leafsurfaces", leafsurfaces, lump.filelen); delete [] leafsurfaces; } static void convert_nodes(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dnode_t); dnode_t* in_nodes = new dnode_t[num]; CHECKED_READ(in_nodes, lump.filelen, lump.fileofs); pdnode_t* out_nodes = new pdnode_t[num]; for (int i = 0; i < num; ++i) { out_nodes[i].planeNum = SWAP32(in_nodes[i].planeNum); for (int j = 0; j < 2; ++j) { assert(in_nodes[i].children[j] > -32768 && in_nodes[i].children[j] < 32768); out_nodes[i].children[j] = SWAP16((short)in_nodes[i].children[j]); } for (int k = 0; k < 3; ++k) { assert(in_nodes[i].mins[k] > -32768 && in_nodes[i].mins[k] < 32768); out_nodes[i].mins[k] = SWAP16((short)in_nodes[i].mins[k]); assert(in_nodes[i].maxs[k] > -32768 && in_nodes[i].maxs[k] < 32768); out_nodes[i].maxs[k] = SWAP16((short)in_nodes[i].maxs[k]); } } int size = num * sizeof(pdnode_t); CHECKED_WRITE("nodes", out_nodes, size); delete [] out_nodes; delete [] in_nodes; } static void convert_leafs(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dleaf_t); dleaf_t* in_leafs = new dleaf_t[num]; CHECKED_READ(in_leafs, lump.filelen, lump.fileofs); pdleaf_t* out_leafs = new pdleaf_t[num]; for (int i = 0; i < num; ++i) { assert(in_leafs[i].cluster > -32768 && in_leafs[i].cluster < 32768); out_leafs[i].cluster = SWAP16((short)in_leafs[i].cluster); assert(in_leafs[i].area > -128 && in_leafs[i].area < 128); out_leafs[i].area = in_leafs[i].area; assert(in_leafs[i].firstLeafSurface >= 0 && in_leafs[i].firstLeafSurface < 65536); out_leafs[i].firstLeafSurface = SWAP16((short)in_leafs[i].firstLeafSurface); assert(in_leafs[i].numLeafSurfaces >= 0 && in_leafs[i].numLeafSurfaces < 65536); out_leafs[i].numLeafSurfaces = SWAP16((short)in_leafs[i].numLeafSurfaces); assert(in_leafs[i].firstLeafBrush >= 0 && in_leafs[i].firstLeafBrush < 65536); out_leafs[i].firstLeafBrush = SWAP16((short)in_leafs[i].firstLeafBrush); assert(in_leafs[i].numLeafBrushes >= 0 && in_leafs[i].numLeafBrushes < 65536); out_leafs[i].numLeafBrushes = SWAP16((short)in_leafs[i].numLeafBrushes); for (int k = 0; k < 3; ++k) { //assert(in_leafs[i].mins[k] > -32768 && in_leafs[i].mins[k] < 32768); out_leafs[i].mins[k] = SWAP16((short)in_leafs[i].mins[k]); //assert(in_leafs[i].maxs[k] > -32768 && in_leafs[i].maxs[k] < 32768); out_leafs[i].maxs[k] = SWAP16((short)in_leafs[i].maxs[k]); } } int size = num * sizeof(pdleaf_t); CHECKED_WRITE("leafs", out_leafs, size); delete [] out_leafs; delete [] in_leafs; } static void convert_models(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dmodel_t); if (num == 0) { return; } dmodel_t* in_models = new dmodel_t[num]; CHECKED_READ(in_models, lump.filelen, lump.fileofs); pdmodel_t* out_models = new pdmodel_t[num]; for (int i = 0; i < num; ++i) { out_models[i].firstSurface = SWAP32(in_models[i].firstSurface); assert(in_models[i].numSurfaces >= 0 && in_models[i].numSurfaces < 65536); out_models[i].numSurfaces = SWAP16((short)in_models[i].numSurfaces); out_models[i].firstBrush = SWAP32(in_models[i].firstBrush); assert(in_models[i].numBrushes >= 0 && in_models[i].numBrushes < 65536); out_models[i].numBrushes = SWAP16((short)in_models[i].numBrushes); for (int k = 0; k < 3; ++k) { out_models[i].mins[k] = SWAPF(in_models[i].mins[k], big_endian); out_models[i].maxs[k] = SWAPF(in_models[i].maxs[k], big_endian); } } int size = num * sizeof(pdmodel_t); CHECKED_WRITE("models", out_models, size); delete [] out_models; delete [] in_models; } static void convert_entities(const lump_t& lump, FILE* in, bool big_endian, const char* path) { if (lump.filelen == 0) { return; } char* entities = new char[lump.filelen]; CHECKED_READ(entities, lump.filelen, lump.fileofs); CHECKED_WRITE("entities", entities, lump.filelen); delete [] entities; } static void convert_lightgrid(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dgrid_t); if (num == 0) { return; } dgrid_t* in_grid = new dgrid_t[num]; CHECKED_READ(in_grid, lump.filelen, lump.fileofs); //figure out how much memory we really need. int memory = 0; int i, j; for(i=0; i= size); char* out_grid = new char[size]; char* data = out_grid + (sizeof(pdgrid_t) * num); //Copy data from old array into new array. memory = 0; for(i=0; ilatLong[0] = in_grid[i].latLong[0]; g->latLong[1] = in_grid[i].latLong[1]; g->flags = 0; g->data = SWAP32(sizeof(pdgrid_t) * num + memory); for(j=0; jflags |= 1 << (j + 4); } if( in_grid[i].ambientLight[j][0] != 0 || in_grid[i].ambientLight[j][1] != 0 || in_grid[i].ambientLight[j][2] != 0 || in_grid[i].directLight[j][0] != 0 || in_grid[i].directLight[j][1] != 0 || in_grid[i].directLight[j][2] != 0) { data[memory++] = in_grid[i].ambientLight[j][0]; data[memory++] = in_grid[i].ambientLight[j][1]; data[memory++] = in_grid[i].ambientLight[j][2]; data[memory++] = in_grid[i].directLight[j][0]; data[memory++] = in_grid[i].directLight[j][1]; data[memory++] = in_grid[i].directLight[j][2]; g->flags |= 1 << j; } } } CHECKED_WRITE("lightgrid", out_grid, size); delete [] out_grid; delete [] in_grid; } static void convert_lightarray(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(short); if (num == 0) { return; } short* lightarray = new short[num]; CHECKED_READ(lightarray, lump.filelen, lump.fileofs); for (int i = 0; i < num; ++i) { lightarray[i] = SWAP16(lightarray[i]); } CHECKED_WRITE("lightarray", lightarray, lump.filelen); delete [] lightarray; } static void convert_shaders(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(pdshader_t); if (num == 0) { return; } pdshader_t* shaders = new pdshader_t[num]; CHECKED_READ(shaders, lump.filelen, lump.fileofs); for (int i = 0; i < num; ++i) { shaders[i].surfaceFlags = SWAP32(shaders[i].surfaceFlags); shaders[i].contentFlags = SWAP32(shaders[i].contentFlags); } CHECKED_WRITE("shaders", shaders, lump.filelen); delete [] shaders; } static void convert_planes(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(pdplane_t); pdplane_t* planes = new pdplane_t[num]; CHECKED_READ(planes, lump.filelen, lump.fileofs); for (int i = 0; i < num; ++i) { planes[i].normal[0] = SWAPF(planes[i].normal[0], big_endian); planes[i].normal[1] = SWAPF(planes[i].normal[1], big_endian); planes[i].normal[2] = SWAPF(planes[i].normal[2], big_endian); planes[i].dist = SWAPF(planes[i].dist, big_endian); } CHECKED_WRITE("planes", planes, lump.filelen); delete [] planes; } static void convert_leafbrushes(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(int); int* leafbrushes = new int[num]; CHECKED_READ(leafbrushes, lump.filelen, lump.fileofs); for (int i = 0; i < num; ++i) { leafbrushes[i] = SWAP32(leafbrushes[i]); } CHECKED_WRITE("leafbrushes", leafbrushes, lump.filelen); delete [] leafbrushes; } static void convert_verts(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(mapVert_t); mapVert_t* in_verts = new mapVert_t[num]; CHECKED_READ(in_verts, lump.filelen, lump.fileofs); pmapVert_t* out_verts = new pmapVert_t[num]; for (int i = 0; i < num; ++i) { for (int j = 0; j < 3; ++j) { assert(in_verts[i].xyz[j] > -32768 && in_verts[i].xyz[j] < 32768); out_verts[i].xyz[j] = SWAP16((short)in_verts[i].xyz[j]); assert(in_verts[i].normal[j] >= -1 && in_verts[i].normal[j] <= 1); out_verts[i].normal[j] = SWAP16((short)(in_verts[i].normal[j] * 32767.f)); } for (int k = 0; k < 2; ++k) { out_verts[i].st[k] = SWAPF(in_verts[i].st[k], big_endian); } for (int m = 0; m < MAXLIGHTMAPS; ++m) { for (int n = 0; n < 2; ++n) { out_verts[i].lightmap[m][n] = SWAPF( (in_verts[i].lightmap[m][n] * POINTS_LIGHT_SCALE), big_endian); } for (int p = 0; p < 4; ++p) { out_verts[i].color[m][p] = in_verts[i].color[m][p]; } } } int size = num * sizeof(pmapVert_t); CHECKED_WRITE("verts", out_verts, size); delete [] out_verts; delete [] in_verts; } static void convert_indexes(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(int); int* in_indexes = new int[num]; CHECKED_READ(in_indexes, lump.filelen, lump.fileofs); short* out_indexes = new short[num]; for (int i = 0; i < num; ++i) { assert(in_indexes[i] > -32768 && in_indexes[i] < 32768); out_indexes[i] = SWAP16((short)in_indexes[i]); } int size = num * sizeof(short); CHECKED_WRITE("indexes", out_indexes, size); delete [] out_indexes; delete [] in_indexes; } static void scale_color(byte* dst, const byte* src, float factor) { byte hichan = 0; int hiindex = 0; for (int c = 0; c < 3; ++c) { if (hichan < src[c]) { hichan = src[c]; hiindex = c; } } float test = (float)src[hiindex] * factor; if (test > 255.f) test = 255.f; factor = test / (float)src[hiindex]; dst[0] = (byte)((float)src[2] * factor); dst[1] = (byte)((float)src[1] * factor); dst[2] = (byte)((float)src[0] * factor); } static void convert_lightmaps(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int in_map_size = LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3; int bmp_size = in_map_size + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); int num = lump.filelen / in_map_size; if (num == 0) { return; } unsigned char* in_lightmaps = new unsigned char[lump.filelen]; CHECKED_READ(in_lightmaps, lump.filelen, lump.fileofs); // Setup a BMP file for conversion char* bmp = new char[bmp_size]; BITMAPFILEHEADER* header = (BITMAPFILEHEADER*)bmp; ((char*)&header->bfType)[0] = 'B'; ((char*)&header->bfType)[1] = 'M'; header->bfSize = bmp_size; header->bfReserved1 = 0; header->bfReserved2 = 0; header->bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); BITMAPINFOHEADER* info = (BITMAPINFOHEADER*)(bmp + sizeof(BITMAPFILEHEADER)); info->biSize = sizeof(BITMAPINFOHEADER); info->biWidth = LIGHTMAP_SIZE; info->biHeight = LIGHTMAP_SIZE; info->biPlanes = 1; info->biBitCount = 24; info->biCompression = BI_RGB; info->biSizeImage = 0; info->biXPelsPerMeter = 1; info->biYPelsPerMeter = 1; info->biClrUsed = 0; info->biClrImportant = 0; // Open the lightmaps output file char fullname[256]; sprintf(fullname, "%s\\lightmaps.%s", path, big_endian ? "mbe" : "mle"); FILE* flightmaps = fopen(fullname, "wb"); if (!flightmaps) { fprintf(stderr, "Error opening %s.\n", fullname); assert(false); exit(-1); } // For each lightmap... for (int i = 0; i < num; ++i) { // Update the BMP unsigned char* in_map = in_lightmaps + i * in_map_size; for (int y = 0; y < LIGHTMAP_SIZE; ++y) { for (int x = 0; x < LIGHTMAP_SIZE; ++x) { byte* dst = (byte*)bmp + header->bfOffBits + ((LIGHTMAP_SIZE - y - 1) * LIGHTMAP_SIZE * 3) + x * 3; byte* src = (byte*)in_map + y * LIGHTMAP_SIZE * 3 + x * 3; scale_color(dst, src, big_endian ? 1.225f : 1.1f); } } FILE* fbmp = fopen("~temp.bmp", "wb"); if (!fbmp) { fprintf(stderr, "Error opening ~temp.bmp.\n"); assert(false); exit(-1); } fwrite(bmp, bmp_size, 1, fbmp); fclose(fbmp); char* out_map = NULL; int out_map_size = 0; /* if (big_endian) { // Use the "texconvpro" GC conversion tool to convert // ~temp.bmp to s3tc ~temp.out FILE* ftcs = fopen("~temp.tcs", "wt"); if (!ftcs) { fprintf(stderr, "Error opening ~temp.tcs.\n"); assert(false); exit(-1); } fprintf(ftcs, "path = 0\n"); fprintf(ftcs, "file 0 = ~temp.bmp\n"); fprintf(ftcs, "image 0 = 0, 0, RGB5A3, 0, 0, 0\n"); fprintf(ftcs, "texture 0 = 0, x\n"); fclose(ftcs); const char* cmdline = "texconvpro ~temp.tcs ~temp.tpl"; system(cmdline); rename("~temp.tpl", "~temp.out"); unlink("~temp.tcs"); } else */ { // Use the "nvdxt" conversion tool to convert // ~temp.bmp to s3tc ~temp.out const char* cmdline = "nvdxt -file ~temp.bmp -u565 -nomipmap"; system(cmdline); rename("~temp.dds", "~temp.out"); } // Read compressed ~temp.out FILE* fout = fopen("~temp.out", "rb"); if (!fout) { fprintf(stderr, "Error opening ~temp.out.\n"); assert(false); exit(-1); } fseek(fout, 0, SEEK_END); out_map_size = ftell(fout); fseek(fout, 0, SEEK_SET); out_map = new char[out_map_size]; fread(out_map, out_map_size, 1, fout); fclose(fout); unlink("~temp.out"); // Append compressed data to lightmaps if (i == 0) { int temp = SWAP32(out_map_size); fwrite(&temp, sizeof(temp), 1, flightmaps); } fwrite(out_map, out_map_size, 1, flightmaps); unlink("~temp.bmp"); } fclose(flightmaps); delete [] bmp; delete [] in_lightmaps; } static void convert_visibility(const lump_t& lump, FILE* in, bool big_endian, const char* path) { if(lump.filelen == 0) return; unsigned char* in_visibility = new unsigned char[lump.filelen]; CHECKED_READ(in_visibility, lump.filelen, lump.fileofs); char* out_visibility = new char[lump.filelen*2]; *((int*)out_visibility + 0) = SWAP32(*((int*)in_visibility + 0)); *((int*)out_visibility + 1) = SWAP32(*((int*)in_visibility + 1)); SPARC vis; vis.Compress(in_visibility + 8, lump.filelen - 8, 0); int size = vis.Save(out_visibility + 8, lump.filelen*2 - 8, big_endian) + 8; CHECKED_WRITE("visibility", out_visibility, size); delete [] out_visibility; delete [] in_visibility; } static void convert_faces(const lump_t& lump, FILE* in, bool big_endian, const char* path) { bool warning = false; int num = lump.filelen / sizeof(dsurface_t); if (num == 0) { return; } dsurface_t* in_surfaces = new dsurface_t[num]; CHECKED_READ(in_surfaces, lump.filelen, lump.fileofs); pdface_t* out_surfaces = new pdface_t[num]; int counter = 0; for (int i = 0; i < num; ++i) { if (in_surfaces[i].surfaceType == MST_PLANAR) { out_surfaces[counter].code = SWAP32(i); assert(in_surfaces[i].shaderNum >= 0 && in_surfaces[i].shaderNum < 256); out_surfaces[counter].shaderNum = in_surfaces[i].shaderNum; assert(in_surfaces[i].fogNum > -128 && in_surfaces[i].fogNum < 128); out_surfaces[counter].fogNum = in_surfaces[i].fogNum; assert(in_surfaces[i].firstVert >= 0 && in_surfaces[i].firstVert < 1048576); assert(in_surfaces[i].numVerts >= 0 && in_surfaces[i].numVerts < 4096); out_surfaces[counter].verts = SWAP32((in_surfaces[i].firstVert << 12) | (in_surfaces[i].numVerts & 0xfff)); assert(in_surfaces[i].firstIndex >= 0 && in_surfaces[i].firstIndex < 1048576); assert(in_surfaces[i].numIndexes >= 0 && in_surfaces[i].numIndexes < 4096); out_surfaces[counter].indexes = SWAP32((in_surfaces[i].firstIndex << 12) | (in_surfaces[i].numIndexes & 0xfff)); for (int j = 0; j < MAXLIGHTMAPS; ++j) { if (!warning && (in_surfaces[i].lightmapNum[j] < -4 || in_surfaces[i].lightmapNum[j] >= 252)) { printf("WARNING: Lightmap index out of range!\n"); warning = true; } out_surfaces[counter].lightmapNum[j] = in_surfaces[i].lightmapNum[j] + 4; if (in_surfaces[i].lightmapNum[0] == LIGHTMAP_BY_VERTEX) { out_surfaces[counter].lightmapStyles[j] = in_surfaces[i].vertexStyles[j]; } else { out_surfaces[counter].lightmapStyles[j] = in_surfaces[i].lightmapStyles[j]; } } for (int m = 0; m < 3; ++m) { assert(in_surfaces[i].lightmapVecs[2][m] >= -1 && in_surfaces[i].lightmapVecs[2][m] <= 1); out_surfaces[counter].lightmapVecs[m] = SWAP16((short)(in_surfaces[i].lightmapVecs[2][m] * 32767.f)); } ++counter; } } if (counter == 0) return; int size = counter * sizeof(pdface_t); CHECKED_WRITE("faces", out_surfaces, size); delete [] out_surfaces; delete [] in_surfaces; } static void convert_patches(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dsurface_t); if (num == 0) { return; } dsurface_t* in_surfaces = new dsurface_t[num]; CHECKED_READ(in_surfaces, lump.filelen, lump.fileofs); pdpatch_t* out_surfaces = new pdpatch_t[num]; int counter = 0; for (int i = 0; i < num; ++i) { if (in_surfaces[i].surfaceType == MST_PATCH) { out_surfaces[counter].code = SWAP32(i); assert(in_surfaces[i].shaderNum >= 0 && in_surfaces[i].shaderNum < 256); out_surfaces[counter].shaderNum = in_surfaces[i].shaderNum; assert(in_surfaces[i].fogNum > -128 && in_surfaces[i].fogNum < 128); out_surfaces[counter].fogNum = in_surfaces[i].fogNum; assert(in_surfaces[i].firstVert >= 0 && in_surfaces[i].firstVert < 1048576); assert(in_surfaces[i].numVerts >= 0 && in_surfaces[i].numVerts < 4096); out_surfaces[counter].verts = SWAP32((in_surfaces[i].firstVert << 12) | (in_surfaces[i].numVerts & 0xfff)); assert(in_surfaces[i].patchWidth >= 0 && in_surfaces[i].patchWidth < 256); out_surfaces[counter].patchWidth = in_surfaces[i].patchWidth; assert(in_surfaces[i].patchHeight >= 0 && in_surfaces[i].patchHeight < 256); out_surfaces[counter].patchHeight = in_surfaces[i].patchHeight; for (int j = 0; j < MAXLIGHTMAPS; ++j) { assert(in_surfaces[i].lightmapNum[j] >= -4 && in_surfaces[i].lightmapNum[j] < 252); out_surfaces[counter].lightmapNum[j] = in_surfaces[i].lightmapNum[j] + 4; if (in_surfaces[i].lightmapNum[0] == LIGHTMAP_BY_VERTEX) { out_surfaces[counter].lightmapStyles[j] = in_surfaces[i].vertexStyles[j]; } else { out_surfaces[counter].lightmapStyles[j] = in_surfaces[i].lightmapStyles[j]; } } for (int m = 0; m < 3; ++m) { for (int k = 0; k < 2; ++k) { assert(in_surfaces[i].lightmapVecs[k][m] > -32768.f && in_surfaces[i].lightmapVecs[k][m] < 32768.f); out_surfaces[counter].lightmapVecs[k][m] = SWAP16((short)in_surfaces[i].lightmapVecs[k][m]); } } ++counter; } } if (counter == 0) return; int size = counter * sizeof(pdpatch_t); CHECKED_WRITE("patches", out_surfaces, size); delete [] out_surfaces; delete [] in_surfaces; } static void convert_trisurfs(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dsurface_t); if (num == 0) { return; } dsurface_t* in_surfaces = new dsurface_t[num]; CHECKED_READ(in_surfaces, lump.filelen, lump.fileofs); pdtrisurf_t* out_surfaces = new pdtrisurf_t[num]; int counter = 0; for (int i = 0; i < num; ++i) { if (in_surfaces[i].surfaceType == MST_TRIANGLE_SOUP) { out_surfaces[counter].code = SWAP32(i); assert(in_surfaces[i].shaderNum >= 0 && in_surfaces[i].shaderNum < 256); out_surfaces[counter].shaderNum = in_surfaces[i].shaderNum; assert(in_surfaces[i].fogNum > -128 && in_surfaces[i].fogNum < 128); out_surfaces[counter].fogNum = in_surfaces[i].fogNum; assert(in_surfaces[i].firstVert >= 0 && in_surfaces[i].firstVert < 1048576); assert(in_surfaces[i].numVerts >= 0 && in_surfaces[i].numVerts < 4096); out_surfaces[counter].verts = SWAP32((in_surfaces[i].firstVert << 12) | (in_surfaces[i].numVerts & 0xfff)); assert(in_surfaces[i].firstIndex >= 0 && in_surfaces[i].firstIndex < 1048576); assert(in_surfaces[i].numIndexes >= 0 && in_surfaces[i].numIndexes < 4096); out_surfaces[counter].indexes = SWAP32((in_surfaces[i].firstIndex << 12) | (in_surfaces[i].numIndexes & 0xfff)); for (int j = 0; j < MAXLIGHTMAPS; ++j) { if (in_surfaces[i].lightmapNum[0] == LIGHTMAP_BY_VERTEX) { out_surfaces[counter].lightmapStyles[j] = in_surfaces[i].vertexStyles[j]; } else { out_surfaces[counter].lightmapStyles[j] = in_surfaces[i].lightmapStyles[j]; } } ++counter; } } if (counter == 0) return; int size = counter * sizeof(pdtrisurf_t); CHECKED_WRITE("trisurfs", out_surfaces, size); delete [] out_surfaces; delete [] in_surfaces; } static void convert_flares(const lump_t& lump, FILE* in, bool big_endian, const char* path) { int num = lump.filelen / sizeof(dsurface_t); if (num == 0) { return; } dsurface_t* in_surfaces = new dsurface_t[num]; CHECKED_READ(in_surfaces, lump.filelen, lump.fileofs); pdflare_t* out_surfaces = new pdflare_t[num]; int counter = 0; for (int i = 0; i < num; ++i) { if (in_surfaces[i].surfaceType == MST_FLARE) { out_surfaces[counter].code = SWAP32(i); assert(in_surfaces[i].shaderNum >= 0 && in_surfaces[i].shaderNum < 256); out_surfaces[counter].shaderNum = in_surfaces[i].shaderNum; assert(in_surfaces[i].fogNum > -128 && in_surfaces[i].fogNum < 128); out_surfaces[counter].fogNum = in_surfaces[i].fogNum; for (int j = 0; j < 3; ++j) { assert(in_surfaces[i].lightmapOrigin[j] > -32768 && in_surfaces[i].lightmapOrigin[j] < 32768); out_surfaces[counter].origin[j] = SWAP16((short)in_surfaces[i].lightmapOrigin[j]); assert(in_surfaces[i].lightmapVecs[2][j] >= -1 && in_surfaces[i].lightmapVecs[2][j] <= 1); out_surfaces[counter].normal[j] = SWAP16((short)(in_surfaces[i].lightmapVecs[2][j] * 32767.f)); out_surfaces[counter].color[j] = (byte)(in_surfaces[i].lightmapVecs[0][j]); } ++counter; } } if (counter == 0) return; int size = counter * sizeof(pdflare_t); CHECKED_WRITE("flares", out_surfaces, size); delete [] out_surfaces; delete [] in_surfaces; } static void convert_surfaces(const lump_t& lump, FILE* in, bool big_endian, const char* path) { convert_faces(lump, in, big_endian, path); convert_patches(lump, in, big_endian, path); convert_trisurfs(lump, in, big_endian, path); convert_flares(lump, in, big_endian, path); } typedef void (*convertfunc_t)(const lump_t& lump, FILE* in, bool big_endian, const char* path); static convertfunc_t Converters[HEADER_LUMPS] = { convert_entities, convert_shaders, convert_planes, convert_nodes, convert_leafs, convert_leafsurfaces, convert_leafbrushes, convert_models, convert_brushes, convert_brushsides, convert_verts, convert_indexes, convert_fogs, convert_surfaces, convert_lightmaps, convert_lightgrid, convert_visibility, convert_lightarray, }; static void write_misc(const dheader_t& header, FILE* in, bool big_endian, const char* path) { int num = header.lumps[LUMP_SURFACES].filelen / sizeof(dsurface_t); num = SWAP32(num); CHECKED_WRITE("misc", &num, sizeof(int)); } /*static void optimize_lightmaps(const dheader_t* header, FILE* in) { // get the vert data int num_verts = header->lumps[LUMP_DRAWVERTS].filelen / sizeof(mapVert_t); mapVert_t* verts = new mapVert_t[num_verts]; CHECKED_READ(verts, header->lumps[LUMP_DRAWVERTS].filelen, header->lumps[LUMP_DRAWVERTS].fileofs); // get the surface data int num_surfs = header->lumps[LUMP_SURFACES].filelen / sizeof(dsurface_t); dsurface_t* surfs = new dsurface_t[num_surfs]; CHECKED_READ(surfs, header->lumps[LUMP_SURFACES].filelen, header->lumps[LUMP_SURFACES].fileofs); // get the lightmap data const int map_size = LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3; int num_lightmaps = header->lumps[LUMP_LIGHTMAPS].filelen / map_size; byte* lightmaps = new byte[header->lumps[LUMP_LIGHTMAPS].filelen]; CHECKED_READ(lightmaps, header->lumps[LUMP_LIGHTMAPS].filelen, header->lumps[LUMP_LIGHTMAPS].fileofs); LMOptimizer optimizer; optimizer.optimize(verts, num_verts, surfs, num_surfs, lightmaps, num_lightmaps); }*/ static void process(const char* name, bool big_endian) { // open the bsp FILE* in = fopen(name, "rb"); if (!in) { fprintf(stderr, "Unable to open %s\n", name); exit(-1); } // get the new path name char* path = new char[strlen(name) + 1]; strcpy(path, name); path[strlen(path) - 4] = '\0'; mkdir(path); dheader_t in_header; fread(&in_header, sizeof(in_header), 1, in); for (int i = 0; i < HEADER_LUMPS; ++i) { Converters[i](in_header.lumps[i], in, big_endian, path); } write_misc(in_header, in, big_endian, path); delete [] path; fclose(in); } int main(int argc, const char** argv) { // check command line if (argc != 2) { fprintf(stderr, "USAGE: %s PATH\n", argv[0]); return -1; } // find all the BSP files in the path char spec[256]; strcpy(spec, argv[1]); strcat(spec, "\\*.bsp"); _finddata_t data; int h = _findfirst(spec, &data); while (h != -1) { printf("Processing %s...\n", data.name); char name[256]; sprintf(name, "%s\\%s", argv[1], data.name); process(name, false); if (_findnext(h, &data)) break; } _findclose(h); return 0; }