From 4f0b02b39634e80a9395de1cd5ab9e7a308d7924 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sat, 23 Jul 2022 18:18:54 +0200 Subject: [PATCH] Add a 2d drawer to canvas textures --- src/common/2d/v_2ddrawer.cpp | 2 + src/common/2d/v_2ddrawer.h | 12 + src/common/2d/v_draw.cpp | 254 +++++++++++++++++- src/common/2d/v_drawtext.cpp | 16 ++ src/common/rendering/gl/gl_framebuffer.cpp | 6 + .../vulkan/system/vk_framebuffer.cpp | 5 + src/common/textures/textures.h | 4 + src/r_data/r_canvastexture.cpp | 15 ++ src/scripting/vmthunks.cpp | 11 + wadsrc/static/zscript/doombase.zs | 1 + wadsrc/static/zscript/engine/base.zs | 30 +++ 11 files changed, 354 insertions(+), 2 deletions(-) diff --git a/src/common/2d/v_2ddrawer.cpp b/src/common/2d/v_2ddrawer.cpp index 0afc05967..02c252468 100644 --- a/src/common/2d/v_2ddrawer.cpp +++ b/src/common/2d/v_2ddrawer.cpp @@ -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) diff --git a/src/common/2d/v_2ddrawer.h b/src/common/2d/v_2ddrawer.h index d718e06d4..bb1663ebb 100644 --- a/src/common/2d/v_2ddrawer.h +++ b/src/common/2d/v_2ddrawer.h @@ -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 Drawer = std::make_shared(); +}; + struct DShape2DBufferInfo : RefCountedBase { TArray buffers; diff --git a/src/common/2d/v_draw.cpp b/src/common/2d/v_draw.cpp index 54c9cc904..7d730c95d 100644 --- a/src/common/2d/v_draw.cpp +++ b/src/common/2d/v_draw.cpp @@ -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; +} + diff --git a/src/common/2d/v_drawtext.cpp b/src/common/2d/v_drawtext.cpp index 2bddac961..f9ca1bdce 100644 --- a/src/common/2d/v_drawtext.cpp +++ b/src/common/2d/v_drawtext.cpp @@ -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 diff --git a/src/common/rendering/gl/gl_framebuffer.cpp b/src/common/rendering/gl/gl_framebuffer.cpp index 52cf004d0..7f0e5f326 100644 --- a/src/common/rendering/gl/gl_framebuffer.cpp +++ b/src/common/rendering/gl/gl_framebuffer.cpp @@ -229,6 +229,12 @@ void OpenGLFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::functionGetHeight()); renderFunc(bounds); + + if (tex->Drawer) + { + ::Draw2D(tex->Drawer.get(), gl_RenderState); + } + GLRenderer->EndOffscreen(); tex->SetUpdated(true); diff --git a/src/common/rendering/vulkan/system/vk_framebuffer.cpp b/src/common/rendering/vulkan/system/vk_framebuffer.cpp index 55ce448fd..e712c9342 100644 --- a/src/common/rendering/vulkan/system/vk_framebuffer.cpp +++ b/src/common/rendering/vulkan/system/vk_framebuffer.cpp @@ -215,6 +215,11 @@ void VulkanFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::functionDrawer) + { + ::Draw2D(tex->Drawer.get(), *mRenderState); + } + mRenderState->EndRenderPass(); VkImageTransition() diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index 2bab841d7..89f0b9212 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -44,6 +44,7 @@ #include "hw_texcontainer.h" #include "floatrect.h" #include "refcounted.h" +#include typedef TMap 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 Drawer; + protected: bool bLastUpdateType = false; diff --git a/src/r_data/r_canvastexture.cpp b/src/r_data/r_canvastexture.cpp index c12d42e76..95fe33ac7 100644 --- a/src/r_data/r_canvastexture.cpp +++ b/src/r_data/r_canvastexture.cpp @@ -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(tex->GetTexture()); + canvasTex->Drawer = canvas->Drawer; + } + } +} + //========================================================================== // // FCanvasTextureInfo :: UpdateAll diff --git a/src/scripting/vmthunks.cpp b/src/scripting/vmthunks.cpp index 94baffd9f..37102bde6 100644 --- a/src/scripting/vmthunks.cpp +++ b/src/scripting/vmthunks.cpp @@ -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 diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index 34a00cdd4..365e9d256 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -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); diff --git a/wadsrc/static/zscript/engine/base.zs b/wadsrc/static/zscript/engine/base.zs index 4737139a7..4bff10736 100644 --- a/wadsrc/static/zscript/engine/base.zs +++ b/wadsrc/static/zscript/engine/base.zs @@ -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);