ClassiCube/SoftwareEngine/Engine/SoftwareEngine.DrawingLine.cs

178 lines
4.8 KiB
C#

using System;
using OpenTK;
namespace SoftwareRasterizer.Engine {
public unsafe partial class SoftwareEngine {
public void Line_DrawVertexLine( Vector3 vertex1, Vector3 vertex2 ) {
Vector3 p1, p2;
Project( ref vertex1, out p1 );
Project( ref vertex2, out p2 );
DrawLine( ref p1, ref p2 );
}
public void Line_DrawIndexedTriangles( Vector3[] vertices, ushort[] indices ) {
for( int i = 0; i < indices.Length; i += 3 ) {
Vector3 vertex1 = vertices[indices[i + 0]];
Vector3 vertex2 = vertices[indices[i + 1]];
Vector3 vertex3 = vertices[indices[i + 2]];
Vector3 p1, p2, p3;
Project( ref vertex1, out p1 );
Project( ref vertex2, out p2 );
Project( ref vertex3, out p3 );
DrawLine( ref p1, ref p2 );
DrawLine( ref p2, ref p3 );
DrawLine( ref p3, ref p1 );
}
}
const int INSIDE = 0; // 0000
const int LEFT = 1; // 0001
const int RIGHT = 2; // 0010
const int BOTTOM = 4; // 0100
const int TOP = 8; // 1000
// Compute the bit code for a point (x, y) using the clip rectangle
// bounded diagonally by (xmin, ymin), and (xmax, ymax)
int ComputeOutCode( float x, float y ) {
int code = INSIDE;
if( x < 0 ) {
code |= LEFT;
} else if( x > xMax ) {
code |= RIGHT;
}
if( y < 0 ) {
code |= BOTTOM;
} else if ( y > yMax ) {
code |= TOP;
}
return code;
}
void DrawLine( ref Vector3 p1, ref Vector3 p2 ) {
float x0 = p1.X;
float y0 = p1.Y;
float x1 = p2.X;
float y1 = p2.Y;
int outcode0 = ComputeOutCode( x0, y0 );
int outcode1 = ComputeOutCode( x1, y1 );
while( true ) {
if( ( outcode0 | outcode1 ) == 0 ) {
myLine( (int)x0, (int)y0, (int)x1, (int)y1 );
return;
} else if( ( outcode0 & outcode1 ) != 0 ) {
return;
} else {
// failed both tests, so calculate the line segment to clip
// from an outside point to an intersection with clip edge
float x = 0, y = 0;
int outcodeOut = outcode0 != 0 ? outcode0 : outcode1;
// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
if( ( outcodeOut & TOP ) != 0 ) {
x = x0 + ( x1 - x0 ) * ( yMax - y0 ) / ( y1 - y0 );
y = yMax;
} else if( ( outcodeOut & BOTTOM ) != 0 ) {
x = x0 + ( x1 - x0 ) * ( 0 - y0 ) / ( y1 - y0 );
y = 0;
} else if( ( outcodeOut & RIGHT ) != 0 ) {
y = y0 + ( y1 - y0 ) * ( xMax - x0 ) / ( x1 - x0 );
x = xMax;
} else if( ( outcodeOut & LEFT ) != 0 ) {
y = y0 + ( y1 - y0 ) * ( 0 - x0 ) / ( x1 - x0 );
x = 0;
}
if( outcodeOut == outcode0 ) {
x0 = x;
y0 = y;
outcode0 = ComputeOutCode( x0, y0 );
} else {
x1 = x;
y1 = y;
outcode1 = ComputeOutCode( x1, y1 );
}
}
}
}
// Freely useable in non-commercial applications as long as
// credits to Po-Han Lin and link to http://www.edepot.com is
// provided in source code and can been seen in compiled executable.
// Commercial applications please inquire about licensing the algorithms.
// THE EXTREMELY FAST LINE ALGORITHM Variation D (Addition Fixed Point)
void myLine( int x1, int y1, int x2, int y2 ) {
bool yLonger = false;
int incrementVal;
int shortLen = y2 - y1;
int longLen= x2 - x1;
if( Math.Abs( shortLen ) > Math.Abs( longLen ) ) {
int swap = shortLen;
shortLen= longLen;
longLen = swap;
yLonger = true;
}
int endVal = longLen;
if( longLen < 0 ) {
incrementVal = -1;
longLen = -longLen;
} else {
incrementVal = 1;
}
int decInc = longLen == 0 ? 0 : ( shortLen << 16 ) / longLen;
int j = 0;
if( yLonger ) {
for( int i = 0; i != endVal; i += incrementVal ) {
int xx = x1 + ( j >> 16 );
int yy = y1 + i;
if( xx >= 0 && yy >= 0 && xx < width && yy < height ) {
PutPixel( xx, yy, 0, FastColour.Red );
}
j += decInc;
}
} else {
for( int i = 0; i != endVal; i += incrementVal ) {
int xx = x1 + i;
int yy = y1 + ( j >> 16 );
if( xx >= 0 && yy >= 0 && xx < width && yy < height ) {
PutPixel( xx, yy, 0, FastColour.Red );
}
j += decInc;
}
}
}
void DrawLin32e( int x0, int y0, int x1, int y1 ) {
int dx = Math.Abs( x1 - x0 );
int dy = Math.Abs( y1 - y0 );
int dirX = ( x0 < x1 ) ? 1 : -1;
int dirY = ( y0 < y1 ) ? 1 : -1;
int err = dx - dy;
while( true ) {
if( x0 >= 0 && y0 >= 0 && x0 < width && y0 < height ) {
PutPixel( x0, y0, 0, FastColour.Red );
}
if ( ( x0 == x1 ) && ( y0 == y1 ) ) break;
int e2 = 2 * err;
if ( e2 > -dy ) {
err -= dy;
x0 += dirX;
}
if( e2 < dx ) {
err += dx;
y0 += dirY;
}
}
}
}
}