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 bool ClipLine( ref PixelBuffer pb, ref int x0, ref int y0, ref int x1, ref int y1 )
        {
            // internal clipping codes
            int xc0 = x0, yc0 = y0,
                xc1 = x1, yc1 = y1;

            // TODO: inline
            int min_clip_x = 0, min_clip_y = 0, max_clip_x = pb.Width - 1, max_clip_y = pb.Height - 1;

            // determine codes for p1 and p2
            int p1_code = 0;
            if( y0 < min_clip_y )
                p1_code |= CLIP_CODE_N;
            else
                if( y0 > max_clip_y )
                    p1_code |= CLIP_CODE_S;

            if( x0 < min_clip_x )
                p1_code |= CLIP_CODE_W;
            else
                if( x0 > max_clip_x )
                    p1_code |= CLIP_CODE_E;
            int p2_code = 0;
            if( y1 < min_clip_y )
                p2_code |= CLIP_CODE_N;
            else
                if( y1 > max_clip_y )
                    p2_code |= CLIP_CODE_S;

            if( x1 < min_clip_x )
                p2_code |= CLIP_CODE_W;
            else
                if( x1 > max_clip_x )
                    p2_code |= CLIP_CODE_E;

            // try and trivially reject
            if( ( p1_code & p2_code ) != 0 )
                return false;

            // test for totally visible, if so leave points untouched
            if( p1_code == 0 && p2_code == 0 )
                return true;

            // determine end clip point for p1
            switch( p1_code )
            {
                case CLIP_CODE_C: break;
                case CLIP_CODE_N:
                    {
                        yc0 = min_clip_y;
                        xc0 = ( int )( x0 + 0.5f + ( min_clip_y - y0 ) * ( x1 - x0 ) / ( y1 - y0 ) );
                    } break;
                case CLIP_CODE_S:
                    {
                        yc0 = max_clip_y;
                        xc0 = ( int )( x0 + 0.5f + ( max_clip_y - y0 ) * ( x1 - x0 ) / ( y1 - y0 ) );
                    } break;
                case CLIP_CODE_W:
                    {
                        xc0 = min_clip_x;
                        yc0 = ( int )( y0 + 0.5f + ( min_clip_x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) );
                    } break;
                case CLIP_CODE_E:
                    {
                        xc0 = max_clip_x;
                        yc0 = ( int )( y0 + 0.5f + ( max_clip_x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) );
                    } break;
                // these cases are more complex, must compute 2 intersections
                case CLIP_CODE_NE:
                    {
                        // north hline intersection
                        yc0 = min_clip_y;
                        xc0 = ( int )( x0 + 0.5f + ( min_clip_y - y0 ) * ( x1 - x0 ) / ( y1 - y0 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc0 < min_clip_x || xc0 > max_clip_x )
                        {
                            // east vline intersection
                            xc0 = max_clip_x;
                            yc0 = ( int )( y0 + 0.5f + ( max_clip_x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) );
                        }
                    } break;
                case CLIP_CODE_SE:
                    {
                        // south hline intersection
                        yc0 = max_clip_y;
                        xc0 = ( int )( x0 + 0.5f + ( max_clip_y - y0 ) * ( x1 - x0 ) / ( y1 - y0 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc0 < min_clip_x || xc0 > max_clip_x )
                        {
                            // east vline intersection
                            xc0 = max_clip_x;
                            yc0 = ( int )( y0 + 0.5f + ( max_clip_x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) );
                        }
                    } break;
                case CLIP_CODE_NW:
                    {
                        // north hline intersection
                        yc0 = min_clip_y;
                        xc0 = ( int )( x0 + 0.5f + ( min_clip_y - y0 ) * ( x1 - x0 ) / ( y1 - y0 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc0 < min_clip_x || xc0 > max_clip_x )
                        {
                            xc0 = min_clip_x;
                            yc0 = ( int )( y0 + 0.5f + ( min_clip_x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) );
                        }
                    } break;
                case CLIP_CODE_SW:
                    {
                        // south hline intersection
                        yc0 = max_clip_y;
                        xc0 = ( int )( x0 + 0.5f + ( max_clip_y - y0 ) * ( x1 - x0 ) / ( y1 - y0 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc0 < min_clip_x || xc0 > max_clip_x )
                        {
                            xc0 = min_clip_x;
                            yc0 = ( int )( y0 + 0.5f + ( min_clip_x - x0 ) * ( y1 - y0 ) / ( x1 - x0 ) );
                        }
                    } break;
                default: break;
            }

            // determine clip point for p2
            switch( p2_code )
            {
                case CLIP_CODE_C: break;
                case CLIP_CODE_N:
                    {
                        yc1 = min_clip_y;
                        xc1 = x1 + ( min_clip_y - y1 ) * ( x0 - x1 ) / ( y0 - y1 );
                    } break;
                case CLIP_CODE_S:
                    {
                        yc1 = max_clip_y;
                        xc1 = x1 + ( max_clip_y - y1 ) * ( x0 - x1 ) / ( y0 - y1 );
                    } break;
                case CLIP_CODE_W:
                    {
                        xc1 = min_clip_x;
                        yc1 = y1 + ( min_clip_x - x1 ) * ( y0 - y1 ) / ( x0 - x1 );
                    } break;
                case CLIP_CODE_E:
                    {
                        xc1 = max_clip_x;
                        yc1 = y1 + ( max_clip_x - x1 ) * ( y0 - y1 ) / ( x0 - x1 );
                    } break;
                // these cases are more complex, must compute 2 intersections
                case CLIP_CODE_NE:
                    {
                        // north hline intersection
                        yc1 = min_clip_y;
                        xc1 = ( int )( x1 + 0.5f + ( min_clip_y - y1 ) * ( x0 - x1 ) / ( y0 - y1 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc1 < min_clip_x || xc1 > max_clip_x )
                        {
                            // east vline intersection
                            xc1 = max_clip_x;
                            yc1 = ( int )( y1 + 0.5f + ( max_clip_x - x1 ) * ( y0 - y1 ) / ( x0 - x1 ) );
                        }
                    } break;
                case CLIP_CODE_SE:
                    {
                        // south hline intersection
                        yc1 = max_clip_y;
                        xc1 = ( int )( x1 + 0.5f + ( max_clip_y - y1 ) * ( x0 - x1 ) / ( y0 - y1 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc1 < min_clip_x || xc1 > max_clip_x )
                        {
                            // east vline intersection
                            xc1 = max_clip_x;
                            yc1 = ( int )( y1 + 0.5f + ( max_clip_x - x1 ) * ( y0 - y1 ) / ( x0 - x1 ) );
                        }
                    } break;
                case CLIP_CODE_NW:
                    {
                        // north hline intersection
                        yc1 = min_clip_y;
                        xc1 = ( int )( x1 + 0.5f + ( min_clip_y - y1 ) * ( x0 - x1 ) / ( y0 - y1 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc1 < min_clip_x || xc1 > max_clip_x )
                        {
                            xc1 = min_clip_x;
                            yc1 = ( int )( y1 + 0.5f + ( min_clip_x - x1 ) * ( y0 - y1 ) / ( x0 - x1 ) );
                        }
                    } break;
                case CLIP_CODE_SW:
                    {
                        // south hline intersection
                        yc1 = max_clip_y;
                        xc1 = ( int )( x1 + 0.5f + ( max_clip_y - y1 ) * ( x0 - x1 ) / ( y0 - y1 ) );
                        // test if intersection is valid, of so then done, else compute next
                        if( xc1 < min_clip_x || xc1 > max_clip_x )
                        {
                            xc1 = min_clip_x;
                            yc1 = ( int )( y1 + 0.5f + ( min_clip_x - x1 ) * ( y0 - y1 ) / ( x0 - x1 ) );
                        }
                    } break;
                default: break;
            }

            // do bounds check
            if( ( xc0 < min_clip_x ) || ( xc0 > max_clip_x ) ||
                ( yc0 < min_clip_y ) || ( yc0 > max_clip_y ) ||
                ( xc1 < min_clip_x ) || ( xc1 > max_clip_x ) ||
                ( yc1 < min_clip_y ) || ( yc1 > max_clip_y ) )
                return false;

            x0 = xc0; y0 = yc0;
            x1 = xc1; y1 = yc1;
            return true;
        }
 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;
                    }
                }
            }
        }