added functionality for textured flat-bottom/top triangles

This commit is contained in:
natsirt867
2025-12-29 23:05:30 -06:00
parent abf9f42715
commit 689bcb3ee7
9 changed files with 172 additions and 35 deletions

View File

@@ -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"
@@ -51,11 +52,15 @@ void setup(void){
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
);
}

View File

@@ -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

View File

@@ -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) {

13
src/swap.c Normal file
View File

@@ -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;
}

7
src/swap.h Normal file
View File

@@ -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

View File

@@ -1,6 +1,7 @@
#ifndef TEXTURE_H
#define TEXTURE_H
#include <stdio.h>
#include <stdint.h>
typedef struct {

View File

@@ -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);
}
}
}
}

View File

@@ -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(...);