2018-09-06 01:53:11 +00:00
|
|
|
#include "color.h"
|
|
|
|
#include "geometry.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
|
|
// MACROS
|
|
|
|
#define DrawPixel(buffer, width, color, x, y)\
|
|
|
|
{\
|
|
|
|
buffer[width * y + x] = color;\
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PRIVATE PROTOTYPES
|
|
|
|
static void FillTriangleFlatBottom(
|
2018-09-07 01:32:15 +00:00
|
|
|
uint32_t *buffer, int width,
|
|
|
|
float *zbuffer, uint32_t color,
|
|
|
|
float x0, float y0, float z0,
|
|
|
|
float x1, float y1, float z1,
|
|
|
|
float x2, float y2, float z2);
|
2018-09-06 01:53:11 +00:00
|
|
|
|
|
|
|
static void FillTriangleFlatTop(
|
2018-09-07 01:32:15 +00:00
|
|
|
uint32_t *buffer, int width,
|
|
|
|
float *zbuffer, uint32_t color,
|
|
|
|
float x0, float y0, float z0,
|
|
|
|
float x1, float y1, float z1,
|
|
|
|
float x2, float y2, float z2);
|
2018-09-06 01:53:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
// PUBLIC FUNCTIONS
|
|
|
|
void FillTriangle(
|
2018-09-07 01:32:15 +00:00
|
|
|
uint32_t *buffer, int width,
|
|
|
|
float *zbuffer, uint32_t color,
|
|
|
|
float x0, float y0, float z0,
|
|
|
|
float x1, float y1, float z1,
|
|
|
|
float x2, float y2, float z2)
|
2018-09-06 01:53:11 +00:00
|
|
|
{
|
|
|
|
// Horizontal or vertical
|
|
|
|
if ((FLOAT_EQUAL(x0,x1) && FLOAT_EQUAL(x1, x2))
|
|
|
|
|| (FLOAT_EQUAL(y0, y1) && FLOAT_EQUAL(y1, y2)))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort in ascending Y order
|
|
|
|
float temp;
|
|
|
|
if (y0 > y1)
|
|
|
|
{
|
|
|
|
SWAP(x0, x1, temp);
|
|
|
|
SWAP(y0, y1, temp);
|
2018-09-07 01:32:15 +00:00
|
|
|
SWAP(z0, z1, temp);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (y0 > y2)
|
|
|
|
{
|
|
|
|
SWAP(x0, x2, temp);
|
|
|
|
SWAP(y0, y2, temp);
|
2018-09-07 01:32:15 +00:00
|
|
|
SWAP(z0, z2, temp);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (y1 > y2)
|
|
|
|
{
|
|
|
|
SWAP(x1, x2, temp);
|
|
|
|
SWAP(y1, y2, temp);
|
2018-09-07 01:32:15 +00:00
|
|
|
SWAP(z1, z2, temp);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Flat top triangle
|
|
|
|
if (FLOAT_EQUAL(y0, y1))
|
|
|
|
{
|
2018-09-07 01:32:15 +00:00
|
|
|
FillTriangleFlatTop(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Flat bottom triangle
|
|
|
|
else if (FLOAT_EQUAL(y1, y2))
|
|
|
|
{
|
2018-09-07 01:32:15 +00:00
|
|
|
FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Other - decompose into two triangles
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Calculate x coordinate at point of decomposition using intercept theorem
|
|
|
|
// New y is the same as y1
|
|
|
|
float x3 = x0 + (((y1 - y0) / (y2 - y0)) * (x2 - x0));
|
|
|
|
float y3 = y1;
|
2018-09-07 01:32:15 +00:00
|
|
|
float z3 = z1;
|
2018-09-06 01:53:11 +00:00
|
|
|
|
2018-09-07 01:32:15 +00:00
|
|
|
FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x3, y3, z3);
|
|
|
|
FillTriangleFlatTop(buffer, width, zbuffer, color, x1, y1, z1, x3, y3, z3, x2, y2, z2);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PRIVATE FUNCTIONS
|
|
|
|
static void FillTriangleFlatBottom(
|
2018-09-07 01:32:15 +00:00
|
|
|
uint32_t *buffer, int width,
|
|
|
|
float *zbuffer, uint32_t color,
|
|
|
|
float x0, float y0, float z0,
|
|
|
|
float x1, float y1, float z1,
|
|
|
|
float x2, float y2, float z2)
|
2018-09-06 01:53:11 +00:00
|
|
|
{
|
|
|
|
if (x2 < x1)
|
|
|
|
{
|
|
|
|
float temp;
|
2018-09-07 01:32:15 +00:00
|
|
|
SWAP(x2, x1, temp);
|
|
|
|
SWAP(y2, y1, temp);
|
|
|
|
SWAP(z2, z1, temp);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Top-left fill convention
|
|
|
|
float dxdy_left = (x1 - x0) / (y1 - y0);
|
|
|
|
float dxdy_right = (x2 - x0) / (y2 - y0);
|
|
|
|
int yStart = (int)ceilf(y0);
|
|
|
|
int yEnd = (int)ceilf(y2) - 1;
|
|
|
|
float xStart = x0 + dxdy_left * (yStart - y0);
|
|
|
|
float xEnd = x0 + dxdy_right * (yStart - y0);
|
|
|
|
|
|
|
|
|
2018-09-07 01:32:15 +00:00
|
|
|
// Inverse z-buffering
|
|
|
|
float z0Inv = 1.0f / z0;
|
|
|
|
float z1Inv = 1.0f / z1;
|
|
|
|
float z2Inv = 1.0f / z2;
|
|
|
|
float dzdy_left = (z1Inv - z0Inv) / (y1 - y0);
|
|
|
|
float dzdy_right = (z2Inv - z0Inv) / (y2 - y0);
|
|
|
|
float zStart = z0Inv;
|
|
|
|
float zEnd = z0Inv;
|
|
|
|
|
|
|
|
|
2018-09-06 01:53:11 +00:00
|
|
|
// Fill
|
|
|
|
for (int y = yStart; y <= yEnd; ++y)
|
|
|
|
{
|
2018-09-07 01:32:15 +00:00
|
|
|
float dzdx = (zEnd - zStart) / (xEnd - xStart);
|
|
|
|
float z = zStart;
|
|
|
|
|
2018-09-06 01:53:11 +00:00
|
|
|
int xStartInt = (int)xStart;
|
|
|
|
int xEndInt = (int)xEnd;
|
|
|
|
|
|
|
|
for (int x = xStartInt; x <= xEndInt; ++x)
|
|
|
|
{
|
2018-09-07 01:32:15 +00:00
|
|
|
int pixel = (y * width) + x;
|
|
|
|
|
|
|
|
if (z > zbuffer[pixel])
|
|
|
|
{
|
|
|
|
DrawPixel(buffer, width, color, x, y);
|
|
|
|
|
|
|
|
zbuffer[pixel] = z;
|
|
|
|
}
|
|
|
|
|
|
|
|
z += dzdx;
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xStart += dxdy_left;
|
|
|
|
xEnd += dxdy_right;
|
2018-09-07 01:32:15 +00:00
|
|
|
|
|
|
|
zStart += dzdy_left;
|
|
|
|
zEnd += dzdy_right;
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void FillTriangleFlatTop(
|
2018-09-07 01:32:15 +00:00
|
|
|
uint32_t *buffer, int width,
|
|
|
|
float *zbuffer, uint32_t color,
|
|
|
|
float x0, float y0, float z0,
|
|
|
|
float x1, float y1, float z1,
|
|
|
|
float x2, float y2, float z2)
|
2018-09-06 01:53:11 +00:00
|
|
|
{
|
|
|
|
if (x1 < x0)
|
|
|
|
{
|
|
|
|
float temp;
|
|
|
|
SWAP(x1, x0, temp);
|
2018-09-07 01:32:15 +00:00
|
|
|
SWAP(y1, y0, temp);
|
|
|
|
SWAP(z1, z0, temp);
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Top-left fill convention
|
|
|
|
float dxdy_left = (x2 - x0) / (y2 - y0);
|
|
|
|
float dxdy_right = (x2 - x1) / (y2 - y1);
|
|
|
|
int yStart = (int)ceilf(y0);
|
|
|
|
int yEnd = (int)ceilf(y2) - 1;
|
|
|
|
float xStart = x0 + dxdy_left * (yStart - y0);
|
|
|
|
float xEnd = x1 + dxdy_right * (yStart - y0);
|
|
|
|
|
|
|
|
|
2018-09-07 01:32:15 +00:00
|
|
|
// Inverse z-buffering
|
|
|
|
float z0Inv = 1.0f / z0;
|
|
|
|
float z1Inv = 1.0f / z1;
|
|
|
|
float z2Inv = 1.0f / z2;
|
|
|
|
float dzdy_left = (z2Inv - z0Inv) / (y2 - y0);
|
|
|
|
float dzdy_right = (z2Inv - z1Inv) / (y2 - y1);
|
|
|
|
float zStart = z0Inv;
|
|
|
|
float zEnd = z1Inv;
|
|
|
|
|
2018-09-06 01:53:11 +00:00
|
|
|
// Fill
|
|
|
|
for (int y = yStart; y <= yEnd; ++y)
|
|
|
|
{
|
2018-09-07 01:32:15 +00:00
|
|
|
float dzdx = (zEnd - zStart) / (xEnd - xStart);
|
|
|
|
float z = zStart;
|
|
|
|
|
2018-09-06 01:53:11 +00:00
|
|
|
int xStartInt = (int)xStart;
|
|
|
|
int xEndInt = (int)xEnd;
|
|
|
|
|
|
|
|
for (int x = xStartInt; x <= xEndInt; ++x)
|
|
|
|
{
|
2018-09-07 01:32:15 +00:00
|
|
|
int pixel = (y * width) + x;
|
|
|
|
|
|
|
|
if (z > zbuffer[pixel])
|
|
|
|
{
|
|
|
|
DrawPixel(buffer, width, color, x, y);
|
|
|
|
|
|
|
|
zbuffer[pixel] = z;
|
|
|
|
}
|
|
|
|
|
|
|
|
z += dzdx;
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xStart += dxdy_left;
|
|
|
|
xEnd += dxdy_right;
|
2018-09-07 01:32:15 +00:00
|
|
|
|
|
|
|
zStart += dzdy_left;
|
|
|
|
zEnd += dzdy_right;
|
2018-09-06 01:53:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|