From 9f6d2440163dbc27c97cd10a4199a53fd97ef152 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 6 Jun 2020 12:51:03 +0200 Subject: [PATCH] - advanced coordinate control for overlays over DTA_Fullscreen images. --- src/common/2d/v_draw.cpp | 113 ++++++++++++------ src/common/2d/v_draw.h | 4 +- .../rendering/hwrenderer/data/hw_skydome.cpp | 2 +- src/common/textures/gametexture.cpp | 2 +- src/common/utility/floatrect.h | 20 ++++ src/g_statusbar/sbarinfo_commands.cpp | 4 +- src/wi_stuff.cpp | 4 +- wadsrc/static/zscript/base.zs | 2 + 8 files changed, 105 insertions(+), 46 deletions(-) diff --git a/src/common/2d/v_draw.cpp b/src/common/2d/v_draw.cpp index d988603e4..dfb604c22 100644 --- a/src/common/2d/v_draw.cpp +++ b/src/common/2d/v_draw.cpp @@ -40,6 +40,7 @@ #include "texturemanager.h" #include "r_videoscale.h" #include "c_cvars.h" +#include "intrect.h" EXTERN_CVAR(Int, vid_aspect) EXTERN_CVAR(Int, uiscale) @@ -329,6 +330,50 @@ DEFINE_ACTION_FUNCTION(_Screen, GetClipRect) return MIN(numret, 4); } + +static void CalcFullscreenScale(F2DDrawer* drawer, double srcwidth, double srcheight, int autoaspect, DoubleRect &rect) +{ + auto GetWidth = [=]() { return drawer->GetWidth(); }; + auto GetHeight = [=]() {return drawer->GetHeight(); }; + + double aspect; + if (srcheight == 200) aspect = srcwidth / 240.; + else if (srcheight == 400) aspect = srcwidth / 480; + else aspect = srcwidth / srcheight; + rect.left = rect.top = 0; + auto screenratio = ActiveRatio(GetWidth(), GetHeight()); + if (autoaspect == 3) + { + if (screenratio >= aspect || aspect < 1.4) autoaspect = 1; // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxed if the screen is taller than the image + else if (screenratio > 1.32) autoaspect = 2; // on anything 4:3 and wider crop the sides of the image. + else + { + // special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows. + double width4_3 = srcheight * (4. / 3.); + rect.width = (double)GetWidth() * srcwidth / width4_3; + rect.height = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image + rect.top = (GetHeight() - rect.height) / 2; + rect.left = -(srcwidth - width4_3) / 2; + return; + } + } + + if ((screenratio > aspect) ^ (autoaspect == 2)) + { + // pillarboxed or vertically cropped (i.e. scale to height) + rect.height = GetHeight(); + rect.width = GetWidth() * aspect / screenratio; + rect.left = (GetWidth() - rect.width) / 2; + } + else + { + // letterboxed or horizontally cropped (i.e. scale to width) + rect.width = GetWidth(); + rect.height = GetHeight() * screenratio / aspect; + rect.top = (GetHeight() - rect.height) / 2; + } +} + //========================================================================== // // Draw parameter parsing @@ -384,49 +429,30 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do parms->destheight = parms->texheight * CleanYfac_1; break; + case DTA_Base: + if (parms->fsscalemode != -1) + { + // First calculate the destination rect for an image of the given size and then reposition this object in it. + DoubleRect rect; + CalcFullscreenScale(drawer, parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect); + parms->x = rect.left + parms->x * rect.width / parms->virtWidth; + parms->y = rect.top + parms->y * rect.height / parms->virtHeight; + parms->destwidth = parms->destwidth * rect.width / parms->virtWidth; + parms->destheight = parms->destheight * rect.height / parms->virtHeight; + return false; + } + break; + case DTA_Fullscreen: case DTA_FullscreenEx: { - double aspect; - double srcwidth = img->GetDisplayWidth(); - double srcheight = img->GetDisplayHeight(); - int autoaspect = parms->fsscalemode; - if (srcheight == 200) aspect = srcwidth / 240.; - else if (srcheight == 400) aspect = srcwidth / 480; - else aspect = srcwidth / srcheight; - parms->x = parms->y = 0; + DoubleRect rect; + CalcFullscreenScale(drawer, img->GetDisplayWidth(), img->GetDisplayHeight(), parms->fsscalemode, rect); parms->keepratio = true; - auto screenratio = ActiveRatio(GetWidth(), GetHeight()); - if (autoaspect == 3) - { - if (screenratio >= aspect || aspect < 1.4) autoaspect = 1; // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxed if the screen is taller than the image - else if (screenratio > 1.32) autoaspect = 2; // on anything 4:3 and wider crop the sides of the image. - else - { - // special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows. - double width4_3 = srcheight * (4. / 3.); - parms->destwidth = (double)GetWidth() * srcwidth / width4_3; - parms->destheight = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image - parms->y = (GetHeight() - parms->destheight) / 2; - parms->x = -(srcwidth - width4_3) / 2; - return false; // Do not call VirtualToRealCoords for this! - } - } - - if ((screenratio > aspect) ^ (autoaspect == 2)) - { - // pillarboxed or vertically cropped (i.e. scale to height) - parms->destheight = GetHeight(); - parms->destwidth =GetWidth() * aspect / screenratio; - parms->x = (GetWidth() - parms->destwidth) / 2; - } - else - { - // letterboxed or horizontally cropped (i.e. scale to width) - parms->destwidth = GetWidth(); - parms->destheight = GetHeight() * screenratio / aspect; - parms->y = (GetHeight() - parms->destheight) / 2; - } + parms->x = rect.left; + parms->y = rect.top; + parms->destwidth = rect.width; + parms->destheight = rect.height; return false; // Do not call VirtualToRealCoords for this! } @@ -598,6 +624,7 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->burn = false; parms->monospace = EMonospacing::Off; parms->spacing = 0; + parms->fsscalemode = -1; // Parse the tag list for attributes. (For floating point attributes, // consider that the C ABI dictates that all floats be promoted to @@ -717,6 +744,14 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->cleanmode = DTA_Base; parms->virtHeight = ListGetDouble(tags); break; + + case DTA_FullscreenScale: + intval = ListGetInt(tags); + if (intval >= 0 && intval <= 3) + { + parms->fsscalemode = (uint8_t)intval; + } + break; case DTA_Fullscreen: diff --git a/src/common/2d/v_draw.h b/src/common/2d/v_draw.h index 2322232e7..daf7e8568 100644 --- a/src/common/2d/v_draw.h +++ b/src/common/2d/v_draw.h @@ -88,6 +88,8 @@ enum DTA_Monospace, // Fonts only: Use a fixed distance between characters. DTA_FullscreenEx, + DTA_FullscreenScale, + }; enum EMonospacing : int @@ -152,7 +154,7 @@ struct DrawParms bool fortext; bool virtBottom; bool burn; - uint8_t fsscalemode; + int8_t fsscalemode; double srcx, srcy; double srcwidth, srcheight; }; diff --git a/src/common/rendering/hwrenderer/data/hw_skydome.cpp b/src/common/rendering/hwrenderer/data/hw_skydome.cpp index 45c813fc7..52bdc4d36 100644 --- a/src/common/rendering/hwrenderer/data/hw_skydome.cpp +++ b/src/common/rendering/hwrenderer/data/hw_skydome.cpp @@ -332,7 +332,7 @@ void FSkyVertexBuffer::SetupMatrices(FGameTexture *tex, float x_offset, float y_ modelMatrix.loadIdentity(); modelMatrix.rotate(-180.0f + x_offset, 0.f, 1.f, 0.f); - float xscale = texw < 1024.f ? floor(1024.f / float(texw)) : 1.f; + float xscale = texw < 1024.f ? floorf(1024.f / float(texw)) : 1.f; float yscale = 1.f; auto texskyoffset = tex->GetSkyOffset() + skyoffset; if (texh <= 128 && tiled) diff --git a/src/common/textures/gametexture.cpp b/src/common/textures/gametexture.cpp index e4e1ac6b2..66775d1e2 100644 --- a/src/common/textures/gametexture.cpp +++ b/src/common/textures/gametexture.cpp @@ -462,7 +462,7 @@ float FTexCoordInfo::TextureAdjustWidth() const { float tscale = fabsf(mTempScale.X); if (tscale == 1.f) return (float)mRenderWidth; - else return mWidth / fabs(tscale); + else return mWidth / fabsf(tscale); } else return (float)mWidth; } diff --git a/src/common/utility/floatrect.h b/src/common/utility/floatrect.h index 8274b8498..34eedabe6 100644 --- a/src/common/utility/floatrect.h +++ b/src/common/utility/floatrect.h @@ -19,3 +19,23 @@ struct FloatRect height*=yfac; } }; + +struct DoubleRect +{ + double left, top; + double width, height; + + + void Offset(double xofs, double yofs) + { + left += xofs; + top += yofs; + } + void Scale(double xfac, double yfac) + { + left *= xfac; + width *= xfac; + top *= yfac; + height *= yfac; + } +}; diff --git a/src/g_statusbar/sbarinfo_commands.cpp b/src/g_statusbar/sbarinfo_commands.cpp index 287b39513..55cbefdbe 100644 --- a/src/g_statusbar/sbarinfo_commands.cpp +++ b/src/g_statusbar/sbarinfo_commands.cpp @@ -1986,10 +1986,10 @@ class CommandAspectRatio : public SBarInfoCommandFlowControl }; int ratio = ratioTypes[0].second; - float distance = fabs(ratioTypes[0].first - aspect); + float distance = fabsf(ratioTypes[0].first - aspect); for (int i = 1; ratioTypes[i].first != 0.0f; i++) { - float d = fabs(ratioTypes[i].first - aspect); + float d = fabsf(ratioTypes[i].first - aspect); if (d < distance) { ratio = ratioTypes[i].second; diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 293eab9c1..1581c5b2a 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -601,7 +601,7 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe // placing the animations precisely where they belong on the base pic animwidth = background->GetDisplayWidth(); animheight = background->GetDisplayHeight(); - if (gameinfo.fullscreenautoaspect == 3 && animheight == 200 && animwidth > 320) animwidth = 320; // deal with widescreen replacements that keep the original coordinates. + if (gameinfo.fullscreenautoaspect > 0) animwidth = 320; // deal with widescreen replacements that keep the original coordinates. DrawTexture(twod, background, 0, 0, DTA_Fullscreen, true, TAG_DONE); } else @@ -658,7 +658,7 @@ void DInterBackground::drawBackground(int state, bool drawsplat, bool snl_pointe } if (a->ctr >= 0) DrawTexture(twod, a->frames[a->ctr], a->loc.x, a->loc.y, - DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, TAG_DONE); + DTA_VirtualWidthF, animwidth, DTA_VirtualHeightF, animheight, DTA_FullscreenScale, gameinfo.fullscreenautoaspect, TAG_DONE); } if (drawsplat) diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index a1800f9fd..abed488f2 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -193,6 +193,8 @@ enum DrawTextureTags DTA_Monospace, // Strings only: Use a fixed distance between characters. DTA_FullscreenEx, // advanced fullscreen control. + DTA_FullscreenScale, // enable DTA_Fullscreen coordinate calculation for placed overlays. + }; class Shape2DTransform : Object native