From b51270fdfa10efcd53141013d25a05b792d651aa Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Sun, 18 Aug 2019 08:07:28 +0200 Subject: [PATCH] - Delay plotter drawing until DrawContents is called --- Source/Core/Rendering/Plotter.cs | 445 ++++++++++++++-------------- Source/Core/Rendering/Renderer2D.cs | 46 ++- 2 files changed, 242 insertions(+), 249 deletions(-) diff --git a/Source/Core/Rendering/Plotter.cs b/Source/Core/Rendering/Plotter.cs index d12e9404..7597e07e 100755 --- a/Source/Core/Rendering/Plotter.cs +++ b/Source/Core/Rendering/Plotter.cs @@ -17,6 +17,7 @@ #region ================== Namespaces using System; +using System.Collections.Generic; using CodeImp.DoomBuilder.Geometry; #endregion @@ -25,10 +26,6 @@ namespace CodeImp.DoomBuilder.Rendering { internal unsafe sealed class Plotter : IDisposable { - private const int DASH_INTERVAL = 16; //mxd - - private PixelColor* pixels; - public Plotter(int width, int height) { this.Texture = new Texture(width, height); @@ -43,269 +40,258 @@ namespace CodeImp.DoomBuilder.Rendering public int Height { get { return Texture.Height; } } public Texture Texture { get; set; } - public void Dispose() - { - if (Texture != null) Texture.Dispose(); - } - - public void Begin(RenderDevice graphics) - { - this.pixels = (PixelColor*)graphics.LockTexture(Texture).ToPointer(); - } - public void DrawContents(RenderDevice graphics) { + pixels = (PixelColor*)graphics.LockTexture(Texture).ToPointer(); + + if (clear) + General.ZeroMemory(new IntPtr(pixels), Width * Height * sizeof(PixelColor)); + + foreach (var command in commands) + { + command(); + } + graphics.UnlockTexture(Texture); } // This clears all pixels black public void Clear() { - // Clear memory - General.ZeroMemory(new IntPtr(pixels), Width * Height * sizeof(PixelColor)); + clear = true; + commands.Clear(); } // This draws a pixel normally - public void DrawVertexSolid(int x, int y, int size, ref PixelColor c, ref PixelColor l, ref PixelColor d) + public void DrawVertexSolid(int x, int y, int size, PixelColor c, PixelColor l, PixelColor d) { - int width = Width; - int height = Height; - int x1 = x - size; - int x2 = x + size; - int y1 = y - size; - int y2 = y + size; + commands.Add(() => + { + 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; + // 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; - } + // 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; - } + // 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; - } - /* - else - { - // Filled square - for(yp = y - size; yp <= y + size; yp++) - for(xp = x - size; xp <= x + size; xp++) - DrawPixelSolid(xp, yp, c); - - // Vertical edges - for(yp = y - size + 1; yp <= y + size - 1; yp++) - { - DrawPixelSolid(x - size, yp, l); - DrawPixelSolid(x + size, yp, d); - } - - // Horizontal edges - for(xp = x - size + 1; xp <= x + size - 1; xp++) - { - DrawPixelSolid(xp, y - size, l); - DrawPixelSolid(xp, y + size, d); - } - - // Corners - DrawPixelSolid(x + size, y + size, d); - DrawPixelSolid(x - size, y - size, l); - } - */ + // 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, ref PixelColor c) + public void DrawGridLineH(int y, int x1, int x2, PixelColor c) { - 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; - } + commands.Add(() => + { + 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; + } + }); } // This draws a dotted grid line vertically - public void DrawGridLineV(int x, int y1, int y2, ref PixelColor c) + public void DrawGridLineV(int x, int y1, int y2, PixelColor c) { - 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; - } + 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; + } + }); } // 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, ref PixelColor c, uint mask = 0xffffffff) + public void DrawLineSolid(int x1, int y1, int x2, int y2, PixelColor c, uint mask = 0xffffffff) { - int width = Width; - int height = Height; + commands.Add(() => + { - // 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; + int width = Width; + int height = Height; - // Distance of the line - int dx = x2 - x1; - int dy = y2 - y1; + // 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; - // Positive (absolute) distance - int dxabs = Math.Abs(dx); - int dyabs = Math.Abs(dy); + // Distance of the line + int dx = x2 - x1; + int dy = y2 - y1; - // Half distance - int x = dyabs >> 1; - int y = dxabs >> 1; + // Positive (absolute) distance + int dxabs = Math.Abs(dx); + int dyabs = Math.Abs(dy); - // Direction - int sdx = Math.Sign(dx); - int sdy = Math.Sign(dy); + // Half distance + int x = dyabs >> 1; + int y = dxabs >> 1; - // Start position - int px = x1; - int py = y1; + // Direction + int sdx = Math.Sign(dx); + int sdy = Math.Sign(dy); - // 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; + // Start position + int px = x1; + int py = y1; - // 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; + // 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; - // 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; + // 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 - { - // 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; - } - } - } - } + // 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; + } + } + } + } + }); } - //mxd - public void DrawLine3DFloor(Vector2D start, Vector2D end, ref PixelColor c, PixelColor c2) + public void DrawLine3DFloor(Vector2D start, Vector2D end, PixelColor c, PixelColor c2) { Vector2D delta = end - start; float length = delta.GetLength(); if(length < DASH_INTERVAL * 2) { - DrawLineSolid((int)start.x, (int)start.y, (int)end.x, (int)end.y, ref c2); + DrawLineSolid((int)start.x, (int)start.y, (int)end.x, (int)end.y, c2); } else { @@ -315,10 +301,21 @@ namespace CodeImp.DoomBuilder.Rendering Vector2D p1 = CurveTools.GetPointOnLine(start, end, d1); Vector2D p2 = CurveTools.GetPointOnLine(start, end, d2); - DrawLineSolid((int)start.x, (int)start.y, (int)p1.x, (int)p1.y, ref c2); - DrawLineSolid((int)p1.x, (int)p1.y, (int)p2.x, (int)p2.y, ref c); - DrawLineSolid((int)p2.x, (int)p2.y, (int)end.x, (int)end.y, ref c2); + DrawLineSolid((int)start.x, (int)start.y, (int)p1.x, (int)p1.y, c2); + DrawLineSolid((int)p1.x, (int)p1.y, (int)p2.x, (int)p2.y, c); + DrawLineSolid((int)p2.x, (int)p2.y, (int)end.x, (int)end.y, c2); } } - } + + public void Dispose() + { + if (Texture != null) Texture.Dispose(); + } + + PixelColor* pixels; + bool clear = true; + List commands = new List(); + + const int DASH_INTERVAL = 16; + } } diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs index 5ddec72a..28a3fea6 100755 --- a/Source/Core/Rendering/Renderer2D.cs +++ b/Source/Core/Rendering/Renderer2D.cs @@ -626,8 +626,6 @@ namespace CodeImp.DoomBuilder.Rendering // Rendertargets available? if(plotter != null) { - plotter.Begin(graphics); - // Redraw grid when structures image was cleared if(clear) { @@ -779,8 +777,6 @@ namespace CodeImp.DoomBuilder.Rendering if(lastgridsize != General.Map.Grid.GridSizeF || lastgridscale != scale || lastgridx != offsetx || lastgridy != offsety || drawmapcenter != lastdrawmapcenter) { - // Create a plotter - gridplotter.Begin(graphics); gridplotter.Clear(); if(General.Settings.RenderGrid) //mxd @@ -816,10 +812,10 @@ namespace CodeImp.DoomBuilder.Rendering Vector2D tl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary).GetTransformed(translatex, translatey, scale, -scale); Vector2D rb = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary).GetTransformed(translatex, translatey, scale, -scale); PixelColor g = General.Colors.Grid64; - gridplotter.DrawGridLineH((int)tl.y, (int)tl.x, (int)rb.x, ref g); - gridplotter.DrawGridLineH((int)rb.y, (int)tl.x, (int)rb.x, ref g); - gridplotter.DrawGridLineV((int)tl.x, (int)tl.y, (int)rb.y, ref g); - gridplotter.DrawGridLineV((int)rb.x, (int)tl.y, (int)rb.y, ref g); + gridplotter.DrawGridLineH((int)tl.y, (int)tl.x, (int)rb.x, g); + gridplotter.DrawGridLineH((int)rb.y, (int)tl.x, (int)rb.x, g); + gridplotter.DrawGridLineV((int)tl.x, (int)tl.y, (int)rb.y, g); + gridplotter.DrawGridLineV((int)rb.x, (int)tl.y, (int)rb.y, g); } //mxd. Render center of map @@ -829,8 +825,8 @@ namespace CodeImp.DoomBuilder.Rendering int cx = (int)center.x; int cy = (int)center.y; PixelColor c = General.Colors.Highlight; - gridplotter.DrawLineSolid(cx, cy + MAP_CENTER_SIZE, cx, cy - MAP_CENTER_SIZE, ref c); - gridplotter.DrawLineSolid(cx - MAP_CENTER_SIZE, cy, cx + MAP_CENTER_SIZE, cy, ref c); + gridplotter.DrawLineSolid(cx, cy + MAP_CENTER_SIZE, cx, cy - MAP_CENTER_SIZE, c); + gridplotter.DrawLineSolid(cx - MAP_CENTER_SIZE, cy, cx + MAP_CENTER_SIZE, cy, c); } // Done @@ -911,19 +907,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, ref c, mask); + gridplotter.DrawLineSolid((int)xminplotline.v1.x, (int)xminplotline.v1.y, (int)xminplotline.v2.x, (int)xminplotline.v2.y, c, mask); } if (xmaxintersect) { - gridplotter.DrawLineSolid((int)xmaxplotline.v1.x, (int)xmaxplotline.v1.y, (int)xmaxplotline.v2.x, (int)xmaxplotline.v2.y, ref c, mask); + gridplotter.DrawLineSolid((int)xmaxplotline.v1.x, (int)xmaxplotline.v1.y, (int)xmaxplotline.v2.x, (int)xmaxplotline.v2.y, c, mask); } if (yminintersect) { - gridplotter.DrawLineSolid((int)yminplotline.v1.x, (int)yminplotline.v1.y, (int)yminplotline.v2.x, (int)yminplotline.v2.y, ref c, mask); + gridplotter.DrawLineSolid((int)yminplotline.v1.x, (int)yminplotline.v1.y, (int)yminplotline.v2.x, (int)yminplotline.v2.y, c, mask); } if (ymaxintersect) { - gridplotter.DrawLineSolid((int)ymaxplotline.v1.x, (int)ymaxplotline.v1.y, (int)ymaxplotline.v2.x, (int)ymaxplotline.v2.y, ref c, mask); + gridplotter.DrawLineSolid((int)ymaxplotline.v1.x, (int)ymaxplotline.v1.y, (int)ymaxplotline.v2.x, (int)ymaxplotline.v2.y, c, mask); } num++; @@ -968,7 +964,7 @@ namespace CodeImp.DoomBuilder.Rendering pos = pos.GetTransformed(translatex, translatey, scale, -scale); // Note: I'm not using Math.Ceiling in this case, because that doesn't work right. - gridplotter.DrawGridLineH((int)pos.y, (int)Math.Round(from + 0.49999f), (int)Math.Round(to + 0.49999f), ref c); + gridplotter.DrawGridLineH((int)pos.y, (int)Math.Round(from + 0.49999f), (int)Math.Round(to + 0.49999f), c); } // Draw all vertical grid lines @@ -987,7 +983,7 @@ namespace CodeImp.DoomBuilder.Rendering pos = pos.GetTransformed(translatex, translatey, scale, -scale); // Note: I'm not using Math.Ceiling in this case, because that doesn't work right. - gridplotter.DrawGridLineV((int)pos.x, (int)Math.Round(from + 0.49999f), (int)Math.Round(to + 0.49999f), ref c); + gridplotter.DrawGridLineV((int)pos.x, (int)Math.Round(from + 0.49999f), (int)Math.Round(to + 0.49999f), c); } } @@ -2042,7 +2038,7 @@ namespace CodeImp.DoomBuilder.Rendering if((v2 - v1).GetLengthSq() < linenormalsize * lengthscaler) return; // Draw line - plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c); + plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, c); } // This renders a single linedef @@ -2058,9 +2054,9 @@ namespace CodeImp.DoomBuilder.Rendering // Draw line. mxd: added 3d-floor indication if(l.ExtraFloorFlag && General.Settings.GZMarkExtraFloors) - plotter.DrawLine3DFloor(v1, v2, ref c, General.Colors.ThreeDFloor); + plotter.DrawLine3DFloor(v1, v2, c, General.Colors.ThreeDFloor); else - plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c); + plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, c); //mxd. Should we bother? if(lengthsq < minlinenormallength) return; //mxd @@ -2072,7 +2068,7 @@ namespace CodeImp.DoomBuilder.Rendering // Draw normal indicator plotter.DrawLineSolid((int)(v1.x + mx), (int)(v1.y + my), (int)((v1.x + mx) - (my * l.LengthInv) * linenormalsize), - (int)((v1.y + my) + (mx * l.LengthInv) * linenormalsize), ref c); + (int)((v1.y + my) + (mx * l.LengthInv) * linenormalsize), c); } // This renders a set of linedefs @@ -2094,9 +2090,9 @@ namespace CodeImp.DoomBuilder.Rendering // Draw line. mxd: added 3d-floor indication if(l.ExtraFloorFlag && General.Settings.GZMarkExtraFloors) - plotter.DrawLine3DFloor(v1, v2, ref c, General.Colors.ThreeDFloor); + plotter.DrawLine3DFloor(v1, v2, c, General.Colors.ThreeDFloor); else - plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c); + plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, c); //mxd. Should we bother? if(lengthsq < minlinenormallength) continue; //mxd @@ -2108,7 +2104,7 @@ namespace CodeImp.DoomBuilder.Rendering // Draw normal indicator plotter.DrawLineSolid((int)(v1.x + mx), (int)(v1.y + my), (int)((v1.x + mx) - (my * l.LengthInv) * linenormalsize), - (int)((v1.y + my) + (mx * l.LengthInv) * linenormalsize), ref c); + (int)((v1.y + my) + (mx * l.LengthInv) * linenormalsize), c); } } @@ -2119,7 +2115,7 @@ namespace CodeImp.DoomBuilder.Rendering Vector2D nv = v.Position.GetTransformed(translatex, translatey, scale, -scale); // Draw pixel here - plotter.DrawVertexSolid((int)nv.x, (int)nv.y, vertexsize, ref General.Colors.Colors[colorindex], ref General.Colors.BrightColors[colorindex], ref General.Colors.DarkColors[colorindex]); + plotter.DrawVertexSolid((int)nv.x, (int)nv.y, vertexsize, General.Colors.Colors[colorindex], General.Colors.BrightColors[colorindex], General.Colors.DarkColors[colorindex]); } // This renders a single vertex at specified coordinates @@ -2129,7 +2125,7 @@ namespace CodeImp.DoomBuilder.Rendering Vector2D nv = v.GetTransformed(translatex, translatey, scale, -scale); // Draw pixel here - plotter.DrawVertexSolid((int)nv.x, (int)nv.y, vertexsize, ref General.Colors.Colors[colorindex], ref General.Colors.BrightColors[colorindex], ref General.Colors.DarkColors[colorindex]); + plotter.DrawVertexSolid((int)nv.x, (int)nv.y, vertexsize, General.Colors.Colors[colorindex], General.Colors.BrightColors[colorindex], General.Colors.DarkColors[colorindex]); } // This renders a set of vertices