From 4c0e6e8fcc71ebf94103601b1c64f1d16c6ea7ec Mon Sep 17 00:00:00 2001 From: Magnus Norddahl <dpjudas@users.noreply.github.com> Date: Tue, 20 Aug 2019 11:00:24 +0200 Subject: [PATCH] - implement plotter as a shader --- Source/Core/Rendering/Plotter.cs | 357 +++++++------------- Source/Core/Rendering/RenderDevice.cs | 17 +- Source/Core/Rendering/Renderer2D.cs | 10 +- Source/Native/BuilderNative.vcxproj | 1 + Source/Native/BuilderNative.vcxproj.filters | 1 + Source/Native/RenderDevice.cpp | 21 -- Source/Native/RenderDevice.h | 3 +- Source/Native/ShaderManager.cpp | 2 + Source/Native/ShaderPlotter.h | 42 +++ Source/Native/Texture.cpp | 10 - Source/Native/Texture.h | 3 - Source/Native/exports.def | 2 - 12 files changed, 172 insertions(+), 297 deletions(-) create mode 100644 Source/Native/ShaderPlotter.h diff --git a/Source/Core/Rendering/Plotter.cs b/Source/Core/Rendering/Plotter.cs index 16cb3b521..1a5dd45c9 100755 --- a/Source/Core/Rendering/Plotter.cs +++ b/Source/Core/Rendering/Plotter.cs @@ -24,7 +24,7 @@ using CodeImp.DoomBuilder.Geometry; namespace CodeImp.DoomBuilder.Rendering { - internal unsafe sealed class Plotter : IDisposable + internal sealed class Plotter : IDisposable { public Plotter(int width, int height) { @@ -42,255 +42,133 @@ namespace CodeImp.DoomBuilder.Rendering public void DrawContents(RenderDevice graphics) { - if (clear == false && commands.Count == 0) + if (clear == false && vertices.Count == 0) return; - pixels = (PixelColor*)graphics.LockTexture(Texture).ToPointer(); + var projmat = Matrix.Scaling(2.0f / this.Texture.Width, 2.0f / this.Texture.Height, 1.0f) * Matrix.Translation(-1.0f, -1.0f, 0.0f); - if (clear) - General.ZeroMemory(new IntPtr(pixels), Width * Height * sizeof(PixelColor)); + graphics.StartRendering(clear, new Color4(0), this.Texture, false); + graphics.SetShader(ShaderName.plotter); + graphics.SetUniform(UniformName.transformsettings, projmat); + graphics.SetAlphaBlendEnable(true); + graphics.SetBlendOperation(BlendOperation.Add); + graphics.SetSourceBlend(Blend.SourceAlpha); + graphics.SetDestinationBlend(Blend.InverseSourceAlpha); + graphics.Draw(PrimitiveType.TriangleList, 0, vertices.Count / 3, vertices.ToArray()); + graphics.SetAlphaBlendEnable(false); + graphics.FinishRendering(); - foreach (var command in commands) + clear = false; + vertices.Clear(); + } + + void DrawLine(int x0, int y0, int x1, int y1, int c, bool dotted = false) + { + var v = new FlatVertex(); + v.c = c; + + float nx, ny, len; + if (x0 == x1) + { + nx = 1.0f; + ny = 0.0f; + len = y1 - y0; + } + else if (y0 == y1) + { + nx = 0.0f; + ny = 1.0f; + len = x1 - x0; + } + else { - command(); + nx = (float)(y1 - y0); + ny = (float)-(x1 - x0); + len = (float)Math.Sqrt(nx * nx + ny * ny); + nx /= len; + ny /= len; } - commands.Clear(); - clear = false; + float dx = -ny * 0.5f; + float dy = nx * 0.5f; - graphics.UnlockTexture(Texture); - } + float xx0 = x0 + 0.5f - dx; + float yy0 = y0 + 0.5f - dy; + float xx1 = x1 + 0.5f + dx; + float yy1 = y1 + 0.5f + dy; - // This clears all pixels black - public void Clear() - { - clear = true; - commands.Clear(); - } - - // This draws a pixel normally - public void DrawVertexSolid(int x, int y, int size, PixelColor c, PixelColor l, PixelColor d) - { - commands.Add(() => + float start, end; + if (!dotted) { - int width = Width; - int height = Height; - int x1 = x - size; - int x2 = x + size; - int y1 = y - size; - int y2 = y + size; - - // Do unchecked? - if ((x1 >= 0) && (x2 < width) && (y1 >= 0) && (y2 < height)) - { - // Filled square - for (int yp = y1; yp <= y2; yp++) - for (int xp = x1; xp <= x2; xp++) - pixels[yp * width + xp] = c; - - // Vertical edges - for (int yp = y1 + 1; yp <= y2 - 1; yp++) - { - pixels[yp * width + x1] = l; - pixels[yp * width + x2] = d; - } - - // Horizontal edges - for (int xp = x1 + 1; xp <= x2 - 1; xp++) - { - pixels[y1 * width + xp] = l; - pixels[y2 * width + xp] = d; - } - - // Corners - pixels[y2 * width + x2] = d; - pixels[y1 * width + x1] = l; - } - }); - } - - // This draws a dotted grid line horizontally - public void DrawGridLineH(int y, int x1, int x2, PixelColor c) - { - commands.Add(() => + start = 0.5f; + end = 0.5f; + } + else { - int width = Width; - int height = Height; - int numpixels = width >> 1; - int offset = y & 0x01; - int ywidth = y * width; - x1 = General.Clamp(x1 >> 1, 0, numpixels - 1); - x2 = General.Clamp(x2 >> 1, 0, numpixels - 1); - - if ((y >= 0) && (y < height)) - { - // Draw all pixels on this line - for (int i = x1; i < x2; i++) pixels[ywidth + ((i << 1) | offset)] = c; - } - }); - } + start = -0.5f; + end = len + 0.5f; + } - // This draws a dotted grid line vertically - public void DrawGridLineV(int x, int y1, int y2, PixelColor c) - { - commands.Add(() => - { - int width = Width; - int height = Height; - int numpixels = height >> 1; - int offset = x & 0x01; - y1 = General.Clamp(y1 >> 1, 0, numpixels - 1); - y2 = General.Clamp(y2 >> 1, 0, numpixels - 1); - - if ((x >= 0) && (x < width)) - { - // Draw all pixels on this line - for (int i = y1; i < y2; i++) pixels[((i << 1) | offset) * width + x] = c; - } - }); - } + float lineextent = 3.0f; // line width in shader + 1 + nx *= lineextent; + ny *= lineextent; - // This draws a line normally - // See: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm - public void DrawLineSolid(int x1, int y1, int x2, int y2, PixelColor c, uint mask = 0xffffffff) - { - commands.Add(() => - { + v.u = start; v.v = -lineextent; v.x = xx0 - nx; v.y = yy0 - ny; vertices.Add(v); + v.u = start; v.v = lineextent; v.x = xx0 + nx; v.y = yy0 + ny; vertices.Add(v); + v.u = end; v.v = lineextent; v.x = xx1 + nx; v.y = yy1 + ny; vertices.Add(v); + vertices.Add(v); + v.u = end; v.v = -lineextent; v.x = xx1 - nx; v.y = yy1 - ny; vertices.Add(v); + v.u = start; v.v = -lineextent; v.x = xx0 - nx; v.y = yy0 - ny; vertices.Add(v); + } - int width = Width; - int height = Height; - - // Check if the line is outside the screen for sure. - // This is quickly done by checking in which area both points are. When this - // is above, below, right or left of the screen, then skip drawing the line. - if (((x1 < 0) && (x2 < 0)) || - ((x1 > width) && (x2 > width)) || - ((y1 < 0) && (y2 < 0)) || - ((y1 > height) && (y2 > height))) return; - - // Distance of the line - int dx = x2 - x1; - int dy = y2 - y1; - - // Positive (absolute) distance - int dxabs = Math.Abs(dx); - int dyabs = Math.Abs(dy); - - // Half distance - int x = dyabs >> 1; - int y = dxabs >> 1; - - // Direction - int sdx = Math.Sign(dx); - int sdy = Math.Sign(dy); - - // Start position - int px = x1; - int py = y1; - - // When the line is completely inside screen, - // then do an unchecked draw, because all of its pixels are - // guaranteed to be within the memory range - if ((x1 >= 0) && (x2 >= 0) && (x1 < width) && (x2 < width) && - (y1 >= 0) && (y2 >= 0) && (y1 < height) && (y2 < height)) - { - // Draw first pixel - pixels[py * width + px] = c; - - // Check if the line is more horizontal than vertical - if (dxabs >= dyabs) - { - for (int i = 0; i < dxabs; i++) - { - y += dyabs; - if (y >= dxabs) - { - y -= dxabs; - py += sdy; - } - px += sdx; - - // Draw pixel - if ((mask & (1 << (i & 0x7))) != 0) - { - pixels[py * width + px] = c; - } - } - } - // Else the line is more vertical than horizontal - else - { - for (int i = 0; i < dyabs; i++) - { - x += dxabs; - if (x >= dyabs) - { - x -= dyabs; - px += sdx; - } - py += sdy; - - // Draw pixel - if ((mask & (1 << (i & 0x7))) != 0) - { - pixels[py * width + px] = c; - } - } - } - } - else - { - // Draw first pixel - if ((px >= 0) && (px < width) && (py >= 0) && (py < height)) - pixels[py * width + px] = c; - - // Check if the line is more horizontal than vertical - if (dxabs >= dyabs) - { - for (int i = 0; i < dxabs; i++) - { - y += dyabs; - if (y >= dxabs) - { - y -= dxabs; - py += sdy; - } - px += sdx; - - // Draw pixel - if ((mask & (1 << (i & 0x7))) != 0) - { - if ((px >= 0) && (px < width) && (py >= 0) && (py < height)) - pixels[py * width + px] = c; - } - } - } - // Else the line is more vertical than horizontal - else - { - for (int i = 0; i < dyabs; i++) - { - x += dxabs; - if (x >= dyabs) - { - x -= dyabs; - px += sdx; - } - py += sdy; - - // Draw pixel - if ((mask & (1 << (i & 0x7))) != 0) - { - if ((px >= 0) && (px < width) && (py >= 0) && (py < height)) - pixels[py * width + px] = c; - } - } - } - } - }); - } + void FillBox(int x0, int y0, int x1, int y1, int c) + { + var v = new FlatVertex(); + v.c = c; + v.u = 0.5f; + v.v = 0.0f; + + v.x = x0; v.y = y0; vertices.Add(v); + v.x = x1; v.y = y0; vertices.Add(v); + v.x = x1; v.y = y1; vertices.Add(v); + vertices.Add(v); + v.x = x0; v.y = y1; vertices.Add(v); + v.x = x0; v.y = y0; vertices.Add(v); + } + + public void DrawVertexSolid(int x, int y, int size, PixelColor c, PixelColor l, PixelColor d) + { + int x0 = x - size; + int x1 = x + size; + int y0 = y - size; + int y1 = y + size; + + int lightcolor = l.ToInt(); + int darkcolor = d.ToInt(); + int centercolor = c.ToInt(); + DrawLine(x1, y1, x0, y1, darkcolor); + DrawLine(x1, y1, x1, y0, darkcolor); + DrawLine(x0, y0, x1, y0, lightcolor); + DrawLine(x0, y0, x0, y1, lightcolor); + FillBox(x0 + 1, y0 + 1, x1, y1, centercolor); + } - public void DrawLine3DFloor(Vector2D start, Vector2D end, PixelColor c, PixelColor c2) + public void DrawGridLineH(int y, int x1, int x2, PixelColor c) + { + DrawLine(x1, y, x2, y, c.ToInt()); + } + + public void DrawGridLineV(int x, int y1, int y2, PixelColor c) + { + DrawLine(x, y1, x, y2, c.ToInt()); + } + + public void DrawLineSolid(int x1, int y1, int x2, int y2, PixelColor c, bool dotted = false) + { + DrawLine(x1, y1, x2, y2, c.ToInt(), true); + } + + public void DrawLine3DFloor(Vector2D start, Vector2D end, PixelColor c, PixelColor c2) { Vector2D delta = end - start; float length = delta.GetLength(); @@ -313,14 +191,19 @@ namespace CodeImp.DoomBuilder.Rendering } } + // This clears all pixels black + public void Clear() + { + clear = true; + } + public void Dispose() { if (Texture != null) Texture.Dispose(); } - PixelColor* pixels; bool clear = true; - List<Action> commands = new List<Action>(); + List<FlatVertex> vertices = new List<FlatVertex>(); const int DASH_INTERVAL = 16; } diff --git a/Source/Core/Rendering/RenderDevice.cs b/Source/Core/Rendering/RenderDevice.cs index 36d448743..5153cf112 100755 --- a/Source/Core/Rendering/RenderDevice.cs +++ b/Source/Core/Rendering/RenderDevice.cs @@ -313,16 +313,6 @@ namespace CodeImp.DoomBuilder.Rendering bitmap.UnlockBits(bmpdata); } - internal IntPtr LockTexture(Texture texture) - { - return RenderDevice_LockTexture(Handle, texture.Handle); - } - - public void UnlockTexture(Texture texture) - { - RenderDevice_UnlockTexture(Handle, texture.Handle); - } - internal void RegisterResource(IRenderResource res) { } @@ -471,12 +461,6 @@ namespace CodeImp.DoomBuilder.Rendering [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)] protected static extern void RenderDevice_SetCubePixels(IntPtr handle, IntPtr texture, CubeMapFace face, IntPtr data); - [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)] - protected static extern IntPtr RenderDevice_LockTexture(IntPtr handle, IntPtr texture); - - [DllImport("BuilderNative.dll", CallingConvention = CallingConvention.Cdecl)] - protected static extern void RenderDevice_UnlockTexture(IntPtr handle, IntPtr texture); - //mxd. Anisotropic filtering steps public static readonly List<float> AF_STEPS = new List<float> { 1.0f, 2.0f, 4.0f, 8.0f, 16.0f }; @@ -518,6 +502,7 @@ namespace CodeImp.DoomBuilder.Rendering things2d_thing, things2d_sprite, things2d_fill, + plotter, world3d_main, world3d_fullbright, world3d_main_highlight, diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs index 28a3fea6d..7f5ee58aa 100755 --- a/Source/Core/Rendering/Renderer2D.cs +++ b/Source/Core/Rendering/Renderer2D.cs @@ -842,8 +842,6 @@ namespace CodeImp.DoomBuilder.Rendering // This renders the grid with a transform applied private void RenderGridTransformed(float size, float angle, float originx, float originy, PixelColor c, Plotter gridplotter) { - const int mask = 0x55555555; // dotted line mask - //mxd. Increase rendered grid size if needed if(!General.Settings.DynamicGridSize && size * scale <= 6f) do { size *= 2; } while(size * scale <= 6f); @@ -907,19 +905,19 @@ namespace CodeImp.DoomBuilder.Rendering if (xminintersect) { - gridplotter.DrawLineSolid((int)xminplotline.v1.x, (int)xminplotline.v1.y, (int)xminplotline.v2.x, (int)xminplotline.v2.y, c, mask); + gridplotter.DrawLineSolid((int)xminplotline.v1.x, (int)xminplotline.v1.y, (int)xminplotline.v2.x, (int)xminplotline.v2.y, c, true); } if (xmaxintersect) { - gridplotter.DrawLineSolid((int)xmaxplotline.v1.x, (int)xmaxplotline.v1.y, (int)xmaxplotline.v2.x, (int)xmaxplotline.v2.y, c, mask); + gridplotter.DrawLineSolid((int)xmaxplotline.v1.x, (int)xmaxplotline.v1.y, (int)xmaxplotline.v2.x, (int)xmaxplotline.v2.y, c, true); } if (yminintersect) { - gridplotter.DrawLineSolid((int)yminplotline.v1.x, (int)yminplotline.v1.y, (int)yminplotline.v2.x, (int)yminplotline.v2.y, c, mask); + gridplotter.DrawLineSolid((int)yminplotline.v1.x, (int)yminplotline.v1.y, (int)yminplotline.v2.x, (int)yminplotline.v2.y, c, true); } if (ymaxintersect) { - gridplotter.DrawLineSolid((int)ymaxplotline.v1.x, (int)ymaxplotline.v1.y, (int)ymaxplotline.v2.x, (int)ymaxplotline.v2.y, c, mask); + gridplotter.DrawLineSolid((int)ymaxplotline.v1.x, (int)ymaxplotline.v1.y, (int)ymaxplotline.v2.x, (int)ymaxplotline.v2.y, c, true); } num++; diff --git a/Source/Native/BuilderNative.vcxproj b/Source/Native/BuilderNative.vcxproj index c86f39db2..14b2aa836 100644 --- a/Source/Native/BuilderNative.vcxproj +++ b/Source/Native/BuilderNative.vcxproj @@ -224,6 +224,7 @@ <ClInclude Include="Shader.h" /> <ClInclude Include="ShaderDisplay2D.h" /> <ClInclude Include="ShaderManager.h" /> + <ClInclude Include="ShaderPlotter.h" /> <ClInclude Include="ShaderThings2D.h" /> <ClInclude Include="ShaderWorld3D.h" /> <ClInclude Include="Texture.h" /> diff --git a/Source/Native/BuilderNative.vcxproj.filters b/Source/Native/BuilderNative.vcxproj.filters index 4fc6c5dc2..e23a92f45 100644 --- a/Source/Native/BuilderNative.vcxproj.filters +++ b/Source/Native/BuilderNative.vcxproj.filters @@ -33,6 +33,7 @@ <ClInclude Include="ShaderManager.h" /> <ClInclude Include="ShaderDisplay2D.h" /> <ClInclude Include="RawMouse.h" /> + <ClInclude Include="ShaderPlotter.h" /> </ItemGroup> <ItemGroup> <None Include="exports.def" /> diff --git a/Source/Native/RenderDevice.cpp b/Source/Native/RenderDevice.cpp index 7b7965b88..4dcf32040 100644 --- a/Source/Native/RenderDevice.cpp +++ b/Source/Native/RenderDevice.cpp @@ -334,17 +334,6 @@ void RenderDevice::SetCubePixels(Texture* texture, CubeMapFace face, const void* InvalidateTexture(texture); } -void* RenderDevice::LockTexture(Texture* texture) -{ - return texture->Lock(); -} - -void RenderDevice::UnlockTexture(Texture* texture) -{ - texture->Unlock(); - InvalidateTexture(texture); -} - void RenderDevice::InvalidateTexture(Texture* texture) { if (texture->IsTextureCreated()) @@ -722,13 +711,3 @@ void RenderDevice_SetCubePixels(RenderDevice* device, Texture* texture, CubeMapF { device->SetCubePixels(texture, face, data); } - -void* RenderDevice_LockTexture(RenderDevice* device, Texture* texture) -{ - return device->LockTexture(texture); -} - -void RenderDevice_UnlockTexture(RenderDevice* device, Texture* texture) -{ - device->UnlockTexture(texture); -} diff --git a/Source/Native/RenderDevice.h b/Source/Native/RenderDevice.h index 756d67b8d..a1750de85 100644 --- a/Source/Native/RenderDevice.h +++ b/Source/Native/RenderDevice.h @@ -27,6 +27,7 @@ enum class ShaderName things2d_thing, things2d_sprite, things2d_fill, + plotter, world3d_main, world3d_fullbright, world3d_main_highlight, @@ -113,8 +114,6 @@ public: void SetPixels(Texture* texture, const void* data); void SetCubePixels(Texture* texture, CubeMapFace face, const void* data); - void* LockTexture(Texture* texture); - void UnlockTexture(Texture* texture); void InvalidateTexture(Texture* texture); diff --git a/Source/Native/ShaderManager.cpp b/Source/Native/ShaderManager.cpp index 1bb2b9051..f9d952652 100644 --- a/Source/Native/ShaderManager.cpp +++ b/Source/Native/ShaderManager.cpp @@ -4,6 +4,7 @@ #include "ShaderDisplay2D.h" #include "ShaderThings2D.h" #include "ShaderWorld3D.h" +#include "ShaderPlotter.h" #include <stdexcept> struct ShaderPair { const char* vs; const char* ps; }; @@ -15,6 +16,7 @@ static const ShaderPair ShaderSources[(int)ShaderName::count] = { { things2D_vs, things2D_ps_thing }, { things2D_vs, things2D_ps_sprite }, { things2D_vs, things2D_ps_fill }, + { plotter_vs, plotter_ps }, { world3D_vs_main, world3D_ps_main }, { world3D_vs_main, world3D_ps_fullbright }, { world3D_vs_main, world3D_ps_main_highlight }, diff --git a/Source/Native/ShaderPlotter.h b/Source/Native/ShaderPlotter.h new file mode 100644 index 000000000..669bc1d26 --- /dev/null +++ b/Source/Native/ShaderPlotter.h @@ -0,0 +1,42 @@ +#pragma once + +static const char* plotter_vs = R"( + in vec3 AttrPosition; + in vec4 AttrColor; + in vec2 AttrUV; + + out vec4 Color; + out vec2 UV; + + uniform mat4 transformsettings; + + void main() + { + gl_Position = transformsettings * vec4(AttrPosition, 1.0f); + Color = AttrColor; + UV = AttrUV; + } +)"; + +const char* plotter_ps = R"( + in vec4 Color; + in vec2 UV; + + out vec4 FragColor; + + void main() + { + // line stipple + int visible = int(UV.x) & 1; + if (visible == 1) + discard; + + // line smoothing + float linewidth = 2.0; + float falloff = 1.5; //1.5..2.5 + float centerdist = abs(UV.y); + float a = pow(clamp((linewidth - centerdist) / linewidth, 0.0, 1.0), falloff); + + FragColor = vec4(Color.rgb, Color.a * a); + } +)"; diff --git a/Source/Native/Texture.cpp b/Source/Native/Texture.cpp index c4c1f11b3..edea30202 100644 --- a/Source/Native/Texture.cpp +++ b/Source/Native/Texture.cpp @@ -38,16 +38,6 @@ void Texture::SetCubePixels(CubeMapFace face, const void* data) memcpy(mPixels[(int)face].data(), data, sizeof(uint32_t) * mWidth * mHeight); } -void* Texture::Lock() -{ - mPixels[0].resize(mWidth * (size_t)mHeight); - return mPixels[0].data(); -} - -void Texture::Unlock() -{ -} - void Texture::Invalidate() { if (mDepthRenderbuffer) glDeleteRenderbuffers(1, &mDepthRenderbuffer); diff --git a/Source/Native/Texture.h b/Source/Native/Texture.h index 1f9cbe963..e6ffbb050 100644 --- a/Source/Native/Texture.h +++ b/Source/Native/Texture.h @@ -22,9 +22,6 @@ public: void SetPixels(const void* data); void SetCubePixels(CubeMapFace face, const void* data); - void* Lock(); - void Unlock(); - bool IsCubeTexture() const { return mCubeTexture; } int GetWidth() const { return mWidth; } int GetHeight() const { return mHeight; } diff --git a/Source/Native/exports.def b/Source/Native/exports.def index 0f5da2f2e..76a903eda 100644 --- a/Source/Native/exports.def +++ b/Source/Native/exports.def @@ -33,8 +33,6 @@ EXPORTS RenderDevice_SetIndexBufferData RenderDevice_SetPixels RenderDevice_SetCubePixels - RenderDevice_LockTexture - RenderDevice_UnlockTexture VertexBuffer_New VertexBuffer_Delete IndexBuffer_New -- GitLab