diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 0168acc0e..df5670f7c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2968,9 +2968,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) CON_LogMessage(M_GetText("Speeding off to level...\n")); } - if (demo.playback && !demo.timing) - precache = false; - if (resetplayer) { if (!FLS || (netgame || multiplayer)) @@ -2986,8 +2983,7 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) demo.savemode = (cv_recordmultiplayerdemos.value == 2) ? DSM_WILLAUTOSAVE : DSM_NOTSAVING; demo.savebutton = 0; G_InitNew(pencoremode, mapname, resetplayer, skipprecutscene); - if (demo.playback && !demo.timing) - precache = true; + if (demo.timing) G_DoneLevelLoad(); diff --git a/src/doomstat.h b/src/doomstat.h index f70f97059..1d487d2f4 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -541,9 +541,6 @@ extern FILE *debugfile; extern INT32 debugload; #endif -// if true, load all graphics at level load -extern boolean precache; - // wipegamestate can be set to -1 // to force a wipe on the next draw extern gamestate_t wipegamestate; diff --git a/src/g_game.c b/src/g_game.c index 86be0e159..9b52b8680 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -330,8 +330,6 @@ static struct { // There is no conflict here. demoghost *ghosts = NULL; -boolean precache = true; // if true, load all graphics at start - INT16 prevmap, nextmap; // save if director is enabled diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index af06ecba6..eccf09af4 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -29,6 +29,9 @@ #include "../r_draw.h" #include "../r_main.h" #include "../r_patch.h" // patch rotation +#include "../p_setup.h" // levelflats +#include "../p_spec.h" // anim_t +#include "../r_sky.h" INT32 patchformat = GL_TEXFMT_AP_88; // use alpha for holes INT32 textureformat = GL_TEXFMT_P_8; // use chromakey for hole @@ -546,6 +549,260 @@ void HWR_FreeTextureCache(void) gl_numtextures = 0; } +static void HWR_PrecacheLevelFlats(void) +{ + levelflat_t levelflat; + lumpnum_t lump; + size_t i, j; + INT32 k; + + // special case for encore +#ifdef GLENCORE + if (encoremode) + { + // go through all sectors to determine if it should be remapped for encore + for (i = 0; i < numsectors; i++) + { + sector_t *sec = §ors[i]; + + // sector checked already? + if (sec->validcount == validcount) + continue; + + sec->validcount = validcount; + + // gotta check sector floor and ceiling + for (j = 0; j < 2; j++) + { + const boolean ceiling = (j == 1); + INT32 pic = ceiling ? sec->ceilingpic : sec->floorpic; + + levelflat = levelflats[pic]; + + lump = levelflat.lumpnum; + HWR_GetFlat(lump, R_NoEncore(sec, ceiling)); + + if (levelflat.speed) // it is an animated flat + { + for (k = 1; k < levelflat.numpics; k++) + { + lump = levelflat.baselumpnum + k; + HWR_GetFlat(lump, R_NoEncore(sec, ceiling)); + } + } + } + } + } + else +#endif + { + // on non encore we have it simple + // just load every flat in the level + for (i = 0; i < numlevelflats; i++) + { + levelflat = levelflats[i]; + lump = levelflat.lumpnum; + + HWR_GetFlat(lump, false); + + if (levelflat.speed) // it is an animated flat + { + for (k = 1; k < levelflat.numpics; k++) + { + lump = levelflat.baselumpnum + k; + HWR_GetFlat(lump, false); + } + } + } + } +} + +static void HWR_PrecacheLevelTextures(void) +{ + char *texturepresent; + anim_t *anim; + size_t i, j; + INT32 h; + + texturepresent = calloc(numtextures, sizeof (*texturepresent)); + if (texturepresent == NULL) I_Error("%s: Out of memory looking up textures", "HWR_PrecacheLevel"); + + for (i = 0; i < numlines; i++) + { + line_t *line = &lines[i]; +#ifdef GLENCORE + const int noencoremap = ((line->flags & ML_TFERLINE) ? 2 : 1); +#else + const int noencoremap = 1; +#endif + + // line checked already? + if (line->validcount == validcount) + continue; + + line->validcount = validcount; + + // two sides + for (j = 0; j < 2; j++) + { + side_t *side = &sides[line->sidenum[j]]; + + // Single-side linedef + if (line->sidenum[j] == 0xffff) + continue; + + if (side->toptexture >= 0 && side->toptexture < numtextures) + { + texturepresent[side->toptexture] = 1|noencoremap; + } + if (side->midtexture >= 0 && side->midtexture < numtextures) + { + texturepresent[side->midtexture] = 1|noencoremap; + } + if (side->bottomtexture >= 0 && side->bottomtexture < numtextures) + { + texturepresent[side->bottomtexture] = 1|noencoremap; + } + } + } + + // check for animated textures + for (anim = anims; anim < lastanim; anim++) + { + if (!anim->istexture) + continue; + + const char texpresent = texturepresent[anim->basepic]; + + if (!texpresent) + continue; + + if (texpresent & 1) + { + for (h = 1; h < anim->numpics; h++) + { + HWR_GetTexture(anim->basepic+h, false); + } + } +#ifdef GLENCORE + if (texpresent & 2) + { + for (h = 1; h < anim->numpics; h++) + { + HWR_GetTexture(anim->basepic+h, true); + } + } +#endif + } + + // Sky texture is always present. + // Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat, + // while the sky texture is stored like a wall texture, with a skynum dependent name. + texturepresent[skytexture] = 1; + + for (i = 0; i < (unsigned)numtextures; i++) + { + const char texpresent = texturepresent[i]; + + if (!texpresent) + continue; + + if (texpresent & 1) + { + HWR_GetTexture(i, false); + } +#ifdef GLENCORE + if (texpresent & 2) + { + HWR_GetTexture(i, true); + } +#endif + } + free(texturepresent); +} + +static void HWR_PrecacheLevelSprites(void) +{ + GLPatch_t *spritepatch; + char *spritepresent; + size_t i, j, k; + lumpnum_t lump; + + thinker_t *th; + mobj_t *mo; + spriteframe_t *sf; + + spritepresent = calloc(numsprites, sizeof (*spritepresent)); + if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "HWR_PrecacheLevel"); + + for (th = thinkercap.next; th != &thinkercap; th = th->next) + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + mo = (mobj_t *)th; + + // ogl is weird + // for some reason it does not want to preload sprites with colormaps + // so just save us the work + if (mo->color || mo->colorized) + continue; + + spritepresent[mo->sprite] = 1; + } + + for (i = 0; i < numsprites; i++) + { + if (!spritepresent[i]) + continue; + + for (j = 0; j < sprites[i].numframes; j++) + { + sf = &sprites[i].spriteframes[j]; + +#define cacheang(a) {\ + lump = sf->lumppat[a];\ + spritepatch = (GLPatch_t *)W_CachePatchNum(lump, PU_CACHE);\ + if (spritepatch != NULL)\ + HWR_GetPatch(spritepatch);\ + } + // see R_InitSprites for more about lumppat,lumpid + switch (sf->rotate) + { + case SRF_SINGLE: + cacheang(0); + break; + case SRF_2D: + cacheang(2); + cacheang(6); + break; + default: + k = 8; + while (k--) + cacheang(k); + break; + } +#undef cacheang + } + } + free(spritepresent); +} + +void HWR_PrecacheLevel(void) +{ + if (rendermode != render_opengl) + return; + + // Precache flats. + HWR_PrecacheLevelFlats(); + + // Precache textures. + HWR_PrecacheLevelTextures(); + + // Precache sprites. + HWR_PrecacheLevelSprites(); +} + void HWR_LoadTextures(size_t pnumtextures) { // we must free it since numtextures changed diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index fe346f4c9..edba8a025 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -49,13 +49,16 @@ typedef struct gl_vissprite_s extern extrasubsector_t *extrasubsectors; extern size_t addsubsector; +void HWR_FreeExtraSubsectors(void); + // -------- // hw_cache.c // -------- void HWR_InitTextureCache(void); void HWR_FreeTextureCache(void); void HWR_FreeMipmapCache(void); -void HWR_FreeExtraSubsectors(void); + +void HWR_PrecacheLevel(void); void HWR_GetFlat(lumpnum_t flatlumpnum, boolean noencoremap); // ^ some flats must NOT be remapped to encore, since we remap them as we cache them for ease, adding a toggle here seems wise. diff --git a/src/p_setup.c b/src/p_setup.c index 633c4094e..a98aa594d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -586,16 +586,30 @@ levelflat_t *levelflats; //SoM: Other files want this info. size_t P_PrecacheLevelFlats(void) { + levelflat_t levelflat; lumpnum_t lump; size_t i, flatmem = 0; + INT32 k; //SoM: 4/18/2000: New flat code to make use of levelflats. for (i = 0; i < numlevelflats; i++) { - lump = levelflats[i].lumpnum; + levelflat = levelflats[i]; + lump = levelflat.lumpnum; if (devparm) flatmem += W_LumpLength(lump); R_GetFlat(lump); + + if (levelflat.speed) // it is an animated flat + { + for (k = 1; k < levelflat.numpics; k++) + { + lump = levelflat.baselumpnum + k; + if (devparm) + flatmem += W_LumpLength(lump); + R_GetFlat(lump); + } + } } return flatmem; @@ -624,6 +638,7 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat) // store the flat lump number levelflat->lumpnum = R_GetFlatNumForName(flatname); + levelflat->baselumpnum = LUMPERROR; #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); @@ -668,6 +683,7 @@ INT32 P_AddLevelFlatRuntime(const char *flatname) // store the flat lump number levelflat->lumpnum = R_GetFlatNumForName(flatname); + levelflat->baselumpnum = LUMPERROR; #ifndef ZDEBUG CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name); @@ -2970,7 +2986,7 @@ boolean P_SetupLevel(boolean skipprecip, boolean reloadinggamestate) if (rendermode != render_none && !reloadinggamestate) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, levelfadecol); - if (precache || dedicated) + if (cv_precachetextures.value) R_PrecacheLevel(); nextmapoverride = 0; diff --git a/src/p_spec.c b/src/p_spec.c index 3f9dfd626..4eb380df0 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -51,19 +51,6 @@ mobj_t *skyboxmo[2]; // This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize. #define MAXFLATSIZE (2048<> ((j-1)*4))&15) +/** Animated texture descriptor + * This keeps track of an animated texture or an animated flat. + * \sa P_UpdateSpecials, P_InitPicAnims, animdef_t + */ +typedef struct +{ + SINT8 istexture; ///< ::true for a texture, ::false for a flat + INT32 picnum; ///< The end flat number + INT32 basepic; ///< The start flat number + INT32 numpics; ///< Number of frames in the animation + tic_t speed; ///< Number of tics for which each frame is shown +} anim_t; + +extern anim_t *lastanim; +extern anim_t *anims; + // at game start void P_InitPicAnims(void); diff --git a/src/r_data.c b/src/r_data.c index 98431510d..5070107be 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -1618,33 +1618,13 @@ INT32 R_TextureNumForName(const char *name) return i; } -// -// R_PrecacheLevel -// -// Preloads all relevant graphics for the level. -// -void R_PrecacheLevel(void) +static void R_PrecacheLevelTextures(void) { - char *texturepresent, *spritepresent; - size_t i, j, k; - lumpnum_t lump; + char *texturepresent; + anim_t *anim; + size_t j; + INT32 h; - thinker_t *th; - spriteframe_t *sf; - - if (demo.playback) - return; - - // do not flush the memory, Z_Malloc twice with same user will cause error in Z_CheckHeap() - if (rendermode != render_soft) - return; - - // Precache flats. - flatmemory = P_PrecacheLevelFlats(); - - // - // Precache textures. - // // no need to precache all software textures in 3D mode // (note they are still used with the reference software view) texturepresent = calloc(numtextures, sizeof (*texturepresent)); @@ -1661,6 +1641,22 @@ void R_PrecacheLevel(void) texturepresent[sides[j].bottomtexture] = 1; } + // check for animated textures + for (anim = anims; anim < lastanim; anim++) + { + if (!anim->istexture) + continue; + + if (!texturepresent[anim->basepic]) + continue; + + for (h = 1; h < anim->numpics; h++) + { + if (!texturecache[anim->basepic+h]) + R_GenerateTexture(anim->basepic+h); + } + } + // Sky texture is always present. // Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat, // while the sky texture is stored like a wall texture, with a skynum dependent name. @@ -1678,16 +1674,27 @@ void R_PrecacheLevel(void) // since we cache entire composite textures } free(texturepresent); +} + +static void R_PrecacheLevelSprites(void) +{ + char *spritepresent; + size_t i, j, k; + lumpnum_t lump; + + thinker_t *th; + spriteframe_t *sf; - // - // Precache sprites. - // spritepresent = calloc(numsprites, sizeof (*spritepresent)); if (spritepresent == NULL) I_Error("%s: Out of memory looking up sprites", "R_PrecacheLevel"); for (th = thinkercap.next; th != &thinkercap; th = th->next) - if (th->function.acp1 == (actionf_p1)P_MobjThinker) - spritepresent[((mobj_t *)th)->sprite] = 1; + { + if (th->function.acp1 != (actionf_p1)P_MobjThinker) + continue; + + spritepresent[((mobj_t *)th)->sprite] = 1; + } spritememory = 0; for (i = 0; i < numsprites; i++) @@ -1698,17 +1705,65 @@ void R_PrecacheLevel(void) for (j = 0; j < sprites[i].numframes; j++) { sf = &sprites[i].spriteframes[j]; - for (k = 0; k < 8; k++) - { - // see R_InitSprites for more about lumppat,lumpid - lump = sf->lumppat[k]; - if (devparm) - spritememory += W_LumpLength(lump); - W_CachePatchNum(lump, PU_CACHE); +#define cacheang(a) {\ + lump = sf->lumppat[a];\ + if (devparm)\ + spritememory += W_LumpLength(lump);\ + W_CachePatchNum(lump, PU_CACHE);\ } + // see R_InitSprites for more about lumppat,lumpid + switch (sf->rotate) + { + case SRF_SINGLE: + cacheang(0); + break; + case SRF_2D: + cacheang(2); + cacheang(6); + break; + default: + k = 8; + while (k--) + cacheang(k); + break; + } +#undef cacheang } } + free(spritepresent); +} + +// +// R_PrecacheLevel +// +// Preloads all relevant graphics for the level. +// +void R_PrecacheLevel(void) +{ + // do not flush the memory, Z_Malloc twice with same user will cause error in Z_CheckHeap() + if (rendermode == render_none) + return; + + if (demo.playback) + return; + +#ifdef HWRENDER + if (rendermode == render_opengl) + { + HWR_PrecacheLevel(); + return; + } +#endif + + // Precache flats. + flatmemory = P_PrecacheLevelFlats(); + + // Precache textures. + R_PrecacheLevelTextures(); + + // Precache sprites. + R_PrecacheLevelSprites(); // FIXME: this is no longer correct with OpenGL render mode CONS_Debug(DBG_SETUP, "Precache level done:\n" diff --git a/src/r_main.c b/src/r_main.c index ba60d2553..b39b58749 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -164,6 +164,9 @@ static void Precipstuff_OnChange(void); consvar_t cv_tailspickup = {"tailspickup", "On", CV_NETVAR|CV_NOSHOWHELP, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; +// if enabled, load all graphics at level load +consvar_t cv_precachetextures = {"precachetextures", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; + consvar_t cv_chasecam[MAXSPLITSCREENPLAYERS] = { {"chasecam", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}, {"chasecam2", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}, @@ -1532,6 +1535,8 @@ void R_RegisterEngineStuff(void) if (dedicated) return; + CV_RegisterVar(&cv_precachetextures); + CV_RegisterVar(&cv_translucency); CV_RegisterVar(&cv_drawdist); CV_RegisterVar(&cv_drawdist_precip); diff --git a/src/r_main.h b/src/r_main.h index 9a976d659..1b8d8c71c 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -174,6 +174,7 @@ extern ps_metric_t ps_numpolyobjects; // REFRESH - the actual rendering functions. // +extern consvar_t cv_precachetextures; extern consvar_t cv_showhud, cv_translucenthud, cv_uncappedhud; extern consvar_t cv_homremoval; extern consvar_t cv_chasecam[MAXSPLITSCREENPLAYERS];