From 989dcfcf1c7abb88b1ef79a8b370782d3a681198 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 7 Jun 2022 00:00:43 +0200 Subject: [PATCH] - avoid storing texture pointers in longer lived data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * these circumvented all internal texture replacement logic. Texture objects should only be resolved right before drawing them * added an explicit ‚tilebackground‘ option for the summary screen to fix problems with bad decision logic based on incorrect texture type checks. Automatic tiling no longer depends on texture type, but solely on size. * added a DrawTexture variant that can be passed a texture ID instead of a pointer --- src/common/2d/v_draw.cpp | 27 ++++++++++--- src/common/2d/v_draw.h | 1 + src/common/console/c_console.cpp | 2 +- src/console/c_cmds.cpp | 2 +- src/d_main.cpp | 14 +++---- src/hu_scores.cpp | 3 +- src/intermission/intermission.cpp | 8 ++-- src/rendering/r_utility.cpp | 2 +- src/wi_stuff.cpp | 63 ++++++++++++++++++------------- 9 files changed, 74 insertions(+), 48 deletions(-) diff --git a/src/common/2d/v_draw.cpp b/src/common/2d/v_draw.cpp index b784b60e2..fbf28a0b0 100644 --- a/src/common/2d/v_draw.cpp +++ b/src/common/2d/v_draw.cpp @@ -194,10 +194,8 @@ int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1; // //========================================================================== -void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, ...) +static void DoDrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, Va_List& tags) { - Va_List tags; - va_start(tags.list, tags_first); DrawParms parms; if (!img || !img->isValid()) return; @@ -210,6 +208,23 @@ void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int t drawer->AddTexture(img, parms); } + +void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, ...) +{ + Va_List tags; + va_start(tags.list, tags_first); + DoDrawTexture(drawer, img, x, y, tags_first, tags); +} + +void DrawTexture(F2DDrawer *drawer, FTextureID texid, bool animate, double x, double y, int tags_first, ...) +{ + Va_List tags; + va_start(tags.list, tags_first); + auto img = TexMan.GetGameTexture(texid, animate); + DoDrawTexture(drawer, img, x, y, tags_first, tags); +} + + //========================================================================== // // ZScript texture drawing function @@ -218,7 +233,7 @@ void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int t int ListGetInt(VMVa_List &tags); -static void DrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y, VMVa_List &args) +static void DoDrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y, VMVa_List &args) { DrawParms parms; uint32_t tag = ListGetInt(args); @@ -242,7 +257,7 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture) auto tex = TexMan.GameByIndex(texid, animate); VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 }; - DrawTexture(twod, tex, x, y, args); + DoDrawTexture(twod, tex, x, y, args); return 0; } @@ -1609,4 +1624,4 @@ DEFINE_ACTION_FUNCTION(_Screen, SetOffset) PARAM_FLOAT(x); PARAM_FLOAT(y); ACTION_RETURN_VEC2(twod->SetOffset(DVector2(x, y))); -} \ No newline at end of file +} diff --git a/src/common/2d/v_draw.h b/src/common/2d/v_draw.h index 673460848..53794b601 100644 --- a/src/common/2d/v_draw.h +++ b/src/common/2d/v_draw.h @@ -274,6 +274,7 @@ void DrawText(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double void DrawChar(F2DDrawer* drawer, FFont* font, int normalcolor, double x, double y, int character, int tag_first, ...); void DrawTexture(F2DDrawer* drawer, FGameTexture* img, double x, double y, int tags_first, ...); +void DrawTexture(F2DDrawer *drawer, FTextureID texid, bool animate, double x, double y, int tags_first, ...); void DoDim(F2DDrawer* drawer, PalEntry color, float amount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr); void Dim(F2DDrawer* drawer, PalEntry color, float damount, int x1, int y1, int w, int h, FRenderStyle* style = nullptr); diff --git a/src/common/console/c_console.cpp b/src/common/console/c_console.cpp index 3d54e6adb..bb7018a13 100644 --- a/src/common/console/c_console.cpp +++ b/src/common/console/c_console.cpp @@ -600,7 +600,7 @@ void C_DrawConsole () if (conback.isValid() && gamestate != GS_FULLCONSOLE) { - DrawTexture (twod, TexMan.GetGameTexture(conback), 0, visheight - screen->GetHeight(), + DrawTexture (twod, conback, false, 0, visheight - screen->GetHeight(), DTA_DestWidth, twod->GetWidth(), DTA_DestHeight, twod->GetHeight(), DTA_ColorOverlay, conshade, diff --git a/src/console/c_cmds.cpp b/src/console/c_cmds.cpp index 7597b7158..a45bc1cca 100644 --- a/src/console/c_cmds.cpp +++ b/src/console/c_cmds.cpp @@ -941,7 +941,7 @@ CCMD(currentpos) AActor *mo = players[consoleplayer].mo; if(mo) { - Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, sector lightlevel: %d, actor lightlevel\n", + Printf("Current player position: (%1.3f,%1.3f,%1.3f), angle: %1.3f, floorheight: %1.3f, sector:%d, sector lightlevel: %d, actor lightlevel: %d\n", mo->X(), mo->Y(), mo->Z(), mo->Angles.Yaw.Normalized360().Degrees, mo->floorz, mo->Sector->sectornum, mo->Sector->lightlevel, mo->LightLevel); } else diff --git a/src/d_main.cpp b/src/d_main.cpp index e658d74a3..b28bd24f6 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -325,7 +325,7 @@ bool advancedemo; FILE *debugfile; gamestate_t wipegamestate = GS_DEMOSCREEN; // can be -1 to force a wipe bool PageBlank; -FGameTexture *Advisory; +FTextureID Advisory; FTextureID Page; const char *Subtitle; bool nospriterename; @@ -1176,7 +1176,7 @@ void D_DoomLoop () r_NoInterpolate = true; Page.SetInvalid(); Subtitle = nullptr; - Advisory = nullptr; + Advisory.SetInvalid(); vid_cursor.Callback(); @@ -1264,7 +1264,7 @@ void D_PageDrawer (void) ClearRect(twod, 0, 0, SCREENWIDTH, SCREENHEIGHT, 0, 0); if (Page.Exists()) { - DrawTexture(twod, TexMan.GetGameTexture(Page, true), 0, 0, + DrawTexture(twod, Page, true, 0, 0, DTA_Fullscreen, true, DTA_Masked, false, DTA_BilinearFilter, true, @@ -1275,9 +1275,9 @@ void D_PageDrawer (void) FFont* font = generic_ui ? NewSmallFont : SmallFont; DrawFullscreenSubtitle(font, GStrings[Subtitle]); } - if (Advisory != nullptr) + if (Advisory.isValid()) { - DrawTexture(twod, Advisory, 4, 160, DTA_320x200, true, TAG_DONE); + DrawTexture(twod, Advisory, true, 4, 160, DTA_320x200, true, TAG_DONE); } } @@ -1466,7 +1466,7 @@ void D_DoAdvanceDemo (void) case 3: if (gameinfo.advisoryTime) { - Advisory = TexMan.GetGameTextureByName("ADVISOR"); + Advisory = TexMan.GetTextureID("ADVISOR", ETextureType::MiscPatch); demosequence = 1; pagetic = (int)(gameinfo.advisoryTime * TICRATE); break; @@ -1475,7 +1475,7 @@ void D_DoAdvanceDemo (void) [[fallthrough]]; case 1: - Advisory = NULL; + Advisory.SetInvalid(); if (!M_DemoNoPlay) { democount++; diff --git a/src/hu_scores.cpp b/src/hu_scores.cpp index c7fa10cdb..d9c36f8b4 100644 --- a/src/hu_scores.cpp +++ b/src/hu_scores.cpp @@ -430,8 +430,7 @@ static void HU_DrawPlayer (player_t *player, bool highlight, int col1, int col2, auto icon = FSetTextureID(player->mo->IntVar(NAME_ScoreIcon)); if (icon.isValid()) { - auto pic = TexMan.GetGameTexture(icon); - DrawTexture(twod, pic, col3, y, + DrawTexture(twod, icon, false, col3, y, DTA_CleanNoMove, true, TAG_DONE); } diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 03034a2dd..0db0cb0ef 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -244,7 +244,7 @@ void DIntermissionScreen::Drawer () { if (!mFlatfill) { - DrawTexture(twod, TexMan.GetGameTexture(mBackground), 0, 0, DTA_Fullscreen, true, TAG_DONE); + DrawTexture(twod, mBackground, false, 0, 0, DTA_Fullscreen, true, TAG_DONE); } else { @@ -258,7 +258,7 @@ void DIntermissionScreen::Drawer () for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) - DrawTexture(twod, TexMan.GetGameTexture(mOverlays[i].mPic), mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE); + DrawTexture(twod, mOverlays[i].mPic, false, mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, TAG_DONE); } FFont* font = generic_ui ? NewSmallFont : SmallFont; DrawFullscreenSubtitle(font, mSubtitle); @@ -311,11 +311,11 @@ void DIntermissionScreenFader::Drawer () if (mType == FADE_In) factor = 1.0 - factor; int color = MAKEARGB(int(factor*255), 0,0,0); - DrawTexture(twod, TexMan.GetGameTexture(mBackground), 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); + DrawTexture(twod, mBackground, false, 0, 0, DTA_Fullscreen, true, DTA_ColorOverlay, color, TAG_DONE); for (unsigned i=0; i < mOverlays.Size(); i++) { if (CheckOverlay(i)) - DrawTexture(twod, TexMan.GetGameTexture(mOverlays[i].mPic), mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); + DrawTexture(twod, mOverlays[i].mPic, false, mOverlays[i].x, mOverlays[i].y, DTA_320x200, true, DTA_ColorOverlay, color, TAG_DONE); } } } diff --git a/src/rendering/r_utility.cpp b/src/rendering/r_utility.cpp index 3ef898d3a..aa85d6e99 100644 --- a/src/rendering/r_utility.cpp +++ b/src/rendering/r_utility.cpp @@ -800,7 +800,7 @@ void R_SetupFrame (FRenderViewpoint &viewpoint, FViewWindow &viewwindow, AActor sector_t *oldsector = viewpoint.ViewLevel->PointInRenderSubsector(iview->Old.Pos)->sector; if (gamestate != GS_TITLELEVEL && - (player && ((player->cheats & CF_CHASECAM)) || (r_deathcamera && viewpoint.camera->health <= 0))) + ((player && (player->cheats & CF_CHASECAM)) || (r_deathcamera && viewpoint.camera->health <= 0))) { // [RH] Use chasecam view DefaultDraw = false; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index aadab86d6..129dba2ec 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -93,6 +93,7 @@ static const char *WI_Cmd[] = { "NoAutostartMap", "Screensize", + "TileBackground", NULL }; @@ -142,7 +143,7 @@ class DInterBackground : public DObject int period; // period in tics between animations yahpt_t loc; // location of animation int data; // ALWAYS: n/a, RANDOM: period deviation (<256) - TArray frames; // actual graphics for frames of animations + TArray frames; // actual graphics for frames of animations // following must be initialized to zero before use! int nexttic; // next value of bcnt (used in conjunction with period) @@ -165,13 +166,14 @@ private: TArray lnodes; TArray anims; int bcnt = 0; // used for timing of background animation - TArray yah; // You Are Here graphic - FGameTexture* splat = nullptr; // splat - FGameTexture *background = nullptr; + TArray yah; // You Are Here graphic + FTextureID splat{}; // splat + FTextureID background{}; wbstartstruct_t *wbs; level_info_t *exitlevel; int bgwidth = -1; int bgheight = -1; + bool tilebackground = false; public: @@ -215,7 +217,7 @@ private: // //==================================================================== - void drawOnLnode(int n, FGameTexture * c[], int numc, double backwidth, double backheight) + void drawOnLnode(int n, FTextureID c[], int numc, double backwidth, double backheight) { int i; for (i = 0; iGetDisplayWidth(); - bottom = c[i]->GetDisplayHeight(); - left = lnodes[n].x - c[i]->GetDisplayLeftOffset(); - top = lnodes[n].y - c[i]->GetDisplayTopOffset(); + auto tex = TexMan.GetGameTexture(c[i]); + right = tex->GetDisplayWidth(); + bottom = tex->GetDisplayHeight(); + left = lnodes[n].x - tex->GetDisplayLeftOffset(); + top = lnodes[n].y - tex->GetDisplayTopOffset(); right += left; bottom += top; if (left >= 0 && right < 320 && top >= 0 && bottom < 200) { - DrawTexture(twod, c[i], lnodes[n].x, lnodes[n].y, DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidthF, backwidth, DTA_VirtualHeightF, backheight, TAG_DONE); + DrawTexture(twod, tex, lnodes[n].x, lnodes[n].y, DTA_FullscreenScale, FSMode_ScaleToFit43, DTA_VirtualWidthF, backwidth, DTA_VirtualHeightF, backheight, TAG_DONE); break; } } @@ -355,20 +357,21 @@ bool DInterBackground::LoadBackground(bool isenterpic) // Strife doesn't have an intermission pic so choose something neutral. if (isenterpic) return false; lumpname = gameinfo.BorderFlat; + tilebackground = true; break; } } if (lumpname == NULL) { // shouldn't happen! - background = NULL; + background.SetInvalid(); return false; } lnodes.Clear(); anims.Clear(); yah.Clear(); - splat = NULL; + splat.SetInvalid(); // a name with a starting '$' indicates an intermission script if (*lumpname != '$') @@ -394,13 +397,13 @@ bool DInterBackground::LoadBackground(bool isenterpic) case 1: // Splat sc.MustGetString(); - splat = TexMan.GetGameTextureByName(sc.String); + splat = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); break; case 2: // Pointers while (sc.GetString() && !sc.Crossed) { - yah.Push(TexMan.GetGameTextureByName(sc.String)); + yah.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); } if (sc.Crossed) sc.UnGet(); @@ -466,6 +469,10 @@ bool DInterBackground::LoadBackground(bool isenterpic) sc.MustGetNumber(); bgheight = sc.Number; break; + + case 16: // tilebackground + tilebackground = true; + break; readanimation: sc.MustGetString(); @@ -500,14 +507,14 @@ bool DInterBackground::LoadBackground(bool isenterpic) if (!sc.CheckString("{")) { sc.MustGetString(); - an.frames.Push(TexMan.GetGameTextureByName(sc.String)); + an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); } else { while (!sc.CheckString("}")) { sc.MustGetString(); - an.frames.Push(TexMan.GetGameTextureByName(sc.String)); + an.frames.Push(TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny)); } } an.ctr = -1; @@ -522,7 +529,7 @@ bool DInterBackground::LoadBackground(bool isenterpic) an.loc.y = sc.Number; sc.MustGetString(); an.frames.Reserve(1); // allocate exactly one element - an.frames[0] = TexMan.GetGameTextureByName(sc.String); + an.frames[0] = TexMan.CheckForTexture(sc.String, ETextureType::MiscPatch, FTextureManager::TEXMAN_TryAny); anims.Push(an); break; @@ -538,7 +545,10 @@ bool DInterBackground::LoadBackground(bool isenterpic) texture = TexMan.GetTextureID("INTERPIC", ETextureType::MiscPatch); } } - background = TexMan.GetGameTexture(texture); + background = texture; + auto tex= TexMan.GetGameTexture(texture); + // extremely small textures will always be tiled. + if (tex && tex->GetDisplayWidth() < 128 && tex->GetDisplayHeight() < 128) tilebackground = true; return noautostartmap; } @@ -605,25 +615,26 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe double animwidth = bgwidth; // For a flat fill or clear background scale animations to 320x200 double animheight = bgheight; - if (background) + if (background.isValid()) { + auto bgtex = TexMan.GetGameTexture(background); // background - if (background->isMiscPatch()) + if (!tilebackground) { // if no explicit size was set scale all animations below to fit the size of the base pic // The base pic is always scaled to fit the screen so this allows // placing the animations precisely where they belong on the base pic if (bgwidth < 0 || bgheight < 0) { - animwidth = background->GetDisplayWidth(); - animheight = background->GetDisplayHeight(); + animwidth = bgtex->GetDisplayWidth(); + animheight = bgtex->GetDisplayHeight(); if (animheight == 200) animwidth = 320; // deal with widescreen replacements that keep the original coordinates. } - DrawTexture(twod, background, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); + DrawTexture(twod, bgtex, 0, 0, DTA_FullscreenEx, FSMode_ScaleToFit43, TAG_DONE); } else { - twod->AddFlatFill(0, 0, twod->GetWidth(), twod->GetHeight(), background, (inter_classic_scaling ? -1 : 0)); + twod->AddFlatFill(0, 0, twod->GetWidth(), twod->GetHeight(), bgtex, (inter_classic_scaling ? -1 : 0)); } } else @@ -674,7 +685,7 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe break; } if (a->ctr >= 0) - DrawTexture(twod, a->frames[a->ctr], a->loc.x, a->loc.y, + DrawTexture(twod, a->frames[a->ctr], false, a->loc.x, a->loc.y, DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, FSMode_ScaleToFit43, TAG_DONE); }