- 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.
This commit is contained in:
Christoph Oelckers 2020-09-27 09:17:41 +02:00
parent db895b43b2
commit dbf2d4d7d7
7 changed files with 346 additions and 86 deletions

View file

@ -401,10 +401,6 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
double xscale = parms.destwidth / parms.texwidth; double xscale = parms.destwidth / parms.texwidth;
double yscale = parms.destheight / parms.texheight; 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; double u1, v1, u2, v2;
PalEntry vertexcolor; PalEntry vertexcolor;
@ -414,9 +410,15 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
dg.mVertCount = 4; dg.mVertCount = 4;
dg.mTexture = img; dg.mTexture = img;
if (img->isWarped()) dg.mFlags |= DTF_Wrap; if (img->isWarped()) dg.mFlags |= DTF_Wrap;
if (parms.indexed) dg.mFlags |= DTF_Indexed;
dg.mTranslationId = 0; dg.mTranslationId = 0;
SetStyle(img, parms, vertexcolor, dg); SetStyle(img, parms, vertexcolor, dg);
if (parms.indexed)
{
dg.mLightLevel = vertexcolor.Luminance();
vertexcolor = 0xffffffff;
}
if (!img->isHardwareCanvas() && parms.TranslationId != -1) if (!img->isHardwareCanvas() && parms.TranslationId != -1)
{ {
@ -428,43 +430,93 @@ void F2DDrawer::AddTexture(FGameTexture* img, DrawParms& parms)
v2 = parms.srcy + parms.srcheight; v2 = parms.srcy + parms.srcheight;
if (parms.flipX) 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)
{ {
double wi = std::min(parms.windowright, parms.texwidth); std::swap(u1, u2);
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) 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[0] = parms.lclip;
dg.mScissor[1] = parms.uclip; dg.mScissor[1] = parms.uclip;
dg.mScissor[2] = parms.rclip; dg.mScissor[2] = parms.rclip;
dg.mScissor[3] = parms.dclip; dg.mScissor[3] = parms.dclip;
dg.mFlags |= DTF_Scissor; dg.mFlags |= DTF_Scissor;
}
else
{
memset(dg.mScissor, 0, sizeof(dg.mScissor));
}
dg.mVertCount = 4; dg.mVertCount = 4;
dg.mVertIndex = (int)mVertices.Reserve(4); dg.mVertIndex = (int)mVertices.Reserve(4);
TwoDVertex *ptr = &mVertices[dg.mVertIndex]; TwoDVertex* ptr = &mVertices[dg.mVertIndex];
ptr->Set(x, y, 0, u1, v1, vertexcolor); ptr++; ptr->Set(x1, y1, 0, u1, v1, vertexcolor); ptr++;
ptr->Set(x, y + h, 0, u1, v2, vertexcolor); ptr++; ptr->Set(x2, y2, 0, u1, v2, vertexcolor); ptr++;
ptr->Set(x + w, y, 0, u2, v1, vertexcolor); ptr++; ptr->Set(x3, y3, 0, u2, v1, vertexcolor); ptr++;
ptr->Set(x + w, y + h, 0, u2, v2, vertexcolor); ptr++; ptr->Set(x4, y4, 0, u2, v2, vertexcolor); ptr++;
}
dg.mIndexIndex = mIndices.Size(); dg.mIndexIndex = mIndices.Size();
dg.mIndexCount += 6; dg.mIndexCount += 6;
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2);
@ -693,7 +745,7 @@ float F2DDrawer::GetClassicFlatScalarHeight()
return sh; 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; 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); dg.mVertIndex = (int)mVertices.Reserve(4);
auto ptr = &mVertices[dg.mVertIndex]; 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) if (local_origin < 4)
{ {
ptr->Set(left, bottom, 0, fU1, fV2, 0xffffffff); ptr++; ptr->Set(left, bottom, 0, fU1, fV2, color); ptr++;
ptr->Set(right, top, 0, fU2, fV1, 0xffffffff); ptr++; ptr->Set(right, top, 0, fU2, fV1, color); ptr++;
} }
else else
{ {
ptr->Set(left, bottom, 0, fU2, fV1, 0xffffffff); ptr++; ptr->Set(left, bottom, 0, fU2, fV1, color); ptr++;
ptr->Set(right, top, 0, fU1, fV2, 0xffffffff); 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.mIndexIndex = mIndices.Size();
dg.mIndexCount += 6; dg.mIndexCount += 6;
AddIndices(dg.mVertIndex, 6, 0, 1, 2, 1, 3, 2); 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() void F2DDrawer::Clear()
{ {
mVertices.Clear(); if (!locked)
mIndices.Clear(); {
mData.Clear(); mVertices.Clear();
mIsFirstPass = true; mIndices.Clear();
mData.Clear();
mIsFirstPass = true;
}
screenFade = 1.f;
} }

View file

@ -84,6 +84,7 @@ public:
DTF_Wrap = 1, DTF_Wrap = 1,
DTF_Scissor = 2, DTF_Scissor = 2,
DTF_Burn = 4, DTF_Burn = 4,
DTF_Indexed = 8,
}; };
@ -164,6 +165,8 @@ public:
TArray<RenderCommand> mData; TArray<RenderCommand> mData;
int Width, Height; int Width, Height;
bool isIn2D; 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: public:
int fullscreenautoaspect = 0; int fullscreenautoaspect = 0;
int cliptop = -1, clipleft = -1, clipwidth = -1, clipheight = -1; 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 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, 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); 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 AddColorOnlyQuad(int left, int top, int width, int height, PalEntry color, FRenderStyle *style = nullptr, bool prepend = false);
void ClearScreen(PalEntry color = 0xff000000); void ClearScreen(PalEntry color = 0xff000000);
@ -199,6 +202,9 @@ public:
void AddPixel(int x1, int y1, uint32_t color); void AddPixel(int x1, int y1, uint32_t color);
void Clear(); void Clear();
void Lock() { locked = true; }
void SetScreenFade(float factor) { screenFade = factor; }
void Unlock() { locked = false; }
int GetWidth() const { return Width; } int GetWidth() const { return Width; }
int GetHeight() const { return Height; } int GetHeight() const { return Height; }
void SetSize(int w, int h) { Width = w; Height = h; } 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 SetClipRect(int x, int y, int w, int h);
void GetClipRect(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; bool mIsFirstPass = true;
}; };

View file

@ -45,6 +45,9 @@ EXTERN_CVAR(Int, vid_aspect)
EXTERN_CVAR(Int, uiscale) EXTERN_CVAR(Int, uiscale)
CVAR(Bool, ui_screenborder_classic_scaling, true, CVAR_ARCHIVE) 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. // Helper for ActiveRatio and CheckRatio. Returns the forced ratio type, or -1 if none.
int ActiveFakeRatio(int width, int height) 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); va_start(tags.list, tags_first);
DrawParms parms; DrawParms parms;
if (!img || !img->isValid()) return;
bool res = ParseDrawTextureTags(drawer, img, x, y, tags_first, tags, &parms, false); bool res = ParseDrawTextureTags(drawer, img, x, y, tags_first, tags, &parms, false);
va_end(tags.list); va_end(tags.list);
if (!res) if (!res)
@ -208,6 +212,7 @@ static void DrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y
{ {
DrawParms parms; DrawParms parms;
uint32_t tag = ListGetInt(args); uint32_t tag = ListGetInt(args);
if (!img || !img->isValid()) return;
bool res = ParseDrawTextureTags(drawer, img, x, y, tag, args, &parms, false); bool res = ParseDrawTextureTags(drawer, img, x, y, tag, args, &parms, false);
if (!res) return; if (!res) return;
drawer->AddTexture(img, parms); 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 GetWidth = [=]() { return parms->viewport.width; };
auto GetHeight = [=]() {return drawer->GetHeight(); }; 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; double aspect;
if (srcheight == 200) aspect = srcwidth / 240.; if (srcheight == 200) aspect = srcwidth / 240.;
@ -341,23 +355,35 @@ static void CalcFullscreenScale(F2DDrawer* drawer, double srcwidth, double srche
else aspect = srcwidth / srcheight; else aspect = srcwidth / srcheight;
rect.left = rect.top = 0; rect.left = rect.top = 0;
auto screenratio = ActiveRatio(GetWidth(), GetHeight()); 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 // 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. 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 else
{ {
// special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows. // 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.); double width4_3 = srcheight * (4. / 3.);
rect.width = (double)GetWidth() * srcwidth / width4_3; rect.width = (double)GetWidth() * srcwidth / width4_3;
rect.height = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image rect.height = GetHeight() * screenratio * (3. / 4.); // use 4:3 for the image
rect.top = (GetHeight() - rect.height) / 2;
rect.left = -(srcwidth - width4_3) / 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; return;
} }
} }
if ((screenratio > aspect) ^ (autoaspect == 2)) if (autoaspect == FSMode_ScaleToHeight || (screenratio > aspect) ^ (autoaspect == FSMode_ScaleToFill))
{ {
// pillarboxed or vertically cropped (i.e. scale to height) // pillarboxed or vertically cropped (i.e. scale to height)
rect.height = GetHeight(); 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) // letterboxed or horizontally cropped (i.e. scale to width)
rect.width = GetWidth(); rect.width = GetWidth();
rect.height = GetHeight() * screenratio / aspect; 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) bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, double xx, double yy)
{ {
auto GetWidth = [=]() { return drawer->GetWidth(); }; auto GetWidth = [=]() { return parms->viewport.width; };
auto GetHeight = [=]() {return drawer->GetHeight(); }; auto GetHeight = [=]() {return parms->viewport.height; };
if (img != NULL) if (img != NULL)
{ {
parms->x = xx; parms->x = xx;
@ -399,12 +436,17 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do
} }
if (parms->destwidth == INT_MAX || parms->fortext) if (parms->destwidth == INT_MAX || parms->fortext)
{ {
parms->destwidth = img->GetDisplayWidth(); parms->destwidth = parms->texwidth;
} }
if (parms->destheight == INT_MAX || parms->fortext) 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) switch (parms->cleanmode)
{ {
@ -429,13 +471,14 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do
break; break;
case DTA_Base: 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. // First calculate the destination rect for an image of the given size and then reposition this object in it.
DoubleRect rect; DoubleRect rect;
CalcFullscreenScale(drawer, parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect); CalcFullscreenScale(parms, parms->virtWidth, parms->virtHeight, parms->fsscalemode, rect);
parms->x = rect.left + parms->x * rect.width / parms->virtWidth; double adder = parms->keepratio < 0 ? 0 : parms->keepratio == 0 ? rect.left : 2 * rect.left;
parms->y = rect.top + parms->y * rect.height / parms->virtHeight; 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->destwidth = parms->destwidth * rect.width / parms->virtWidth;
parms->destheight = parms->destheight * rect.height / parms->virtHeight; parms->destheight = parms->destheight * rect.height / parms->virtHeight;
return false; return false;
@ -446,12 +489,13 @@ bool SetTextureParms(F2DDrawer * drawer, DrawParms *parms, FGameTexture *img, do
case DTA_FullscreenEx: case DTA_FullscreenEx:
{ {
DoubleRect rect; DoubleRect rect;
CalcFullscreenScale(drawer, img->GetDisplayWidth(), img->GetDisplayHeight(), parms->fsscalemode, rect); CalcFullscreenScale(parms, parms->texwidth, parms->texheight, parms->fsscalemode, rect);
parms->keepratio = true; parms->keepratio = -1;
parms->x = rect.left; parms->x = parms->viewport.left + rect.left;
parms->y = rect.top; parms->y = parms->viewport.top + rect.top;
parms->destwidth = rect.width; parms->destwidth = rect.width;
parms->destheight = rect.height; parms->destheight = rect.height;
parms->top = parms->left = 0;
return false; // Do not call VirtualToRealCoords for this! 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()) 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->virtWidth, parms->virtHeight, parms->virtBottom, !parms->keepratio);
} }
parms->x += parms->viewport.left;
parms->y += parms->viewport.top;
} }
return false; return false;
@ -603,8 +649,8 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
parms->color = 0xffffffff; parms->color = 0xffffffff;
//parms->shadowAlpha = 0; //parms->shadowAlpha = 0;
parms->shadowColor = 0; parms->shadowColor = 0;
parms->virtWidth = drawer->GetWidth(); parms->virtWidth = INT_MAX; // these need to match the viewport if not explicitly set, but we do not know that yet.
parms->virtHeight = drawer->GetHeight(); parms->virtHeight = INT_MAX;
parms->keepratio = false; parms->keepratio = false;
parms->style.BlendOp = 255; // Dummy "not set" value parms->style.BlendOp = 255; // Dummy "not set" value
parms->masked = true; parms->masked = true;
@ -624,6 +670,11 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
parms->monospace = EMonospacing::Off; parms->monospace = EMonospacing::Off;
parms->spacing = 0; parms->spacing = 0;
parms->fsscalemode = -1; 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, // Parse the tag list for attributes. (For floating point attributes,
// consider that the C ABI dictates that all floats be promoted to // 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: case DTA_FullscreenScale:
intval = ListGetInt(tags); 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; break;
@ -821,6 +881,10 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
parms->flipY = ListGetInt(tags); parms->flipY = ListGetInt(tags);
break; break;
case DTA_FlipOffsets:
parms->flipoffsets = ListGetInt(tags);
break;
case DTA_SrcX: case DTA_SrcX:
parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth(); parms->srcx = ListGetDouble(tags) / img->GetDisplayWidth();
break; break;
@ -861,6 +925,16 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
parms->left = ListGetDouble(tags); parms->left = ListGetDouble(tags);
break; break;
case DTA_TopLeft:
assert(fortext == false);
if (fortext) return false;
if (ListGetInt(tags))
{
parms->left = 0;
parms->top = 0;
}
break;
case DTA_CenterOffset: case DTA_CenterOffset:
assert(fortext == false); assert(fortext == false);
if (fortext) return false; if (fortext) return false;
@ -871,6 +945,16 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
} }
break; 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: case DTA_CenterBottomOffset:
assert(fortext == false); assert(fortext == false);
if (fortext) return false; if (fortext) return false;
@ -958,6 +1042,14 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
} }
break; break;
case DTA_ScaleX:
parms->patchscalex = ListGetDouble(tags);
break;
case DTA_ScaleY:
parms->patchscaley = ListGetDouble(tags);
break;
case DTA_Masked: case DTA_Masked:
parms->masked = ListGetInt(tags); parms->masked = ListGetInt(tags);
break; break;
@ -967,8 +1059,10 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
break; break;
case DTA_KeepRatio: case DTA_KeepRatio:
// I think this is a terribly misleading name, since it actually turns parms->keepratio = ListGetInt(tags) ? -1 : 0;
// *off* aspect ratio correction. break;
case DTA_Pin:
parms->keepratio = ListGetInt(tags); parms->keepratio = ListGetInt(tags);
break; break;
@ -1012,11 +1106,39 @@ bool ParseDrawTextureTags(F2DDrawer *drawer, FGameTexture *img, double x, double
parms->burn = true; parms->burn = true;
break; 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); tag = ListGetInt(tags);
} }
ListEnd(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 clipleft = drawer->clipleft;
auto cliptop = drawer->cliptop; auto cliptop = drawer->cliptop;
auto clipwidth = drawer->clipwidth; auto clipwidth = drawer->clipwidth;
@ -1084,12 +1206,10 @@ template bool ParseDrawTextureTags<VMVa_List>(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) double vwidth, double vheight, bool vbottom, bool handleaspect)
{ {
auto Width = drawer->GetWidth(); float myratio = float(handleaspect ? ActiveRatio (Width, Height) : (4.0 / 3.0));
auto Height = drawer->GetHeight();
float myratio = handleaspect ? ActiveRatio (Width, Height) : (4.0f / 3.0f);
// if 21:9 AR, map to 16:9 for all callers. // if 21:9 AR, map to 16:9 for all callers.
// this allows for black bars and stops the stretching of fullscreen images // 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) DEFINE_ACTION_FUNCTION(_Screen, VirtualToRealCoords)
{ {
PARAM_PROLOGUE; PARAM_PROLOGUE;

View file

@ -2,6 +2,7 @@
#include "v_2ddrawer.h" #include "v_2ddrawer.h"
#include "c_cvars.h" #include "c_cvars.h"
#include "intrect.h"
// TagItem definitions for DrawTexture. As far as I know, tag lists // TagItem definitions for DrawTexture. As far as I know, tag lists
// originated on the Amiga. // originated on the Amiga.
@ -13,11 +14,38 @@
// uint32_t ti_Data; // uint32_t ti_Data;
// }; // };
#define TAG_DONE (0) /* Used to indicate the end of the Tag list */ enum tags : uint32_t
#define TAG_END (0) /* Ditto */ {
/* list pointed to in ti_Data */ 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 enum
{ {
@ -89,6 +117,19 @@ enum
DTA_FullscreenEx, DTA_FullscreenEx,
DTA_FullscreenScale, 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 fortext;
bool virtBottom; bool virtBottom;
bool burn; bool burn;
bool flipoffsets;
bool indexed;
int8_t fsscalemode; int8_t fsscalemode;
double srcx, srcy; double srcx, srcy;
double srcwidth, srcheight; double srcwidth, srcheight;
double patchscalex, patchscaley;
double rotateangle;
IntRect viewport;
}; };
struct Va_List struct Va_List
@ -187,14 +233,8 @@ int GetUIScale(F2DDrawer* drawer, int altval);
int GetConScale(F2DDrawer* drawer, int altval); int GetConScale(F2DDrawer* drawer, int altval);
EXTERN_CVAR(Int, uiscale); EXTERN_CVAR(Int, uiscale);
EXTERN_CVAR(Int, con_scaletext);
EXTERN_CVAR(Int, con_scale); 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) inline int active_con_scale(F2DDrawer *drawer)
{ {
return GetConScale(drawer, con_scale); return GetConScale(drawer, con_scale);

View file

@ -39,6 +39,16 @@
#include "v_collection.h" #include "v_collection.h"
#include "v_text.h" #include "v_text.h"
#include "renderstyle.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; class player_t;
struct FRemapTable; struct FRemapTable;

View file

@ -55,6 +55,7 @@
#include "texturemanager.h" #include "texturemanager.h"
#include "v_draw.h" #include "v_draw.h"
#include "doommenu.h" #include "doommenu.h"
#include "sbar.h"
FIntermissionDescriptorList IntermissionDescriptors; FIntermissionDescriptorList IntermissionDescriptors;

View file

@ -195,6 +195,20 @@ enum DrawTextureTags
DTA_FullscreenEx, // advanced fullscreen control. DTA_FullscreenEx, // advanced fullscreen control.
DTA_FullscreenScale, // enable DTA_Fullscreen coordinate calculation for placed overlays. 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 class Shape2DTransform : Object native