mirror of
https://git.do.srb2.org/STJr/UltimateZoneBuilder.git
synced 2024-11-24 21:01:33 +00:00
436 lines
10 KiB
C#
436 lines
10 KiB
C#
|
|
#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;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Drawing;
|
|
using System.ComponentModel;
|
|
using CodeImp.DoomBuilder.Map;
|
|
using SlimDX.Direct3D;
|
|
using SlimDX.Direct3D9;
|
|
using SlimDX;
|
|
using CodeImp.DoomBuilder.Geometry;
|
|
using System.Drawing.Imaging;
|
|
|
|
#endregion
|
|
|
|
namespace CodeImp.DoomBuilder.Rendering
|
|
{
|
|
internal unsafe class Renderer2D : IDisposable
|
|
{
|
|
#region ================== Constants
|
|
|
|
#endregion
|
|
|
|
#region ================== Variables
|
|
|
|
// Owner
|
|
private D3DGraphics graphics;
|
|
|
|
// Rendering memory
|
|
private Bitmap image;
|
|
private BitmapData pixeldata;
|
|
private PixelColor* pixels;
|
|
private int width;
|
|
private int height;
|
|
|
|
// View settings (world coordinates)
|
|
private float scale;
|
|
private float offsetx;
|
|
private float offsety;
|
|
|
|
// Disposing
|
|
private bool isdisposed = false;
|
|
|
|
#endregion
|
|
|
|
#region ================== Properties
|
|
|
|
public float OffsetX { get { return offsetx; } }
|
|
public float OffsetY { get { return offsety; } }
|
|
public float Scale { get { return scale; } }
|
|
public bool IsDisposed { get { return isdisposed; } }
|
|
|
|
#endregion
|
|
|
|
#region ================== Constructor / Disposer
|
|
|
|
// Constructor
|
|
public Renderer2D(D3DGraphics graphics)
|
|
{
|
|
// Initialize
|
|
this.graphics = graphics;
|
|
|
|
// Create image memory
|
|
CreateMemory();
|
|
|
|
// We have no destructor
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
// Diposer
|
|
public void Dispose()
|
|
{
|
|
// Not already disposed?
|
|
if(!isdisposed)
|
|
{
|
|
// Clean up
|
|
graphics.RenderTarget.BackgroundImage = null;
|
|
if(image != null) image.Dispose();
|
|
pixels = null;
|
|
|
|
// Done
|
|
isdisposed = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Control
|
|
|
|
// This is called resets when the device is reset
|
|
// (when resized or display adapter was changed)
|
|
public void Reset()
|
|
{
|
|
// Re-create image memory
|
|
CreateMemory();
|
|
}
|
|
|
|
// Allocates new image memory to render on
|
|
public void CreateMemory()
|
|
{
|
|
// Get new width and height
|
|
width = graphics.RenderTarget.ClientSize.Width;
|
|
height = graphics.RenderTarget.ClientSize.Height;
|
|
|
|
// Trash old image
|
|
graphics.RenderTarget.BackgroundImage = null;
|
|
if(image != null) image.Dispose();
|
|
|
|
// Allocate memory
|
|
image = new Bitmap(width, height, PixelFormat.Format32bppArgb);
|
|
graphics.RenderTarget.BackgroundImage = image;
|
|
}
|
|
|
|
// This begins a drawing session
|
|
public unsafe bool StartRendering()
|
|
{
|
|
// Lock memory
|
|
pixeldata = image.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
|
|
pixels = (PixelColor*)pixeldata.Scan0.ToPointer();
|
|
|
|
// Erase image
|
|
General.ZeroMemory(pixeldata.Scan0, width * height * 4);
|
|
|
|
// Ready for rendering
|
|
return true;
|
|
}
|
|
|
|
// This ends a drawing session
|
|
public void FinishRendering()
|
|
{
|
|
// Unlock memory
|
|
image.UnlockBits(pixeldata);
|
|
|
|
// Refresh
|
|
graphics.RenderTarget.Invalidate();
|
|
}
|
|
|
|
// This changes view position
|
|
public void PositionView(float x, float y)
|
|
{
|
|
// Change position in world coordinates
|
|
offsetx = x;
|
|
offsety = y;
|
|
}
|
|
|
|
// This changes zoom
|
|
public void ScaleView(float scale)
|
|
{
|
|
// Change zoom scale
|
|
this.scale = scale;
|
|
|
|
// Recalculate linedefs (normal lengths must be adjusted)
|
|
foreach(Linedef l in General.Map.Data.Linedefs) l.NeedUpdate();
|
|
}
|
|
|
|
// This unprojects mouse coordinates into map coordinates
|
|
public Vector2D GetMapCoordinates(Vector2D mousepos)
|
|
{
|
|
Vector3 mp, res;
|
|
|
|
// FIXME!
|
|
|
|
// Get mouse position in Vector3
|
|
//mp = new Vector3(mousepos.x, mousepos.y, 1f);
|
|
|
|
// Unproject
|
|
//res = mp.Unproject(graphics.Viewport, matproj, matview, matworld);
|
|
|
|
// Return result
|
|
//return new Vector2D(res.X, res.Y);
|
|
return new Vector2D();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Pixel Rendering
|
|
|
|
// This draws a pixel normally
|
|
private void DrawPixelSolid(int x, int y, PixelColor c)
|
|
{
|
|
// Draw pixel when within range
|
|
if((x >= 0) && (x < width) && (y >= 0) && (y < height))
|
|
pixels[y * width + x] = c;
|
|
}
|
|
|
|
// This draws a pixel alpha blended
|
|
private void DrawPixelAlpha(int x, int y, PixelColor c)
|
|
{
|
|
// Draw only when within range
|
|
if((x >= 0) && (x < width) && (y >= 0) && (y < height))
|
|
{
|
|
// Get the target pixel
|
|
PixelColor* p = pixels + (y * width + x);
|
|
|
|
// Not drawn on target yet?
|
|
if(*(int*)p == 0)
|
|
{
|
|
// Simply apply color to pixel
|
|
*p = c;
|
|
}
|
|
else
|
|
{
|
|
// Blend with pixel
|
|
if((int)p->a + (int)c.a > 255) p->a = 255; else p->a += c.a;
|
|
p->r = (byte)((float)p->r * (1f - (float)c.a) + (float)c.r * (float)c.a);
|
|
p->g = (byte)((float)p->g * (1f - (float)c.a) + (float)c.g * (float)c.a);
|
|
p->b = (byte)((float)p->b * (1f - (float)c.a) + (float)c.b * (float)c.a);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This draws a line alpha blended
|
|
// See: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
|
|
private void DrawLineAlpha(int x1, int y1, int x2, int y2, PixelColor c)
|
|
{
|
|
int i;
|
|
|
|
// 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;
|
|
|
|
// Draw first pixel
|
|
DrawPixelAlpha(px, py, c);
|
|
|
|
// Check if the line is more horizontal than vertical
|
|
if(dxabs >= dyabs)
|
|
{
|
|
for(i = 0; i < dxabs; i++)
|
|
{
|
|
y += dyabs;
|
|
if(y >= dxabs)
|
|
{
|
|
y -= dxabs;
|
|
py += sdy;
|
|
}
|
|
px += sdx;
|
|
|
|
// Draw pixel
|
|
DrawPixelAlpha(px, py, c);
|
|
}
|
|
}
|
|
// Else the line is more vertical than horizontal
|
|
else
|
|
{
|
|
for(i = 0; i < dyabs; i++)
|
|
{
|
|
x += dxabs;
|
|
if(x >= dyabs)
|
|
{
|
|
x -= dyabs;
|
|
px += sdx;
|
|
}
|
|
py += sdy;
|
|
|
|
// Draw pixel
|
|
DrawPixelAlpha(px, py, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This draws a line normally
|
|
// See: http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
|
|
private void DrawLineSolid(int x1, int y1, int x2, int y2, PixelColor c)
|
|
{
|
|
int i;
|
|
|
|
// 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;
|
|
|
|
// Draw first pixel
|
|
DrawPixelSolid(px, py, c);
|
|
|
|
// Check if the line is more horizontal than vertical
|
|
if(dxabs >= dyabs)
|
|
{
|
|
for(i = 0; i < dxabs; i++)
|
|
{
|
|
y += dyabs;
|
|
if(y >= dxabs)
|
|
{
|
|
y -= dxabs;
|
|
py += sdy;
|
|
}
|
|
px += sdx;
|
|
|
|
// Draw pixel
|
|
DrawPixelSolid(px, py, c);
|
|
}
|
|
}
|
|
// Else the line is more vertical than horizontal
|
|
else
|
|
{
|
|
for(i = 0; i < dyabs; i++)
|
|
{
|
|
x += dxabs;
|
|
if(x >= dyabs)
|
|
{
|
|
x -= dyabs;
|
|
px += sdx;
|
|
}
|
|
py += sdy;
|
|
|
|
// Draw pixel
|
|
DrawPixelSolid(px, py, c);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ================== Map Rendering
|
|
|
|
// This renders a set of Linedefs
|
|
public unsafe void RenderLinedefs(MapSet map, ICollection<Linedef> linedefs)
|
|
{
|
|
Vector2D voffset = new Vector2D(-offsetx + (width * 0.5f) / scale, -offsety - (height * 0.5f) / scale);
|
|
Vector2D vscale = new Vector2D(scale, -scale);
|
|
PixelColor c = PixelColor.FromColor(Color.SkyBlue);
|
|
Vector2D v1, v2;
|
|
|
|
// Go for all linedefs
|
|
foreach(Linedef l in linedefs)
|
|
{
|
|
// Transform vertex coordinates
|
|
v1 = l.Start.Position.GetTransformed(voffset, vscale);
|
|
v2 = l.End.Position.GetTransformed(voffset, vscale);
|
|
|
|
// Draw line
|
|
DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, c);
|
|
}
|
|
}
|
|
|
|
// This renders a set of Linedefs
|
|
public void RenderVertices(MapSet map, ICollection<Vertex> vertices)
|
|
{
|
|
Vector2D nv;
|
|
Vector2D voffset = new Vector2D(-offsetx + (width * 0.5f) / scale, -offsety - (height * 0.5f) / scale);
|
|
Vector2D vscale = new Vector2D(scale, -scale);
|
|
PixelColor c = PixelColor.FromInt(-1);
|
|
int x, y;
|
|
|
|
// Go for all vertices
|
|
foreach(Vertex v in vertices)
|
|
{
|
|
// Transform vertex coordinates
|
|
nv = v.Position.GetTransformed(voffset, vscale);
|
|
x = (int)nv.x;
|
|
y = (int)nv.y;
|
|
|
|
// Draw pixel here
|
|
DrawPixelSolid(x, y, c);
|
|
DrawPixelSolid(x + 1, y, c);
|
|
DrawPixelSolid(x, y + 1, c);
|
|
DrawPixelSolid(x - 1, y, c);
|
|
DrawPixelSolid(x, y - 1, c);
|
|
DrawPixelSolid(x + 1, y - 1, c);
|
|
DrawPixelSolid(x + 1, y + 1, c);
|
|
DrawPixelSolid(x - 1, y - 1, c);
|
|
DrawPixelSolid(x - 1, y + 1, c);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|