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