From dbf2d4d7d740babc695c442753326d08376beb66 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 27 Sep 2020 09:17:41 +0200 Subject: [PATCH] - backported all new scaling and rotation options for the 2D drawer from Raze. With proper scaling and viewport support, things should become a lot easier now. The 2D drawer now also can rotate content by arbitrary angles. --- src/common/2d/v_2ddrawer.cpp | 142 +++++++++++++++------- src/common/2d/v_2ddrawer.h | 13 +- src/common/2d/v_draw.cpp | 192 +++++++++++++++++++++++++----- src/common/2d/v_draw.h | 60 ++++++++-- src/g_statusbar/sbar.h | 10 ++ src/intermission/intermission.cpp | 1 + wadsrc/static/zscript/base.zs | 14 +++ 7 files changed, 346 insertions(+), 86 deletions(-) diff --git a/src/common/2d/v_2ddrawer.cpp b/src/common/2d/v_2ddrawer.cpp index 564c122c3..acdef7bff 100644 --- a/src/common/2d/v_2ddrawer.cpp +++ b/src/common/2d/v_2ddrawer.cpp @@ -401,10 +401,6 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms) double xscale = parms.destwidth / parms.texwidth; double yscale = parms.destheight / parms.texheight; - double x = parms.x - parms.left * xscale; - double y = parms.y - parms.top * yscale; - double w = parms.destwidth; - double h = parms.destheight; double u1, v1, u2, v2; PalEntry vertexcolor; @@ -414,9 +410,15 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms) dg.mVertCount = 4; dg.mTexture = img; if (img->isWarped()) dg.mFlags |= DTF_Wrap; + if (parms.indexed) dg.mFlags |= DTF_Indexed; dg.mTranslationId = 0; SetStyle(img, parms, vertexcolor, dg); + if (parms.indexed) + { + dg.mLightLevel = vertexcolor.Luminance(); + vertexcolor = 0xffffffff; + } if (!img->isHardwareCanvas() && parms.TranslationId != -1) { @@ -427,44 +429,94 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms) u2 = parms.srcx + parms.srcwidth; v2 = parms.srcy + parms.srcheight; - if (parms.flipX) - std::swap(u1, u2); - - if (parms.flipY) - std::swap(v1, v2); - - // This is crap. Only kept for backwards compatibility with scripts that may have used it. - // Note that this only works for unflipped full textures. - if (parms.windowleft > 0 || parms.windowright < parms.texwidth) + if (parms.flipX) { - double wi = std::min(parms.windowright, parms.texwidth); - x += parms.windowleft * xscale; - w -= (parms.texwidth - wi + parms.windowleft) * xscale; - - u1 = float(u1 + parms.windowleft / parms.texwidth); - u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); + std::swap(u1, u2); } - if (x < (double)parms.lclip || y < (double)parms.uclip || x + w >(double)parms.rclip || y + h >(double)parms.dclip) + if (parms.flipY) { + std::swap(v1, v2); + } + + if (parms.rotateangle == 0) + { + double x = parms.x - parms.left * xscale; + double y = parms.y - parms.top * yscale; + double w = parms.destwidth; + double h = parms.destheight; + + + // This is crap. Only kept for backwards compatibility with scripts that may have used it. + // Note that this only works for unflipped and unrotated full textures. + if (parms.windowleft > 0 || parms.windowright < parms.texwidth) + { + double wi = std::min(parms.windowright, parms.texwidth); + x += parms.windowleft * xscale; + w -= (parms.texwidth - wi + parms.windowleft) * xscale; + + u1 = float(u1 + parms.windowleft / parms.texwidth); + u2 = float(u2 - (parms.texwidth - wi) / parms.texwidth); + } + + if (x < (double)parms.lclip || y < (double)parms.uclip || x + w >(double)parms.rclip || y + h >(double)parms.dclip) + { + dg.mScissor[0] = parms.lclip; + dg.mScissor[1] = parms.uclip; + dg.mScissor[2] = parms.rclip; + dg.mScissor[3] = parms.dclip; + dg.mFlags |= DTF_Scissor; + } + else + { + memset(dg.mScissor, 0, sizeof(dg.mScissor)); + } + + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + TwoDVertex* ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++; + ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++; + ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++; + ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++; + } + else + { + double radang = parms.rotateangle * (pi::pi() / 180.); + double cosang = cos(radang); + double sinang = sin(radang); + double xd1 = -parms.left; + double yd1 = -parms.top; + double xd2 = xd1 + parms.texwidth; + double yd2 = yd1 + parms.texheight; + + double x1 = parms.x + xscale * (xd1 * cosang + yd1 * sinang); + double y1 = parms.y - yscale * (xd1 * sinang - yd1 * cosang); + + double x2 = parms.x + xscale * (xd1 * cosang + yd2 * sinang); + double y2 = parms.y - yscale * (xd1 * sinang - yd2 * cosang); + + double x3 = parms.x + xscale * (xd2 * cosang + yd1 * sinang); + double y3 = parms.y - yscale * (xd2 * sinang - yd1 * cosang); + + double x4 = parms.x + xscale * (xd2 * cosang + yd2 * sinang); + double y4 = parms.y - yscale * (xd2 * sinang - yd2 * cosang); + dg.mScissor[0] = parms.lclip; dg.mScissor[1] = parms.uclip; dg.mScissor[2] = parms.rclip; dg.mScissor[3] = parms.dclip; dg.mFlags |= DTF_Scissor; - } - else - { - memset(dg.mScissor, 0, sizeof(dg.mScissor)); - } - dg.mVertCount = 4; - dg.mVertIndex = (int)mVertices.Reserve(4); - TwoDVertex *ptr = &mVertices[dg.mVertIndex]; - ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++; - ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++; - ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++; - ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++; + dg.mVertCount = 4; + dg.mVertIndex = (int)mVertices.Reserve(4); + TwoDVertex* ptr = &mVertices[dg.mVertIndex]; + ptr->Set(x1, y1, 0, u1, v1, vertexcolor); ptr++; + ptr->Set(x2, y2, 0, u1, v2, vertexcolor); ptr++; + ptr->Set(x3, y3, 0, u2, v1, vertexcolor); ptr++; + ptr->Set(x4, y4, 0, u2, v2, vertexcolor); ptr++; + + } dg.mIndexIndex = mIndices.Size(); dg.mIndexCount += 6; AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); @@ -693,7 +745,7 @@ float F2DDrawer::GetClassicFlatScalarHeight() return sh; } -void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin, double flatscale) +void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin, double flatscale, PalEntry color) { float fU1, fU2, fV1, fV2; @@ -789,18 +841,18 @@ void F2DDrawer::AddFlatFill(int left, int top, int right, int bottom, FGameTextu dg.mVertIndex = (int)mVertices.Reserve(4); auto ptr = &mVertices[dg.mVertIndex]; - ptr->Set(left, top, 0, fU1, fV1, 0xffffffff); ptr++; + ptr->Set(left, top, 0, fU1, fV1, color); ptr++; if (local_origin < 4) { - ptr->Set(left, bottom, 0, fU1, fV2, 0xffffffff); ptr++; - ptr->Set(right, top, 0, fU2, fV1, 0xffffffff); ptr++; + ptr->Set(left, bottom, 0, fU1, fV2, color); ptr++; + ptr->Set(right, top, 0, fU2, fV1, color); ptr++; } else { - ptr->Set(left, bottom, 0, fU2, fV1, 0xffffffff); ptr++; - ptr->Set(right, top, 0, fU1, fV2, 0xffffffff); ptr++; + ptr->Set(left, bottom, 0, fU2, fV1, color); ptr++; + ptr->Set(right, top, 0, fU1, fV2, color); ptr++; } - ptr->Set(right, bottom, 0, fU2, fV2, 0xffffffff); ptr++; + ptr->Set(right, bottom, 0, fU2, fV2, color); ptr++; dg.mIndexIndex = mIndices.Size(); dg.mIndexCount += 6; AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); @@ -945,8 +997,12 @@ void F2DDrawer::AddPixel(int x1, int y1, uint32_t color) void F2DDrawer::Clear() { - mVertices.Clear(); - mIndices.Clear(); - mData.Clear(); - mIsFirstPass = true; + if (!locked) + { + mVertices.Clear(); + mIndices.Clear(); + mData.Clear(); + mIsFirstPass = true; + } + screenFade = 1.f; } diff --git a/src/common/2d/v_2ddrawer.h b/src/common/2d/v_2ddrawer.h index 00c0fcba1..ff23f7919 100644 --- a/src/common/2d/v_2ddrawer.h +++ b/src/common/2d/v_2ddrawer.h @@ -84,6 +84,7 @@ public: DTF_Wrap = 1, DTF_Scissor = 2, DTF_Burn = 4, + DTF_Indexed = 8, }; @@ -164,6 +165,8 @@ public: TArray mData; int Width, Height; bool isIn2D; + bool locked; // prevents clearing of the data so it can be reused multiple times (useful for screen fades) + float screenFade = 1.f; public: int fullscreenautoaspect = 0; int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1; @@ -186,7 +189,7 @@ public: void AddPoly(FGameTexture* img, FVector4 *vt, size_t vtcount, unsigned int *ind, size_t idxcount, int translation, PalEntry color, FRenderStyle style, int clipx1, int clipy1, int clipx2, int clipy2); void FillPolygon(int* rx1, int* ry1, int* xb1, int32_t npoints, int picnum, int palette, int shade, int props, const FVector2& xtex, const FVector2& ytex, const FVector2& otex, int clipx1, int clipy1, int clipx2, int clipy2); - void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0); + void AddFlatFill(int left, int top, int right, int bottom, FGameTexture *src, int local_origin = false, double flatscale = 1.0, PalEntry color = 0xffffffff); void AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr, bool prepend = false); void ClearScreen(PalEntry color = 0xff000000); @@ -199,6 +202,9 @@ public: void AddPixel(int x1, int y1, uint32_t color); void Clear(); + void Lock() { locked = true; } + void SetScreenFade(float factor) { screenFade = factor; } + void Unlock() { locked = false; } int GetWidth() const { return Width; } int GetHeight() const { return Height; } void SetSize(int w, int h) { Width = w; Height = h; } @@ -210,6 +216,11 @@ public: void SetClipRect(int x, int y, int w, int h); void GetClipRect(int* x, int* y, int* w, int* h); + int DrawCount() const + { + return mData.Size(); + } + bool mIsFirstPass = true; }; diff --git a/src/common/2d/v_draw.cpp b/src/common/2d/v_draw.cpp index 4556eeb03..a37f930f3 100644 --- a/src/common/2d/v_draw.cpp +++ b/src/common/2d/v_draw.cpp @@ -45,6 +45,9 @@ EXTERN_CVAR(Int, vid_aspect) EXTERN_CVAR(Int, uiscale) CVAR(Bool, ui_screenborder_classic_scaling, true, CVAR_ARCHIVE) +static void VirtualToRealCoords(F2DDrawer* drawer, double Width, double Height, double& x, double& y, double& w, double& h, + double vwidth, double vheight, bool vbottom, bool handleaspect); + // Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none. int ActiveFakeRatio(int width, int height) { @@ -187,6 +190,7 @@ void DrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int t va_start(tags.list, tags_first); DrawParms parms; + if (!img || !img->isValid()) return; bool res = ParseDrawTextureTags(drawer, img, x, y, tags_first, tags, &parms, false); va_end(tags.list); if (!res) @@ -208,6 +212,7 @@ static void DrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y { DrawParms parms; uint32_t tag = ListGetInt(args); + if (!img || !img->isValid()) return; bool res = ParseDrawTextureTags(drawer, img, x, y, tag, args, &parms, false); if (!res) return; drawer->AddTexture(img, parms); @@ -330,10 +335,19 @@ DEFINE_ACTION_FUNCTION(_Screen, GetClipRect) } -static void CalcFullscreenScale(F2DDrawer* drawer, double srcwidth, double srcheight, int autoaspect, DoubleRect &rect) +void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, int oautoaspect, DoubleRect &rect) { - auto GetWidth = [=]() { return drawer->GetWidth(); }; - auto GetHeight = [=]() {return drawer->GetHeight(); }; + auto GetWidth = [=]() { return parms->viewport.width; }; + auto GetHeight = [=]() {return parms->viewport.height; }; + + int autoaspect = oautoaspect; + if (autoaspect == FSMode_ScaleToScreen) + { + rect.left = rect.top = 0; + rect.width = GetWidth(); + rect.height = GetHeight(); + return; + } double aspect; if (srcheight == 200) aspect = srcwidth / 240.; @@ -341,23 +355,35 @@ static void CalcFullscreenScale(F2DDrawer* drawer, double srcwidth, double srche else aspect = srcwidth / srcheight; rect.left = rect.top = 0; auto screenratio = ActiveRatio(GetWidth(), GetHeight()); - if (autoaspect == 3) + if (autoaspect == FSMode_ScaleToFit43 || autoaspect == FSMode_ScaleToFit43Top || autoaspect == FSMode_ScaleToFit43Bottom) { - 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. + // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxed if the screen is taller than the image + if (screenratio >= aspect || aspect < 1.4) autoaspect = FSMode_ScaleToFit; + else if (screenratio > 1.32) autoaspect = FSMode_ScaleToFill; // 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; + switch (oautoaspect) + { + default: + rect.top = (GetHeight() - rect.height) / 2; + break; + case FSMode_ScaleToFit43Top: + rect.top = 0; + break; + case FSMode_ScaleToFit43Bottom: + rect.top = (GetHeight() - rect.height); + break; + } return; } } - if ((screenratio > aspect) ^ (autoaspect == 2)) + if (autoaspect == FSMode_ScaleToHeight || (screenratio > aspect) ^ (autoaspect == FSMode_ScaleToFill)) { // pillarboxed or vertically cropped (i.e. scale to height) rect.height = GetHeight(); @@ -369,7 +395,18 @@ static void CalcFullscreenScale(F2DDrawer* drawer, double srcwidth, double srche // letterboxed or horizontally cropped (i.e. scale to width) rect.width = GetWidth(); rect.height = GetHeight() * screenratio / aspect; - rect.top = (GetHeight() - rect.height) / 2; + switch (oautoaspect) + { + default: + rect.top = (GetHeight() - rect.height) / 2; + break; + case FSMode_ScaleToFit43Top: + rect.top = 0; + break; + case FSMode_ScaleToFit43Bottom: + rect.top = (GetHeight() - rect.height); + break; + } } } @@ -381,8 +418,8 @@ static void CalcFullscreenScale(F2DDrawer* drawer, double srcwidth, double srche bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, double xx, double yy) { - auto GetWidth = [=]() { return drawer->GetWidth(); }; - auto GetHeight = [=]() {return drawer->GetHeight(); }; + auto GetWidth = [=]() { return parms->viewport.width; }; + auto GetHeight = [=]() {return parms->viewport.height; }; if (img != NULL) { parms->x = xx; @@ -399,12 +436,17 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do } if (parms->destwidth == INT_MAX || parms->fortext) { - parms->destwidth = img->GetDisplayWidth(); + parms->destwidth = parms->texwidth; } if (parms->destheight == INT_MAX || parms->fortext) { - parms->destheight = img->GetDisplayHeight(); + parms->destheight = parms->texheight; } + parms->destwidth *= parms->patchscalex; + parms->destheight *= parms->patchscaley; + + if (parms->flipoffsets && parms->flipY) parms->top = parms->texheight - parms->top; + if (parms->flipoffsets && parms->flipX) parms->left = parms->texwidth - parms->left; switch (parms->cleanmode) { @@ -429,13 +471,14 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do break; case DTA_Base: - if (parms->fsscalemode != -1) + if (parms->fsscalemode > 0) { // 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; + 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; parms->destwidth = parms->destwidth * rect.width / parms->virtWidth; parms->destheight = parms->destheight * rect.height / parms->virtHeight; return false; @@ -446,12 +489,13 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do case DTA_FullscreenEx: { DoubleRect rect; - CalcFullscreenScale(drawer, img->GetDisplayWidth(), img->GetDisplayHeight(), parms->fsscalemode, rect); - parms->keepratio = true; - parms->x = rect.left; - parms->y = rect.top; + 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; parms->destwidth = rect.width; parms->destheight = rect.height; + parms->top = parms->left = 0; return false; // Do not call VirtualToRealCoords for this! } @@ -478,9 +522,11 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do } if (parms->virtWidth != GetWidth() || parms->virtHeight != GetHeight()) { - VirtualToRealCoords(drawer, parms->x, parms->y, parms->destwidth, parms->destheight, + VirtualToRealCoords(drawer, GetWidth(), GetHeight(), parms->x, parms->y, parms->destwidth, parms->destheight, parms->virtWidth, parms->virtHeight, parms->virtBottom, !parms->keepratio); } + parms->x += parms->viewport.left; + parms->y += parms->viewport.top; } return false; @@ -603,8 +649,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->color = 0xffffffff; //parms->shadowAlpha = 0; parms->shadowColor = 0; - parms->virtWidth = drawer->GetWidth(); - parms->virtHeight = drawer->GetHeight(); + parms->virtWidth = INT_MAX; // these need to match the viewport if not explicitly set, but we do not know that yet. + parms->virtHeight = INT_MAX; parms->keepratio = false; parms->style.BlendOp = 255; // Dummy "not set" value parms->masked = true; @@ -624,6 +670,11 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->monospace = EMonospacing::Off; parms->spacing = 0; parms->fsscalemode = -1; + parms->patchscalex = parms->patchscaley = 1; + parms->viewport = { 0,0,drawer->GetWidth(), drawer->GetHeight() }; + parms->rotateangle = 0; + parms->flipoffsets = false; + parms->indexed = false; // Parse the tag list for attributes. (For floating point attributes, // consider that the C ABI dictates that all floats be promoted to @@ -746,9 +797,18 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double case DTA_FullscreenScale: intval = ListGetInt(tags); - if (intval >= 0 && intval <= 3) + if (intval >= FSMode_None && intval < FSMode_Max) { - parms->fsscalemode = (uint8_t)intval; + parms->fsscalemode = (int8_t)intval; + } + else if (intval >= FSMode_Predefined && intval < FSMode_Predefined_Max) + { + static const uint8_t modes[] = { FSMode_ScaleToFit43, FSMode_ScaleToFit43, FSMode_ScaleToFit43, FSMode_ScaleToFit43, FSMode_ScaleToFit43Top}; + static const uint16_t widths[] = { 320, 320, 640, 640, 320}; + static const uint16_t heights[] = { 200, 240, 400, 480, 200}; + parms->fsscalemode = modes[intval - FSMode_Predefined]; + parms->virtWidth = widths[intval - FSMode_Predefined]; + parms->virtHeight = heights[intval - FSMode_Predefined]; } break; @@ -821,6 +881,10 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->flipY = ListGetInt(tags); break; + case DTA_FlipOffsets: + parms->flipoffsets = ListGetInt(tags); + break; + case DTA_SrcX: parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth(); break; @@ -861,6 +925,16 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->left = ListGetDouble(tags); break; + case DTA_TopLeft: + assert(fortext == false); + if (fortext) return false; + if (ListGetInt(tags)) + { + parms->left = 0; + parms->top = 0; + } + break; + case DTA_CenterOffset: assert(fortext == false); if (fortext) return false; @@ -871,6 +945,16 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double } break; + case DTA_CenterOffsetRel: + assert(fortext == false); + if (fortext) return false; + if (ListGetInt(tags)) + { + parms->left = img->GetDisplayLeftOffset() + img->GetDisplayWidth() * 0.5; + parms->top = img->GetDisplayTopOffset() + img->GetDisplayHeight() * 0.5; + } + break; + case DTA_CenterBottomOffset: assert(fortext == false); if (fortext) return false; @@ -958,6 +1042,14 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double } break; + case DTA_ScaleX: + parms->patchscalex = ListGetDouble(tags); + break; + + case DTA_ScaleY: + parms->patchscaley = ListGetDouble(tags); + break; + case DTA_Masked: parms->masked = ListGetInt(tags); break; @@ -967,8 +1059,10 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double break; case DTA_KeepRatio: - // I think this is a terribly misleading name, since it actually turns - // *off* aspect ratio correction. + parms->keepratio = ListGetInt(tags) ? -1 : 0; + break; + + case DTA_Pin: parms->keepratio = ListGetInt(tags); break; @@ -1012,11 +1106,39 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double parms->burn = true; break; + case DTA_ViewportX: + parms->viewport.left = ListGetInt(tags); + break; + + case DTA_ViewportY: + parms->viewport.top = ListGetInt(tags); + break; + + case DTA_ViewportWidth: + parms->viewport.width = ListGetInt(tags); + break; + + case DTA_ViewportHeight: + parms->viewport.height = ListGetInt(tags); + break; + + case DTA_Rotate: + assert(fortext == false); + if (fortext) return false; + parms->rotateangle = ListGetDouble(tags); + break; + + case DTA_Indexed: + parms->indexed = !!ListGetInt(tags); + break; } tag = ListGetInt(tags); } ListEnd(tags); + if (parms->virtWidth == INT_MAX) parms->virtWidth = parms->viewport.width; + if (parms->virtHeight == INT_MAX) parms->virtHeight = parms->viewport.height; + auto clipleft = drawer->clipleft; auto cliptop = drawer->cliptop; auto clipwidth = drawer->clipwidth; @@ -1084,12 +1206,10 @@ template bool ParseDrawTextureTags(F2DDrawer* drawer, FGameTexture *i // //========================================================================== -void VirtualToRealCoords(F2DDrawer *drawer, double &x, double &y, double &w, double &h, +static void VirtualToRealCoords(F2DDrawer *drawer, double Width, double Height, double &x, double &y, double &w, double &h, double vwidth, double vheight, bool vbottom, bool handleaspect) { - auto Width = drawer->GetWidth(); - auto Height = drawer->GetHeight(); - float myratio = handleaspect ? ActiveRatio (Width, Height) : (4.0f / 3.0f); + float myratio = float(handleaspect ? ActiveRatio (Width, Height) : (4.0 / 3.0)); // if 21:9 AR, map to 16:9 for all callers. // this allows for black bars and stops the stretching of fullscreen images @@ -1129,6 +1249,14 @@ void VirtualToRealCoords(F2DDrawer *drawer, double &x, double &y, double &w, dou } } +void VirtualToRealCoords(F2DDrawer* drawer, double& x, double& y, double& w, double& h, + double vwidth, double vheight, bool vbottom, bool handleaspect) +{ + auto Width = drawer->GetWidth(); + auto Height = drawer->GetHeight(); + VirtualToRealCoords(drawer, Width, Height, x, y, w, h, vwidth, vheight, vbottom, handleaspect); +} + DEFINE_ACTION_FUNCTION(_Screen, VirtualToRealCoords) { PARAM_PROLOGUE; diff --git a/src/common/2d/v_draw.h b/src/common/2d/v_draw.h index c48fd417b..c18566936 100644 --- a/src/common/2d/v_draw.h +++ b/src/common/2d/v_draw.h @@ -2,6 +2,7 @@ #include "v_2ddrawer.h" #include "c_cvars.h" +#include "intrect.h" // TagItem definitions for DrawTexture. As far as I know, tag lists // originated on the Amiga. @@ -13,11 +14,38 @@ // uint32_t ti_Data; // }; -#define TAG_DONE (0) /* Used to indicate the end of the Tag list */ -#define TAG_END (0) /* Ditto */ - /* list pointed to in ti_Data */ +enum tags : uint32_t +{ + TAG_DONE = (0), /* Used to indicate the end of the Tag list */ + TAG_END = (0), /* Ditto */ + /* list pointed to in ti_Data */ -#define TAG_USER ((uint32_t)(1u<<30)) + TAG_USER = ((uint32_t)(1u << 30)) +}; + +enum +{ + FSMode_None = 0, + FSMode_ScaleToFit = 1, + FSMode_ScaleToFill = 2, + FSMode_ScaleToFit43 = 3, + FSMode_ScaleToScreen = 4, + FSMode_ScaleToFit43Top = 5, + FSMode_ScaleToFit43Bottom = 6, + FSMode_ScaleToHeight = 7, + + + FSMode_Max, + + // These all use ScaleToFit43, their purpose is to cut down on verbosity because they imply the virtual screen size. + FSMode_Predefined = 1000, + FSMode_Fit320x200 = 1000, + FSMode_Fit320x240, + FSMode_Fit640x400, + FSMode_Fit640x480, + FSMode_Fit320x200Top, + FSMode_Predefined_Max, +}; enum { @@ -89,6 +117,19 @@ enum DTA_FullscreenEx, DTA_FullscreenScale, + DTA_ScaleX, + DTA_ScaleY, + + DTA_ViewportX, // Defines the viewport on the screen that should be rendered to. + DTA_ViewportY, + DTA_ViewportWidth, + DTA_ViewportHeight, + DTA_CenterOffsetRel, // Apply texture offsets relative to center, instead of top left. This is standard alignment for Build's 2D content. + DTA_TopLeft, // always align to top left. Added to have a boolean condition for this alignment. + DTA_Pin, // Pin a non-widescreen image to the left/right edge of the screen. + DTA_Rotate, + DTA_FlipOffsets, // Flips offsets when using DTA_FlipX and DTA_FlipY, this cannot be automatic due to unexpected behavior with unoffsetted graphics. + DTA_Indexed, // Use an indexed texture combined with the given translation. }; @@ -154,9 +195,14 @@ struct DrawParms bool fortext; bool virtBottom; bool burn; + bool flipoffsets; + bool indexed; int8_t fsscalemode; double srcx, srcy; double srcwidth, srcheight; + double patchscalex, patchscaley; + double rotateangle; + IntRect viewport; }; struct Va_List @@ -187,14 +233,8 @@ int GetUIScale(F2DDrawer* drawer, int altval); int GetConScale(F2DDrawer* drawer, int altval); EXTERN_CVAR(Int, uiscale); -EXTERN_CVAR(Int, con_scaletext); EXTERN_CVAR(Int, con_scale); -inline int active_con_scaletext(F2DDrawer* drawer, bool newconfont = false) -{ - return newconfont ? GetConScale(drawer, con_scaletext) : GetUIScale(drawer, con_scaletext); -} - inline int active_con_scale(F2DDrawer *drawer) { return GetConScale(drawer, con_scale); diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 8a1ad1bc7..bd4b719ad 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -39,6 +39,16 @@ #include "v_collection.h" #include "v_text.h" #include "renderstyle.h" +#include "v_2ddrawer.h" +#include "v_draw.h" +#include "c_cvars.h" + + +EXTERN_CVAR(Int, con_scaletext); +inline int active_con_scaletext(F2DDrawer* drawer, bool newconfont = false) +{ + return newconfont ? GetConScale(drawer, con_scaletext) : GetUIScale(drawer, con_scaletext); +} class player_t; struct FRemapTable; diff --git a/src/intermission/intermission.cpp b/src/intermission/intermission.cpp index 46bd7a841..d52b2ebcc 100644 --- a/src/intermission/intermission.cpp +++ b/src/intermission/intermission.cpp @@ -55,6 +55,7 @@ #include "texturemanager.h" #include "v_draw.h" #include "doommenu.h" +#include "sbar.h" FIntermissionDescriptorList IntermissionDescriptors; diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index 643abc90b..b1a86b017 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -195,6 +195,20 @@ enum DrawTextureTags DTA_FullscreenEx, // advanced fullscreen control. DTA_FullscreenScale, // enable DTA_Fullscreen coordinate calculation for placed overlays. + DTA_ScaleX, + DTA_ScaleY, + + DTA_ViewportX, // Defines the viewport on the screen that should be rendered to. + DTA_ViewportY, + DTA_ViewportWidth, + DTA_ViewportHeight, + DTA_CenterOffsetRel, // Apply texture offsets relative to center, instead of top left. This is standard alignment for Build's 2D content. + DTA_TopLeft, // always align to top left. Added to have a boolean condition for this alignment. + DTA_Pin, // Pin a non-widescreen image to the left/right edge of the screen. + DTA_Rotate, + DTA_FlipOffsets, // Flips offsets when using DTA_FlipX and DTA_FlipY, this cannot be automatic due to unexpected behavior with unoffsetted graphics. + DTA_Indexed, // Use an indexed texture combined with the given translation. + }; class Shape2DTransform : Object native