diff --git a/src/console.c b/src/console.c index 69160c240..0c3eac4f7 100644 --- a/src/console.c +++ b/src/console.c @@ -1728,12 +1728,12 @@ static void CON_DrawBackpic(void) // Get the lumpnum for CONSBACK, STARTUP (Only during game startup) or fallback into MISSING. if (con_startup) - piclump = W_CheckNumForName("STARTUP"); + piclump = W_CheckNumForPatchName("STARTUP"); else - piclump = W_CheckNumForName("CONSBACK"); + piclump = W_CheckNumForPatchName("CONSBACK"); if (piclump == LUMPERROR) - piclump = W_GetNumForName("MISSING"); + piclump = W_GetNumForPatchName("MISSING"); // Cache the patch. con_backpic = W_CachePatchNum(piclump, PU_PATCH); diff --git a/src/d_main.c b/src/d_main.c index c139650d1..afa10ae3c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -758,9 +758,9 @@ void D_SRB2Loop(void) /* Smells like a hack... Don't fade Sonic's ass into the title screen. */ if (gamestate != GS_TITLESCREEN) { - gstartuplumpnum = W_CheckNumForName("STARTUP"); + gstartuplumpnum = W_CheckNumForPatchName("STARTUP"); if (gstartuplumpnum == LUMPERROR) - gstartuplumpnum = W_GetNumForName("MISSING"); + gstartuplumpnum = W_GetNumForPatchName("MISSING"); V_DrawScaledPatch(0, 0, 0, W_CachePatchNum(gstartuplumpnum, PU_PATCH)); } diff --git a/src/f_finale.c b/src/f_finale.c index 9ff50147e..810af4e82 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -2336,7 +2336,7 @@ void F_SkyScroll(const char *patchname) } #define LOADTTGFX(arr, name, maxf) \ -lumpnum = W_CheckNumForName(name); \ +lumpnum = W_CheckNumForPatchName(name); \ if (lumpnum != LUMPERROR) \ { \ arr[0] = W_CachePatchName(name, PU_PATCH_LOWPRIORITY); \ @@ -2350,7 +2350,7 @@ else if (strlen(name) <= 6) \ { \ sprintf(&lumpname[cnt], "%.2hu", (UINT16)(i+1)); \ lumpname[8] = 0; \ - lumpnum = W_CheckNumForName(lumpname); \ + lumpnum = W_CheckNumForPatchName(lumpname); \ if (lumpnum != LUMPERROR) \ arr[i] = W_CachePatchName(lumpname, PU_PATCH_LOWPRIORITY); \ else \ @@ -4116,7 +4116,7 @@ static void F_GetPageTextGeometry(UINT8 *pagelines, boolean *rightside, INT32 *b // reuse: // cutnum -> promptnum // scenenum -> pagenum - lumpnum_t iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); + lumpnum_t iconlump = W_CheckNumForPatchName(textprompts[cutnum]->page[scenenum].iconname); *pagelines = textprompts[cutnum]->page[scenenum].lines ? textprompts[cutnum]->page[scenenum].lines : 4; *rightside = (iconlump != LUMPERROR && textprompts[cutnum]->page[scenenum].rightside); @@ -4508,7 +4508,7 @@ void F_TextPromptDrawer(void) if (!promptactive) return; - iconlump = W_CheckNumForName(textprompts[cutnum]->page[scenenum].iconname); + iconlump = W_CheckNumForPatchName(textprompts[cutnum]->page[scenenum].iconname); F_GetPageTextGeometry(&pagelines, &rightside, &boxh, &texth, &texty, &namey, &chevrony, &textx, &textr); // Draw gfx first diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 1c951475b..d784c2358 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -272,7 +272,7 @@ void HU_LoadFontCharacters(fontdef_t *font, const char *prefix) for (i = 0; i < FONTSIZE; i++, j++) { sprintf(buffer, "%.5s%.3d", prefix, j); - if (W_CheckNumForName(buffer) == LUMPERROR) + if (W_CheckNumForPatchName(buffer) == LUMPERROR) font->chars[i] = NULL; else font->chars[i] = (patch_t *)W_CachePatchName(buffer, PU_HUDGFX); diff --git a/src/m_menu.c b/src/m_menu.c index 4d8ee17e8..f25c78e88 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -4030,11 +4030,11 @@ static void M_DrawThermo(INT32 x, INT32 y, consvar_t *cv) lumpnum_t leftlump, rightlump, centerlump[2], cursorlump; patch_t *p; - leftlump = W_GetNumForName("M_THERML"); - rightlump = W_GetNumForName("M_THERMR"); - centerlump[0] = W_GetNumForName("M_THERMM"); - centerlump[1] = W_GetNumForName("M_THERMM"); - cursorlump = W_GetNumForName("M_THERMO"); + leftlump = W_GetNumForPatchName("M_THERML"); + rightlump = W_GetNumForPatchName("M_THERMR"); + centerlump[0] = W_GetNumForPatchName("M_THERMM"); + centerlump[1] = W_GetNumForPatchName("M_THERMM"); + cursorlump = W_GetNumForPatchName("M_THERMO"); V_DrawScaledPatch(xx, y, 0, p = W_CachePatchNum(leftlump,PU_PATCH)); xx += p->width - p->leftoffset; diff --git a/src/st_stuff.c b/src/st_stuff.c index 7df6f8848..e088a448c 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -1269,19 +1269,19 @@ tic_t lt_exitticker = 0, lt_endtime = 0; // static void ST_cacheLevelTitle(void) { -#define SETPATCH(default, warning, custom, idx) \ +#define SETPATCH(def, warning, custom, idx) \ { \ lumpnum_t patlumpnum = LUMPERROR; \ if (mapheaderinfo[gamemap-1]->custom[0] != '\0') \ { \ - patlumpnum = W_CheckNumForName(mapheaderinfo[gamemap-1]->custom); \ + patlumpnum = W_CheckNumForPatchName(mapheaderinfo[gamemap-1]->custom); \ if (patlumpnum != LUMPERROR) \ lt_patches[idx] = (patch_t *)W_CachePatchNum(patlumpnum, PU_HUDGFX); \ } \ if (patlumpnum == LUMPERROR) \ { \ if (!(mapheaderinfo[gamemap-1]->levelflags & LF_WARNINGTITLE)) \ - lt_patches[idx] = (patch_t *)W_CachePatchName(default, PU_HUDGFX); \ + lt_patches[idx] = (patch_t *)W_CachePatchName(def, PU_HUDGFX); \ else \ lt_patches[idx] = (patch_t *)W_CachePatchName(warning, PU_HUDGFX); \ } \ diff --git a/src/w_wad.c b/src/w_wad.c index 78d26f905..cc7cdc201 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -98,6 +98,7 @@ typedef struct lumpnum_cache_s { char lumpname[32]; lumpnum_t lumpnum; + UINT32 hash; } lumpnum_cache_t; static lumpnum_cache_t lumpnumcache[LUMPNUMCACHESIZE]; @@ -1475,6 +1476,63 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump) return INT16_MAX; } +static lumpnum_t CheckLumpInCache(const char *name, boolean longname) +{ + if (longname) + { + UINT32 hash = quickncasehash(name, 32); + + // Loop backwards so that we check most recent entries first + for (INT32 i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) + { + if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].hash == hash + && stricmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) + { + lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); + return lumpnumcache[lumpnumcacheindex].lumpnum; + } + } + } + else + { + UINT32 hash = quickncasehash(name, 8); + + // Loop backwards so that we check most recent entries first + for (INT32 i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) + { + if (lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].hash == hash + && lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8] == '\0' + && strnicmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) + { + lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); + return lumpnumcache[lumpnumcacheindex].lumpnum; + } + } + } + + return LUMPERROR; +} + +static void AddLumpToCache(lumpnum_t lumpnum, const char *name, boolean longname) +{ + if (longname && strlen(name) >= 32) + return; + + lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); + memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); + if (longname) + { + strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32); + lumpnumcache[lumpnumcacheindex].hash = quickncasehash(name, 32); + } + else + { + strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8); + lumpnumcache[lumpnumcacheindex].hash = quickncasehash(name, 8); + } + lumpnumcache[lumpnumcacheindex].lumpnum = lumpnum; +} + // // W_CheckNumForName // Returns LUMPERROR if name not found. @@ -1487,17 +1545,10 @@ lumpnum_t W_CheckNumForName(const char *name) if (!*name) // some doofus gave us an empty string? return LUMPERROR; - // Check the lumpnumcache first. Loop backwards so that we check - // most recent entries first - for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) - { - if (!lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname[8] - && strncmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name, 8) == 0) - { - lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); - return lumpnumcache[lumpnumcacheindex].lumpnum; - } - } + // Check the lumpnumcache first. + lumpnum_t cachenum = CheckLumpInCache(name, false); + if (cachenum != LUMPERROR) + return cachenum; // scan wad files backwards so patch lump files take precedence for (i = numwadfiles - 1; i >= 0; i--) @@ -1511,12 +1562,11 @@ lumpnum_t W_CheckNumForName(const char *name) else { // Update the cache. - lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); - memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); - strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8); - lumpnumcache[lumpnumcacheindex].lumpnum = (i<<16)+check; + lumpnum_t lumpnum = (i << 16) + check; - return lumpnumcache[lumpnumcacheindex].lumpnum; + AddLumpToCache(lumpnum, name, false); + + return lumpnum; } } @@ -1534,16 +1584,10 @@ lumpnum_t W_CheckNumForLongName(const char *name) if (!*name) // some doofus gave us an empty string? return LUMPERROR; - // Check the lumpnumcache first. Loop backwards so that we check - // most recent entries first - for (i = lumpnumcacheindex + LUMPNUMCACHESIZE; i > lumpnumcacheindex; i--) - { - if (strcmp(lumpnumcache[i & (LUMPNUMCACHESIZE - 1)].lumpname, name) == 0) - { - lumpnumcacheindex = i & (LUMPNUMCACHESIZE - 1); - return lumpnumcache[lumpnumcacheindex].lumpnum; - } - } + // Check the lumpnumcache first. + lumpnum_t cachenum = CheckLumpInCache(name, true); + if (cachenum != LUMPERROR) + return cachenum; // scan wad files backwards so patch lump files take precedence for (i = numwadfiles - 1; i >= 0; i--) @@ -1556,16 +1600,12 @@ lumpnum_t W_CheckNumForLongName(const char *name) if (check == INT16_MAX) return LUMPERROR; else { - if (strlen(name) < 32) - { - // Update the cache. - lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1); - memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', 32); - strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 32); - lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check; - } + // Update the cache. + lumpnum_t lumpnum = (i << 16) + check; - return (i << 16) + check; + AddLumpToCache(lumpnum, name, true); + + return lumpnum; } } @@ -1647,6 +1687,159 @@ lumpnum_t W_GetNumForLongName(const char *name) return i; } +// +// Same as W_CheckNumForNamePwad, but handles namespaces. +// +static UINT16 W_CheckNumForPatchNamePwad(const char *name, UINT16 wad, boolean longname) +{ + UINT16 i, start, end; + static char uname[8 + 1] = { 0 }; + UINT32 hash = 0; + lumpinfo_t *lump_p; + + if (!TestValidLump(wad,0)) + return INT16_MAX; + + if (!longname) + { + strlcpy(uname, name, sizeof uname); + strupr(uname); + hash = quickncasehash(uname, 8); + } + + // SRB2 doesn't have a specific namespace for graphics, which means someone can do weird things + // like placing graphics inside a namespace it doesn't make sense for them to be in, like Sounds/ or SOC/ + // So for now, this checks for lumps OUTSIDE of the flats namespace. + // When this situation changes, change the loops below to check for lumps INSIDE the namespaces to look in. + // TODO: cache namespace lump IDs + if (W_FileHasFolders(wadfiles[wad])) + { + start = W_CheckNumForFolderStartPK3("Flats/", wad, 0); + end = W_CheckNumForFolderEndPK3("Flats/", wad, start); + } + else + { + start = W_CheckNumForMarkerStartPwad("F_START", wad, 0); + end = W_CheckNumForNamePwad("F_END", wad, start); + if (end != INT16_MAX) + end++; + } + + lump_p = wadfiles[wad]->lumpinfo; + + if (start == INT16_MAX) + start = wadfiles[wad]->numlumps; + + for (i = 0; i < start; i++, lump_p++) + { + if ((!longname && lump_p->hash == hash && !strncmp(lump_p->name, uname, sizeof(uname) - 1)) + || (longname && stricmp(lump_p->longname, name) == 0)) + return i; + } + + if (end != INT16_MAX && start < end) + { + lump_p = wadfiles[wad]->lumpinfo + end; + + for (i = end; i < wadfiles[wad]->numlumps; i++, lump_p++) + { + if ((!longname && lump_p->hash == hash && !strncmp(lump_p->name, uname, sizeof(uname) - 1)) + || (longname && stricmp(lump_p->longname, name) == 0)) + return i; + } + } + + // not found. + return INT16_MAX; +} + +// +// W_CheckNumForPatchNameInternal +// Gets a lump number out of a patch name. Returns LUMPERROR if name not found. +// +static lumpnum_t W_CheckNumForPatchNameInternal(const char *name, boolean longname) +{ + INT32 i; + lumpnum_t check = INT16_MAX; + + if (!*name) // some doofus gave us an empty string? + return LUMPERROR; + + // Check the lumpnumcache first. + lumpnum_t cachenum = CheckLumpInCache(name, longname); + if (cachenum != LUMPERROR) + return cachenum; + + // scan wad files backwards so patch lump files take precedence + for (i = numwadfiles - 1; i >= 0; i--) + { + check = W_CheckNumForPatchNamePwad(name,(UINT16)i,longname); + if (check != INT16_MAX) + break; //found it + } + + if (check == INT16_MAX) return LUMPERROR; + else + { + // Update the cache. + lumpnum_t lumpnum = (i << 16) + check; + + AddLumpToCache(lumpnum, name, longname); + + return lumpnum; + } +} + +// +// W_CheckNumForPatchName +// Wrapper for W_CheckNumForPatchNameInternal(name, false). Returns LUMPERROR if name not found. +// +lumpnum_t W_CheckNumForPatchName(const char *name) +{ + return W_CheckNumForPatchNameInternal(name, false); +} + +// +// Like W_CheckNumForPatchName, but can find entries with long names. +// Wrapper for W_CheckNumForPatchNameInternal(name, true). Returns LUMPERROR if name not found. +// +lumpnum_t W_CheckNumForLongPatchName(const char *name) +{ + return W_CheckNumForPatchNameInternal(name, true); +} + +// +// W_GetNumForPatchName +// +// Calls W_CheckNumForPatchName, but bombs out if not found. +// +lumpnum_t W_GetNumForPatchName(const char *name) +{ + lumpnum_t i; + + i = W_CheckNumForPatchName(name); + + if (i == LUMPERROR) + I_Error("W_CheckNumForPatchName: %s not found!\n", name); + + return i; +} + +// +// Like W_GetNumForPatchName, but can find entries with long names +// +lumpnum_t W_GetNumForLongPatchName(const char *name) +{ + lumpnum_t i; + + i = W_CheckNumForLongPatchName(name); + + if (i == LUMPERROR) + I_Error("W_GetNumForLongPatchName: %s not found!\n", name); + + return i; +} + // // W_CheckNumForNameInBlock // Checks only in blocks from blockstart lump to blockend lump @@ -2291,10 +2484,10 @@ void *W_CachePatchName(const char *name, INT32 tag) { lumpnum_t num; - num = W_CheckNumForName(name); + num = W_CheckNumForPatchName(name); if (num == LUMPERROR) - return W_CachePatchNum(W_GetNumForName("MISSING"), tag); + return W_CachePatchNum(W_GetNumForPatchName("MISSING"), tag); return W_CachePatchNum(num, tag); } @@ -2302,10 +2495,10 @@ void *W_CachePatchLongName(const char *name, INT32 tag) { lumpnum_t num; - num = W_CheckNumForLongName(name); + num = W_CheckNumForLongPatchName(name); if (num == LUMPERROR) - return W_CachePatchNum(W_GetNumForLongName("MISSING"), tag); + return W_CachePatchNum(W_GetNumForLongPatchName("MISSING"), tag); return W_CachePatchNum(num, tag); } #ifndef NOMD5 diff --git a/src/w_wad.h b/src/w_wad.h index 80e0e32fd..3dcb9b6e8 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -193,6 +193,12 @@ lumpnum_t W_CheckNumForName(const char *name); lumpnum_t W_CheckNumForLongName(const char *name); lumpnum_t W_GetNumForName(const char *name); // like W_CheckNumForName but I_Error on LUMPERROR lumpnum_t W_GetNumForLongName(const char *name); + +lumpnum_t W_CheckNumForPatchName(const char *name); +lumpnum_t W_CheckNumForLongPatchName(const char *name); +lumpnum_t W_GetNumForPatchName(const char *name); // like W_CheckNumForPatchName but I_Error on LUMPERROR +lumpnum_t W_GetNumForLongPatchName(const char *name); + lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, const char *blockend); UINT8 W_LumpExists(const char *name); // Lua uses this.