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; } } } } }