Add a 2d drawer to canvas textures

This commit is contained in:
Magnus Norddahl 2022-07-23 18:18:54 +02:00 committed by Christoph Oelckers
parent cd20d707d4
commit 4f0b02b396
11 changed files with 354 additions and 2 deletions

View file

@ -49,6 +49,8 @@ EXTERN_CVAR(Float, transsouls)
CVAR(Float, classic_scaling_factor, 1.0, CVAR_ARCHIVE)
CVAR(Float, classic_scaling_pixelaspect, 1.2f, CVAR_ARCHIVE)
IMPLEMENT_CLASS(FCanvas, false, false)
IMPLEMENT_CLASS(DShape2DTransform, false, false)
static void Shape2DTransform_Clear(DShape2DTransform* self)

View file

@ -274,6 +274,18 @@ public:
bool mIsFirstPass = true;
};
// DCanvas is already taken so using FCanvas instead.
class FCanvas : public DObject
{
DECLARE_CLASS(FCanvas, DObject)
public:
FCanvas()
{
Drawer->SetSize(256, 256);
}
std::shared_ptr<F2DDrawer> Drawer = std::make_shared<F2DDrawer>();
};
struct DShape2DBufferInfo : RefCountedBase
{
TArray<F2DVertexBuffer> buffers;

View file

@ -194,7 +194,7 @@ int CleanXfac_1, CleanYfac_1, CleanWidth_1, CleanHeight_1;
//
//==========================================================================
static void DoDrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, Va_List& tags)
void DoDrawTexture(F2DDrawer *drawer, FGameTexture* img, double x, double y, int tags_first, Va_List& tags)
{
DrawParms parms;
@ -233,7 +233,7 @@ void DrawTexture(F2DDrawer *drawer, FTextureID texid, bool animate, double x, do
int ListGetInt(VMVa_List &tags);
static void DoDrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y, VMVa_List &args)
void DoDrawTexture(F2DDrawer *drawer, FGameTexture *img, double x, double y, VMVa_List &args)
{
DrawParms parms;
uint32_t tag = ListGetInt(args);
@ -261,6 +261,22 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawTexture)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawTexture)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(texid);
PARAM_BOOL(animate);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
auto tex = TexMan.GameByIndex(texid, animate);
VMVa_List args = { param + 4, 0, numparam - 5, va_reginfo + 4 };
DoDrawTexture(self->Drawer.get(), tex, x, y, args);
return 0;
}
//==========================================================================
//
// ZScript arbitrary textured shape drawing functions
@ -320,6 +336,22 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawShape)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawShape)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(texid);
PARAM_BOOL(animate);
PARAM_POINTER(shape, DShape2D);
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
auto tex = TexMan.GameByIndex(texid, animate);
VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 };
DrawShape(self->Drawer.get(), tex, shape, args);
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, DrawShapeFill)
{
PARAM_PROLOGUE;
@ -339,6 +371,23 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawShapeFill)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawShapeFill)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_COLOR(color);
PARAM_FLOAT(amount);
PARAM_POINTER(shape, DShape2D);
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
VMVa_List args = { param + 3, 0, numparam - 4, va_reginfo + 3 };
color.a = int(amount * 255.0f);
DrawShapeFill(self->Drawer.get(), color, shape, args);
return 0;
}
//==========================================================================
//
// Clipping rect
@ -364,6 +413,17 @@ DEFINE_ACTION_FUNCTION(_Screen, SetClipRect)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, SetClipRect)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(x);
PARAM_INT(y);
PARAM_INT(w);
PARAM_INT(h);
self->Drawer->SetClipRect(x, y, w, h);
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, ClearClipRect)
{
PARAM_PROLOGUE;
@ -371,6 +431,13 @@ DEFINE_ACTION_FUNCTION(_Screen, ClearClipRect)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, ClearClipRect)
{
PARAM_SELF_PROLOGUE(FCanvas);
self->Drawer->ClearClipRect();
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, ClearScreen)
{
PARAM_PROLOGUE;
@ -378,6 +445,13 @@ DEFINE_ACTION_FUNCTION(_Screen, ClearScreen)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, ClearScreen)
{
PARAM_SELF_PROLOGUE(FCanvas);
self->Drawer->ClearScreen();
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, SetScreenFade)
{
PARAM_PROLOGUE;
@ -386,6 +460,14 @@ DEFINE_ACTION_FUNCTION(_Screen, SetScreenFade)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, SetScreenFade)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_FLOAT(x);
self->Drawer->SetScreenFade(float(x));
return 0;
}
void F2DDrawer::GetClipRect(int *x, int *y, int *w, int *h)
{
@ -407,6 +489,18 @@ DEFINE_ACTION_FUNCTION(_Screen, GetClipRect)
return min(numret, 4);
}
DEFINE_ACTION_FUNCTION(FCanvas, GetClipRect)
{
PARAM_SELF_PROLOGUE(FCanvas);
int x, y, w, h;
self->Drawer->GetClipRect(&x, &y, &w, &h);
if (numret > 0) ret[0].SetInt(x);
if (numret > 1) ret[1].SetInt(y);
if (numret > 2) ret[2].SetInt(w);
if (numret > 3) ret[3].SetInt(h);
return min(numret, 4);
}
void CalcFullscreenScale(DrawParms *parms, double srcwidth, double srcheight, int oautoaspect, DoubleRect &rect)
{
@ -510,6 +604,24 @@ DEFINE_ACTION_FUNCTION(_Screen, GetFullscreenRect)
return min(numret, 4);
}
DEFINE_ACTION_FUNCTION(FCanvas, GetFullscreenRect)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_FLOAT(virtw);
PARAM_FLOAT(virth);
PARAM_INT(fsmode);
DrawParms parms;
DoubleRect rect;
parms.viewport.width = self->Drawer->GetWidth();
parms.viewport.height = self->Drawer->GetHeight();
CalcFullscreenScale(&parms, virtw, virth, fsmode, rect);
if (numret >= 1) ret[0].SetFloat(rect.left);
if (numret >= 2) ret[1].SetFloat(rect.top);
if (numret >= 3) ret[2].SetFloat(rect.width);
if (numret >= 4) ret[3].SetFloat(rect.height);
return min(numret, 4);
}
//==========================================================================
@ -1403,6 +1515,23 @@ DEFINE_ACTION_FUNCTION(_Screen, VirtualToRealCoords)
return min(numret, 2);
}
DEFINE_ACTION_FUNCTION(FCanvas, VirtualToRealCoords)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(w);
PARAM_FLOAT(h);
PARAM_FLOAT(vw);
PARAM_FLOAT(vh);
PARAM_BOOL(vbottom);
PARAM_BOOL(handleaspect);
VirtualToRealCoords(self->Drawer.get(), x, y, w, h, vw, vh, vbottom, handleaspect);
if (numret >= 1) ret[0].SetVector2(DVector2(x, y));
if (numret >= 2) ret[1].SetVector2(DVector2(w, h));
return min(numret, 2);
}
void VirtualToRealCoordsInt(F2DDrawer *drawer, int &x, int &y, int &w, int &h,
int vwidth, int vheight, bool vbottom, bool handleaspect)
{
@ -1444,6 +1573,19 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Screen, DrawLine, DrawLine)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawLine)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(x0);
PARAM_INT(y0);
PARAM_INT(x1);
PARAM_INT(y1);
PARAM_INT(color);
PARAM_INT(alpha);
self->Drawer->AddLine((float)x0, (float)y0, (float)x1, (float)y1, -1, -1, INT_MAX, INT_MAX, color | MAKEARGB(255, 0, 0, 0), alpha);
return 0;
}
static void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, uint32_t realcolor, int alpha)
{
if (!twod->HasBegun2D()) ThrowAbortException(X_OTHER, "Attempt to draw to screen outside a draw function");
@ -1464,6 +1606,20 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Screen, DrawThickLine, DrawThickLine)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawThickLine)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(x0);
PARAM_INT(y0);
PARAM_INT(x1);
PARAM_INT(y1);
PARAM_FLOAT(thickness);
PARAM_INT(color);
PARAM_INT(alpha);
self->Drawer->AddThickLine(x0, y0, x1, y1, thickness, color, alpha);
return 0;
}
//==========================================================================
//
// ClearRect
@ -1523,6 +1679,19 @@ DEFINE_ACTION_FUNCTION(_Screen, Clear)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, Clear)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(x1);
PARAM_INT(y1);
PARAM_INT(x2);
PARAM_INT(y2);
PARAM_INT(color);
PARAM_INT(palcol);
ClearRect(self->Drawer.get(), x1, y1, x2, y2, palcol, color);
return 0;
}
//==========================================================================
//
// DoDim
@ -1587,6 +1756,20 @@ DEFINE_ACTION_FUNCTION(_Screen, Dim)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, Dim)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(color);
PARAM_FLOAT(amount);
PARAM_INT(x1);
PARAM_INT(y1);
PARAM_INT(w);
PARAM_INT(h);
PARAM_INT(style);
Dim(self->Drawer.get(), color, float(amount), x1, y1, w, h, &LegacyRenderStyles[style]);
return 0;
}
//==========================================================================
//
@ -1643,6 +1826,19 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawLineFrame)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawLineFrame)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_COLOR(color);
PARAM_INT(left);
PARAM_INT(top);
PARAM_INT(width);
PARAM_INT(height);
PARAM_INT(thickness);
DrawFrame(self->Drawer.get(), color, left, top, width, height, thickness);
return 0;
}
void V_CalcCleanFacs(int designwidth, int designheight, int realwidth, int realheight, int* cleanx, int* cleany, int* _cx1, int* _cx2)
{
if (designheight < 240 && realheight >= 480) designheight = 240;
@ -1658,6 +1854,14 @@ DEFINE_ACTION_FUNCTION(_Screen, SetOffset)
ACTION_RETURN_VEC2(twod->SetOffset(DVector2(x, y)));
}
DEFINE_ACTION_FUNCTION(FCanvas, SetOffset)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
ACTION_RETURN_VEC2(self->Drawer->SetOffset(DVector2(x, y)));
}
DEFINE_ACTION_FUNCTION(_Screen, EnableStencil)
{
PARAM_PROLOGUE;
@ -1669,6 +1873,15 @@ DEFINE_ACTION_FUNCTION(_Screen, EnableStencil)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, EnableStencil)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_BOOL(on);
self->Drawer->AddEnableStencil(on);
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, SetStencil)
{
PARAM_PROLOGUE;
@ -1682,6 +1895,17 @@ DEFINE_ACTION_FUNCTION(_Screen, SetStencil)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, SetStencil)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_INT(offs);
PARAM_INT(op);
PARAM_INT(flags);
self->Drawer->AddSetStencil(offs, op, flags);
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, ClearStencil)
{
PARAM_PROLOGUE;
@ -1692,6 +1916,14 @@ DEFINE_ACTION_FUNCTION(_Screen, ClearStencil)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, ClearStencil)
{
PARAM_SELF_PROLOGUE(FCanvas);
self->Drawer->AddClearStencil();
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, SetTransform)
{
PARAM_PROLOGUE;
@ -1704,6 +1936,16 @@ DEFINE_ACTION_FUNCTION(_Screen, SetTransform)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, SetTransform)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_OBJECT_NOT_NULL(transform, DShape2DTransform);
self->Drawer->SetTransform(*transform);
return 0;
}
DEFINE_ACTION_FUNCTION(_Screen, ClearTransform)
{
PARAM_PROLOGUE;
@ -1714,3 +1956,11 @@ DEFINE_ACTION_FUNCTION(_Screen, ClearTransform)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, ClearTransform)
{
PARAM_SELF_PROLOGUE(FCanvas);
self->Drawer->ClearTransform();
return 0;
}

View file

@ -235,6 +235,22 @@ DEFINE_ACTION_FUNCTION(_Screen, DrawChar)
return 0;
}
DEFINE_ACTION_FUNCTION(FCanvas, DrawChar)
{
PARAM_SELF_PROLOGUE(FCanvas);
PARAM_POINTER(font, FFont);
PARAM_INT(cr);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_INT(chr);
PARAM_VA_POINTER(va_reginfo) // Get the hidden type information array
VMVa_List args = { param + 5, 0, numparam - 6, va_reginfo + 5 };
DrawChar(self->Drawer.get(), font, cr, x, y, chr, args);
return 0;
}
//==========================================================================
//
// DrawText

View file

@ -229,6 +229,12 @@ void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function<voi
bounds.height = FHardwareTexture::GetTexDimension(tex->GetHeight());
renderFunc(bounds);
if (tex->Drawer)
{
::Draw2D(tex->Drawer.get(), gl_RenderState);
}
GLRenderer->EndOffscreen();
tex->SetUpdated(true);

View file

@ -215,6 +215,11 @@ void VulkanFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function<voi
renderFunc(bounds);
if (tex->Drawer)
{
::Draw2D(tex->Drawer.get(), *mRenderState);
}
mRenderState->EndRenderPass();
VkImageTransition()

View file

@ -44,6 +44,7 @@
#include "hw_texcontainer.h"
#include "floatrect.h"
#include "refcounted.h"
#include <memory>
typedef TMap<int, bool> SpriteHits;
class FImageSource;
@ -302,6 +303,7 @@ public:
friend class FTextureManager;
};
class F2DDrawer;
// A texture that can be drawn to.
@ -322,6 +324,8 @@ public:
void SetAspectRatio(double aspectScale, bool useTextureRatio) { aspectRatio = (float)aspectScale * (useTextureRatio? ((float)Width / Height) : 1); }
std::shared_ptr<F2DDrawer> Drawer;
protected:
bool bLastUpdateType = false;

View file

@ -110,6 +110,21 @@ void SetCameraToTexture(AActor *viewpoint, const FString &texturename, double fo
}
}
void SetCanvasToTexture(FCanvas* canvas, const FString& texturename)
{
FTextureID textureid = TexMan.CheckForTexture(texturename, ETextureType::Wall, FTextureManager::TEXMAN_Overridable);
if (textureid.isValid())
{
// Only proceed if the texture actually has a canvas.
auto tex = TexMan.GetGameTexture(textureid);
if (tex && tex->GetTexture()->isCanvas())
{
FCanvasTexture* canvasTex = static_cast<FCanvasTexture*>(tex->GetTexture());
canvasTex->Drawer = canvas->Drawer;
}
}
}
//==========================================================================
//
// FCanvasTextureInfo :: UpdateAll

View file

@ -102,6 +102,17 @@ DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCameraTextureAspectRatio, SetCameraTex
return 0;
}
void SetCanvasToTexture(FCanvas* canvas, const FString& texturename);
DEFINE_ACTION_FUNCTION_NATIVE(_TexMan, SetCanvasToTexture, SetCanvasToTexture)
{
PARAM_PROLOGUE;
PARAM_OBJECT(canvas, FCanvas);
PARAM_STRING(texturename);
SetCanvasToTexture(canvas, texturename);
return 0;
}
//=====================================================================================
//
// sector_t exports

View file

@ -28,6 +28,7 @@ extend struct TexMan
{
native static void SetCameraToTexture(Actor viewpoint, String texture, double fov);
native static void SetCameraTextureAspectRatio(String texture, double aspectScale, bool useTextureRatio = true);
native static void SetCanvasToTexture(Canvas canvas, String texture);
deprecated("3.8", "Use Level.ReplaceTextures() instead") static void ReplaceTextures(String from, String to, int flags)
{
level.ReplaceTextures(from, to, flags);

View file

@ -502,6 +502,36 @@ class Shape2D : Object native
native void PushTriangle( int a, int b, int c );
}
class Canvas : Object native
{
native void Clear(int left, int top, int right, int bottom, Color color, int palcolor = -1);
native void Dim(Color col, double amount, int x, int y, int w, int h, ERenderStyle style = STYLE_Translucent);
native vararg void DrawTexture(TextureID tex, bool animate, double x, double y, ...);
native vararg void DrawShape(TextureID tex, bool animate, Shape2D s, ...);
native vararg void DrawShapeFill(Color col, double amount, Shape2D s, ...);
native vararg void DrawChar(Font font, int normalcolor, double x, double y, int character, ...);
native vararg void DrawText(Font font, int normalcolor, double x, double y, String text, ...);
native void DrawLine(int x0, int y0, int x1, int y1, Color color, int alpha = 255);
native void DrawLineFrame(Color color, int x0, int y0, int w, int h, int thickness = 1);
native void DrawThickLine(int x0, int y0, int x1, int y1, double thickness, Color color, int alpha = 255);
native Vector2, Vector2 VirtualToRealCoords(Vector2 pos, Vector2 size, Vector2 vsize, bool vbottom=false, bool handleaspect=true);
native void SetClipRect(int x, int y, int w, int h);
native void ClearClipRect();
native int, int, int, int GetClipRect();
native int, int, int, int GetViewWindow();
native double, double, double, double GetFullscreenRect(double vwidth, double vheight, int fsmode);
native Vector2 SetOffset(double x, double y);
native void ClearScreen(color col = 0);
native void SetScreenFade(double factor);
native void EnableStencil(bool on);
native void SetStencil(int offs, int op, int flags = -1);
native void ClearStencil();
native void SetTransform(Shape2DTransform transform);
native void ClearTransform();
}
struct Screen native
{
native static Color PaletteColor(int index);