From 07d96af39cab4ffad0dab18a77209b7283957422 Mon Sep 17 00:00:00 2001 From: supadupaplex Date: Mon, 15 Mar 2021 01:15:20 +0700 Subject: [PATCH] added various fixes for BSP>BS2 conversion --- README.md | 40 ++++++++++ bs2pc.c | 92 +++++++++++++++++++++- bs2pc.h | 9 +++ bs2pc_lumps.h | 2 + bs2pc_map.c | 207 ++++++++++++++++++++++++++++++++++++++++--------- bs2pc_subdiv.c | 9 ++- bs2pc_util.c | 14 ++++ bs2pc_wad.c | 34 +++++++- 8 files changed, 361 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 9ce44ea..1363989 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,43 @@ +BS2PC PS2 fix by Supadupaplex +============================= + +This version of BS2PC contains various fixes/hacks for bsp to bs2 map conversion +that I made throughout 2017-2019 with some additional tweaks and new stuff +(I hope I didn't break anything when I was putting this thing together). + +Fixes list: +1. increased subdivisions and vertices count caps +2. qsort WAD lumps: fix crashing on some WADs +3. slow texture lump iteration: fix animated textures +4. prefer WAD texture sizes over sizes stored in bsp: scaling artifacts can + be avoided if WAD textures are manually resized to match power of 2 +5. calculate bs2 texture lump size based on WAD texture sizes +6. added options: -nomerge, -szreport, -wadonly +7. give warning if bs2 map file is too big +8. added options: -noresize, -dryrun +9. fixed '{' textures brightness + +[Latest builds](https://github.com/supadupaplex/BS2PC/releases) + + + Usage: bs2pc [-game \"path to base WAD directory for .bsp to .bs2\"] + [-game \"path to mod WAD directory\"] \"source file\" [\"target file\"] + [-nomerge] [-szreport] [-wadonly] [-noresize] [-dryrun] + -nomerge - [bsp to bs2] skip BS2PC_MergeStrips func, suggested by Triang3l: + \"this function is unfinished. In this state it can bring + performance boost but it also can cause glitches on water + and transparent surfaces\" + -szreport - [bsp to bs2] report map file lump sizes + -wadonly - [all] load textures from WAD files only, ignore textures stored + directly in bsp/bs2 files + -noresize - [bs2 to bsp] skip resizing textures - (!) breaks maps, useful + for PS2 texture harvesting only + -dryrun - [all] skip write to output file (might be useful for + troubleshooting or lump sizes inspection) + + +Original readme: + BS2PC ===== diff --git a/bs2pc.c b/bs2pc.c index c0a6d67..aa8662a 100644 --- a/bs2pc.c +++ b/bs2pc.c @@ -1,3 +1,5 @@ +#pragma warning(disable : 4996) + /* Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 2017 Triang3l @@ -28,6 +30,47 @@ extern const char *build_info; #include #include +bool bs2pc_errors = false; + +// [SDP] fix #6: config +bool bs2pc_doMergeStrips = true; +bool bs2pc_szReport = false; +bool bs2pc_wadOnly = false; +bool bs2pc_noResize = false; +bool bs2pc_dryRun = false; + +#define INFO_STR "\ +\n\ +=== .bsp to .bs2 conversion fix by Supadupaplex ===\n\ +\n\ +Fixes list:\n\ +1. increased subdivisions and vertices count caps\n\ +2. qsort WAD lumps: fix crashing on some WADs\n\ +3. slow texture lump iteration: fix animated textures\n\ +4. prefer WAD texture sizes over sizes stored in bsp: scaling artifacts can\n\ + be avoided if WAD textures are manually resized to match power of 2\n\ +5. calculate bs2 texture lump size based on WAD texture sizes\n\ +6. added options: -nomerge, -szreport, -wadonly\n\ +7. give warning if bs2 map file is too big\n\ +8. added options: -noresize, -dryrun\n\ +9. fixed '{' textures brightness\n\ +\n\ +Usage: bs2pc [-game \"path to base WAD directory for .bsp to .bs2\"]\n\ + [-game \"path to mod WAD directory\"] \"source file\" [\"target file\"]\n\ + [-nomerge] [-szreport] [-wadonly] [-noresize] [-dryrun]\n\ +-nomerge - [bsp to bs2] skip BS2PC_MergeStrips func, suggested by Triang3l:\n\ + \"this function is unfinished. In this state it can bring\n\ + performance boost but it also can cause glitches on water\n\ + and transparent surfaces\"\n\ +-szreport - [bsp to bs2] report map file lump sizes\n\ +-wadonly - [all] load textures from WAD files only, ignore textures stored\n\ + directly in bsp/bs2 files\n\ +-noresize - [bs2 to bsp] skip resizing textures - (!) breaks maps, useful\n\ + for PS2 texture harvesting only\n\ +-dryrun - [all] skip write to output file (might be useful for\n\ + troubleshooting or lump sizes inspection)\n\ +" + int main(int argc, const char * const *argv) { int argi; bool parsingGame = false; @@ -48,6 +91,34 @@ int main(int argc, const char * const *argv) { } else { if (bs2pc_strcasecmp(arg, "-game") == 0) { parsingGame = true; + } else if (bs2pc_strcasecmp(arg, "-nomerge") == 0) { + /* [SDP] fix #6: skip BS2PC_MergeStrips() function call as + * it was suggested by Triang3l + */ + bs2pc_doMergeStrips = false; + fputs("> Strip merging is disabled\n", stderr); + } + else if (bs2pc_strcasecmp(arg, "-szreport") == 0) { + // [SDP] fix #6: report lump sizes + bs2pc_szReport = true; + fputs("> Lump sizes report enabled\n", stderr); + } else if (bs2pc_strcasecmp(arg, "-wadonly") == 0) { + // [SDP] fix #6: ignore textures baked in the map file + bs2pc_wadOnly = true; + fputs("> Forced WAD textures\n", stderr); + } else if (bs2pc_strcasecmp(arg, "-noresize") == 0) { + /* [SDP] fix #8: don't resize textures when converting + * bs2 to bsp (useful for PS2 texture harvesting only) + */ + bs2pc_noResize = true; + fputs("> Skip texture resize\n", stderr); + } else if (bs2pc_strcasecmp(arg, "-dryrun") == 0) { + // [SDP] fix #8: dry run + bs2pc_dryRun = true; + fputs("> Skip write to output file\n", stderr); + } else if (arg[0] == '-') { + fprintf(stderr, "> Bad argument: %s\n", arg); + exit(EXIT_FAILURE); } else if (targetFileName == NULL) { if (sourceFileName != NULL) { targetFileName = arg; @@ -58,11 +129,11 @@ int main(int argc, const char * const *argv) { } } if (sourceFileName == NULL) { - fputs("Usage: [-game \"path to base WAD directory for .bsp to .bs2\"] [-game \"path to mod WAD directory\"] \"source file name\" [\"target file name\"].\n", stderr); - return EXIT_SUCCESS; + fputs(INFO_STR, stderr); + return EXIT_FAILURE; } - fputs("Loading the source file...\n", stderr); + fprintf(stderr, "Loading the source file: %s\n", sourceFileName); sourceFile = (unsigned char *) BS2PC_LoadFile(sourceFileName, &sourceFileSize); if (sourceFileSize <= sizeof(unsigned int)) { fputs("Source file size is invalid.\n", stderr); @@ -84,6 +155,11 @@ int main(int argc, const char * const *argv) { fputs("Compressing .bs2...\n", stderr); targetFile = BS2PC_CompressWithSize(bs2pc_gbxMap, bs2pc_gbxMapSize, &targetFileSize); + if (bs2pc_dryRun) { + fputs("Skip writing the .bs2 file.\n", stderr); + goto exit; + } + fputs("Writing the .bs2 file...\n", stderr); if (targetFileName == NULL) { targetFileNameLength = strlen(sourceFileName); @@ -114,6 +190,11 @@ int main(int argc, const char * const *argv) { BS2PC_ConvertGbxToId(); + if (bs2pc_dryRun) { + fputs("Skip writing the .bsp file.\n", stderr); + goto exit; + } + fputs("Writing the .bsp file...\n", stderr); if (targetFileName == NULL) { targetFileNameLength = strlen(sourceFileName); @@ -131,5 +212,10 @@ int main(int argc, const char * const *argv) { fprintf(stderr, "%s converted to %s.\n", sourceFileName, targetFileName); } +exit: + // [SDP] change exit code if errors occured + if (bs2pc_errors) + return EXIT_FAILURE; + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/bs2pc.h b/bs2pc.h index 56ace4b..ec75643 100644 --- a/bs2pc.h +++ b/bs2pc.h @@ -75,6 +75,15 @@ void BS2PC_ConvertGbxToId(); void BS2PC_ConvertIdToGbx(); extern const unsigned char bs2pc_nodrawIdTexture[1152]; +extern bool bs2pc_errors; + +// [SDP] fix #6: config export +extern bool bs2pc_doMergeStrips; +extern bool bs2pc_szReport; +extern bool bs2pc_wadOnly; +extern bool bs2pc_noResize; +extern bool bs2pc_dryRun; + // Polygon subdivision #pragma pack(push, 4) diff --git a/bs2pc_lumps.h b/bs2pc_lumps.h index 9a791b6..35d8eba 100644 --- a/bs2pc_lumps.h +++ b/bs2pc_lumps.h @@ -24,6 +24,7 @@ enum { LUMP_ID_COUNT }; +extern char *bs2pc_idLumpNames[LUMP_ID_COUNT]; enum { LUMP_GBX_PLANES, @@ -45,6 +46,7 @@ enum { LUMP_GBX_COUNT }; +extern char *bs2pc_gbxLumpNames[LUMP_GBX_COUNT]; #pragma pack(push, 4) diff --git a/bs2pc_map.c b/bs2pc_map.c index 327a707..2b82b62 100644 --- a/bs2pc_map.c +++ b/bs2pc_map.c @@ -1,3 +1,5 @@ +#pragma warning(disable : 4996) + #include "bs2pc.h" #include #include @@ -6,6 +8,43 @@ #include #include +char *bs2pc_idLumpNames[LUMP_ID_COUNT] = { + "Entities", + "Planes", + "Textures", + "Vertices", + "Visibility", + "Nodes", + "Texinfo", + "Faces", + "Lightmaps", + "Clipnodes", + "Leafs", + "Marksurfaces", + "Edges", + "Surfedges", + "Models", +}; + +char *bs2pc_gbxLumpNames[LUMP_GBX_COUNT] = { + "Planes", + "Nodes", + "Leafs", + "Edges", + "Surfedges", + "Vertices", + "Hull0", + "Clipnodes", + "Models", + "Faces", + "Marksurfaces", + "Visibility", + "Lightmaps", + "Textures", + "Entities", + "Polygons", +}; + unsigned char *bs2pc_idMap, *bs2pc_gbxMap; unsigned int bs2pc_idMapSize, bs2pc_gbxMapSize; @@ -15,7 +54,7 @@ static unsigned int bs2pc_idTextureLumpSize; static bool *bs2pc_gbxTexturesSpecial = NULL; // Whether textures are special - texinfo needs this. static void BS2PC_ProcessGbxTextureLump() { - const dmiptex_gbx_t *texture = (const dmiptex_gbx_t *) BS2PC_GbxLump(LUMP_GBX_TEXTURES); + dmiptex_gbx_t *texture = (dmiptex_gbx_t *) BS2PC_GbxLump(LUMP_GBX_TEXTURES); unsigned int index, count = BS2PC_GbxLumpCount(LUMP_GBX_TEXTURES); if (count == 0) { @@ -32,6 +71,12 @@ static void BS2PC_ProcessGbxTextureLump() { const char *name = texture->name; unsigned int width, height; + // [SDP] fix #8: skip resize (useful for PS2 texture harvesting only) + if (bs2pc_noResize) { + texture->width = texture->scaled_width; + texture->height = texture->scaled_height; + } + if (name[0] == '*' || bs2pc_strncasecmp(name, "sky", 3) == 0 || bs2pc_strncasecmp(name, "clip", 4) == 0 || @@ -42,10 +87,12 @@ static void BS2PC_ProcessGbxTextureLump() { width = texture->width; height = texture->height; - bs2pc_idTextureLumpSize += width * height + - (width >> 1) * (height >> 1) + - (width >> 2) * (height >> 2) + - (width >> 3) * (height >> 3); + // [SDP] fix #6: (wadonly, bs2>bsp) don't add bitmap size + if (!bs2pc_wadOnly) + bs2pc_idTextureLumpSize += width * height + + (width >> 1) * (height >> 1) + + (width >> 2) * (height >> 2) + + (width >> 3) * (height >> 3); ++texture; } @@ -79,9 +126,12 @@ static bs2pc_idTextureAdditionalInfo_t *bs2pc_idTextureAdditionalInfo = NULL; static unsigned int bs2pc_idAnimatedStart = UINT_MAX, bs2pc_idAnimatedCount = 0; static unsigned int bs2pc_gbxTextureDataSize = 0; +// [SDP] fix #3: index of the last animated texture frame in texture lump +unsigned int bs2pc_idAnimatedLast = UINT_MAX; + static unsigned int BS2PC_FindAnimatedIdTexture(const char *sequenceName, unsigned char frame) { char name[16]; - unsigned int low, mid, high; + unsigned int tex; int difference; if (bs2pc_idAnimatedCount == 0) { @@ -93,18 +143,14 @@ static unsigned int BS2PC_FindAnimatedIdTexture(const char *sequenceName, unsign strncpy(name + 2, sequenceName, sizeof(name) - 3); name[sizeof(name) - 1] = '\0'; - low = bs2pc_idAnimatedStart; - high = bs2pc_idAnimatedStart + bs2pc_idAnimatedCount - 1; - while (low <= high) { - mid = low + ((high - low) >> 1); - difference = BS2PC_CompareTextureNames(bs2pc_idTextures[mid]->name, name); + /* [SDP] fix #3: use dumb search for animated texture frames because + * many maps have unsorted texture lump + */ + unsigned int firstNonAnimated = bs2pc_idAnimatedLast + 1; + for (tex = bs2pc_idAnimatedStart; tex < firstNonAnimated; tex++) { + difference = BS2PC_CompareTextureNames(bs2pc_idTextures[tex]->name, name); if (difference == 0) { - return mid; - } - if (difference > 0) { - high = mid - 1; - } else { - low = mid + 1; + return tex; } } @@ -180,6 +226,7 @@ static void BS2PC_ProcessIdTextureLump() { for (index = 0; index < validCount; ++index) { const dmiptex_id_t *texture = bs2pc_idTextures[index]; + const dmiptex_id_t *wadTex; const char *name = texture->name; bs2pc_idTextureAdditionalInfo_t *info = &bs2pc_idTextureAdditionalInfo[index]; unsigned int scaledWidth, scaledHeight; @@ -189,6 +236,7 @@ static void BS2PC_ProcessIdTextureLump() { if (bs2pc_idAnimatedStart == UINT_MAX) { bs2pc_idAnimatedStart = index; } + bs2pc_idAnimatedLast = index; ++bs2pc_idAnimatedCount; } else if (name[0] == '!' || name[0] == '*' || bs2pc_strncasecmp(name, "water", 5) == 0) { flags = SURF_DRAWTURB | SURF_DRAWTILED | SURF_SPECIAL | SURF_HASPOLYS; @@ -209,8 +257,19 @@ static void BS2PC_ProcessIdTextureLump() { info->animNext = UINT_MAX; info->alternateAnims = UINT_MAX; - scaledWidth = BS2PC_TextureDimensionToGbx(texture->width); - scaledHeight = BS2PC_TextureDimensionToGbx(texture->height); + // [SDP] fix #5: calculate texture lump size based on WAD data + wadTex = (const dmiptex_id_t *)BS2PC_LoadTextureFromWad(name); + if (wadTex) + { + scaledWidth = BS2PC_TextureDimensionToGbx(wadTex->width); + scaledHeight = BS2PC_TextureDimensionToGbx(wadTex->height); + } + else + { + scaledWidth = BS2PC_TextureDimensionToGbx(texture->width); + scaledHeight = BS2PC_TextureDimensionToGbx(texture->height); + } + while (true) { bs2pc_gbxTextureDataSize += scaledWidth * scaledHeight; if (scaledWidth <= 8 || scaledHeight <= 8) { @@ -221,8 +280,13 @@ static void BS2PC_ProcessIdTextureLump() { } } + /* [SDP] fix #3: safer processing of animated textures + * - bs2pc_idAnimatedCount: how many animated textures + * - bs2pc_idAnimatedStart: first animated texture index + * - bs2pc_idAnimatedLast: last animated texture index + */ if (bs2pc_idAnimatedCount != 0) { - unsigned int firstNonAnimated = bs2pc_idAnimatedStart + bs2pc_idAnimatedCount; + unsigned int firstNonAnimated = bs2pc_idAnimatedLast + 1; for (index = bs2pc_idAnimatedStart; index < firstNonAnimated; ++index) { const char *name = bs2pc_idTextures[index]->name; unsigned int seq[10], altSeq[10], count = 1, altCount = 0, frame, found; @@ -232,7 +296,7 @@ static void BS2PC_ProcessIdTextureLump() { continue; // Shouldn't happen, but still, reject. } if (name[1] != '0') { - break; // Only the beginnings of the chains are needed, the rest will be found with binary search. + continue; } // Build the sequences. @@ -464,14 +528,25 @@ static void BS2PC_AllocateIdMapFromGbx() { memcpy(bs2pc_idMap, &headerId, sizeof(dheader_id_t)); } +// [SDP] fix #6: (szreport) added lump sizes report +#define MiB (float)(1024*1024) +#define PRINT_LUMP_SZ(LUMP_NAME, LUMP_SZ) \ + fprintf(stderr, "\t%-15s\t%.2f MiB\n", (LUMP_NAME), (LUMP_SZ) / MiB) static void BS2PC_AllocateGbxMapFromId() { dheader_gbx_t headerGbx; - unsigned int mapSize; + unsigned int mapSize, lmp; memset(&headerGbx, 0, sizeof(headerGbx)); headerGbx.version = BSPVERSION_GBX; mapSize = (sizeof(headerGbx) + 15) & ~15; + if (bs2pc_szReport) + { + fputs(" BSP lump sizes:\n", stderr); + for (lmp = 0; lmp < LUMP_ID_COUNT; lmp++) + PRINT_LUMP_SZ(bs2pc_idLumpNames[lmp], BS2PC_IdLumpSize(lmp)); + } + headerGbx.lumpofs[LUMP_GBX_PLANES] = mapSize; headerGbx.lumpnum[LUMP_GBX_PLANES] = BS2PC_IdLumpSize(LUMP_ID_PLANES) / sizeof(dplane_id_t); headerGbx.lumplen[LUMP_GBX_PLANES] = headerGbx.lumpnum[LUMP_GBX_PLANES] * sizeof(dplane_gbx_t); @@ -548,6 +623,13 @@ static void BS2PC_AllocateGbxMapFromId() { headerGbx.lumplen[LUMP_GBX_POLYS] = bs2pc_faceSubdivisionSize; mapSize += (headerGbx.lumplen[LUMP_GBX_POLYS] + 15) & ~15; + if (bs2pc_szReport) + { + fputs(" BS2 lump sizes:\n", stderr); + for (lmp = 0; lmp < LUMP_GBX_COUNT; lmp++) + PRINT_LUMP_SZ(bs2pc_gbxLumpNames[lmp], (headerGbx.lumplen[lmp] + 15) & ~15); + } + bs2pc_gbxMapSize = mapSize; bs2pc_gbxMap = (unsigned char *) BS2PC_Alloc(mapSize, true); memcpy(bs2pc_gbxMap, &headerGbx, sizeof(dheader_gbx_t)); @@ -1016,8 +1098,13 @@ void BS2PC_ConvertTexturesToId() { for (textureIndex = 0; textureIndex < textureCount; ++textureIndex) { const dmiptex_gbx_t *textureGbx = &texturesGbx[textureIndex]; miptexOffsets[textureIndex] = miptexOffset; - miptexOffset += sizeof(dmiptex_id_t) + - textureGbx->width * textureGbx->height + + miptexOffset += sizeof(dmiptex_id_t); + + // [SDP] fix #6: (wadonly, bs2>bsp) don't add bitmap size + if (bs2pc_wadOnly) + continue; + + miptexOffset += textureGbx->width * textureGbx->height + (textureGbx->width >> 1) * (textureGbx->height >> 1) + (textureGbx->width >> 2) * (textureGbx->height >> 2) + (textureGbx->width >> 3) * (textureGbx->height >> 3) + @@ -1032,7 +1119,7 @@ void BS2PC_ConvertTexturesToId() { unsigned int width, height; const unsigned char *paletteGbx; unsigned char *paletteId; - bool liquid; + bool keepColors; unsigned int colorIndex; memcpy(headerId->name, textureGbx->name, sizeof(headerId->name)); @@ -1041,6 +1128,12 @@ void BS2PC_ConvertTexturesToId() { headerId->width = width; headerId->height = height; + if (bs2pc_wadOnly) { + // [SDP] fix #6: (wadonly, bs2>bsp) ignore textures stored in bs2 + memset(headerId->offsets, 0x00, sizeof(headerId->offsets)); + continue; + } + headerId->offsets[0] = sizeof(dmiptex_id_t); headerId->offsets[1] = headerId->offsets[0] + width * height; headerId->offsets[2] = headerId->offsets[1] + (width >> 1) * (height >> 1); @@ -1063,7 +1156,8 @@ void BS2PC_ConvertTexturesToId() { paletteId = textureId + headerId->offsets[3] + (width >> 3) * (height >> 3); *((unsigned short *) paletteId) = 256; paletteId += sizeof(unsigned short); - liquid = (textureGbx->name[0] == '!') || + // [SDP] fix #9: '{' textures need the same treatment as '!' + keepColors = (textureGbx->name[0] == '!') || (textureGbx->name[0] == '{') || (textureGbx->name[0] >= '0' && textureGbx->name[0] <= '9' && textureGbx->name[1] == '!'); for (colorIndex = 0; colorIndex < 256; ++colorIndex) { unsigned int colorIndexGbx, colorIndexLow; @@ -1078,7 +1172,7 @@ void BS2PC_ConvertTexturesToId() { } colorGbx = paletteGbx + colorIndexGbx * 4; - if (liquid) { + if (keepColors) { *(paletteId++) = colorGbx[0]; *(paletteId++) = colorGbx[1]; *(paletteId++) = colorGbx[2]; @@ -1107,8 +1201,39 @@ void BS2PC_ConvertTexturesToGbx() { for (textureIndex = 0; textureIndex < textureCount; ++textureIndex, ++textureGbx, ++additionalInfo) { const dmiptex_id_t *textureId = bs2pc_idTextures[textureIndex]; - // Save for the case if a WAD has a differently sized texture. - unsigned int width = textureId->width, height = textureId->height; + /* [SDP] fix #4: take WAD texture size over BSP size to work + * around texture scaling artifacts (manual power of 2 texture + * scaling required to be done in WADs) + * - bsp_with/bsp_height: bsp texture dimensions + * - with/height: wad texture dimensions + * - scaledWidth/scaledHeight: power of 2 dimensions + */ + unsigned int width, height, bsp_width, bsp_height; + const dmiptex_id_t * wadTex; + wadTex = (const dmiptex_id_t *)BS2PC_LoadTextureFromWad(textureId->name); + if (wadTex == NULL) + { + bsp_width = width = textureId->width; + bsp_height = height = textureId->height; + } + else + { + bsp_width = textureId->width; + bsp_height = textureId->height; + width = wadTex->width; + height = wadTex->height; +#if 0 // [SDP] Debug + if (bsp_width != width) + { + fprintf(stderr, "Name: %s \n", textureId->name); + fprintf(stderr, "bsp: %d x %d, wad: %d x %d, bs2: %d x %d\n", + bsp_width, bsp_height, width, height, + BS2PC_TextureDimensionToGbx(width), + BS2PC_TextureDimensionToGbx(height)); + } +#endif + } + unsigned int scaledWidth = BS2PC_TextureDimensionToGbx(width); unsigned int scaledHeight = BS2PC_TextureDimensionToGbx(height); unsigned int tempWidth, tempHeight; @@ -1117,12 +1242,13 @@ void BS2PC_ConvertTexturesToGbx() { bspoffset_t lastGbxMipOffset = gbxMipOffset; unsigned int colorIndex; unsigned char *colorGbx; - bool liquid = (textureId->name[0] == '!'); + // [SDP] fix #9: '{' textures need the same treatment as '!' + bool keepColors = (textureId->name[0] == '!') || (textureId->name[0] == '{'); textureGbx->offset = gbxMipOffset; textureGbx->palette = gbxPaletteOffset; - textureGbx->width = width; - textureGbx->height = height; + textureGbx->width = bsp_width; + textureGbx->height = bsp_height; textureGbx->scaled_width = scaledWidth; textureGbx->scaled_height = scaledHeight; memcpy(textureGbx->name, textureId->name, sizeof(textureGbx->name)); @@ -1161,8 +1287,12 @@ void BS2PC_ConvertTexturesToGbx() { textureGbx->anim_next = textureGbx->alternate_anims = UINT_MAX; } - if (textureId->offsets[0] == 0 || textureId->offsets[1] == 0 || - textureId->offsets[2] == 0 || textureId->offsets[3] == 0) { + // [SDP] fix #6: (wadonly, bsp>bs2) ignore textures stored in bsp + if (bs2pc_wadOnly || + textureId->offsets[0] == 0 || + textureId->offsets[1] == 0 || + textureId->offsets[2] == 0 || + textureId->offsets[3] == 0) { textureId = (const dmiptex_id_t *) BS2PC_LoadTextureFromWad(textureId->name); if (textureId != NULL && (textureId->offsets[0] == 0 || textureId->offsets[1] == 0 || textureId->offsets[2] == 0 || textureId->offsets[3] == 0)) { @@ -1193,7 +1323,8 @@ void BS2PC_ConvertTexturesToGbx() { } else { unsigned int x, y; char *dest = bs2pc_gbxMap + gbxMipOffset; - fprintf(stderr, "Texture %s not found or is incomplete in WADs, replacing with a checkerboard.\n", textureGbx->name); + fprintf(stderr, "[ERROR] Texture %-16s not found or is incomplete in WADs, replacing with a checkerboard.\n", textureGbx->name); + bs2pc_errors = true; for (y = 0; y < tempHeight; ++y) { for (x = 0; x < tempWidth; ++x) { *(dest++) = (((((y & 15)) < 8) ^ (((x & 15)) < 8)) ? 0 : 255); @@ -1228,7 +1359,7 @@ void BS2PC_ConvertTexturesToGbx() { colorGbx = bs2pc_gbxMap + gbxPaletteOffset + colorIndexGbx * 4; if (colorIndex < colorCount) { - if (liquid) { + if (keepColors) { *(colorGbx++) = *(colorId++); *(colorGbx++) = *(colorId++); *(colorGbx++) = *(colorId++); @@ -1252,9 +1383,9 @@ void BS2PC_ConvertTexturesToGbx() { *(colorGbx++) = 0; *(colorGbx++) = 0x80; } - *(colorGbx++) = (liquid ? 0xff : 0x7f); + *(colorGbx++) = (keepColors ? 0xff : 0x7f); *(colorGbx++) = 0; - *(colorGbx++) = (liquid ? 0xff : 0x7f); + *(colorGbx++) = (keepColors ? 0xff : 0x7f); *(colorGbx++) = 0x80; } if (textureGbx->name[0] == '{') { diff --git a/bs2pc_subdiv.c b/bs2pc_subdiv.c index f7682c3..271e121 100644 --- a/bs2pc_subdiv.c +++ b/bs2pc_subdiv.c @@ -8,13 +8,15 @@ static float bs2pc_subdivideSize; -#define BS2PC_MAX_POLY_VERTS 1024 +// [SDP] fix #1: increased caps +#define BS2PC_MAX_POLY_VERTS 8192 +#define BS2PC_MAX_POLY_STRIPS 8192 + static float bs2pc_polyPositions[BS2PC_MAX_POLY_VERTS][3]; #define BS2PC_POLY_POSITION_EPSILON 0.001f static unsigned int bs2pc_polyVertCount; #define BS2PC_MAX_POLY_STRIP_INDICES BS2PC_MAX_POLY_VERTS -#define BS2PC_MAX_POLY_STRIPS 256 typedef struct { unsigned short firstIndex; unsigned short indexCount; @@ -355,7 +357,8 @@ unsigned char *BS2PC_SubdivideIdSurface(unsigned int faceIndex, unsigned int fac bs2pc_polyStripSets[0].stripCount = 0; bs2pc_polyVertCount = 0; BS2PC_SubdividePolygon(numverts, verts); - BS2PC_MergeStrips(); + if (bs2pc_doMergeStrips) // [SDP] fix #6: skip BS2PC_MergeStrips() func call + BS2PC_MergeStrips(); stripSet = &bs2pc_polyStripSets[bs2pc_currentPolyStripSet]; subdivSize = 2 * sizeof(unsigned int) /* face index, vertex count */ + diff --git a/bs2pc_util.c b/bs2pc_util.c index 89a9d57..fd07fc7 100644 --- a/bs2pc_util.c +++ b/bs2pc_util.c @@ -1,3 +1,5 @@ +#pragma warning(disable : 4996) + #include "bs2pc.h" #include #include @@ -219,6 +221,18 @@ void *BS2PC_CompressWithSize(const void *source, unsigned int sourceSize, unsign if (outTargetSize != NULL) { *outTargetSize = targetSize + sizeof(unsigned int); } + + // [SDP] fix #7: give warning if resulting map file is too big + #define MiB (float)(1024*1024) + float DecomprSize = sourceSize / MiB; + float ComprSize = *outTargetSize / MiB; + float TotalSize = DecomprSize + ComprSize; + fprintf(stderr, "\tDecompressed map size:\t %.2f MiB \n", DecomprSize); + fprintf(stderr, "\tCompressed map size:\t %.2f MiB \n", ComprSize); + fprintf(stderr, "\tTotal map size:\t\t %.2f MiB \n", TotalSize); + if (DecomprSize > 8.0f || TotalSize > 12.0f) + fputs("[WARNING] map file is too big and can cause crashes\n", stderr); + return target; } diff --git a/bs2pc_wad.c b/bs2pc_wad.c index 516cabb..b14e369 100644 --- a/bs2pc_wad.c +++ b/bs2pc_wad.c @@ -1,9 +1,13 @@ +#pragma warning(disable : 4996) + #include "bs2pc.h" #include #include #include #include +#define QSORT_WAD // [SDP] fix #2: WAD qsort/dumb search switch (IDK what is better, left both) + typedef struct bs2pc_wadDirectory_s { char *path; size_t pathLength; @@ -60,6 +64,14 @@ typedef struct bs2pc_wad_s { static bs2pc_wad_t *bs2pc_wads = NULL; +#ifdef QSORT_WAD +int lmpcmp(const void * p1, const void * p2) { + bs2pc_wadLumpInfo_t *pl1 = (bs2pc_wadLumpInfo_t *) p1; + bs2pc_wadLumpInfo_t *pl2 = (bs2pc_wadLumpInfo_t *) p2; + return BS2PC_CompareTextureNames((const char *) pl1->name, (const char *) pl2->name); +} +#endif + static void BS2PC_LoadWad(const char *fileName /* Assuming / slash */) { FILE *file; char *fileNameWithGame; @@ -124,6 +136,12 @@ static void BS2PC_LoadWad(const char *fileName /* Assuming / slash */) { fclose(file); return; } +#ifdef QSORT_WAD + if (wad->lumpCount > 1) { + fputs("Qsorting WAD lumps...\n", stderr); + qsort(wad->lumps, wad->lumpCount, sizeof(*wad->lumps), lmpcmp); + } +#endif wad->next = bs2pc_wads; bs2pc_wads = wad; @@ -208,8 +226,10 @@ unsigned char *BS2PC_LoadTextureFromWad(const char *name) { for (wad = bs2pc_wads; wad != NULL; wad = wad->next) { const bs2pc_wadLumpInfo_t *lumps = wad->lumps; - unsigned int low = 0, mid, high = wad->lumpCount; int difference; + +#ifdef QSORT_WAD + int low = 0, mid, high = wad->lumpCount; while (low <= high) { mid = low + ((high - low) >> 1); difference = BS2PC_CompareTextureNames(lumps[mid].name, name); @@ -223,7 +243,17 @@ unsigned char *BS2PC_LoadTextureFromWad(const char *name) { low = mid + 1; } } - +#else // QSORT_WAD + unsigned int lmp; + // [SDP] fix #2: use dumb search for WAD textures because many WADs are unsorted + for (lmp = 0; lmp < wad->lumpCount; lmp++) { + difference = BS2PC_CompareTextureNames(lumps[lmp].name, name); + if (difference == 0) { + lumpInfo = &lumps[lmp]; + break; + } + } +#endif // QSORT_WAD if (lumpInfo == NULL) { continue; }