From 0701b9b3032ee1197cac8eface3639a5d6a646fd Mon Sep 17 00:00:00 2001 From: natsirt867 Date: Thu, 1 Jan 2026 16:29:17 -0600 Subject: [PATCH] added texture mapping functionality --- src/main.c | 2 +- src/texture.c | 2 +- src/triangle.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++--- src/triangle.h | 6 +++- 4 files changed, 89 insertions(+), 7 deletions(-) diff --git a/src/main.c b/src/main.c index b7514d5..cea89c7 100644 --- a/src/main.c +++ b/src/main.c @@ -223,7 +223,7 @@ void update(void){ projected_points[j].y *= (window_height / 2.0); // Invert the y values to account for flipped screen y coordinates - projected_points[j].y *= -1; + //projected_points[j].y *= -1; // translate the projected points to the middle of the screen projected_points[j].x += (window_width / 2.0); diff --git a/src/texture.c b/src/texture.c index 60555c5..4aa8f8a 100755 --- a/src/texture.c +++ b/src/texture.c @@ -70,4 +70,4 @@ const uint8_t REDBRICK_TEXTURE[] = { 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x48, 0x48, 0x48, 0xff, 0x54, 0x54, 0x54, 0xff, 0x48, 0x48, 0x48, 0xff, 0x38, 0x38, 0x38, 0xff, 0x34, 0x34, 0x34, 0xff, 0x34, 0x34, 0x34, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x38, 0x38, 0x38, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x20, 0x20, 0x20, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x2c, 0x2c, 0x2c, 0xff, 0x38, 0x38, 0x38, 0xff, 0x54, 0x54, 0x54, 0xff, 0x38, 0x38, 0x38, 0xff, 0x54, 0x54, 0x54, 0xff, 0x38, 0x38, 0x38, 0xff, 0x38, 0x38, 0x38, 0xff, 0x38, 0x38, 0x38, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x38, 0x38, 0x38, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x54, 0x54, 0x54, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x54, 0x54, 0x54, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x38, 0x38, 0x38, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x40, 0x40, 0x40, 0xff, 0x38, 0x38, 0x38, 0xff, 0x38, 0x38, 0x38, 0xff, 0x40, 0x40, 0x40, 0xff, 0x38, 0x38, 0x38, 0xff, 0x38, 0x38, 0x38, 0xff, 0x40, 0x40, 0x40, 0xff, 0x48, 0x48, 0x48, 0xff, 0x40, 0x40, 0x40, 0xff, 0x38, 0x38, 0x38, 0xff, 0x40, 0x40, 0x40, 0xff, 0x54, 0x54, 0x54, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x38, 0x38, 0x38, 0xff, 0x54, 0x54, 0x54, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x40, 0x40, 0x40, 0xff, 0x38, 0x38, 0x38, 0xff, 0x40, 0x40, 0x40, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x48, 0x48, 0x48, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, 0x54, 0x54, 0x54, 0xff, -}; +}; \ No newline at end of file diff --git a/src/triangle.c b/src/triangle.c index 668e40f..876dac3 100644 --- a/src/triangle.c +++ b/src/triangle.c @@ -1,5 +1,6 @@ #include "triangle.h" #include "display.h" +#include "vector.h" #include "swap.h" // Draw a filled triangle with a flat bottom @@ -77,6 +78,78 @@ void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32 } } +//////////////////////////////////////////////////////////////////////////////// +// Return the barycentric weights alpha, beta and gamma for point p +//////////////////////////////////////////////////////////////////////////////// +// +// B +// /|\ +// / | \ +// / | \ +// / (p) \ +// / / \ \ +// / / \ \ +// A-------------C +// +//////////////////////////////////////////////////////////////////////////////// +vec3_t barycentric_weights(vec2_t a, vec2_t b, vec2_t c, vec2_t p) { + // Find the vectors between the vertices ABC and point p + vec2_t ac = vec2_sub(c, a); + vec2_t ab = vec2_sub(b, a); + vec2_t ap = vec2_sub(p, a); + vec2_t pc = vec2_sub(c, p); + vec2_t pb = vec2_sub(b, p); + + // Compute the area of the full paralellogram / triangle ABC using 2D cross product + float area_parallelogram_abc = (ac.x * ab.y - ac.y * ab.x); // || AC x AB || + + // Alpha is the area of the small parallelogram / triangle PBC divided by the area of the full parallelogram / triangle ABC + float alpha = (pc.x * pb.y - pc.y * pb.x) / area_parallelogram_abc; + + // Beta is the area of the small parallelogram / triangle APC divided by the area of the ufll parallelogram / triangle ABC + float beta = (ac.x * ap.y - ac.y * ap.x) / area_parallelogram_abc; + + // Gamma is found by taking 1 - alpha - beta since barycentric normalized coordinates always add up to 1.0 + float gamma = 1 - alpha - beta; + + vec3_t weights = { alpha, beta, gamma }; + return weights; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Function to draw the textured pixel at position x and y using interpoation +//////////////////////////////////////////////////////////////////////////////// +void draw_texel( + int x, int y, color_t* texture, + vec2_t point_a, vec2_t point_b, vec2_t point_c, + float u0, float v0, float u1, float v1, float u2, float v2 +) { + vec2_t point_p = { x, y }; + + vec3_t weights = barycentric_weights(point_a, point_b, point_c, point_p); + + float alpha = weights.x; + float beta = weights.y; + float gamma = weights.z; + + // Perform the interpolation of all the U and V values using barycentric weights (coords) + float interpolated_u = (u0 * alpha) + (u1 * beta) + (u2 * gamma); + float interpolated_v = (v0 * alpha) + (v1 * beta) + (v2 * gamma); + + // Map the UV coordinate to the full texture width and height + int tex_x = abs((int)(interpolated_u * texture_width)); + int tex_y = abs((int)(interpolated_v * texture_height)); + + // TODO: figure out elegant way for stopping the values of tex_x and tex_y if outside bounds of array to prevent a buffer overflow in the texture[] array + if ((texture_width * tex_y) + tex_x >= 0 && (texture_width * tex_y) + tex_x < (texture_width * texture_height)) { + draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]); + } else { + //draw_pixel(x, y, 0xFFFFFFFF); + } +} + + //////////////////////////////////////////////////////////////////////////////// // Draw a textured triangle with the flat-top/flat-bottom method // We split the original triangle in two, half flat-bottom and half flat-top @@ -107,7 +180,7 @@ void draw_textured_triangle( int x2, int y2, float u2, float v2, color_t* texture ) { - // We need to sort the vertices by y-coordinate asecnding (y0 < y1 < y2) + // We need to sort the vertices by y-coordinate ascending (y0 < y1 < y2) if (y0 > y1) { int_swap(&y0, &y1); int_swap(&x0, &x1); @@ -129,6 +202,11 @@ void draw_textured_triangle( float_swap(&v0, &v1); } + // Create vector points after we sort the vertices + vec2_t point_a = { x0, y0 }; + vec2_t point_b = { x1, y1 }; + vec2_t point_c = { x2, y2 }; + ////////////////////////////////////////////////////// // Render the upper part of the triangle (flat-bottom) ////////////////////////////////////////////////////// @@ -150,14 +228,14 @@ void draw_textured_triangle( for (int x = x_start; x < x_end; x++) { // Draw our pixel with the color that comes from the texture - draw_pixel(x, y, 0xFFFF00FF); + draw_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2); } } } ////////////////////////////////////////////////////// - // Render the upper part of the triangle (flat-bottom) + // Render the bottom part of the triangle (flat-top) ////////////////////////////////////////////////////// inv_slope_1 = 0; inv_slope_2 = 0; @@ -177,7 +255,7 @@ void draw_textured_triangle( for (int x = x_start; x < x_end; x++) { // Draw our pixel with the color that comes from the texture - draw_pixel(x, y, 0xFFFF00FF); + draw_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2); } } } diff --git a/src/triangle.h b/src/triangle.h index 0403db1..586fa96 100644 --- a/src/triangle.h +++ b/src/triangle.h @@ -32,6 +32,10 @@ void draw_textured_triangle( color_t* texture ); -// TODO: void draw_textured_triangle(...); +void draw_texel( + int x, int y, color_t* texture, + vec2_t point_a, vec2_t point_b, vec2_t point_c, + float u0, float v0, float u1, float v1, float u2, float v2 +); #endif