public void DrawLine( ref PixelBuffer pb, ref RasterLine line, bool useFixed ) { if( useFixed == true ) throw new NotImplementedException( "fixed math not implemented" ); int x0 = ( int )( line.Vertices[ line.v0 ].PX + 0.5f ); int y0 = ( int )( line.Vertices[ line.v0 ].PY + 0.5f ); int x1 = ( int )( line.Vertices[ line.v1 ].PX + 0.5f ); int y1 = ( int )( line.Vertices[ line.v1 ].PY + 0.5f ); if( ClipLine( ref pb, ref x0, ref y0, ref x1, ref y1 ) == false ) return; if( ( line.VertexFormat & RasterVertexFormat.Color ) == RasterVertexFormat.Color ) { #if false this.DrawLineVaryColor( ref pb, ref line ); #else line.Color[ 0 ] = line.Vertices[ line.v0 ].R; line.Color[ 1 ] = line.Vertices[ line.v0 ].G; line.Color[ 2 ] = line.Vertices[ line.v0 ].B; line.Color[ 3 ] = line.Vertices[ line.v0 ].A; this.DrawLineSolidColor( ref pb, ref line, x0, y0, x1, y1 ); #endif } else { this.DrawLineSolidColor( ref pb, ref line, x0, y0, x1, y1 ); } }
private void DrawLineVaryColor( ref PixelBuffer pb, ref RasterLine line, int x0, int y0, int x1, int y1 ) { }
private void DrawLineSolidColor( ref PixelBuffer pb, ref RasterLine line, int x0, int y0, int x1, int y1 ) { byte[] color = new byte[ 4 ]{ ( byte )( line.Color[ 0 ] * 255.0f ), ( byte )( line.Color[ 1 ] * 255.0f ), ( byte )( line.Color[ 2 ] * 255.0f ), ( byte )( line.Color[ 3 ] * 255.0f ), }; // pre-compute first pixel address in video buffer based on 16bit data int pbOffset = pb.Offset + ( y0 * pb.Stride ) + ( x0 * pb.BytesPerPixel ); // compute horizontal and vertical deltas int dx = x1 - x0; // diff in x's int dy = y1 - y0; // diff in y's // test which direction the line is going in i.e. slope angle int x_inc; // step along x if( dx >= 0 ) { // moving right x_inc = pb.BytesPerPixel; } else { // moving left x_inc = -pb.BytesPerPixel; dx = -dx; // need absolute value } // test y component of slope int y_inc; // step along y if( dy >= 0 ) { // moving down y_inc = pb.Stride; } else { // moving up y_inc = -pb.Stride; dy = -dy; // need absolute value } // compute (dx,dy) * 2 int dx2 = dx * 2; int dy2 = dy * 2; // now based on which delta is greater we can draw the line if( dx > dy ) { int error = dy2 - dx; // the discriminant i.e. error i.e. decision variable // draw the line if( pb.BytesPerPixel == 3 ) { for( int index = 0; index <= dx; index++ ) { // set the pixel pb.Buffer[ pbOffset ] = color[ 0 ]; pb.Buffer[ pbOffset + 1 ] = color[ 1 ]; pb.Buffer[ pbOffset + 2 ] = color[ 2 ]; // test if error has overflowed if( error >= 0 ) { error -= dx2; // move to next line pbOffset += y_inc; } // adjust the error term error += dy2; // move to the next pixel pbOffset += x_inc; } } else { for( int index = 0; index <= dx; index++ ) { pb.Buffer[ pbOffset ] = color[ 0 ]; pb.Buffer[ pbOffset + 1 ] = color[ 1 ]; pb.Buffer[ pbOffset + 2 ] = color[ 2 ]; pb.Buffer[ pbOffset + 3 ] = color[ 3 ]; if( error >= 0 ) { error -= dx2; pbOffset += y_inc; } error += dy2; pbOffset += x_inc; } } } else { int error = dx2 - dy; // the discriminant i.e. error i.e. decision variable // draw the line if( pb.BytesPerPixel == 3 ) { for( int index = 0; index <= dy; index++ ) { // set the pixel pb.Buffer[ pbOffset ] = color[ 0 ]; pb.Buffer[ pbOffset + 1 ] = color[ 1 ]; pb.Buffer[ pbOffset + 2 ] = color[ 2 ]; // test if error overflowed if( error >= 0 ) { error -= dy2; // move to next line pbOffset += x_inc; } // adjust the error term error += dx2; // move to the next pixel pbOffset += y_inc; } } else { for( int index = 0; index <= dy; index++ ) { pb.Buffer[ pbOffset ] = color[ 0 ]; pb.Buffer[ pbOffset + 1 ] = color[ 1 ]; pb.Buffer[ pbOffset + 2 ] = color[ 2 ]; pb.Buffer[ pbOffset + 3 ] = color[ 3 ]; if( error >= 0 ) { error -= dy2; pbOffset += x_inc; } error += dx2; pbOffset += y_inc; } } } }
public void glDrawElements( int mode, int count, ushort[] indices, int offset ) { if( Ptr_VertexEnabled == false ) return; float viewportWidthHalf = Viewport_Width / 2.0f; float viewportHeightHalf = Viewport_Height / 2.0f; float viewportAspectRatio = Viewport_Width / ( float )Viewport_Height; Matrix projectionMatrix = M_Proj[ M_ProjIndex ]; bool projectionIsAffine = projectionMatrix.IsAffine; Matrix modelViewMatrix = M_ModelView[ M_ModelViewIndex ]; bool modelViewIsIdentity = modelViewMatrix.IsIdentity; bool modelViewIsAffine = modelViewMatrix.IsAffine; Matrix textureMatrix = M_Texture[ M_TextureIndex ]; bool textureIsIdentity = textureMatrix.IsIdentity; bool textureIsAffine = textureMatrix.IsAffine; Matrix modelProjMatrix; Matrix.Multiply( ref modelViewMatrix, ref projectionMatrix, out modelProjMatrix ); bool modelProjMatrixIsAffine = modelProjMatrix.IsAffine; Matrix finalProjectionMatrix; Matrix.Multiply( ref projectionMatrix, ref M_Viewport, out finalProjectionMatrix ); RasterVertexFormat vertexFormat = RasterVertexFormat.Position | RasterVertexFormat.Normal; if( ( State_ShadeModel == GL_SMOOTH ) && ( Ptr_ColorEnabled == true ) ) vertexFormat |= RasterVertexFormat.Color; if( ( State_Texture[ 0 ] != null ) && ( Ptr_TexCoordEnabled == true ) ) // TODO: something with tex coord state? vertexFormat |= RasterVertexFormat.Texture; RasterPolygon polygon = new RasterPolygon(); polygon.VertexFormat = vertexFormat; polygon.Vertices = _vertices; polygon.Color = ( float[] )State_Color.Clone(); polygon.PerspectiveTexturing = ( State_PerspectiveCorrection == GL_NICEST ); polygon.Textures = new TextureObject[ RasterPolygon.MaximumTextureStages ]{ State_Texture[ 0 ], State_Texture[ 1 ] }; #if DRAW_LINE RasterLine line = new RasterLine(); line.VertexFormat = polygon.VertexFormat; line.Vertices = polygon.Vertices; line.Color = ( float[] )State_Color.Clone(); #endif // Build RasterVertex buffer from input // TODO: maybe have different loops for different modes - depends on if this is a bottleneck with all the compares/etc for( int n = offset, v = 0; n < offset + count; n++, v++ ) { int index = indices[ n ]; { int idx = Ptr_Vertex.Offset + ( index * ( Ptr_Vertex.Stride + Ptr_Vertex.Size ) ); _vertices[ v ].W = 1.0f; _vertices[ v ].X = Ptr_Vertex.Floats[ idx ]; _vertices[ v ].Y = Ptr_Vertex.Floats[ idx + 1 ]; // TODO: make this faster - eliminate switch if( Ptr_Vertex.Size >= 3 ) { _vertices[ v ].Z = Ptr_Vertex.Floats[ idx + 2 ]; if( Ptr_Vertex.Size == 4 ) _vertices[ v ].W = Ptr_Vertex.Floats[ idx + 3 ]; } } if( Ptr_NormalEnabled == true ) { int idx = Ptr_Normal.Offset + ( index * ( Ptr_Normal.Stride + Ptr_Normal.Size ) ); _vertices[ v ].NX = Ptr_Normal.Floats[ idx ]; _vertices[ v ].NY = Ptr_Normal.Floats[ idx + 1 ]; _vertices[ v ].NZ = Ptr_Normal.Floats[ idx + 2 ]; } else { _vertices[ v ].NX = State_Normal.X; _vertices[ v ].NY = State_Normal.Y; _vertices[ v ].NZ = State_Normal.Z; } if( Ptr_ColorEnabled == true ) { int idx = Ptr_Color.Offset + ( index * ( Ptr_Color.Stride + Ptr_Color.Size ) ); _vertices[ v ].R = Ptr_Color.Floats[ idx ]; _vertices[ v ].G = Ptr_Color.Floats[ idx + 1 ]; _vertices[ v ].B = Ptr_Color.Floats[ idx + 2 ]; _vertices[ v ].A = Ptr_Color.Floats[ idx + 3 ]; } if( Ptr_TexCoordEnabled == true ) { int idx = Ptr_TexCoord[ 0 ].Offset + ( index * ( Ptr_TexCoord[ 0 ].Stride + Ptr_TexCoord[ 0 ].Size ) ); _vertices[ v ].S = Ptr_TexCoord[ 0 ].Floats[ idx ]; _vertices[ v ].T = Ptr_TexCoord[ 0 ].Floats[ idx + 1 ]; #if false if( Ptr_TexCoord[ 0 ].Size >= 3 ) { _vertices[ v ].R = Ptr_TexCoord[ 0 ].Floats[ idx + 2 ]; if( Ptr_TexCoord[ 0 ].Size == 4 ) _vertices[ v ].Q = Ptr_TexCoord[ 0 ].Floats[ idx + 3 ]; else _vertices[ v ].Q = 1.0f; } else { _vertices[ v ].R = 0.0f; _vertices[ v ].Q = 1.0f; } #endif } else { _vertices[ v ].S = State_TexCoord[ 0 ][ 0 ]; _vertices[ v ].T = State_TexCoord[ 0 ][ 1 ]; #if false _vertices[ v ].R = State_TexCoord[ 0 ][ 2 ]; _vertices[ v ].Q = State_TexCoord[ 0 ][ 3 ]; #endif } if( ( vertexFormat & RasterVertexFormat.Texture ) == RasterVertexFormat.Texture ) { if( textureIsIdentity == false ) { float v0 = _vertices[ v ].S; float v1 = _vertices[ v ].T; #if true _vertices[ v ].S = v0 * textureMatrix.M11 + v1 * textureMatrix.M21 + textureMatrix.M41; _vertices[ v ].T = v0 * textureMatrix.M12 + v1 * textureMatrix.M22 + textureMatrix.M42; #else float v2 = v.R; float v3 = v.Q; _vertices[ v ].S = v0 * textureMatrix.M11 + v1 * textureMatrix.M21 + v2 * textureMatrix.M31 + v3 * textureMatrix.M41; _vertices[ v ].T = v0 * textureMatrix.M12 + v1 * textureMatrix.M22 + v2 * textureMatrix.M32 + v3 * textureMatrix.M42; _vertices[ v ].R = v0 * tmat.M13 + v1 * tmat.M23 + v2 * tmat.M33 + v3 * tmat.M42; _vertices[ v ].Q = v0 * tmat.M14 + v1 * tmat.M24 + v2 * tmat.M34 + v3 * tmat.M43; #endif } // RasterVertex expects texture coordinates multiplied out _vertices[ v ].S *= State_Texture[ 0 ].Width; _vertices[ v ].T *= State_Texture[ 0 ].Height; // TODO: clamp texture coords here? } // Transform Viewport_Far = 100.0f; Viewport_Near = 0.1f; { // World -> Model/View //Vector4 vec_w = new Vector4() Vector3 vec_w = new Vector3() { X = _vertices[ v ].X, Y = _vertices[ v ].Y, Z = _vertices[ v ].Z, //W = 1.0f, }; //Vector4 vec_c; Vector3 vec_c; Matrix.TransformAffine( ref modelViewMatrix, modelViewIsAffine, ref vec_w, out vec_c ); //Matrix.Multiply( ref modelViewMatrix, ref vec_w, out vec_c ); // Clip against near/far plane if( ( vec_c.Z > Viewport_Far ) || ( vec_c.Z < Viewport_Near ) ) _vertices[ v ].State = RasterVertexState.Clipped; else { // Clip against view frustum // TODO: clipping of vertices _vertices[ v ].State = RasterVertexState.Normal; } _vertices[ v ].X = vec_c.X; _vertices[ v ].Y = vec_c.Y; _vertices[ v ].Z = vec_c.Z; // Model/View -> Screen Vector3 vec_s; Matrix.TransformAffine( ref projectionMatrix, projectionIsAffine, ref vec_c, out vec_s ); //Vector4 vec_s; //Matrix.Multiply( ref projectionMatrix, ref vec_c, out vec_s ); //Matrix.TransformAffine( ref modelProjMatrix, modelProjMatrixIsAffine, ref vec_w, out vec_s ); _vertices[ v ].PX = vec_s.X; _vertices[ v ].PY = vec_s.Y; //_vertices[ v ].Z = vec_s.Z; //float det = 1.0f / ( vec_c.Z * projectionMatrix.M34 ); //_vertices[ v ].PX = ( vec_c.X * projectionMatrix.M11 ) * det; //_vertices[ v ].PY = ( vec_c.Y * projectionMatrix.M22 ) * det; // Adjust to screen space _vertices[ v ].PX = ( _vertices[ v ].PX + viewportWidthHalf ); _vertices[ v ].PY = -_vertices[ v ].PY * viewportAspectRatio + viewportHeightHalf; } } /* //Matrix.TransformAffine( ref _projectionMatrix, false, ref cp, out tp ); // UNSAFE: no clue if this works for anything but the settings I had when I wrote it float det = 1.0f / ( cp.Z * projectionMatrix.M34 ); tp.X = ( cp.X * projectionMatrix.M11 ) * det; tp.Y = ( cp.Y * projectionMatrix.M22 ) * det; //// World->Screen //Vector3 tp; //Matrix.TransformAffine( ref finalProjectionMatrix, finalProjectionMatrix.IsAffine, ref tx, out tp ); //// UNSAFE: no clue if this works for anything but the settings I had when I wrote it ////float det = 1.0f / ( tx.Z * projectionMatrix.M34 ); ////tp.X = ( tx.X * projectionMatrix.M11 ) * det; ////tp.Y = ( tx.Y * projectionMatrix.M22 ) * det; ////tp.Z = ( tx.Z * projectionMatrix.M33 ) * det; */ PixelBuffer pb; this.RasterBuffer.LockPixels( out pb ); switch( mode ) { case GL_POINTS: break; case GL_LINES: break; case GL_LINE_STRIP: case GL_LINE_LOOP: break; case GL_TRIANGLES: for( int n = offset; n < offset + count; n += 3 ) { polygon.v0 = indices[ n ]; polygon.v1 = indices[ n + 1 ]; polygon.v2 = indices[ n + 2 ]; // Clipping // NOTE: vertices that are clipped will have clip flags set already if( ( _vertices[ polygon.v0 ].State == RasterVertexState.Clipped ) && ( _vertices[ polygon.v1 ].State == RasterVertexState.Clipped ) && ( _vertices[ polygon.v2 ].State == RasterVertexState.Clipped ) ) continue; // Backface culling if( State_CullFace == true ) { // TODO: inline this math? // u = v0->v1, v = v0->v2, n = u x v Vector3 u = new Vector3() { X = _vertices[ polygon.v1 ].X - _vertices[ polygon.v0 ].X, Y = _vertices[ polygon.v1 ].Y - _vertices[ polygon.v0 ].Y, Z = _vertices[ polygon.v1 ].Z - _vertices[ polygon.v0 ].Z, }; Vector3 v = new Vector3() { X = _vertices[ polygon.v2 ].X - _vertices[ polygon.v0 ].X, Y = _vertices[ polygon.v2 ].Y - _vertices[ polygon.v0 ].Y, Z = _vertices[ polygon.v2 ].Z - _vertices[ polygon.v0 ].Z, }; Vector3 normal; Vector3.CrossProduct( ref u, ref v, out normal ); float dot = ( normal.X * _vertices[ polygon.v0 ].X ) + ( normal.Y * _vertices[ polygon.v0 ].Y ) + ( normal.Z * _vertices[ polygon.v0 ].Z ); if( State_FrontFace == GL_CCW ) dot *= -1.0f; if( State_CullFaceMode == GL_FRONT ) dot *= -1.0f; // > 0 = visible, 0 = scathing, < 0 = invisible if( dot <= 0.0f ) { polygon.State = RasterPolygonState.BackfaceCulled; continue; } } else polygon.State = RasterPolygonState.Valid; // etc this.RasterBuffer.DrawTriangle( ref pb, ref polygon, false ); #if DRAW_LINE line.v0 = polygon.v0; line.v1 = polygon.v1; this.RasterBuffer.DrawLine( ref pb, ref line, false ); line.v0 = polygon.v1; line.v1 = polygon.v2; this.RasterBuffer.DrawLine( ref pb, ref line, false ); line.v0 = polygon.v2; line.v1 = polygon.v0; this.RasterBuffer.DrawLine( ref pb, ref line, false ); #endif } break; case GL_TRIANGLE_STRIP: break; case GL_TRIANGLE_FAN: break; } this.RasterBuffer.UnlockPixels(); }