|
@@ -16,127 +16,159 @@
|
|
|
|
|
|
bool doPerpectiveCorrection = true;
|
|
|
|
|
|
-void drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
|
|
|
+static vec3_t barycentricWeights(vec2_t a, vec2_t b, vec2_t c, vec2_t p)
|
|
|
{
|
|
|
- drawLine(x0, y0, x1, y1, colour);
|
|
|
- drawLine(x1, y1, x2, y2, colour);
|
|
|
- drawLine(x2, y2, x0, y0, colour);
|
|
|
-}
|
|
|
+ vec2_t ab = vec2SubVectors(b, a);
|
|
|
+ vec2_t bc = vec2SubVectors(c, b);
|
|
|
+ vec2_t ac = vec2SubVectors(c, a);
|
|
|
+ vec2_t ap = vec2SubVectors(p, a);
|
|
|
+ vec2_t bp = vec2SubVectors(p, b);
|
|
|
+ vec3_t ret;
|
|
|
|
|
|
-/* ----------------------------------- Filled triangles ----------------------------------- */
|
|
|
+ double areaTriangleABC = (ab.x * ac.y) - (ab.y * ac.x);
|
|
|
|
|
|
-/* This function expect Point 0 to be the top, 1 to be the bottom left, 2 to be the bottom right */
|
|
|
-static void drawFillBottomFlatTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
|
|
|
-{
|
|
|
- int i;
|
|
|
- int32_t deltaXL = x1 - x0;
|
|
|
- int32_t deltaXR = x2 - x0;
|
|
|
- int32_t deltaY = y1 - y0;
|
|
|
- int32_t sideLength = abs(deltaY);
|
|
|
+ double alpha = ((bc.x * bp.y) - (bp.x * bc.y)) / areaTriangleABC;
|
|
|
+ double beta = ((ap.x * ac.y) - (ac.x * ap.y)) / areaTriangleABC;
|
|
|
+ double gamma = 1 - alpha - beta;
|
|
|
|
|
|
- double incrementXL = deltaXL / (double)sideLength;
|
|
|
- double incrementXR = deltaXR / (double)sideLength;
|
|
|
- double incrementY = deltaY / (double)sideLength;
|
|
|
+ ret.x = alpha;
|
|
|
+ ret.y = beta;
|
|
|
+ ret.z = gamma;
|
|
|
|
|
|
- double currentXL = x0;
|
|
|
- double currentXR = x0;
|
|
|
- double currentY = y0;
|
|
|
+ return ret;
|
|
|
+}
|
|
|
|
|
|
- for(i = 0; i < sideLength; i++)
|
|
|
- {
|
|
|
- drawHLine(round(currentXL), round(currentY), round(currentXR), colour);
|
|
|
- currentXL += incrementXL;
|
|
|
- currentXR += incrementXR;
|
|
|
- currentY += incrementY;
|
|
|
- }
|
|
|
+void drawTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
|
|
|
+{
|
|
|
+ drawLine(x0, y0, x1, y1, colour);
|
|
|
+ drawLine(x1, y1, x2, y2, colour);
|
|
|
+ drawLine(x2, y2, x0, y0, colour);
|
|
|
}
|
|
|
|
|
|
-/* This function expect Point 2 to be the bottom, 0 to be the top left, 1 to be the top right */
|
|
|
-static void drawFillTopFlatTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
|
|
|
+/* ----------------------------------- Filled triangles ----------------------------------- */
|
|
|
+static void drawZPixel(int32_t x, int32_t y, vec4_t a, vec4_t b, vec4_t c, colour_t colour)
|
|
|
{
|
|
|
- int i;
|
|
|
- int32_t deltaXL = x0 - x2;
|
|
|
- int32_t deltaXR = x1 - x2;
|
|
|
- int32_t deltaY = y0 - y2;
|
|
|
- int32_t sideLength = abs(deltaY);
|
|
|
+ vec2_t pointP = { x, y };
|
|
|
+ vec2_t a2 = vec2FromVec4(a);
|
|
|
+ vec2_t b2 = vec2FromVec4(b);
|
|
|
+ vec2_t c2 = vec2FromVec4(c);
|
|
|
|
|
|
- if (sideLength == 0)
|
|
|
+ if ((x < 0) || (y < 0) || (x > windowWidth) ||(y > windowHeight))
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- double incrementXL = deltaXL / (double)sideLength;
|
|
|
- double incrementXR = deltaXR / (double)sideLength;
|
|
|
- double incrementY = deltaY / (double)sideLength;
|
|
|
+ vec3_t weights = barycentricWeights(a2, b2, c2, pointP);
|
|
|
+
|
|
|
+ double alpha = weights.x;
|
|
|
+ double beta = weights.y;
|
|
|
+ double gamma = weights.z;
|
|
|
+ double interpolatedReciprocalW;
|
|
|
|
|
|
- double currentXL = x2;
|
|
|
- double currentXR = x2;
|
|
|
- double currentY = y2;
|
|
|
+ interpolatedReciprocalW = (1 / a.w) * alpha + (1 / b.w) * beta + (1 / c.w) * gamma;
|
|
|
|
|
|
- for(i = 0; i <= sideLength; i++)
|
|
|
+ /* Inverse to get logical W invrementing going further to us */
|
|
|
+ interpolatedReciprocalW = 1 - interpolatedReciprocalW;
|
|
|
+ if (interpolatedReciprocalW < zBuffer[(windowWidth * y) + x])
|
|
|
{
|
|
|
- drawHLine(round(currentXL), round(currentY), round(currentXR), colour);
|
|
|
- currentXL += incrementXL;
|
|
|
- currentXR += incrementXR;
|
|
|
- currentY += incrementY;
|
|
|
+ drawPixel(x, y, colour);
|
|
|
+
|
|
|
+ /* Update Z Buffer */
|
|
|
+ zBuffer[(windowWidth * y) + x] = interpolatedReciprocalW;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void drawFilledTriangle(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2, colour_t colour)
|
|
|
+void drawFilledTriangle(struct triangle_t *t)
|
|
|
{
|
|
|
- int32_t My, Mx;
|
|
|
- if (y0 > y1)
|
|
|
+ int32_t x, y;
|
|
|
+
|
|
|
+ if (t->points[0].y > t->points[1].y)
|
|
|
{
|
|
|
- intSwap(&x0, &x1); intSwap(&y0, &y1);
|
|
|
+ doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
|
|
|
+ doubleSwap(&t->points[0].z, &t->points[1].z); doubleSwap(&t->points[0].w, &t->points[1].w);
|
|
|
}
|
|
|
- if (y1 > y2)
|
|
|
+ if (t->points[1].y > t->points[2].y)
|
|
|
{
|
|
|
- intSwap(&x1, &x2); intSwap(&y1, &y2);
|
|
|
+ doubleSwap(&t->points[1].x, &t->points[2].x); doubleSwap(&t->points[1].y, &t->points[2].y);
|
|
|
+ doubleSwap(&t->points[1].z, &t->points[2].z); doubleSwap(&t->points[1].w, &t->points[2].w);
|
|
|
}
|
|
|
- if (y0 > y1)
|
|
|
+ if (t->points[0].y > t->points[1].y)
|
|
|
{
|
|
|
- intSwap(&x0, &x1); intSwap(&y0, &y1);
|
|
|
+ doubleSwap(&t->points[0].x, &t->points[1].x); doubleSwap(&t->points[0].y, &t->points[1].y);
|
|
|
+ doubleSwap(&t->points[0].z, &t->points[1].z); doubleSwap(&t->points[0].w, &t->points[1].w);
|
|
|
}
|
|
|
|
|
|
- /* Determine the mid intersection and point */
|
|
|
- My = y1;
|
|
|
- Mx = x0 + (double)((x2 - x0) * (y1 - y0)) / (double)(y2 - y0);
|
|
|
+ vec4_t a = t->points[0];
|
|
|
+ vec4_t b = t->points[1];
|
|
|
+ vec4_t c = t->points[2];
|
|
|
|
|
|
- /* Fill top */
|
|
|
- if (y0 != y1)
|
|
|
- {
|
|
|
- drawFillBottomFlatTriangle(x0, y0, x1, y1, Mx, My, colour);
|
|
|
- }
|
|
|
- /* Fill bottom */
|
|
|
- if (y1 != y2)
|
|
|
+ /* Render the top part */
|
|
|
+ double inverseSlope1 = 0;
|
|
|
+ double inverseSlope2 = 0;
|
|
|
+ int32_t x0 = a.x, y0 = a.y;
|
|
|
+ int32_t x1 = b.x, y1 = b.y;
|
|
|
+ int32_t x2 = c.x, y2 = c.y;
|
|
|
+
|
|
|
+ if ((y1 - y0) != 0) { inverseSlope1 = (double)(x1 - x0) / abs(y1 - y0); }
|
|
|
+ if ((y2 - y0) != 0) { inverseSlope2 = (double)(x2 - x0) / abs(y2 - y0); }
|
|
|
+
|
|
|
+ if ((y1 - y0) != 0)
|
|
|
{
|
|
|
- drawFillTopFlatTriangle(x1, y1, Mx, My, x2, y2, colour);
|
|
|
- }
|
|
|
-}
|
|
|
+ for (y = y0 ; y <= y1 ; y++)
|
|
|
+ {
|
|
|
+ int32_t xStart = x1 + (y - y1) * inverseSlope1;
|
|
|
+ int32_t xEnd = x0 + (y - y0) * inverseSlope2;
|
|
|
|
|
|
-/* ----------------------------------- Textured triangles ----------------------------------- */
|
|
|
-static vec3_t barycentricWeights(vec2_t a, vec2_t b, vec2_t c, vec2_t p)
|
|
|
-{
|
|
|
- vec2_t ab = vec2SubVectors(b, a);
|
|
|
- vec2_t bc = vec2SubVectors(c, b);
|
|
|
- vec2_t ac = vec2SubVectors(c, a);
|
|
|
- vec2_t ap = vec2SubVectors(p, a);
|
|
|
- vec2_t bp = vec2SubVectors(p, b);
|
|
|
- vec3_t ret;
|
|
|
+ if (doZBuffer)
|
|
|
+ {
|
|
|
+ if (xEnd < xStart)
|
|
|
+ {
|
|
|
+ intSwap(&xStart, &xEnd);
|
|
|
+ }
|
|
|
+ for (x = xStart ; x <= xEnd ; x++)
|
|
|
+ {
|
|
|
+ drawZPixel(x, y, a, b, c,t->colour);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ drawHLine(xStart, y, xEnd, t->colour);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- double areaTriangleABC = (ab.x * ac.y) - (ab.y * ac.x);
|
|
|
+ /* Render the bottom part */
|
|
|
+ inverseSlope1 = 0;
|
|
|
+ if ((y2 - y1) != 0) { inverseSlope1 = (double)(x2 - x1) / abs(y2 - y1); }
|
|
|
|
|
|
- double alpha = ((bc.x * bp.y) - (bp.x * bc.y)) / areaTriangleABC;
|
|
|
- double beta = ((ap.x * ac.y) - (ac.x * ap.y)) / areaTriangleABC;
|
|
|
- double gamma = 1 - alpha - beta;
|
|
|
+ if ((y2 - y1) != 0)
|
|
|
+ {
|
|
|
+ for (y = y1 ; y <= y2 ; y++)
|
|
|
+ {
|
|
|
+ int32_t xStart = x2 + (y - y2) * inverseSlope1;
|
|
|
+ int32_t xEnd = x0 + (y - y0) * inverseSlope2;
|
|
|
|
|
|
- ret.x = alpha;
|
|
|
- ret.y = beta;
|
|
|
- ret.z = gamma;
|
|
|
+ if (doZBuffer)
|
|
|
+ {
|
|
|
+ if (xEnd < xStart)
|
|
|
+ {
|
|
|
+ intSwap(&xStart, &xEnd);
|
|
|
+ }
|
|
|
+ for (x = xStart ; x <= xEnd ; x++)
|
|
|
+ {
|
|
|
+ drawZPixel(x, y, a, b, c,t->colour);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ drawHLine(xStart, y, xEnd, t->colour);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return ret;
|
|
|
}
|
|
|
|
|
|
+/* ----------------------------------- Textured triangles ----------------------------------- */
|
|
|
static void drawTexel(int32_t x, int32_t y, vec4_t a, vec4_t b, vec4_t c, tex2_t ta, tex2_t tb, tex2_t tc, colour_t *texture)
|
|
|
{
|
|
|
vec2_t pointP = { x, y };
|
|
@@ -144,21 +176,26 @@ static void drawTexel(int32_t x, int32_t y, vec4_t a, vec4_t b, vec4_t c, tex2_t
|
|
|
vec2_t b2 = vec2FromVec4(b);
|
|
|
vec2_t c2 = vec2FromVec4(c);
|
|
|
|
|
|
+ if ((x < 0) || (y < 0) || (x > windowWidth) ||(y > windowHeight))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
vec3_t weights = barycentricWeights(a2, b2, c2, pointP);
|
|
|
|
|
|
double alpha = weights.x;
|
|
|
double beta = weights.y;
|
|
|
double gamma = weights.z;
|
|
|
- double interpolatedU, interpolatedV;
|
|
|
+ double interpolatedU, interpolatedV, interpolatedReciprocalW;
|
|
|
int32_t texX, texY;
|
|
|
|
|
|
+ interpolatedReciprocalW = (1 / a.w) * alpha + (1 / b.w) * beta + (1 / c.w) * gamma;
|
|
|
+
|
|
|
if (doPerpectiveCorrection)
|
|
|
{
|
|
|
- double interpolatedReciprocalW;
|
|
|
-
|
|
|
interpolatedU = (ta.u / a.w) * alpha + (tb.u / b.w) * beta + (tc.u / c.w) * gamma;
|
|
|
interpolatedV = ((1 - ta.v) / a.w) * alpha + ((1 - tb.v) / b.w) * beta + ((1 - tc.v) / c.w) * gamma;
|
|
|
- interpolatedReciprocalW = (1 / a.w) * alpha + (1 / b.w) * beta + (1 / c.w) * gamma;
|
|
|
+
|
|
|
|
|
|
interpolatedU /= interpolatedReciprocalW;
|
|
|
interpolatedV /= interpolatedReciprocalW;
|
|
@@ -175,7 +212,22 @@ static void drawTexel(int32_t x, int32_t y, vec4_t a, vec4_t b, vec4_t c, tex2_t
|
|
|
texX = texX % textureWidth;
|
|
|
texY = texY % textureWidth;
|
|
|
|
|
|
- drawPixel(x, y, texture[(texY * textureWidth) + texX]);
|
|
|
+ if (doZBuffer)
|
|
|
+ {
|
|
|
+ /* Inverse to get logical W invrementing going further to us */
|
|
|
+ interpolatedReciprocalW = 1 - interpolatedReciprocalW;
|
|
|
+ if (interpolatedReciprocalW < zBuffer[(windowWidth * y) + x])
|
|
|
+ {
|
|
|
+ drawPixel(x, y, texture[(texY * textureWidth) + texX]);
|
|
|
+
|
|
|
+ /* Update Z Buffer */
|
|
|
+ zBuffer[(windowWidth * y) + x] = interpolatedReciprocalW;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ drawPixel(x, y, texture[(texY * textureWidth) + texX]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|