2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#region ================== Copyright (c) 2007 Pascal vd Heiden
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
|
|
|
|
* This program is released under GNU General Public License
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region ================== Namespaces
|
|
|
|
|
|
|
|
using System;
|
2019-08-18 06:07:28 +00:00
|
|
|
using System.Collections.Generic;
|
2013-05-20 10:43:34 +00:00
|
|
|
using CodeImp.DoomBuilder.Geometry;
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
namespace CodeImp.DoomBuilder.Rendering
|
|
|
|
{
|
2019-08-18 05:43:46 +00:00
|
|
|
internal unsafe sealed class Plotter : IDisposable
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2019-08-18 05:43:46 +00:00
|
|
|
public Plotter(int width, int height)
|
|
|
|
{
|
|
|
|
this.Texture = new Texture(width, height);
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2019-08-18 05:43:46 +00:00
|
|
|
~Plotter()
|
|
|
|
{
|
|
|
|
Dispose();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2019-08-18 05:43:46 +00:00
|
|
|
public int Width { get { return Texture.Width; } }
|
|
|
|
public int Height { get { return Texture.Height; } }
|
|
|
|
public Texture Texture { get; set; }
|
2010-08-14 09:30:54 +00:00
|
|
|
|
2019-08-18 06:07:28 +00:00
|
|
|
public void DrawContents(RenderDevice graphics)
|
2019-08-18 05:43:46 +00:00
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
pixels = (PixelColor*)graphics.LockTexture(Texture).ToPointer();
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2019-08-18 06:07:28 +00:00
|
|
|
if (clear)
|
|
|
|
General.ZeroMemory(new IntPtr(pixels), Width * Height * sizeof(PixelColor));
|
|
|
|
|
|
|
|
foreach (var command in commands)
|
|
|
|
{
|
|
|
|
command();
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
2019-08-18 06:11:09 +00:00
|
|
|
commands.Clear();
|
|
|
|
clear = false;
|
|
|
|
|
2019-08-18 05:43:46 +00:00
|
|
|
graphics.UnlockTexture(Texture);
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
|
|
|
|
// This clears all pixels black
|
|
|
|
public void Clear()
|
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
clear = true;
|
|
|
|
commands.Clear();
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This draws a pixel normally
|
2019-08-18 06:07:28 +00:00
|
|
|
public void DrawVertexSolid(int x, int y, int size, PixelColor c, PixelColor l, PixelColor d)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
});
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This draws a dotted grid line horizontally
|
2019-08-18 06:07:28 +00:00
|
|
|
public void DrawGridLineH(int y, int x1, int x2, PixelColor c)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
});
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This draws a dotted grid line vertically
|
2019-08-18 06:07:28 +00:00
|
|
|
public void DrawGridLineV(int x, int y1, int y2, PixelColor c)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
});
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// This draws a line normally
|
|
|
|
// See: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
|
2019-08-18 06:07:28 +00:00
|
|
|
public void DrawLineSolid(int x1, int y1, int x2, int y2, PixelColor c, uint mask = 0xffffffff)
|
2009-04-19 18:07:22 +00:00
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
commands.Add(() =>
|
|
|
|
{
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
2019-08-18 06:07:28 +00:00
|
|
|
public void DrawLine3DFloor(Vector2D start, Vector2D end, PixelColor c, PixelColor c2)
|
2014-12-03 23:15:26 +00:00
|
|
|
{
|
2013-05-20 10:43:34 +00:00
|
|
|
Vector2D delta = end - start;
|
|
|
|
float length = delta.GetLength();
|
|
|
|
|
2014-12-03 23:15:26 +00:00
|
|
|
if(length < DASH_INTERVAL * 2)
|
|
|
|
{
|
2019-08-18 06:07:28 +00:00
|
|
|
DrawLineSolid((int)start.x, (int)start.y, (int)end.x, (int)end.y, c2);
|
2014-12-03 23:15:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-05-20 10:43:34 +00:00
|
|
|
float d1 = DASH_INTERVAL / length;
|
|
|
|
float d2 = 1.0f - d1;
|
|
|
|
|
|
|
|
Vector2D p1 = CurveTools.GetPointOnLine(start, end, d1);
|
|
|
|
Vector2D p2 = CurveTools.GetPointOnLine(start, end, d2);
|
|
|
|
|
2019-08-18 06:07:28 +00:00
|
|
|
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);
|
2013-05-20 10:43:34 +00:00
|
|
|
}
|
|
|
|
}
|
2019-08-18 06:07:28 +00:00
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
{
|
|
|
|
if (Texture != null) Texture.Dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
PixelColor* pixels;
|
|
|
|
bool clear = true;
|
|
|
|
List<Action> commands = new List<Action>();
|
|
|
|
|
|
|
|
const int DASH_INTERVAL = 16;
|
|
|
|
}
|
2009-04-19 18:07:22 +00:00
|
|
|
}
|