diff --git a/src/main.c b/src/main.c index cea89c7..c53a2f4 100644 --- a/src/main.c +++ b/src/main.c @@ -131,8 +131,8 @@ void update(void){ // Change the mesh scale/rotation values per animation frame mesh.rotation.x += 0.01; - //mesh.rotation.y += 0.01; - //mesh.rotation.z += 0.01; + mesh.rotation.y += 0.01; + mesh.rotation.z += 0.01; //mesh.scale.x += 0.01; //mesh.scale.y += 0.01; @@ -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); @@ -242,9 +242,9 @@ void update(void){ triangle_t projected_triangle = { .points = { - { projected_points[0].x, projected_points[0].y,}, - { projected_points[1].x, projected_points[1].y }, - { projected_points[2].x, projected_points[2].y }, + { projected_points[0].x, projected_points[0].y, projected_points[0].z, projected_points[0].w }, + { projected_points[1].x, projected_points[1].y, projected_points[1].z, projected_points[1].w }, + { projected_points[2].x, projected_points[2].y, projected_points[2].z, projected_points[2].w }, }, .texcoords = { { mesh_face.a_uv.u, mesh_face.a_uv.v }, @@ -261,7 +261,7 @@ void update(void){ array_push(triangles_to_render, projected_triangle); } - // sort avg_depth of triangle faces for all z vertexs per triangle + // sort avg_depth of triangle faces for all z vertices per triangle // painters algorithm avg_depth_bubble_sort(triangles_to_render, array_length(triangles_to_render)); /*for (int t = 0; t < array_length(triangles_to_render); t++) { @@ -293,9 +293,9 @@ void render(void){ // Draw textured triangle if (render_method == RENDER_TEXTURED || render_method == RENDER_TEXTURED_WIRE) { 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 + triangle.points[0].x, triangle.points[0].y, triangle.points[0].z, triangle.points[0].w, triangle.texcoords[0].u, triangle.texcoords[0].v, // vertex A + triangle.points[1].x, triangle.points[1].y, triangle.points[1].z, triangle.points[1].w, triangle.texcoords[1].u, triangle.texcoords[1].v, // vertex B + triangle.points[2].x, triangle.points[2].y, triangle.points[2].z, triangle.points[2].w, triangle.texcoords[2].u, triangle.texcoords[2].v, // vertex C mesh_texture ); diff --git a/src/mesh.c b/src/mesh.c index c8aef05..d06c3f3 100644 --- a/src/mesh.c +++ b/src/mesh.c @@ -25,23 +25,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 = 0xFFFFFFFF }, - { .a = 1, .b = 3, .c = 4, .a_uv = { 0, 0 }, .b_uv = { 1, 1 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 1, .b = 2, .c = 3, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 1, .b = 3, .c = 4, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, // right - { .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 }, + { .a = 4, .b = 3, .c = 5, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 4, .b = 5, .c = 6, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, // back - { .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 }, + { .a = 6, .b = 5, .c = 7, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 6, .b = 7, .c = 8, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, // left - { .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 }, + { .a = 8, .b = 7, .c = 2, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 8, .b = 2, .c = 1, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, // top - { .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 }, + { .a = 2, .b = 7, .c = 5, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 2, .b = 5, .c = 3, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF }, // bottom - { .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 } + { .a = 6, .b = 8, .c = 1, .a_uv = { 0, 1 }, .b_uv = { 0, 0 }, .c_uv = { 1, 0 }, .color = 0xFFFFFFFF }, + { .a = 6, .b = 1, .c = 4, .a_uv = { 0, 1 }, .b_uv = { 1, 0 }, .c_uv = { 1, 1 }, .color = 0xFFFFFFFF } }; void load_cube_mesh_data(void) { diff --git a/src/triangle.c b/src/triangle.c index 876dac3..82c2335 100644 --- a/src/triangle.c +++ b/src/triangle.c @@ -122,26 +122,43 @@ vec3_t barycentric_weights(vec2_t a, vec2_t b, vec2_t c, vec2_t p) { //////////////////////////////////////////////////////////////////////////////// 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 + vec4_t point_a, vec4_t point_b, vec4_t point_c, + tex2_t a_uv, tex2_t b_uv, tex2_t c_uv ) { - vec2_t point_p = { x, y }; + vec2_t p = { x, y }; + vec2_t a = vec2_from_vec4(point_a); + vec2_t b = vec2_from_vec4(point_b); + vec2_t c = vec2_from_vec4(point_c); - vec3_t weights = barycentric_weights(point_a, point_b, point_c, point_p); + vec3_t weights = barycentric_weights(a, b, c, 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); + + // Variables to store the interpolated values of U, V, and also W for the current pixel + float interpolated_u; + float interpolated_v; + float interpolated_reciprocal_w; + + // Perform the interpolation of all the U/w and V/w values using barycentric weights (coords) and a factor of 1/w (recpirocal) + interpolated_u = (a_uv.u / point_a.w) * alpha + (b_uv.u / point_b.w) * beta + (c_uv.u / point_c.w) * gamma; + interpolated_v = (a_uv.v / point_a.w) * alpha + (b_uv.v / point_b.w) * beta + (c_uv.v / point_c.w) * gamma; + + // TODO: Could move outside of of function for performance increase, heavy to caclulate every pixel + // Also interpolate the value of 1/w for the current pixel + interpolated_reciprocal_w = (1 / point_a.w) * alpha + (1 / point_b.w) * beta + (1 / point_c.w) * gamma; + + // Divide back both interpolated values by 1/w + interpolated_u /= interpolated_reciprocal_w; + interpolated_v /= interpolated_reciprocal_w; // 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)); + int tex_x = abs((int)(interpolated_u * texture_width)) % texture_width; + int tex_y = abs((int)(interpolated_v * texture_height)) % 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 + // perhaps modulo operator above? (interpolated_u * texture width) % texture_width to wrap coordinates to valid ranges (for height also)? 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 { @@ -175,15 +192,17 @@ void draw_texel( //////////////////////////////////////////////////////////////////////////////// // TODO: use color_t type or uint32_t type? 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, + int x0, int y0, float z0, float w0, float u0, float v0, + int x1, int y1, float z1, float w1, float u1, float v1, + int x2, int y2, float z2, float w2, float u2, float v2, color_t* texture ) { // We need to sort the vertices by y-coordinate ascending (y0 < y1 < y2) if (y0 > y1) { int_swap(&y0, &y1); int_swap(&x0, &x1); + float_swap(&z0, &z1); + float_swap(&w0, &w1); float_swap(&u0, &u1); float_swap(&v0, &v1); } @@ -191,6 +210,8 @@ void draw_textured_triangle( if (y1 > y2) { int_swap(&y1, &y2); int_swap(&x1, &x2); + float_swap(&z1, &z2); + float_swap(&w1, &w2); float_swap(&u1, &u2); float_swap(&v1, &v2); } @@ -198,14 +219,19 @@ void draw_textured_triangle( if (y0 > y1) { int_swap(&y0, &y1); int_swap(&x0, &x1); + float_swap(&z0, &z1); + float_swap(&w0, &w1); float_swap(&u0, &u1); 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 }; + // Create vector points and texture coords after we sort the vertices + vec4_t point_a = { x0, y0, z0, w0 }; + vec4_t point_b = { x1, y1, z1, w1 }; + vec4_t point_c = { x2, y2, z2, w2 }; + tex2_t a_uv = { u0, v0 }; + tex2_t b_uv = { u1, v1 }; + tex2_t c_uv = { u2, v2 }; ////////////////////////////////////////////////////// // Render the upper part of the triangle (flat-bottom) @@ -228,7 +254,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_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2); + draw_texel(x, y, texture, point_a, point_b, point_c, a_uv, b_uv, c_uv); } } } @@ -255,7 +281,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_texel(x, y, texture, point_a, point_b, point_c, u0, v0, u1, v1, u2, v2); + draw_texel(x, y, texture, point_a, point_b, point_c, a_uv, b_uv, c_uv); } } } diff --git a/src/triangle.h b/src/triangle.h index 586fa96..6e51c5f 100644 --- a/src/triangle.h +++ b/src/triangle.h @@ -17,7 +17,7 @@ typedef struct { } face_t; typedef struct { - vec2_t points[3]; + vec4_t points[3]; tex2_t texcoords[3]; color_t color; float avg_depth; @@ -26,16 +26,16 @@ typedef struct { void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); void draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); 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, + int x0, int y0, float z0, float w0, float u0, float v0, + int x1, int y1, float z1, float w1, float u1, float v1, + int x2, int y2, float z2, float w2, float u2, float v2, color_t* texture ); 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 + vec4_t point_a, vec4_t point_b, vec4_t point_c, + tex2_t a_uv, tex2_t b_uv, tex2_t c_uv ); #endif diff --git a/src/vector.c b/src/vector.c index 4fdec26..ec9f989 100644 --- a/src/vector.c +++ b/src/vector.c @@ -168,6 +168,11 @@ vec3_t vec3_from_vec4(vec4_t v) { return result; } +vec2_t vec2_from_vec4(vec4_t v) { + vec2_t result = { v.x, v.y }; + return result; +} + /* vec3_t cube_vertice[8] = { diff --git a/src/vector.h b/src/vector.h index 5c32ad0..a2134b4 100644 --- a/src/vector.h +++ b/src/vector.h @@ -48,4 +48,6 @@ void vec3_normalize(vec3_t* v); //////////////////////////////////////////////////////////////////////////////// vec4_t vec4_from_vec3(vec3_t v); vec3_t vec3_from_vec4(vec4_t v); +vec2_t vec2_from_vec4(vec4_t v); + #endif