From 6776508239311d7599d70ead77c8eab1e4932899 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 16 Sep 2020 16:42:44 +0200 Subject: [PATCH] - widescreen asset setup and consolidation of .def file loading. --- source/blood/src/blood.cpp | 10 +----- source/build/include/build.h | 2 +- source/build/src/defs.cpp | 4 +-- source/common/2d/v_draw.cpp | 6 ++-- source/core/gamecontrol.cpp | 33 +++++++++++++++++- source/core/gamecontrol.h | 1 + source/core/statusbar.cpp | 19 ++++++++++ source/core/statusbar.h | 1 + source/exhumed/src/exhumed.cpp | 8 +---- source/exhumed/src/status.cpp | 2 ++ source/games/duke/src/game.cpp | 31 ++-------------- source/games/duke/src/hudweapon_r.cpp | 12 +++---- source/games/duke/src/sbar_d.cpp | 9 ++--- source/games/duke/src/sbar_r.cpp | 5 ++- source/sw/src/game.cpp | 2 +- source/sw/src/sbar.cpp | 5 ++- .../static/filter/duke/tiles/duke3d/2462.PNG | Bin 0 -> 5864 bytes 17 files changed, 85 insertions(+), 65 deletions(-) create mode 100644 wadsrc/static/filter/duke/tiles/duke3d/2462.PNG diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index 562342e91..cd9e9d01b 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -417,16 +417,8 @@ void GameInterface::app_init() I_FatalError("TILES###.ART files not found"); levelLoadDefaults(); + LoadDefinitions(); - loaddefinitionsfile(BLOODWIDESCREENDEF); - - const char* defsfile = G_DefFile(); - uint32_t stime = I_msTime(); - if (!loaddefinitionsfile(defsfile)) - { - uint32_t etime = I_msTime(); - Printf(PRINT_NONOTIFY, "Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime - stime); - } TileFiles.SetBackup(); powerupInit(); Printf(PRINT_NONOTIFY, "Loading cosine table\n"); diff --git a/source/build/include/build.h b/source/build/include/build.h index e66077be9..546364b9a 100644 --- a/source/build/include/build.h +++ b/source/build/include/build.h @@ -950,7 +950,7 @@ int32_t md_definehud (int32_t modelid, int32_t tilex, vec3f_t add, int32_t md_undefinetile(int32_t tile); int32_t md_undefinemodel(int32_t modelid); -int32_t loaddefinitionsfile(const char *fn); +int32_t loaddefinitionsfile(const char *fn, bool loadadds = false); // if loadboard() fails with -2 return, try loadoldboard(). if it fails with // -2, board is dodgy diff --git a/source/build/src/defs.cpp b/source/build/src/defs.cpp index b9c187b15..3d79dd4f1 100644 --- a/source/build/src/defs.cpp +++ b/source/build/src/defs.cpp @@ -3204,7 +3204,7 @@ static int32_t defsparser(scriptfile *script) } -int32_t loaddefinitionsfile(const char *fn) +int32_t loaddefinitionsfile(const char *fn, bool loadadds) { scriptfile *script; @@ -3217,7 +3217,7 @@ int32_t loaddefinitionsfile(const char *fn) defsparser(script); } - if (userConfig.AddDefs) for (auto& m : *userConfig.AddDefs) + if (userConfig.AddDefs && loadadds) for (auto& m : *userConfig.AddDefs) { Printf("Loading module \"%s\"\n",m.GetChars()); defsparser_include(m, NULL, NULL); // Q: should we let the external script see our symbol table? diff --git a/source/common/2d/v_draw.cpp b/source/common/2d/v_draw.cpp index dabd72c3d..222659aa7 100644 --- a/source/common/2d/v_draw.cpp +++ b/source/common/2d/v_draw.cpp @@ -335,7 +335,7 @@ DEFINE_ACTION_FUNCTION(_Screen, GetClipRect) } -static void CalcFullscreenScale(F2DDrawer* drawer, DrawParms *parms, double srcwidth, double srcheight, int oautoaspect, DoubleRect &rect) +void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, int oautoaspect, DoubleRect &rect) { auto GetWidth = [=]() { return parms->viewport.width; }; auto GetHeight = [=]() {return parms->viewport.height; }; @@ -475,7 +475,7 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do { // First calculate the destination rect for an image of the given size and then reposition this object in it. DoubleRect rect; - CalcFullscreenScale(drawer, parms, parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect); + CalcFullscreenScale(parms, parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect); double adder = parms->keepratio < 0 ? 0 : parms->keepratio == 0 ? rect.left : 2 * rect.left; parms->x = parms->viewport.left + adder + parms->x * rect.width / parms->virtWidth; parms->y = parms->viewport.top + rect.top + parms->y * rect.height / parms->virtHeight; @@ -489,7 +489,7 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do case DTA_FullscreenEx: { DoubleRect rect; - CalcFullscreenScale(drawer, parms, parms->texwidth, parms->texheight, parms->fsscalemode, rect); + CalcFullscreenScale(parms, parms->texwidth, parms->texheight, parms->fsscalemode, rect); parms->keepratio = -1; parms->x = parms->viewport.left + rect.left; parms->y = parms->viewport.top + rect.top; diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index b83dfe9fb..e2a242c37 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -1414,4 +1414,35 @@ void DrawCrosshair(int deftile, int health, double xdelta, double scale, PalEntr } DrawGenericCrosshair(crosshair == 0 ? 2 : *crosshair, health, xdelta); } -} \ No newline at end of file +} +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + +void LoadDefinitions() +{ + loaddefinitionsfile("engine/engine.def"); // Internal stuff that is required. + + const char* defsfile = G_DefFile(); + + cycle_t deftimer; + deftimer.Reset(); + deftimer.Clock(); + if (!loaddefinitionsfile(defsfile, true)) + { + deftimer.Unclock(); + Printf(PRINT_NONOTIFY, "Definitions file \"%s\" loaded in %.3f ms.\n", defsfile, deftimer.TimeMS()); + } + userConfig.AddDefs.reset(); + + // load the widescreen replacements last so that they do not clobber the CRC for the original items so that mod-side replacement are picked up. + if (fileSystem.FindFile("engine/widescreen.def") >= 0 && !Args->CheckParm("-nowidescreen")) + { + loaddefinitionsfile("engine/widescreen.def"); + } + + +} + diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h index 1103b0c6c..244e077ce 100644 --- a/source/core/gamecontrol.h +++ b/source/core/gamecontrol.h @@ -161,6 +161,7 @@ struct GrpEntry extern int g_gameType; const char* G_DefaultDefFile(void); const char* G_DefFile(void); +void LoadDefinitions(); // game check shortcuts inline bool isNam() diff --git a/source/core/statusbar.cpp b/source/core/statusbar.cpp index bd3645567..17f7595b7 100644 --- a/source/core/statusbar.cpp +++ b/source/core/statusbar.cpp @@ -821,6 +821,25 @@ short DBaseStatusBar::CalcMagazineAmount(short ammo_remaining, short clip_capaci // //============================================================================ +void DBaseStatusBar::Set43ClipRect() +{ + auto GetWidth = [=]() { return twod->GetWidth(); }; + auto GetHeight = [=]() {return twod->GetHeight(); }; + + auto screenratio = ActiveRatio(GetWidth(), GetHeight()); + if (screenratio < 1.34) return; + + int width = xs_CRoundToInt(GetWidth() * 1.333 / screenratio); + int left = (GetWidth() - width) / 2; + twod->SetClipRect(left, 0, width, GetHeight()); +} + +//============================================================================ +// +// +// +//============================================================================ + void setViewport(int viewSize) { int x0, y0, x1, y1; diff --git a/source/core/statusbar.h b/source/core/statusbar.h index c6580e3ae..d6023e917 100644 --- a/source/core/statusbar.h +++ b/source/core/statusbar.h @@ -197,6 +197,7 @@ public: } void DoDrawAutomapHUD(int crdefault, int highlight); short CalcMagazineAmount(short ammo_remaining, short clip_capacity, bool reloading); + void Set43ClipRect(); //protected: void DrawPowerups (); diff --git a/source/exhumed/src/exhumed.cpp b/source/exhumed/src/exhumed.cpp index 1cf6e32f8..18827e30a 100644 --- a/source/exhumed/src/exhumed.cpp +++ b/source/exhumed/src/exhumed.cpp @@ -521,14 +521,8 @@ void GameInterface::app_init() // temp - moving InstallEngine(); before FadeOut as we use nextpage() in FadeOut InstallEngine(); + LoadDefinitions(); - const char* defsfile = G_DefFile(); - uint32_t stime = I_msTime(); - if (!loaddefinitionsfile(defsfile)) - { - uint32_t etime = I_msTime(); - Printf(PRINT_NONOTIFY, "Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime - stime); - } TileFiles.SetBackup(); InitView(); diff --git a/source/exhumed/src/status.cpp b/source/exhumed/src/status.cpp index c4661165f..930b0c86b 100644 --- a/source/exhumed/src/status.cpp +++ b/source/exhumed/src/status.cpp @@ -854,7 +854,9 @@ private: { // draw the main bar itself BeginStatusBar(320, 200, 40); + if (hud_size == Hud_StbarOverlay) Set43ClipRect(); DrawGraphic(tileGetTexture(kTileStatusBar), 160, 200, DI_ITEM_CENTER_BOTTOM, 1, -1, -1, 1, 1); + twod->ClearClipRect(); } else if (hud_size == Hud_Mini) { diff --git a/source/games/duke/src/game.cpp b/source/games/duke/src/game.cpp index 9371b31a6..f73f6fae4 100644 --- a/source/games/duke/src/game.cpp +++ b/source/games/duke/src/game.cpp @@ -228,34 +228,6 @@ static void setupbackdrop() // //--------------------------------------------------------------------------- -static void loaddefs() -{ - const char* defsfile = G_DefFile(); - cycle_t deftimer; - deftimer.Reset(); - deftimer.Clock(); - if (!loaddefinitionsfile(defsfile)) - { - deftimer.Unclock(); - Printf(PRINT_NONOTIFY, "Definitions file \"%s\" loaded in %.3f ms.\n", defsfile, deftimer.TimeMS()); - } - TileFiles.SetBackup(); - userConfig.AddDefs.reset(); - - // load the internal replacements last so that they do not clobber the CRC for the original items so that mod-side replacement are picked up. - if (fileSystem.FindFile("engine/duke-widescreen.def") >= 0) - { - loaddefinitionsfile("engine/duke-widescreen.def"); - } - -} - -//--------------------------------------------------------------------------- -// -// -// -//--------------------------------------------------------------------------- - static void initTiles() { if (TileFiles.artLoadFiles("tiles%03i.art") < 0) @@ -340,7 +312,8 @@ void GameInterface::app_init() ps[j].auto_aim = 0; } - loaddefs(); + LoadDefinitions(); + TileFiles.SetBackup(); if (ud.multimode > 1) { diff --git a/source/games/duke/src/hudweapon_r.cpp b/source/games/duke/src/hudweapon_r.cpp index 388c8a13e..9c973ee76 100644 --- a/source/games/duke/src/hudweapon_r.cpp +++ b/source/games/duke/src/hudweapon_r.cpp @@ -75,10 +75,10 @@ void displaymasks_r(int snum, double smoothratio) if (ps[snum].scuba_on) { - int pin = 0; + //int pin = 0; // to get the proper clock value with regards to interpolation we have add a smoothratio based offset to the value. double interpclock = ud.levelclock + (TICSPERFRAME/65536.) * smoothratio; - if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_STRETCH; + int pin = RS_STRETCH; hud_drawsprite((320 - (tilesiz[SCUBAMASK].x >> 1) - 15), (200 - (tilesiz[SCUBAMASK].y >> 1) + (calcSinTableValue(interpclock) / 1024.)), 49152, 0, SCUBAMASK, 0, p, 2 + 16 + pin); hud_drawsprite((320 - tilesiz[SCUBAMASK + 4].x), (200 - tilesiz[SCUBAMASK + 4].y), 65536, 0, SCUBAMASK + 4, 0, p, 2 + 16 + pin); hud_drawsprite(tilesiz[SCUBAMASK + 4].x, (200 - tilesiz[SCUBAMASK + 4].y), 65536, 0, SCUBAMASK + 4, 0, p, 2 + 4 + 16 + pin); @@ -422,7 +422,7 @@ void displayweapon_r(int snum, double smoothratio) auto displaycrossbow = [&] { - if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; + //if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; static const uint8_t kb_frames[] = { 0,1,1,2,2,3,2,3,2,3,2,2,2,2,2,2,2,2,2,4,4,4,4,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7 }; if (kb_frames[*kb] == 2 || kb_frames[*kb] == 3) { @@ -449,7 +449,7 @@ void displayweapon_r(int snum, double smoothratio) auto displaychicken = [&] { - if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; + //if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; if (*kb) { static const uint8_t kb_frames[] = { 0,1,1,2,2,3,2,3,2,3,2,2,2,2,2,2,2,2,2,4,4,4,4,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7 }; @@ -760,7 +760,7 @@ void displayweapon_r(int snum, double smoothratio) dy = 20; if ((*kb) < 20) { - if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; + //if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; static const int8_t remote_frames[] = { 1,1,1,1,1,2,2,2,2,3,3,3,4,4,4,5,5,5,5,5,6,6,6 }; if (*kb) @@ -811,7 +811,7 @@ void displayweapon_r(int snum, double smoothratio) auto displayblaster = [&] { - if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; + //if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) pin = RS_ALIGN_R; if ((*kb)) { char cat_frames[] = { 0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; diff --git a/source/games/duke/src/sbar_d.cpp b/source/games/duke/src/sbar_d.cpp index 7179bfdfe..0400be88e 100644 --- a/source/games/duke/src/sbar_d.cpp +++ b/source/games/duke/src/sbar_d.cpp @@ -380,14 +380,15 @@ public: void Statusbar(int snum) { - int tile = hud_size < Hud_StbarOverlay ? TILE_BOTTOMSTATUSBAR : BOTTOMSTATUSBAR; // always use the narrow version for the overlay. auto p = &ps[snum]; - int h = tilesiz[tile].y; + int h = tilesiz[BOTTOMSTATUSBAR].y; int top = 200 - h; - int left = (320 - tilesiz[tile].x) / 2; + int left = (320 - tilesiz[BOTTOMSTATUSBAR].x) / 2; BeginStatusBar(320, 200, h); DrawInventory(p, 160, 154, 0); - DrawGraphic(tileGetTexture(tile), left, top, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1); + if (hud_size == Hud_StbarOverlay) Set43ClipRect(); + DrawGraphic(tileGetTexture(BOTTOMSTATUSBAR), left, top, DI_ITEM_LEFT_TOP, 1, -1, -1, 1, 1); + twod->ClearClipRect(); FString format; diff --git a/source/games/duke/src/sbar_r.cpp b/source/games/duke/src/sbar_r.cpp index 2615b0b80..befcc4467 100644 --- a/source/games/duke/src/sbar_r.cpp +++ b/source/games/duke/src/sbar_r.cpp @@ -343,6 +343,7 @@ public: double h = tilesiz[BOTTOMSTATUSBAR].y * scale; double wh = 0; if (hud_size < Hud_Stbar) wh = tilesiz[WEAPONBAR].y * scale; + double left = (320 - tilesiz[BOTTOMSTATUSBAR].x * scale) / 2; double top = 200 - h; BeginStatusBar(320, 200, wh + h); @@ -351,7 +352,9 @@ public: if (hud_size < Hud_Stbar) DrawWeaponBar(p, top); - DrawGraphic(tileGetTexture(BOTTOMSTATUSBAR), 0, top, DI_ITEM_LEFT_TOP, 1, -1, -1, scale, scale); + if (hud_size == Hud_StbarOverlay) Set43ClipRect(); + DrawGraphic(tileGetTexture(BOTTOMSTATUSBAR), left, top, DI_ITEM_LEFT_TOP, 1, -1, -1, scale, scale); + twod->ClearClipRect(); FString format; diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index a413679e2..5165c72ce 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -227,7 +227,7 @@ void GameInterface::app_init() if (!SW_SHAREWARE) LoadCustomInfoFromScript("swcustom.txt"); // Load user customisation information - if (!loaddefinitionsfile(G_DefFile())) Printf(PRINT_NONOTIFY, "Definitions file loaded.\n"); + LoadDefinitions(); TileFiles.SetBackup(); userConfig.AddDefs.reset(); InitFX(); diff --git a/source/sw/src/sbar.cpp b/source/sw/src/sbar.cpp index e43db115c..d6b0769e9 100644 --- a/source/sw/src/sbar.cpp +++ b/source/sw/src/sbar.cpp @@ -665,7 +665,10 @@ private: USERp u = User[pp->PlayerSprite]; BeginStatusBar(320, 200, tileHeight(STATUS_BAR)); - DrawGraphic(tileGetTexture(STATUS_BAR), 0, 200, DI_ITEM_LEFT_BOTTOM, 1, -1, -1, 1, 1); + if (hud_size == Hud_StbarOverlay) Set43ClipRect(); + int left = (320 - tilesiz[STATUS_BAR].x) / 2; + DrawGraphic(tileGetTexture(STATUS_BAR), left, 200, DI_ITEM_LEFT_BOTTOM, 1, -1, -1, 1, 1); + twod->ClearClipRect(); DisplayPanelNumber(PANEL_HEALTH_BOX_X + PANEL_HEALTH_XOFF, PANEL_BOX_Y + PANEL_HEALTH_YOFF, u->Health); DisplayPanelNumber(PANEL_ARMOR_BOX_X + PANEL_ARMOR_XOFF, PANEL_BOX_Y + PANEL_ARMOR_YOFF, pp->Armor); if (u->WeaponNum != WPN_FIST && u->WeaponNum != WPN_SWORD) diff --git a/wadsrc/static/filter/duke/tiles/duke3d/2462.PNG b/wadsrc/static/filter/duke/tiles/duke3d/2462.PNG new file mode 100644 index 0000000000000000000000000000000000000000..64deb2c43d1a6b74c6289e17a10beb5a05484fbf GIT binary patch literal 5864 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