diff --git a/src/main.c b/src/main.c index 732ea72..b7514d5 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include "vector.h" #include "light.h" #include "mesh.h" +#include "texture.h" #include "triangle.h" #include "array.h" #include "matrix.h" @@ -50,12 +51,16 @@ void setup(void){ float znear = 0.1; float zfar = 100.0; proj_matrix = mat4_make_perspective(fov, aspect, znear, zfar); - + + // Load the hardcoded texture data from the static array + mesh_texture = (uint32_t*)REDBRICK_TEXTURE; + texture_width = 64; + texture_height = 64; // Loads the cube values in the mesh data structure - //load_cube_mesh_data(); + load_cube_mesh_data(); //load_obj_file_data("./assets/f22.obj"); - load_obj_file_data("./assets/cube.obj"); + //load_obj_file_data("./assets/cube.obj"); } void process_input(void){ @@ -126,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; @@ -241,6 +246,11 @@ void update(void){ { projected_points[1].x, projected_points[1].y }, { projected_points[2].x, projected_points[2].y }, }, + .texcoords = { + { mesh_face.a_uv.u, mesh_face.a_uv.v }, + { mesh_face.b_uv.u, mesh_face.b_uv.v }, + { mesh_face.c_uv.u, mesh_face.c_uv.v } + }, // every triangle has a colour (as does each face) .color = triangle_color, .avg_depth = avg_depth @@ -282,12 +292,12 @@ 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, // vertex A - // triangle.points[1].x, triangle.points[1].y, // vertex B - // triangle.points[2].x, triangle.points[2].y, // vertex C - // triangle.color - //); + 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 + ); } diff --git a/src/matrix.h b/src/matrix.h index 18a0fea..9877210 100644 --- a/src/matrix.h +++ b/src/matrix.h @@ -2,8 +2,8 @@ // Created by tristan on 12/4/25. // -#ifndef INC_3DRENDERER_MATRIX_H -#define INC_3DRENDERER_MATRIX_H +#ifndef MATRIX_H +#define MATRIX_H #include "vector.h" #include "math.h" @@ -25,4 +25,4 @@ mat4_t mat4_make_perspective(float fov, float aspect, float znear, float zfar); mat4_t mat4_mul_mat4(mat4_t a, mat4_t b); vec4_t mat4_mul_vec4_project(mat4_t mat_proj, vec4_t v); -#endif //INC_3DRENDERER_MATRIX_H +#endif diff --git a/src/mesh.c b/src/mesh.c index 7aed05d..c8aef05 100644 --- a/src/mesh.c +++ b/src/mesh.c @@ -23,26 +23,25 @@ vec3_t cube_vertices[N_CUBE_VERTICES] = { { .x = -1, .y = -1, .z = 1 } // 8 }; - face_t cube_faces[N_CUBE_FACES] = { // front - { .a = 1, .b = 2, .c = 3, .color = 0xFFFFFFFF }, - { .a = 1, .b = 3, .c = 4, .color = 0xFFFFFFFF}, + { .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, .color = 0xFFFFFFFF}, - { .a = 4, .b = 5, .c = 6, .color = 0xFFFFFFFF }, + { .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, .color = 0xFFFFFFFF }, - { .a = 6, .b = 7, .c = 8, .color = 0xFFFFFFFF }, + { .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, .color = 0xFFFFFFFF }, - { .a = 8, .b = 2, .c = 1, .color = 0xFFFFFFFF }, + { .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, .color = 0xFFFFFFFF }, - { .a = 2, .b = 5, .c = 3, .color = 0xFFFFFFFF }, + { .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, .color = 0xFFFFFFFF }, - { .a = 6, .b = 1, .c = 4, .color = 0xFFFFFFFF } + { .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/src/swap.c b/src/swap.c new file mode 100644 index 0000000..8ef0bb3 --- /dev/null +++ b/src/swap.c @@ -0,0 +1,13 @@ +#include "swap.h" + +void int_swap(int *a, int *b) { + int tmp = *a; + *a = *b; + *b = tmp; +} + +void float_swap(float *a, float *b) { + float tmp = *a; + *a = *b; + *b = tmp; +} diff --git a/src/swap.h b/src/swap.h new file mode 100644 index 0000000..a8dc570 --- /dev/null +++ b/src/swap.h @@ -0,0 +1,7 @@ +#ifndef SWAP_H +#define SWAP_H + +void int_swap(int* a, int* b); +void float_swap(float* a, float* b); + +#endif diff --git a/src/texture.c b/src/texture.c index 4aa8f8a..60555c5 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/texture.h b/src/texture.h index 12d995b..2ef7554 100755 --- a/src/texture.h +++ b/src/texture.h @@ -1,6 +1,7 @@ #ifndef TEXTURE_H #define TEXTURE_H +#include #include typedef struct { @@ -13,4 +14,4 @@ extern int texture_height; extern uint32_t* mesh_texture; extern const uint8_t REDBRICK_TEXTURE[]; -#endif \ No newline at end of file +#endif diff --git a/src/triangle.c b/src/triangle.c index eeac3a8..668e40f 100644 --- a/src/triangle.c +++ b/src/triangle.c @@ -1,11 +1,6 @@ #include "triangle.h" #include "display.h" - -void int_swap(int *a, int *b) { - int tmp = *a; - *a = *b; - *b = tmp; -} +#include "swap.h" // Draw a filled triangle with a flat bottom void fill_flat_bottom_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color) { @@ -81,3 +76,109 @@ void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32 fill_flat_top_triangle(x1, y1, Mx, My, x2, y2, color); } } + +//////////////////////////////////////////////////////////////////////////////// +// 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 +//////////////////////////////////////////////////////////////////////////////// +// +// v0 +// /\ +// / \ +// / \ +// / \ +// v1-------v3 +// \_ \ +// \_ \ +// \_ \ +// \_ \ +// \_ \ +// \_ \ +// \_ \ +// \_ \ +// \\ +// \ +// v2 +//////////////////////////////////////////////////////////////////////////////// +// 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, + color_t* texture +) { + // We need to sort the vertices by y-coordinate asecnding (y0 < y1 < y2) + if (y0 > y1) { + int_swap(&y0, &y1); + int_swap(&x0, &x1); + float_swap(&u0, &u1); + float_swap(&v0, &v1); + } + + if (y1 > y2) { + int_swap(&y1, &y2); + int_swap(&x1, &x2); + float_swap(&u1, &u2); + float_swap(&v1, &v2); + } + + if (y0 > y1) { + int_swap(&y0, &y1); + int_swap(&x0, &x1); + float_swap(&u0, &u1); + float_swap(&v0, &v1); + } + + ////////////////////////////////////////////////////// + // Render the upper part of the triangle (flat-bottom) + ////////////////////////////////////////////////////// + float inv_slope_1 = 0; + float inv_slope_2 = 0; + + // first and second slope of triangle legs + 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); // swap if x_start is to the right of x_end + } + + 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); + } + } + } + + + ////////////////////////////////////////////////////// + // Render the upper part of the triangle (flat-bottom) + ////////////////////////////////////////////////////// + inv_slope_1 = 0; + inv_slope_2 = 0; + + // first and second slope of triangle legs + 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); // swap if x_start is to the right of x_end + } + + 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); + } + } + } +} diff --git a/src/triangle.h b/src/triangle.h index 094f9ab..0403db1 100644 --- a/src/triangle.h +++ b/src/triangle.h @@ -25,6 +25,12 @@ 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, + color_t* texture + ); // TODO: void draw_textured_triangle(...);