diff --git a/scripts/display.c b/scripts/display.c index d119ef2..1630ac2 100644 --- a/scripts/display.c +++ b/scripts/display.c @@ -71,17 +71,7 @@ void draw_rect(int x, int y, int width, int height, uint32_t color) { } } -void draw_triangle_old(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) { - draw_line(x0, y0, x1, y1, color); - draw_line(x1, y1, x2, y2, color); - draw_line(x2, y2, x0, y0, color); -} -void draw_triangle(triangle_t triangle, uint32_t color) { - draw_line(triangle.points[0].x, triangle.points[0].y, triangle.points[1].x, triangle.points[1].y, color); - draw_line(triangle.points[1].x, triangle.points[1].y, triangle.points[2].x, triangle.points[2].y, color); - draw_line(triangle.points[2].x, triangle.points[2].y, triangle.points[0].x, triangle.points[0].y, color); -} void draw_line(int x0, int y0, int x1, int y1, uint32_t color) { int delta_x = (x1 - x0); diff --git a/scripts/display.h b/scripts/display.h index fec1017..2bf885d 100644 --- a/scripts/display.h +++ b/scripts/display.h @@ -38,8 +38,6 @@ void draw_grid(void); void draw_pixel(int x, int y, uint32_t color); void draw_line(int x0, int y0, int x1, int y1, uint32_t color); void draw_rect(int x, int y, int width, int height, uint32_t color); -void draw_triangle(triangle_t triangle, uint32_t color); -void draw_triangle_old(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); void render_color_buffer(void); void clear_color_buffer(uint32_t color); void destroy_window(void); diff --git a/scripts/main.c b/scripts/main.c index d1f2397..fa0bf75 100644 --- a/scripts/main.c +++ b/scripts/main.c @@ -38,7 +38,7 @@ light_t light = { .direction = { .x = 0, .y = 0, .z = 1 }}; bool is_running = false; int cull_method = CULL_BACKFACE; -int render_method = RENDER_FILL_TRIANGLE; +int render_method = RENDER_TEXTURED; bool sort_faces = true; uint32_t previous_frame_time = 0; @@ -68,8 +68,8 @@ void setup(void) { texture_width = 64; // load cube mesh data - load_file("..\\assets\\f22.obj"); - //load_cube_mesh_data(); + //load_file("..\\assets\\f22.obj"); + load_cube_mesh_data(); } @@ -152,9 +152,9 @@ void update(void) { previous_frame_time = SDL_GetTicks(); - mesh.rotation.y += 0.01f; + //mesh.rotation.y += 0.01f; mesh.rotation.x -= 0.01f; - mesh.rotation.z += 0.01f; + //mesh.rotation.z += 0.01f; //mesh.translation.x += 0.004f; mesh.translation.z = 5.0f; @@ -334,10 +334,20 @@ void render(void) { draw_triangle(triangle, 0xff0000ff); break; case RENDER_TEXTURED: - //draw_textured_triangle(triangle, mesh_texture); + draw_textured_triangle( + triangle.points[0].x, triangle.points[0].y, triangle.texcoords[0].u, triangle.texcoords[0].v, // vertex A + triangle.points[1].x, triangle.points[1].y, triangle.texcoords[1].u, triangle.texcoords[1].v, // vertex B + triangle.points[2].x, triangle.points[2].y, triangle.texcoords[2].u, triangle.texcoords[2].v, // vertex C + mesh_texture + ); break; case RENDER_TEXTURED_LINE: - //draw_textured_triangle(triangle, mesh_texture); + draw_textured_triangle( + triangle.points[0].x, triangle.points[0].y, triangle.texcoords[0].u, triangle.texcoords[0].v, // vertex A + triangle.points[1].x, triangle.points[1].y, triangle.texcoords[1].u, triangle.texcoords[1].v, // vertex B + triangle.points[2].x, triangle.points[2].y, triangle.texcoords[2].u, triangle.texcoords[2].v, // vertex C + mesh_texture + ); draw_triangle(triangle, 0xff0000ff); default: break; diff --git a/scripts/mesh.c b/scripts/mesh.c index 9e4ff97..69ae2fc 100644 --- a/scripts/mesh.c +++ b/scripts/mesh.c @@ -29,23 +29,23 @@ vec3_t cube_vertices[N_CUBE_VERTICES] = { face_t cube_faces[N_CUBE_FACES] = { // front - { .a = 1, .b = 2, .c = 3, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = COLOR_ORANGE}, - { .a = 1, .b = 3, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = COLOR_ORANGE}, + { .a = 1, .b = 2, .c = 3, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, + { .a = 1, .b = 3, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, // right - { .a = 4, .b = 3, .c = 5, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = COLOR_TEAL_GREEN }, - { .a = 4, .b = 5, .c = 6, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = COLOR_TEAL_GREEN}, + { .a = 4, .b = 3, .c = 5, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, + { .a = 4, .b = 5, .c = 6, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, // back - { .a = 6, .b = 5, .c = 7, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = COLOR_RED }, - { .a = 6, .b = 7, .c = 8, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = COLOR_RED }, + { .a = 6, .b = 5, .c = 7, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, + { .a = 6, .b = 7, .c = 8, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, // left - { .a = 8, .b = 7, .c = 2, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = COLOR_PURPLE }, - { .a = 8, .b = 2, .c = 1, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = COLOR_PURPLE }, + { .a = 8, .b = 7, .c = 2, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, + { .a = 8, .b = 2, .c = 1, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, // top - { .a = 2, .b = 7, .c = 5, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = COLOR_GREY }, - { .a = 2, .b = 5, .c = 3, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = COLOR_GREY }, + { .a = 2, .b = 7, .c = 5, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, + { .a = 2, .b = 5, .c = 3, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, // bottom - { .a = 6, .b = 8, .c = 1, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = COLOR_LIGHT_GREEN_BLUE }, - { .a = 6, .b = 1, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = COLOR_LIGHT_GREEN_BLUE } + { .a = 6, .b = 8, .c = 1, .a_uv = { 0, 0 }, .b_uv = { 0, 1 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, + { .a = 6, .b = 1, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF } }; void load_cube_mesh_data(void) { diff --git a/scripts/triangle.c b/scripts/triangle.c index ce1ec68..2d8f4ff 100644 --- a/scripts/triangle.c +++ b/scripts/triangle.c @@ -24,6 +24,12 @@ uint32_t invert_rgb(uint32_t color) { return a | rgb; } +void draw_triangle(triangle_t triangle, uint32_t color) { + draw_line(triangle.points[0].x, triangle.points[0].y, triangle.points[1].x, triangle.points[1].y, color); + draw_line(triangle.points[1].x, triangle.points[1].y, triangle.points[2].x, triangle.points[2].y, color); + draw_line(triangle.points[2].x, triangle.points[2].y, triangle.points[0].x, triangle.points[0].y, color); +} + /////////////////////////////////////////////////////////////////////////////// // Draw a filled a triangle with a flat bottom /////////////////////////////////////////////////////////////////////////////// @@ -141,7 +147,60 @@ void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32 } } -void draw_textured_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t* texture) { +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_subtract(c, a); + vec2_t ab = vec2_subtract(b, a); + vec2_t ap = vec2_subtract(p, a); + vec2_t pc = vec2_subtract(c, p); + vec2_t pb = vec2_subtract(b, p); + + // Compute the area of the full parallegram/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 full parallelogram/triangle ABC + float beta = (ac.x * ap.y - ac.y * ap.x) / area_parallelogram_abc; + + // Weight gamma is easily found since barycentric coordinates always add up to 1.0 + float gamma = 1 - alpha - beta; + + vec3_t weights = { alpha, beta, gamma }; + return weights; +} +//////////////////////////// +// Function to draw textue at x/y using interpolation +void draw_texel( + int x, int y, uint32_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 U and V values using barycentric weights + 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)); + + draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]); + + +} + +void draw_textured_triangle( + int x0, int y0, float u0, float v0, + int x1, int y1, float u1, float v1, + int x2, int y2, float u2, float v2, + uint32_t* texture) { // sort by y int temp = 0, min_idx = 0, mid_idx = 1, max_idx = 2; @@ -159,21 +218,62 @@ void draw_textured_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint int_swap(&x0, &x1); } + // create vector points after sorting vertices + vec2_t point_a = { x0, y0 }; + vec2_t point_b = { x1, y1 }; + vec2_t point_c = { x2, y2 }; + + + // FLAT BOTTOM + float inv_slope_1 = 0; float inv_slope_2 = 0; - /*if (triangle.points[mid_idx].y - triangle.points[min_idx].y != 0) { - inv_slope_1 = (float)(triangle.points[mid_idx].x - triangle.points[min_idx].x) / fabsf(triangle.points[mid_idx].y - triangle.points[min_idx].y); + if (y1 - y0 != 0) inv_slope_1 = (float)(x1 - x0) / abs(y1 - y0); + if (y2 - y0 != 0) inv_slope_2 = (float)(x2 - x0) / abs(y2 - y0); + + if (y1 - y0 != 0) { + for (int y = y0; y <= y1; y++) { + int x_start = x1 + (y - y1) * inv_slope_1; + int x_end = x0 + (y - y0) * inv_slope_2; + + if (x_end < x_start) { + int_swap(&x_start, &x_end); + } + + for (int x = x_start; x < x_end; x++) { + // draw pixel with color from texture + //draw_pixel(x, y, (x % 2 == 0 && y % 2 == 0) ? 0xFF00FF00 : 0xFF000000); + draw_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2); + } + } } - if (triangle.points[max_idx].y - triangle.points[min_idx].y != 0) { - inv_slope_2 = (float)(triangle.points[max_idx].x - triangle.points[min_idx].x) / fabsf(triangle.points[max_idx].y - triangle.points[min_idx].y); + // FLAT TOP + inv_slope_1 = 0; + inv_slope_2 = 0; + + if (y2 - y1 != 0) inv_slope_1 = (float)(x2 - x1) / abs(y2 - y1); + if (y2 - y0 != 0) inv_slope_2 = (float)(x2 - x0) / abs(y2 - y0); + + if (y2 - y1 != 0) { + for (int y = y1; y <= y2; y++) { + int x_start = x1 + (y - y1) * inv_slope_1; + int x_end = x0 + (y - y0) * inv_slope_2; + + if (x_end < x_start) { + int_swap(&x_start, &x_end); + } + + for (int x = x_start; x < x_end; x++) { + // draw pixel with color from texture + //draw_pixel(x, y, (x % 2 == 0 && y % 2 == 0) ? 0xFF00FF00 : 0xFF000000); + draw_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2); + } + } } - for (int y = triangle.points[min_idx].y; y <= triangle.points[mid_idx].y; y++) { - //float x_start = triangle - } - */ + } \ No newline at end of file diff --git a/scripts/triangle.h b/scripts/triangle.h index 31371de..a687ab6 100644 --- a/scripts/triangle.h +++ b/scripts/triangle.h @@ -32,8 +32,16 @@ typedef struct { float average_depth; } triangle_t; +void draw_triangle(triangle_t triangle, uint32_t color); void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, color_t color); -void draw_textured_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t* texture); - +void draw_textured_triangle( + int x0, int y0, float u0, float v0, + int x1, int y1, float u1, float v1, + int x2, int y2, float u2, float v2, + uint32_t* texture); +void draw_texel( + int x, int y, uint32_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