- Delay plotter drawing until DrawContents is called

This commit is contained in:
Magnus Norddahl 2019-08-18 08:07:28 +02:00
parent 3142437444
commit b51270fdfa
2 changed files with 242 additions and 249 deletions

View file

@ -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<Action> commands = new List<Action>();
const int DASH_INTERVAL = 16;
}
}

View file

@ -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