I don't know whats wrong here, I have two bits of code that do the same thing but only one works and I can't see why.
The first listing draws the blue helicopter. The problem is there are gaps between the triangles. Also some triangles are missing.
Maybe its a fencepost error related to pre-increment in a loop.
Maybe Incorrect accumulation of fractional parts.
Maybe Incorrect cutoff of fractional parts.
Wheres wally?
__forceinline int * floatToInt(int *int_pointer, float f)
{
*int_pointer = floor(f);
return int_pointer;
}
//textureTriangle2D members are all floats
void Rasterizer::textureTriangle(textureTriangle2D & tri)
{
real temp; // real is a float
int slopeLeft;
int slopeRight;
//sort top to bottom
//y is 0 at top of screen
if (tri.y1 > tri.y3)
{
SWAP(tri.y1, tri.y3, temp);
SWAP(tri.x1, tri.x3, temp);
}
if (tri.y1 > tri.y2)
{
SWAP(tri.y1, tri.y2, temp);
SWAP(tri.x1, tri.x2, temp);
}
if (tri.y2 > tri.y3)
{
SWAP(tri.y2, tri.y3, temp);
SWAP(tri.x2, tri.x3, temp);
}
//height of top and bottom half of triangle
real topHeight = tri.y2 - tri.y1;
real bottomHeight = tri.y3 - tri.y2;
floatToInt(&slopeRight, ((tri.x2 - tri.x1) * 65536) / topHeight);
floatToInt(&slopeLeft, ((tri.x3 - tri.x1) * 65536) / (topHeight + bottomHeight));
int x1, x2, y1;
floatToInt(&x1, tri.x1 * 65536);
x2 = x1;
floatToInt(&y1, tri.y1);
int currentLocation;
currentLocation = (pitch * y1);
//flat bottom
int h = floor(topHeight);
if (h > 0)
{
if (tri.x2 > tri.x1)
flatBottomTriangle(x1, slopeLeft, x2, slopeRight, h, currentLocation);
else
flatBottomTriangle(x2, slopeRight, x1, slopeLeft, h, currentLocation);
}
int offset;
floatToInt(&offset, slopeLeft * floor(topHeight));
x1 = x1 + offset;
floatToInt(&x2, tri.x2 * 65536);
currentLocation += pitch *floor(topHeight);
floatToInt(&slopeRight, ((tri.x3 - tri.x2) * 65536) / (bottomHeight));
int h = floor(bottomHeight);
if (h > 0)
{
if (tri.x2 > tri.x1)
flatBottomTriangle(x1, slopeLeft, x2, slopeRight, h, currentLocation);
else
flatBottomTriangle(x2, slopeRight, x1, slopeLeft, h, currentLocation);
}
}
__forceinline void flatBottomTriangle(int x1, int slopeLeft, int x2, int slopeRight, real height, int currentLocation)
{
do
{
x1 += slopeLeft;
x2 += slopeRight;
int index = currentLocation + (x1 >> 16);
while ( index ++ < currentLocation+(x2 >> 16) )
{
//show overlapping pixels in red
if (screenBuffer[index ] == 0)
screenBuffer[index ] = 255;
else
screenBuffer[index ] = 255 << 16;
}
currentLocation += pitch;
}
while( --height > 0 );
}
For what its worth I also have the following code which does the same thing and works. I can't see the difference. It draws they grey helicopter.
__forceinline int * floatToInt(int *int_pointer, float f)
{
*int_pointer = floor(f);
/*__asm fld f;
__asm mov edx,int_pointer;
__asm FRNDINT;
__asm fistp dword ptr [edx];*/
return int_pointer;
}
//all textureTriangle2D members are floats
void Rasterizer::flatTriangle( flatTriangle2D & tri )
{
real temp;
int clip;
bool topDone = false;
if ( tri.y1 > tri.y3 )
{
SWAP( tri.x1, tri.x3, temp );
SWAP( tri.y1, tri.y3, temp );
}
if ( tri.y1 > tri.y2 )
{
SWAP( tri.y1, tri.y2, temp );
SWAP( tri.x1, tri.x2, temp );
}
if ( tri.y2 > tri.y3 )
{
SWAP( tri.x2, tri.x3, temp );
SWAP( tri.y2, tri.y3, temp );
}
real x2x1 = tri.x2 - tri.x1;
real x3x1 = tri.x3 - tri.x1;
real x3x2 = tri.x3 - tri.x2;
real y3y1 = tri.y3 - tri.y1;
real y3y2 = tri.y3 - tri.y2;
real y2y1 = tri.y2 - tri.y1;
int x1;
int x2;
int y1;
int y2;
int y3;
int tmp1 = 0;
int tmp2 = 0;
floatToInt( &y1, tri.y1 );
floatToInt( &y2, tri.y2 );
floatToInt( &y3, tri.y3 );
int shortSlope;
int longSlope;
floatToInt( &longSlope, ( x3x1 * 65536 ) / y3y1 );
//flat bottom
if ( y1 != y2 )
{
topDone = true;
floatToInt( &x1, tri.x1 * 65536 );
floatToInt( &shortSlope, ( x2x1 * 65536 ) / y2y1 );
x2 = x1;
for (; y1 < y2; y1++)
{
if ( x2 > x1 )
{
tmp1 = x1 >> 16;
tmp2 = x2 >> 16;
if ( tmp1 < clipRect.left )
tmp1 = clipRect.left;
if ( tmp2 > clipRect.right )
tmp2 = clipRect.right;
if ( tmp1 < clipRect.right && tmp2 > clipRect.left)
hLine( tmp1, tmp2, y1, tri.colour );
}
else // from x2 to x1
{
tmp1 = x2 >> 16;
tmp2 = x1 >> 16;
if ( tmp1 < clipRect.left)
tmp1 = clipRect.left;
if ( tmp2 > clipRect.right )
tmp2 = clipRect.right;
if ( ( tmp1 < clipRect.right ) && ( tmp2 > clipRect.left ) )
hLine( tmp1, tmp2, y1, tri.colour );
}
x1 += shortSlope;
x2 += longSlope;
}
}
//flat top
if ( y2 != y3 )
{
floatToInt( &x1, tri.x2 * 65536 );
if ( ! topDone )
{
floatToInt( &x2, tri.x1 * 65536 );
}
floatToInt( &shortSlope, ( x3x2 * 65536 ) / y3y2 );
for (; y2 < y3; y2++)
{
if ( x2 >= x1 )
{
tmp1 = x1 >> 16;
tmp2 = x2 >> 16;
if ( tmp1 < clipRect.left )
tmp1 = clipRect.left;
if ( tmp2 > clipRect.right )
tmp2 = clipRect.right;
if ( tmp1 < clipRect.right && tmp2 > clipRect.left)
hLine( tmp1, tmp2, y2, tri.colour );
}
else // x2 starts x1 ends
{
tmp1 = x2 >> 16;
tmp2 = x1 >> 16;
if ( tmp1 < clipRect.left)
tmp1 = clipRect.left;
if ( tmp2 > clipRect.right )
tmp2 = clipRect.right;
if ( ( tmp1 < clipRect.right ) && ( tmp2 > clipRect.left ) )
hLine( tmp1, tmp2, y2, tri.colour );
}
x1 += shortSlope;
x2 += longSlope;
}
}
}
inline void Rasterizer::hLine(int x, int x1, int y, COLOUR_DEPTH colour)
{
y *= pitch;
while (x < x1)
{
screenBuffer[ y + x++ ] = colour;
}
}