diff --git a/src/p_setup.c b/src/p_setup.c index e034c35b8..3cacbca54 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2345,9 +2345,7 @@ static void P_RunLevelScript(const char *scriptname) lumpnum_t lumpnum; char newname[9]; - strncpy(newname, scriptname, 8); - - newname[8] = '\0'; + strlcpy(newname, scriptname, sizeof(newname)); lumpnum = W_CheckNumForName(newname); @@ -3314,6 +3312,12 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local) if (!mapsadded) CONS_Printf(M_GetText("No maps added\n")); +#ifdef HWRENDER + // Free GPU textures before freeing patches. + if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) + HWR_ClearAllTextures(); +#endif + // // search for sprite replacements // @@ -3324,7 +3328,7 @@ UINT16 P_PartialAddWadFile(const char *wadfilename, boolean local) // Reload it all anyway, just in case they // added some textures but didn't insert a // TEXTURES/etc. list. - //R_LoadTexturesPwad(wadnum); + R_LoadTexturesPwad(wadnum); // everything from MultiSetupWadFile until ST_Start was here originally @@ -3388,13 +3392,8 @@ boolean P_MultiSetupWadFiles(boolean fullsetup) if (partadd_stage == 1) { -#ifdef HWRENDER - // Free GPU textures before freeing patches. - if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED)) - HWR_ClearAllTextures(); -#endif // Reload all textures, unconditionally for better or worse. - R_LoadTextures(); + //R_LoadTextures(); if (fullsetup) ++partadd_stage; diff --git a/src/r_data.c b/src/r_data.c index 688b03972..ce0965e0d 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -235,6 +235,7 @@ UINT32 ASTBlendTexturePixel(RGBA_t background, RGBA_t foreground, int style, UIN // Painfully simple texture id cacheing to make maps load faster. :3 static struct { char name[9]; + UINT32 hash; INT32 id; } *tidcache = NULL; static INT32 tidcachelen = 0; @@ -520,32 +521,151 @@ void R_FlushTextureCache(void) int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum); void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index); -// -// R_LoadTextures -// Initializes the texture list with the textures from the world map. -// #define TX_START "TX_START" #define TX_END "TX_END" -void R_LoadTextures(void) + +static INT32 +Rloadtextures (INT32 i, INT32 w) { - INT32 i, k, w; UINT16 j; + INT32 k; UINT16 texstart, texend, texturesLumpPos; softwarepatch_t *patchlump; texpatch_t *patch; texture_t *texture; - // Free previous memory before numtextures change. - if (numtextures) + // Get the lump numbers for the markers in the WAD, if they exist. + if (W_FileHasFolders(wadfiles[w])) { - for (i = 0; i < numtextures; i++) + texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + while (texturesLumpPos != INT16_MAX) { - Z_Free(textures[i]); - Z_Free(texturecache[i]); + R_ParseTEXTURESLump(w, texturesLumpPos, &i); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); } - Z_Free(texturetranslation); - Z_Free(textures); } + else + { + texstart = W_CheckNumForMarkerStartPwad(TX_START, (UINT16)w, 0); + texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + if (texturesLumpPos != INT16_MAX) + R_ParseTEXTURESLump(w, texturesLumpPos, &i); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) + return i; + + // Work through each lump between the markers in the WAD. + for (j = 0; j < (texend - texstart); j++) + { + UINT16 wadnum = (UINT16)w; + lumpnum_t lumpnum = texstart + j; + + if (W_FileHasFolders(wadfiles[w])) + { + if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder + continue; // If it is then SKIP IT + } + + patchlump = (softwarepatch_t *)W_CacheLumpNumPwad(wadnum, lumpnum, PU_STATIC); + + //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((wadnum, lumpnum), patchlump->width, patchlump->height); + texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); + + // Set texture properties. + M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + texture->hash = quickncasehash(texture->name, 8); + texture->width = SHORT(patchlump->width); + texture->height = SHORT(patchlump->height); + texture->type = TEXTURETYPE_SINGLEPATCH; + texture->patchcount = 1; + texture->holes = false; + + // Allocate information for the texture's patches. + patch = &texture->patches[0]; + + patch->originx = patch->originy = 0; + patch->wad = wadnum; + patch->lump = texstart + j; + + Z_Free(patchlump); + + // determine width power of 2 +#if 1 + // [WDJ] only need to determine if exact power of 2. + k = 1; + while (k < texture->width) + k<<=1; +#else + // Largest power of 2 that fits within width. + k = 1; + while (k << 1 <= texture->width) + k <<= 1; +#endif + if (k != texture->width) + { + // Odd width + k = 1; // make texturewidthmask = 0 + } + + texturewidthmask[i] = k - 1; + textureheight[i] = texture->height << FRACBITS; + i++; + } + + return i; +} + +static INT32 +count_range +( const char * marker_start, + const char * marker_end, + const char * folder, + UINT16 wadnum) +{ + UINT16 j; + UINT16 texstart, texend; + INT32 count = 0; + + // Count flats + if (W_FileHasFolders(wadfiles[wadnum])) + { + texstart = W_CheckNumForFolderStartPK3(folder, wadnum, 0); + texend = W_CheckNumForFolderEndPK3(folder, wadnum, texstart); + } + else + { + texstart = W_CheckNumForMarkerStartPwad(marker_start, wadnum, 0); + texend = W_CheckNumForNamePwad(marker_end, wadnum, texstart); + } + + if (texstart != INT16_MAX && texend != INT16_MAX) + { + // PK3s have subfolders, so we can't just make a simple sum + if (W_FileHasFolders(wadfiles[wadnum])) + { + for (j = texstart; j < texend; j++) + { + if (!W_IsLumpFolder(wadnum, j)) // Check if lump is a folder; if not, then count it + count++; + } + } + else // Add all the textures between markers + { + count += (texend - texstart); + } + } + + return count; +} + +static INT32 R_CountTextures(UINT16 wadnum) +{ + UINT16 texturesLumpPos; + INT32 count = 0; // Load patches and textures. @@ -554,159 +674,127 @@ void R_LoadTextures(void) // the markers. // This system will allocate memory for all duplicate/patched textures even if it never uses them, // but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures. - for (w = 0, numtextures = 0; w < numwadfiles; w++) + + // Count the textures from TEXTURES lumps + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", wadnum, 0); + + while (texturesLumpPos != INT16_MAX) { - if (W_FileHasFolders(wadfiles[w])) - { - texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); - } - else - { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - } - - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - while (texturesLumpPos != INT16_MAX) - { - numtextures += R_CountTexturesInTEXTURESLump((UINT16)w, (UINT16)texturesLumpPos); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); - } - - // Add all the textures between TX_START and TX_END - if (texstart == INT16_MAX || texend == INT16_MAX) - continue; - - // PK3s have subfolders, so we can't just make a simple sum - if (W_FileHasFolders(wadfiles[w])) - { - for (j = texstart; j < texend; j++) - { - if (W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it - continue; - - numtextures++; - } - } - else - { - numtextures += (UINT32)(texend - texstart); - } + count += R_CountTexturesInTEXTURESLump(wadnum, texturesLumpPos); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", wadnum, texturesLumpPos + 1); } - // If no textures found by this point, bomb out - if (!numtextures) - I_Error("No textures detected in any WADs!\n"); + // Count single-patch textures + count += count_range(TX_START, TX_END, "textures/", wadnum); + + return count; +} + +static void +recallocuser +( void * user, + size_t old, + size_t new) +{ + char *p = Z_Realloc(*(void**)user, + new, PU_STATIC, user); + + if (new > old) + memset(&p[old], 0, (new - old)); +} + +static void R_AllocateTextures(INT32 add) +{ + const INT32 newtextures = (numtextures + add); + const size_t newsize = newtextures * sizeof (void*); + const size_t oldsize = numtextures * sizeof (void*); + + INT32 i; // Allocate memory and initialize to 0 for all the textures we are initialising. - // There are actually 5 buffers allocated in one for convenience. - textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); + recallocuser(&textures, oldsize, newsize); // Allocate texture column offset table. - texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); + recallocuser(&texturecolumnofs, oldsize, newsize); // Allocate texture referencing cache. - texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); - // Allocate texture width mask table. - texturewidthmask = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); - // Allocate texture height mask table. - textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); + recallocuser(&texturecache, oldsize, newsize); + // Allocate texture width table. + recallocuser(&texturewidthmask, oldsize, newsize); + // Allocate texture height table. + recallocuser(&textureheight, oldsize, newsize); // Create translation table for global animation. - texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL); + Z_Realloc(texturetranslation, (newtextures + 1) * sizeof(*texturetranslation), PU_STATIC, &texturetranslation); - for (i = 0; i < numtextures; i++) - texturetranslation[i] = i; - - for (i = 0, w = 0; w < numwadfiles; w++) + for (i = 0; i < numtextures; ++i) { - // Get the lump numbers for the markers in the WAD, if they exist. - if (W_FileHasFolders(wadfiles[w])) - { - texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - while (texturesLumpPos != INT16_MAX) - { - R_ParseTEXTURESLump(w, texturesLumpPos, &i); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); - } - } - else - { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0) + 1; - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - if (texturesLumpPos != INT16_MAX) - R_ParseTEXTURESLump(w, texturesLumpPos, &i); - } - - if (texstart == INT16_MAX || texend == INT16_MAX) - continue; - - // Work through each lump between the markers in the WAD. - for (j = 0; j < (texend - texstart); j++) - { - UINT16 wadnum = (UINT16)w; - lumpnum_t lumpnum = texstart + j; - - if (W_FileHasFolders(wadfiles[w])) - { - if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder - continue; // If it is then SKIP IT - } - - patchlump = (softwarepatch_t *)W_CacheLumpNumPwad(wadnum, lumpnum, PU_STATIC); - - //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad(wadnum, lumpnum), patchlump->width, patchlump->height); - texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); - - // Set texture properties. - M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); - texture->width = SHORT(patchlump->width); - texture->height = SHORT(patchlump->height); - texture->type = TEXTURETYPE_SINGLEPATCH; - texture->patchcount = 1; - texture->holes = false; - - // Allocate information for the texture's patches. - patch = &texture->patches[0]; - - patch->originx = patch->originy = 0; - patch->wad = wadnum; - patch->lump = texstart + j; - - Z_Free(patchlump); - - // determine width power of 2 -#if 1 - // [WDJ] only need to determine if exact power of 2. - k = 1; - while (k < texture->width) - k<<=1; -#else - // Largest power of 2 that fits within width. - k = 1; - while (k << 1 <= texture->width) - k <<= 1; -#endif - if (k != texture->width) - { - // Odd width - k = 1; // make texturewidthmask = 0 - } - - texturewidthmask[i] = k - 1; - textureheight[i] = texture->height << FRACBITS; - i++; - } + // R_FlushTextureCache relies on the user for + // Z_Free, texturecache has been reallocated so the + // user is now garbage memory. + Z_SetUser(texturecache[i], (void**)&texturecache[i]); } + while (i < newtextures) + { + texturetranslation[i] = i; + i++; + } +} + +static INT32 R_DefineTextures(INT32 i, UINT16 w) +{ + return Rloadtextures(i, w); +} + +static void R_FinishLoadingTextures(INT32 add) +{ + numtextures += add; + #ifdef HWRENDER if (rendermode == render_opengl) HWR_LoadMapTextures(numtextures); #endif } +// +// R_LoadTextures +// Initializes the texture list with the textures from the world map. +// +void R_LoadTextures(void) +{ + INT32 i, w; + INT32 newtextures = 0; + + for (w = 0; w < numwadfiles; w++) + { + newtextures += R_CountTextures((UINT16)w); + } + + // If no textures found by this point, bomb out + if (!newtextures) + I_Error("No textures detected in any WADs!\n"); + + R_AllocateTextures(newtextures); + + for (i = 0, w = 0; w < numwadfiles; w++) + { + i = R_DefineTextures(i, w); + } + + R_FinishLoadingTextures(i); +} + +void R_LoadTexturesPwad(UINT16 wadnum) +{ + INT32 newtextures = R_CountTextures(wadnum); + + if (!newtextures) + return; + + R_AllocateTextures(newtextures); + newtextures = R_DefineTextures(numtextures, wadnum) - numtextures; + R_FinishLoadingTextures(newtextures); +} + static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) { char *texturesToken; @@ -958,6 +1046,7 @@ static texture_t *R_ParseTexture(boolean actuallyLoadTexture) // Allocate memory for a zero-patch texture. Obviously, we'll be adding patches momentarily. resultTexture = (texture_t *)Z_Calloc(sizeof(texture_t), PU_STATIC, NULL); M_Memcpy(resultTexture->name, newTextureName, 8); + resultTexture->hash = quickncasehash(newTextureName, 8); resultTexture->width = newTextureWidth; resultTexture->height = newTextureHeight; resultTexture->type = TEXTURETYPE_COMPOSITE; @@ -1741,19 +1830,22 @@ void R_ClearTextureNumCache(boolean btell) INT32 R_CheckTextureNumForName(const char *name) { INT32 i; + UINT32 hash; // "NoTexture" marker. if (name[0] == '-') return 0; + hash = quickncasehash(name, 8); + for (i = 0; i < tidcachelen; i++) - if (!strncasecmp(tidcache[i].name, name, 8)) + if (tidcache[i].hash == hash && !strncasecmp(tidcache[i].name, name, 8)) return tidcache[i].id; // Need to parse the list backwards, so textures loaded more recently are used in lieu of ones loaded earlier //for (i = 0; i < numtextures; i++) <- old for (i = (numtextures - 1); i >= 0; i--) // <- new - if (!strncasecmp(textures[i]->name, name, 8)) + if (textures[i]->hash == hash && !strncasecmp(textures[i]->name, name, 8)) { tidcachelen++; Z_Realloc(tidcache, tidcachelen * sizeof(*tidcache), PU_STATIC, &tidcache); @@ -1762,6 +1854,7 @@ INT32 R_CheckTextureNumForName(const char *name) #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "texture #%s: %s\n", sizeu1(tidcachelen), tidcache[tidcachelen-1].name); #endif + tidcache[tidcachelen-1].hash = hash; tidcache[tidcachelen-1].id = i; return i; } diff --git a/src/r_data.h b/src/r_data.h index 58afc34d0..295cff401 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -53,6 +53,7 @@ typedef struct // Keep name for switch changing, etc. char name[8]; UINT8 type; // TEXTURETYPE_ + UINT32 hash; INT16 width, height; boolean holes; // All the patches[patchcount] are drawn back to front into the cached texture. @@ -76,6 +77,7 @@ extern CV_PossibleValue_t Color_cons_t[]; // Load TEXTURE1/TEXTURE2/PNAMES definitions, create lookup tables void R_LoadTextures(void); +void R_LoadTexturesPwad(UINT16 wadnum); void R_FlushTextureCache(void); UINT8 *R_GenerateTexture(size_t texnum);