From 541c4dec446cccb946b95b3f47404a6586d09a85 Mon Sep 17 00:00:00 2001 From: jb Date: Sat, 26 Jul 2025 20:04:50 -0700 Subject: [PATCH] nuclear option --- scripts/array.c | 6 +- scripts/array.h | 2 +- scripts/display.c | 35 ++-- scripts/display.h | 38 ++--- scripts/light.c | 27 ++- scripts/light.h | 5 +- scripts/main.c | 401 ++++++++++++++++++++------------------------- scripts/main.cpp | 41 ----- scripts/main_old.c | 172 ------------------- scripts/matrix.c | 160 +++++++++--------- scripts/matrix.h | 18 +- scripts/mesh.c | 88 ++++------ scripts/mesh.h | 39 ++--- scripts/swap.h | 7 +- scripts/texture.c | 2 +- scripts/texture.h | 2 +- scripts/triangle.c | 191 ++++++++++++--------- scripts/triangle.h | 36 ++-- scripts/vector.c | 191 +++++++++++---------- scripts/vector.h | 52 +++--- 20 files changed, 626 insertions(+), 887 deletions(-) delete mode 100644 scripts/main.cpp delete mode 100644 scripts/main_old.c diff --git a/scripts/array.c b/scripts/array.c index 8d05d07..34c87ae 100644 --- a/scripts/array.c +++ b/scripts/array.c @@ -18,8 +18,8 @@ void* array_hold(void* array, int count, int item_size) { return array; } else { int needed_size = ARRAY_OCCUPIED(array) + count; - int double_curr = ARRAY_CAPACITY(array) * 2; - int capacity = needed_size > double_curr ? needed_size : double_curr; + int float_curr = ARRAY_CAPACITY(array) * 2; + int capacity = needed_size > float_curr ? needed_size : float_curr; int occupied = needed_size; int raw_size = sizeof(int) * 2 + item_size * capacity; int* base = (int*)realloc(ARRAY_RAW_DATA(array), raw_size); @@ -37,4 +37,4 @@ void array_free(void* array) { if (array != NULL) { free(ARRAY_RAW_DATA(array)); } -} \ No newline at end of file +} diff --git a/scripts/array.h b/scripts/array.h index 4b44afb..cad327f 100644 --- a/scripts/array.h +++ b/scripts/array.h @@ -11,4 +11,4 @@ void* array_hold(void* array, int count, int item_size); int array_length(void* array); void array_free(void* array); -#endif \ No newline at end of file +#endif diff --git a/scripts/display.c b/scripts/display.c index 1630ac2..49afbb4 100644 --- a/scripts/display.c +++ b/scripts/display.c @@ -1,9 +1,5 @@ -#include "display.h" - -#include #include -#include "triangle.h" - +#include "display.h" SDL_Window* window = NULL; SDL_Renderer* renderer = NULL; uint32_t* color_buffer = NULL; @@ -20,8 +16,8 @@ bool initialize_window(void) { // Set width and height of the SDL window with the max screen resolution SDL_DisplayMode display_mode; SDL_GetCurrentDisplayMode(0, &display_mode); - window_width = 800;//display_mode.w; - window_height = 800;//display_mode.h; + window_width = display_mode.w; + window_height = display_mode.h; // Create a SDL Window window = SDL_CreateWindow( @@ -30,7 +26,7 @@ bool initialize_window(void) { SDL_WINDOWPOS_CENTERED, window_width, window_height, - 0//SDL_WINDOW_BORDERLESS + SDL_WINDOW_BORDERLESS ); if (!window) { fprintf(stderr, "Error creating SDL window.\n"); @@ -61,23 +57,11 @@ void draw_pixel(int x, int y, uint32_t color) { } } -void draw_rect(int x, int y, int width, int height, uint32_t color) { - for (int i = 0; i < width; i++) { - for (int j = 0; j < height; j++) { - int current_x = x + i; - int current_y = y + j; - draw_pixel(current_x, current_y, color); - } - } -} - - - void draw_line(int x0, int y0, int x1, int y1, uint32_t color) { int delta_x = (x1 - x0); int delta_y = (y1 - y0); - int longest_side_length = abs(delta_x) > abs(delta_y) ? abs(delta_x) : abs(delta_y); + int longest_side_length = (abs(delta_x) >= abs(delta_y)) ? abs(delta_x) : abs(delta_y); float x_inc = delta_x / (float)longest_side_length; float y_inc = delta_y / (float)longest_side_length; @@ -90,7 +74,16 @@ void draw_line(int x0, int y0, int x1, int y1, uint32_t color) { current_x += x_inc; current_y += y_inc; } +} +void draw_rect(int x, int y, int width, int height, uint32_t color) { + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + int current_x = x + i; + int current_y = y + j; + draw_pixel(current_x, current_y, color); + } + } } void render_color_buffer(void) { diff --git a/scripts/display.h b/scripts/display.h index 2bf885d..e4bb7e2 100644 --- a/scripts/display.h +++ b/scripts/display.h @@ -5,11 +5,23 @@ #include #include -#include "triangle.h" - -#define FPS 30 +#define FPS 60 #define FRAME_TARGET_TIME (1000 / FPS) +enum cull_method { + CULL_NONE, + CULL_BACKFACE +}; + +enum render_method { + RENDER_WIRE, + RENDER_WIRE_VERTEX, + RENDER_FILL_TRIANGLE, + RENDER_FILL_TRIANGLE_WIRE, + RENDER_TEXTURED, + RENDER_TEXTURED_WIRE +}; + extern SDL_Window* window; extern SDL_Renderer* renderer; extern uint32_t* color_buffer; @@ -17,28 +29,12 @@ extern SDL_Texture* color_buffer_texture; extern int window_width; extern int window_height; -enum render_methods { - RENDER_WIRE_VERTEX, - RENDER_WIRE, - RENDER_FILL_TRIANGLE, - RENDER_FILL_TRIANGLE_LINE, - RENDER_TEXTURED, - RENDER_TEXTURED_LINE, -}; - -enum cull_methods { - CULL_NONE, - CULL_BACKFACE, -}; - -typedef uint32_t color_t; - -bool initialize_window(void); +bool initialize_window(void); 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 render_color_buffer(void); +void render_color_buffer(void); void clear_color_buffer(uint32_t color); void destroy_window(void); diff --git a/scripts/light.c b/scripts/light.c index 617a585..e39b88c 100644 --- a/scripts/light.c +++ b/scripts/light.c @@ -1,13 +1,22 @@ -#include +#include "light.h" -uint32_t light_apply_intensity(uint32_t original_color, float p) { - if (p < 0) p = 0; - if (p > 1) p = 1; +light_t light = { + .direction = { 0, 0, 1 } +}; + +/////////////////////////////////////////////////////////////////////////////// +// Change color based on a percentage factor to represent light intensity +/////////////////////////////////////////////////////////////////////////////// +uint32_t light_apply_intensity(uint32_t original_color, float percentage_factor) { + if (percentage_factor < 0) percentage_factor = 0; + if (percentage_factor > 1) percentage_factor = 1; uint32_t a = (original_color & 0xFF000000); - uint32_t r = (original_color & 0x00FF0000) * p; - uint32_t g = (original_color & 0x0000FF00) * p; - uint32_t b = (original_color & 0x000000FF) * p; + uint32_t r = (original_color & 0x00FF0000) * percentage_factor; + uint32_t g = (original_color & 0x0000FF00) * percentage_factor; + uint32_t b = (original_color & 0x000000FF) * percentage_factor; - return (a | (r & 0x00FF0000) | (g & 0x0000FF00) | (b & 0x000000FF)); -} \ No newline at end of file + uint32_t new_color = a | (r & 0x00FF0000) | (g & 0x0000FF00) | (b & 0x000000FF); + + return new_color; +} diff --git a/scripts/light.h b/scripts/light.h index 9e914ae..e57af24 100644 --- a/scripts/light.h +++ b/scripts/light.h @@ -8,7 +8,8 @@ typedef struct { vec3_t direction; } light_t; -uint32_t light_apply_intensity(uint32_t original_color, float p); +extern light_t light; + +uint32_t light_apply_intensity(uint32_t original_color, float percentage_factor); #endif - diff --git a/scripts/main.c b/scripts/main.c index fa0bf75..1b3f19f 100644 --- a/scripts/main.c +++ b/scripts/main.c @@ -1,51 +1,40 @@ #include #include #include -#include #include -#include "display.h" -#include "mesh.h" -#include "vector.h" #include "array.h" +#include "display.h" +#include "vector.h" #include "matrix.h" #include "light.h" +#include "triangle.h" #include "texture.h" +#include "mesh.h" -#define STEP 0.075 - -uint32_t colors[12] = { - 0xFF6A2EFF, // purple - 0xFFE9C46A, // sand yellow - 0xFF2A9D8F, // teal green - 0xFFF4A261, // orange - 0xFF264653, // dark blue-grey - 0xFFB5838D, // mauve - 0xFFD7263D, // red - 0xFF38A3A5, // turquoise - 0xFF757575, // grey - 0xFF70C1B3, // light green-blue - 0xFFFFC300, // yellow - 0xFF5D2E8C // deep purple -}; - -triangle_t* triangles_to_render = NULL; //[N_MESH_FACES]; - -vec3_t camera_position = { 0, 0, 0 }; - -mat4_t proj_matrix; -light_t light = { .direction = { .x = 0, .y = 0, .z = 1 }}; - +/////////////////////////////////////////////////////////////////////////////// +// Array of triangles that should be rendered frame by frame +/////////////////////////////////////////////////////////////////////////////// +triangle_t* triangles_to_render = NULL; +int render_method, cull_method; +/////////////////////////////////////////////////////////////////////////////// +// Global variables for execution status and game loop +/////////////////////////////////////////////////////////////////////////////// bool is_running = false; +int previous_frame_time = 0; -int cull_method = CULL_BACKFACE; -int render_method = RENDER_TEXTURED; -bool sort_faces = true; - -uint32_t previous_frame_time = 0; +vec3_t camera_position = { .x = 0, .y = 0, .z = 0 }; +mat4_t proj_matrix; +/////////////////////////////////////////////////////////////////////////////// +// Setup function to initialize variables and game objects +/////////////////////////////////////////////////////////////////////////////// void setup(void) { + // Initialize render mode and triangle culling method + render_method = RENDER_TEXTURED_WIRE; + cull_method = CULL_BACKFACE; + // Allocate the required memory in bytes to hold the color buffer - color_buffer = (uint32_t*) malloc(sizeof(uint32_t) * window_width * window_height); + color_buffer = (uint32_t*)malloc(sizeof(uint32_t) * window_width * window_height); // Creating a SDL texture that is used to display the color buffer color_buffer_texture = SDL_CreateTexture( @@ -56,27 +45,29 @@ void setup(void) { window_height ); - float fov = M_PI / 3; + // Initialize the perspective projection matrix + float fov = M_PI / 3.0; // the same as 180/3, or 60deg float aspect = (float)window_height / (float)window_width; - float znear = 0.0f; - float zfar = 100.0f; - + float znear = 0.1; + float zfar = 100.0; proj_matrix = mat4_make_perspective(fov, aspect, znear, zfar); + // Manually load the hardcoded texture data from the static array mesh_texture = (uint32_t*)REDBRICK_TEXTURE; - texture_height = 64; texture_width = 64; + texture_height = 64; - // load cube mesh data - //load_file("..\\assets\\f22.obj"); + // Loads the vertex and face values for the mesh data structure load_cube_mesh_data(); - + // load_obj_file_data("./assets/f22.obj"); } +/////////////////////////////////////////////////////////////////////////////// +// Poll system events and handle keyboard input +/////////////////////////////////////////////////////////////////////////////// void process_input(void) { SDL_Event event; SDL_PollEvent(&event); - switch (event.type) { case SDL_QUIT: is_running = false; @@ -84,106 +75,57 @@ void process_input(void) { case SDL_KEYDOWN: if (event.key.keysym.sym == SDLK_ESCAPE) is_running = false; - //break; - if (event.key.keysym.sym == SDLK_UP) - mesh.rotation.z += STEP; - if (event.key.keysym.sym == SDLK_LEFT) - mesh.rotation.x += STEP; - if (event.key.keysym.sym == SDLK_RIGHT) - mesh.rotation.y += STEP; - break; - case SDL_KEYUP: - SDL_Keycode key = event.key.keysym.sym; - if (key == SDLK_c) { - cull_method = !cull_method; - } - - if (key == SDLK_s) { - sort_faces = !sort_faces; - } - - if (key == SDLK_1) { + if (event.key.keysym.sym == SDLK_1) render_method = RENDER_WIRE_VERTEX; - } - if (key == SDLK_2) { + if (event.key.keysym.sym == SDLK_2) render_method = RENDER_WIRE; - } - if (key == SDLK_3) { + if (event.key.keysym.sym == SDLK_3) render_method = RENDER_FILL_TRIANGLE; - } - if (key == SDLK_4) { - render_method = RENDER_FILL_TRIANGLE_LINE; - } - if (key == SDLK_5) { + if (event.key.keysym.sym == SDLK_4) + render_method = RENDER_FILL_TRIANGLE_WIRE; + if (event.key.keysym.sym == SDLK_5) render_method = RENDER_TEXTURED; - } - if (key == SDLK_6) { - render_method = RENDER_TEXTURED_LINE; - } - + if (event.key.keysym.sym == SDLK_6) + render_method = RENDER_TEXTURED_WIRE; + if (event.key.keysym.sym == SDLK_c) + cull_method = CULL_BACKFACE; + if (event.key.keysym.sym == SDLK_d) + cull_method = CULL_NONE; break; - - - } } -//////////////////////////////////////////////////////////////////////////////// -// Function that receives a 3D vector and returns a projected 2D point -//////////////////////////////////////////////////////////////////////////////// -vec2_t project(vec3_t point) { - float fov_factor = 1; // placeholder - vec2_t projected_point = { - .x = roundf((fov_factor * point.x) / point.z), - .y = roundf((fov_factor * point.y) / point.z), - }; - return projected_point; -} - +/////////////////////////////////////////////////////////////////////////////// +// Update function frame by frame with a fixed time step +/////////////////////////////////////////////////////////////////////////////// void update(void) { - //while (!SDL_TICKS_PASSED(SDL_GetTicks(), previous_frame_time + FRAME_TARGET_TIME)); - + // Wait some time until the reach the target frame time in milliseconds int time_to_wait = FRAME_TARGET_TIME - (SDL_GetTicks() - previous_frame_time); - // only delay execution if we are running too fast + // Only delay execution if we are running too fast if (time_to_wait > 0 && time_to_wait <= FRAME_TARGET_TIME) { SDL_Delay(time_to_wait); } previous_frame_time = SDL_GetTicks(); - //mesh.rotation.y += 0.01f; - mesh.rotation.x -= 0.01f; - //mesh.rotation.z += 0.01f; + // Initialize the array of triangles to render + triangles_to_render = NULL; - //mesh.translation.x += 0.004f; - mesh.translation.z = 5.0f; + // Change the mesh scale, rotation, and translation values per animation frame + mesh.rotation.x += 0.000; + mesh.rotation.y += 0.003; + mesh.rotation.z += 0.000; + mesh.translation.z = 5.0; - //mesh.scale.x += 0.002f; - //mesh.scale.y += 0.002f; - - // create scale matrix that will be used + // Create scale, rotation, and translation matrices that will be used to multiply the mesh vertices mat4_t scale_matrix = mat4_make_scale(mesh.scale.x, mesh.scale.y, mesh.scale.z); - - // create translation matrix mat4_t translation_matrix = mat4_make_translation(mesh.translation.x, mesh.translation.y, mesh.translation.z); - - // create rotation matrices mat4_t rotation_matrix_x = mat4_make_rotation_x(mesh.rotation.x); mat4_t rotation_matrix_y = mat4_make_rotation_y(mesh.rotation.y); mat4_t rotation_matrix_z = mat4_make_rotation_z(mesh.rotation.z); - // create world matrix - mat4_t world_matrix = mat4_identity(); - world_matrix = mat4_mul_mat4(&scale_matrix, &world_matrix); - world_matrix = mat4_mul_mat4(&rotation_matrix_x, &world_matrix); - world_matrix = mat4_mul_mat4(&rotation_matrix_y, &world_matrix); - world_matrix = mat4_mul_mat4(&rotation_matrix_z, &world_matrix); - world_matrix = mat4_mul_mat4(&translation_matrix, &world_matrix); - - - triangles_to_render = NULL; - + // Loop all triangle faces of our mesh int num_faces = array_length(mesh.faces); for (int i = 0; i < num_faces; i++) { face_t mesh_face = mesh.faces[i]; @@ -195,39 +137,51 @@ void update(void) { vec4_t transformed_vertices[3]; + // Loop all three vertices of this current face and apply transformations for (int j = 0; j < 3; j++) { vec4_t transformed_vertex = vec4_from_vec3(face_vertices[j]); - // use matrix to scale original matrix - transformed_vertex = mat4_multiply_vec4(world_matrix, transformed_vertex); + // Create a World Matrix combining scale, rotation, and translation matrices + mat4_t world_matrix = mat4_identity(); - // save translated vertex in the array of transformed vertices + // Order matters: First scale, then rotate, then translate. [T]*[R]*[S]*v + world_matrix = mat4_mul_mat4(scale_matrix, world_matrix); + world_matrix = mat4_mul_mat4(rotation_matrix_z, world_matrix); + world_matrix = mat4_mul_mat4(rotation_matrix_y, world_matrix); + world_matrix = mat4_mul_mat4(rotation_matrix_x, world_matrix); + world_matrix = mat4_mul_mat4(translation_matrix, world_matrix); + + // Multiply the world matrix by the original vector + transformed_vertex = mat4_mul_vec4(world_matrix, transformed_vertex); + + // Save transformed vertex in the array of transformed vertices transformed_vertices[j] = transformed_vertex; } - vec3_t vector_a = vec3_from_vec4(transformed_vertices[0]); /* A */ - vec3_t vector_b = vec3_from_vec4(transformed_vertices[1]); /* / \ */ - vec3_t vector_c = vec3_from_vec4(transformed_vertices[2]); /* C---B */ + // Get individual vectors from A, B, and C vertices to compute normal + vec3_t vector_a = vec3_from_vec4(transformed_vertices[0]); /* A */ + vec3_t vector_b = vec3_from_vec4(transformed_vertices[1]); /* / \ */ + vec3_t vector_c = vec3_from_vec4(transformed_vertices[2]); /* C---B */ - // get the vector subtraction of B-A and C-A - vec3_t vector_ab = vec3_subtract(vector_b, vector_a); - vec3_t vector_ac = vec3_subtract(vector_c, vector_a); + // Get the vector subtraction of B-A and C-A + vec3_t vector_ab = vec3_sub(vector_b, vector_a); + vec3_t vector_ac = vec3_sub(vector_c, vector_a); vec3_normalize(&vector_ab); vec3_normalize(&vector_ac); - // compute the face normal using the cross product to find perpindicular + // Compute the face normal (using cross product to find perpendicular) vec3_t normal = vec3_cross(vector_ab, vector_ac); vec3_normalize(&normal); + // Find the vector between vertex A in the triangle and the camera origin + vec3_t camera_ray = vec3_sub(camera_position, vector_a); + + // Calculate how aligned the camera ray is with the face normal (using dot product) + float dot_normal_camera = vec3_dot(normal, camera_ray); + + // Backface culling test to see if the current face should be projected if (cull_method == CULL_BACKFACE) { - // check backface culling - - // find the vector between a point in the triangle and the camera origin - vec3_t camera_ray = vec3_subtract(camera_position, vector_a); - - // calculate how aligned the camera ray is with the face normal - float dot_normal_camera = vec3_dot(normal, camera_ray); - + // Backface culling, bypassing triangles that are looking away from the camera if (dot_normal_camera < 0) { continue; } @@ -235,130 +189,117 @@ void update(void) { vec4_t projected_points[3]; + // Loop all three vertices to perform projection for (int j = 0; j < 3; j++) { - // project the current vertex + // Project the current vertex projected_points[j] = mat4_mul_vec4_project(proj_matrix, transformed_vertices[j]); + // Flip vertically since the y values of the 3D mesh grow bottom->up and in screen space y values grow top->down + projected_points[j].y *= -1; + // Scale into the view projected_points[j].x *= (window_width / 2.0); projected_points[j].y *= (window_height / 2.0); - // invert y to account for flipped screen y coordinates - projected_points[j].y *= -1; - // Translate the projected points to the middle of the screen projected_points[j].x += (window_width / 2.0); projected_points[j].y += (window_height / 2.0); - - //projected_triangle.points[j] = projected_point; } - // calculate color using normal and light direction, then invert - float dot_color_p = -vec3_dot(normal, light.direction); + // Calculate the average depth for each face based on the vertices after transformation + float avg_depth = (transformed_vertices[0].z + transformed_vertices[1].z + transformed_vertices[2].z) / 3.0; - color_t flat_shaded_color = light_apply_intensity(0xFFFFFFFF, dot_color_p); + // Calculate the shade intensity based on how aliged is the normal with the flipped light direction ray + float light_intensity_factor = -vec3_dot(normal, light.direction); + + // Calculate the triangle color based on the light angle + uint32_t triangle_color = light_apply_intensity(mesh_face.color, light_intensity_factor); - // calculate the average depth of the triangle - float avg_depth = (transformed_vertices[0].z + transformed_vertices[1].z + transformed_vertices[2].z) / 3.0f; -#define FUNC3 (int) triangle_t projected_triangle = { .points = { - { FUNC3(projected_points[0].x), FUNC3(projected_points[0].y) }, - { FUNC3(projected_points[1].x), FUNC3(projected_points[1].y) }, - { FUNC3(projected_points[2].x), FUNC3(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 }, - { mesh_face.b_uv.u, mesh_face.b_uv.v }, - { mesh_face.c_uv.u, mesh_face.c_uv.v }, + { 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 } }, - .color = flat_shaded_color, - .average_depth = avg_depth, + .color = triangle_color, + .avg_depth = avg_depth }; - //vec2_t midpoint = triangle_midpoint(projected_triangle); - //draw_rect(midpoint.x, midpoint.y, 10, 10, 0xFFFF0000); - - // save the projected triangle in the array of triangles + // Save the projected triangle in the array of triangles to render array_push(triangles_to_render, projected_triangle); - + } + + // Sort the triangles to render by their avg_depth + int num_triangles = array_length(triangles_to_render); + for (int i = 0; i < num_triangles; i++) { + for (int j = i; j < num_triangles; j++) { + if (triangles_to_render[i].avg_depth < triangles_to_render[j].avg_depth) { + // Swap the triangles positions in the array + triangle_t temp = triangles_to_render[i]; + triangles_to_render[i] = triangles_to_render[j]; + triangles_to_render[j] = temp; + } + } } } -int depth_comp(const void* a, const void* b) { - triangle_t arg_a = *(const triangle_t*)a; - triangle_t arg_b = *(const triangle_t*)b; - - if (arg_a.average_depth > arg_b.average_depth) return -1; - if (arg_a.average_depth < arg_b.average_depth) return 1; - return 0; -} - +/////////////////////////////////////////////////////////////////////////////// +// Render function to draw objects on the display +/////////////////////////////////////////////////////////////////////////////// void render(void) { + SDL_RenderClear(renderer); + draw_grid(); - //uint32_t colors[] = { 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFF757500, 0xFF007575, 0xFF750075 }; - // Loop all projected points and render them - size_t arr_length = array_length(triangles_to_render); - // sort triangles - if (sort_faces) qsort(triangles_to_render, arr_length, sizeof(triangle_t), depth_comp); - - for (int i = 0; i < arr_length; i++) { + // Loop all projected triangles and render them + int num_triangles = array_length(triangles_to_render); + for (int i = 0; i < num_triangles; i++) { triangle_t triangle = triangles_to_render[i]; - switch (render_method) { - case RENDER_WIRE: - draw_triangle(triangle, 0x0000ff); - break; - case RENDER_WIRE_VERTEX: - draw_triangle(triangle, 0x0000ff); - draw_rect(triangle.points[0].x, triangle.points[0].y, 3, 3, 0xFFFFFF00); - draw_rect(triangle.points[1].x, triangle.points[1].y, 3, 3, 0xFFFFFF00); - draw_rect(triangle.points[2].x, triangle.points[2].y, 3, 3, 0xFFFFFF00); - break; - case RENDER_FILL_TRIANGLE: - draw_filled_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, - triangle.color - ); - break; - case RENDER_FILL_TRIANGLE_LINE: - draw_filled_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_triangle(triangle, 0xff0000ff); - break; - case RENDER_TEXTURED: - 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.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; + // Draw filled triangle + if (render_method == RENDER_FILL_TRIANGLE || render_method == RENDER_FILL_TRIANGLE_WIRE) { + draw_filled_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 + if (render_method == RENDER_TEXTURED || render_method == RENDER_TEXTURED_WIRE) { + draw_textured_triangle( + 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 + ); + } + + // Draw triangle wireframe + if (render_method == RENDER_WIRE || render_method == RENDER_WIRE_VERTEX || render_method == RENDER_FILL_TRIANGLE_WIRE || render_method == RENDER_TEXTURED_WIRE) { + draw_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 + 0xFFFFFFFF + ); + } + + // Draw triangle vertex points + if (render_method == RENDER_WIRE_VERTEX) { + draw_rect(triangle.points[0].x - 3, triangle.points[0].y - 3, 6, 6, 0xFFFF0000); // vertex A + draw_rect(triangle.points[1].x - 3, triangle.points[1].y - 3, 6, 6, 0xFFFF0000); // vertex B + draw_rect(triangle.points[2].x - 3, triangle.points[2].y - 3, 6, 6, 0xFFFF0000); // vertex C + } } - //vec2_t m = triangle_midpoint(t); - //draw_rect(m.x, m.y, 10, 10, 0xFFFF0000); - - //draw_line(10, 10, 500, 500, 0x00FF00); + // Clear the array of triangles to render every frame loop array_free(triangles_to_render); render_color_buffer(); @@ -368,13 +309,19 @@ void render(void) { SDL_RenderPresent(renderer); } +/////////////////////////////////////////////////////////////////////////////// +// Free the memory that was dynamically allocated by the program +/////////////////////////////////////////////////////////////////////////////// void free_resources(void) { free(color_buffer); array_free(mesh.faces); array_free(mesh.vertices); } -int main(int argc, char *argv[]) { +/////////////////////////////////////////////////////////////////////////////// +// Main function +/////////////////////////////////////////////////////////////////////////////// +int main(int argv, char* args[]) { is_running = initialize_window(); setup(); diff --git a/scripts/main.cpp b/scripts/main.cpp deleted file mode 100644 index 42199f7..0000000 --- a/scripts/main.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include - -int main(int argc, char* args []) { - SDL_Init(SDL_INIT_VIDEO); - - SDL_Window* window = SDL_CreateWindow("Blank Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN); - if (window == nullptr) { - SDL_Log("Failed to create window: %s", SDL_GetError()); - return 1; - } - - SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED); - if (renderer == nullptr) { - SDL_Log("Failed to create renderer: %s", SDL_GetError()); - SDL_DestroyWindow(window); - SDL_Quit(); - return 1; - } - - bool running = true; - SDL_Event event; - - while (running) { - // Close window with any input - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN || event.type == SDL_MOUSEBUTTONDOWN) { - running = false; - break; - } - } - - SDL_SetRenderDrawColor(renderer, 100, 100, 180, 255); // Set the background color to purple - SDL_RenderClear(renderer); - SDL_RenderPresent(renderer); - } - - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); - return 0; -} diff --git a/scripts/main_old.c b/scripts/main_old.c deleted file mode 100644 index d7fc117..0000000 --- a/scripts/main_old.c +++ /dev/null @@ -1,172 +0,0 @@ -#include -#include -#include -#include - -bool is_running = false; - -SDL_Window* window = NULL; -SDL_Renderer* renderer = NULL; - -uint32_t* color_buffer = NULL; -SDL_Texture* color_buffer_texture = NULL; - -int window_width = 800; -int window_height = 600; - -bool initialize_window(void) { - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { - fprintf(stderr, "Error initializing SDL.\n"); - return false; - } - - // Set width and height of the SDL window with the max screen resolution - SDL_DisplayMode display_mode; - SDL_GetCurrentDisplayMode(0, &display_mode); - window_width = display_mode.w; - window_height = display_mode.h; - - // Create a SDL Window - window = SDL_CreateWindow( - NULL, - SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, - window_width, - window_height, - SDL_WINDOW_BORDERLESS - ); - if (!window) { - fprintf(stderr, "Error creating SDL window.\n"); - return false; - } - - // Create a SDL renderer - renderer = SDL_CreateRenderer(window, -1, 0); - if (!renderer) { - fprintf(stderr, "Error creating SDL renderer.\n"); - return false; - } - - return true; -} - -void setup(void) { - // Allocate the required memory in bytes to hold the color buffer - color_buffer = (uint32_t*) malloc(sizeof(uint32_t) * window_width * window_height); - - // Creating a SDL texture that is used to display the color buffer - color_buffer_texture = SDL_CreateTexture( - renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - window_width, - window_height - ); -} - -void process_input(void) { - SDL_Event event; - SDL_PollEvent(&event); - - switch (event.type) { - case SDL_QUIT: - is_running = false; - break; - case SDL_KEYDOWN: - if (event.key.keysym.sym == SDLK_ESCAPE) - is_running = false; - break; - } -} - -void update(void) { - // TODO: -} - -void draw_rect(int xpos, int ypos, int width, int height, uint32_t color) { - for (int y = ypos; y < (ypos + height); y++) { - for (int x = xpos; x < (xpos + width); x++) { - color_buffer[(window_width * y) + x] = color; - } - } -} - -void draw_grid(void) { - // TODO: - uint32_t color = 0xc0c0c0; - bool draw_line = false; - int grid_spacing = 40; - - /*for (int y = 0; y < window_height; y++) { - draw_line = !(y % grid_spacing); - for (int x = 0; x < window_width; x++) { - if (draw_line || !(x % grid_spacing)) { - color_buffer[(window_width * y) + x] = color; - } - } - }*/ - for (int y = 0; y < window_height; y = y + grid_spacing) { - for (int x = 0; x < window_width; x++) { - color_buffer[(window_width * y) + x] = color; - } - } - for (int x = 0; x < window_width; x = x + grid_spacing) { - for (int y = 0; y < window_height; y++) { - color_buffer[(window_width * y) + x] = color; - } - } -} - -void render_color_buffer(void) { - SDL_UpdateTexture( - color_buffer_texture, - NULL, - color_buffer, - (int)(window_width * sizeof(uint32_t)) - ); - SDL_RenderCopy(renderer, color_buffer_texture, NULL, NULL); -} - -void clear_color_buffer(uint32_t color) { - for (int y = 0; y < window_height; y++) { - for (int x = 0; x < window_width; x++) { - color_buffer[(window_width * y) + x] = color; - } - } -} - -void render(void) { - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderClear(renderer); - - draw_grid(); - draw_rect(20, 120, 150, 100, 0xFFFF00); - - render_color_buffer(); - clear_color_buffer(0xFF000000); - - SDL_RenderPresent(renderer); -} - -void destroy_window(void) { - free(color_buffer); - SDL_DestroyRenderer(renderer); - SDL_DestroyWindow(window); - SDL_Quit(); -} - -int main(int argc, char *argv[]) { - is_running = initialize_window(); - - setup(); - - while (is_running) { - process_input(); - update(); - render(); - } - - destroy_window(); - - return 0; -} diff --git a/scripts/matrix.c b/scripts/matrix.c index dd981c3..636a5bd 100644 --- a/scripts/matrix.c +++ b/scripts/matrix.c @@ -1,139 +1,131 @@ +#include #include "matrix.h" mat4_t mat4_identity(void) { + // | 1 0 0 0 | + // | 0 1 0 0 | + // | 0 0 1 0 | + // | 0 0 0 1 | mat4_t m = {{ - { 1, 0, 0, 0}, - { 0, 1, 0, 0}, - { 0, 0, 1, 0}, - { 0, 0, 0, 1}, + { 1, 0, 0, 0 }, + { 0, 1, 0, 0 }, + { 0, 0, 1, 0 }, + { 0, 0, 0, 1 } }}; - return m; } mat4_t mat4_make_scale(float sx, float sy, float sz) { + // | sx 0 0 0 | + // | 0 sy 0 0 | + // | 0 0 sz 0 | + // | 0 0 0 1 | mat4_t m = mat4_identity(); - m.m[0][0] *= sx; - m.m[1][1] *= sy; - m.m[2][2] *= sz; - + m.m[0][0] = sx; + m.m[1][1] = sy; + m.m[2][2] = sz; return m; } mat4_t mat4_make_translation(float tx, float ty, float tz) { - /* - * 1 0 0 tx - * 0 1 0 ty - * 0 0 1 tz - * 0 0 0 1 - */ - + // | 1 0 0 tx | + // | 0 1 0 ty | + // | 0 0 1 tz | + // | 0 0 0 1 | mat4_t m = mat4_identity(); m.m[0][3] = tx; m.m[1][3] = ty; m.m[2][3] = tz; - return m; } -mat4_t mat4_make_rotation_y(float ra) { - /* - * cos 0 -sin 0 - * 0 1 0 0 - * sin 0 cos 0 - * 0 0 0 1 - */ - const float cosine = cosf(ra); - const float sine = sinf(ra); +mat4_t mat4_make_rotation_x(float angle) { + float c = cos(angle); + float s = sin(angle); + // | 1 0 0 0 | + // | 0 c -s 0 | + // | 0 s c 0 | + // | 0 0 0 1 | mat4_t m = mat4_identity(); - m.m[0][0] = cosine; - m.m[0][2] = -sine; - m.m[2][0] = sine; - m.m[2][2] = cosine; - + m.m[1][1] = c; + m.m[1][2] = -s; + m.m[2][1] = s; + m.m[2][2] = c; return m; } -mat4_t mat4_make_rotation_x(float ra) { - /* - * 1 0 0 0 - * 0 cos sin 0 - * 0 -sin cos 0 - * 0 0 0 1 - */ - const float cosine = cosf(ra); - const float sine = sinf(ra); +mat4_t mat4_make_rotation_y(float angle) { + float c = cos(angle); + float s = sin(angle); + // | c 0 s 0 | + // | 0 1 0 0 | + // | -s 0 c 0 | + // | 0 0 0 1 | mat4_t m = mat4_identity(); - m.m[1][1] = cosine; - m.m[1][2] = sine; - m.m[2][1] = -sine; - m.m[2][2] = cosine; - + m.m[0][0] = c; + m.m[0][2] = s; + m.m[2][0] = -s; + m.m[2][2] = c; return m; } - -mat4_t mat4_make_rotation_z(float ra) { - /* - * cos sin 0 0 - * -sin cos 0 0 - * 0 0 1 0 - * 0 0 0 1 - */ - const float cosine = cosf(ra); - const float sine = sinf(ra); +mat4_t mat4_make_rotation_z(float angle) { + float c = cos(angle); + float s = sin(angle); + // | c -s 0 0 | + // | s c 0 0 | + // | 0 0 1 0 | + // | 0 0 0 1 | mat4_t m = mat4_identity(); - m.m[0][0] = cosine; - m.m[0][1] = sine; - m.m[1][0] = -sine; - m.m[1][1] = cosine; - + m.m[0][0] = c; + m.m[0][1] = -s; + m.m[1][0] = s; + m.m[1][1] = c; return m; } -vec4_t mat4_multiply_vec4(mat4_t m, vec4_t v) { - vec4_t ret = {}; - - ret.x = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3] * v.w; - ret.y = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3] * v.w; - ret.z = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3] * v.w; - ret.w = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3] * v.w; - - return ret; +vec4_t mat4_mul_vec4(mat4_t m, vec4_t v) { + vec4_t result; + result.x = m.m[0][0] * v.x + m.m[0][1] * v.y + m.m[0][2] * v.z + m.m[0][3] * v.w; + result.y = m.m[1][0] * v.x + m.m[1][1] * v.y + m.m[1][2] * v.z + m.m[1][3] * v.w; + result.z = m.m[2][0] * v.x + m.m[2][1] * v.y + m.m[2][2] * v.z + m.m[2][3] * v.w; + result.w = m.m[3][0] * v.x + m.m[3][1] * v.y + m.m[3][2] * v.z + m.m[3][3] * v.w; + return result; } -mat4_t mat4_mul_mat4(mat4_t* a, mat4_t* b) { - mat4_t ret = {}; - - for (int r = 0; r < 4; r++) { - for (int c = 0; c < 4; c++) { - ret.m[r][c] = (a->m[r][0] * b->m[0][c]) + (a->m[r][1] * b->m[1][c]) + (a->m[r][2] * b->m[2][c]) + (a->m[r][3] * b->m[3][c]); +mat4_t mat4_mul_mat4(mat4_t a, mat4_t b) { + mat4_t m; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + m.m[i][j] = a.m[i][0] * b.m[0][j] + a.m[i][1] * b.m[1][j] + a.m[i][2] * b.m[2][j] + a.m[i][3] * b.m[3][j]; } } - - return ret; + return m; } mat4_t mat4_make_perspective(float fov, float aspect, float znear, float zfar) { + // | (h/w)*1/tan(fov/2) 0 0 0 | + // | 0 1/tan(fov/2) 0 0 | + // | 0 0 zf/(zf-zn) (-zf*zn)/(zf-zn) | + // | 0 0 1 0 | mat4_t m = {{{ 0 }}}; - m.m[0][0] = aspect * (1 / tanf(fov / 2)); - m.m[1][1] = 1 / tanf(fov / 2); + m.m[0][0] = aspect * (1 / tan(fov / 2)); + m.m[1][1] = 1 / tan(fov / 2); m.m[2][2] = zfar / (zfar - znear); m.m[2][3] = (-zfar * znear) / (zfar - znear); - m.m[3][2] = 1.0f; + m.m[3][2] = 1.0; return m; } vec4_t mat4_mul_vec4_project(mat4_t mat_proj, vec4_t v) { // multiply the projection matrix by our original vector - vec4_t result = mat4_multiply_vec4(mat_proj, v); + vec4_t result = mat4_mul_vec4(mat_proj, v); - // perform perspective divide with original z-value + // perform perspective divide with original z-value that is now stored in w if (result.w != 0.0) { result.x /= result.w; result.y /= result.w; result.z /= result.w; } - return result; -} \ No newline at end of file +} diff --git a/scripts/matrix.h b/scripts/matrix.h index 79a789d..c03324f 100644 --- a/scripts/matrix.h +++ b/scripts/matrix.h @@ -1,23 +1,21 @@ #ifndef MATRIX_H #define MATRIX_H -#include #include "vector.h" -typedef struct mat4_t mat4_t; -struct mat4_t { +typedef struct { float m[4][4]; -}; +} mat4_t; mat4_t mat4_identity(void); mat4_t mat4_make_scale(float sx, float sy, float sz); mat4_t mat4_make_translation(float tx, float ty, float tz); -mat4_t mat4_make_rotation_x(float ra); -mat4_t mat4_make_rotation_y(float ra); -mat4_t mat4_make_rotation_z(float ra); -mat4_t mat4_mul_mat4(mat4_t* a, mat4_t* b); -vec4_t mat4_multiply_vec4(mat4_t m, vec4_t v); +mat4_t mat4_make_rotation_x(float angle); +mat4_t mat4_make_rotation_y(float angle); +mat4_t mat4_make_rotation_z(float angle); mat4_t mat4_make_perspective(float fov, float aspect, float znear, float zfar); +vec4_t mat4_mul_vec4(mat4_t m, vec4_t v); +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 \ No newline at end of file +#endif diff --git a/scripts/mesh.c b/scripts/mesh.c index 69ae2fc..5eaf321 100644 --- a/scripts/mesh.c +++ b/scripts/mesh.c @@ -1,19 +1,14 @@ -#include #include #include -#include -#include "mesh.h" - -#include - #include "array.h" +#include "mesh.h" mesh_t mesh = { .vertices = NULL, .faces = NULL, .rotation = { 0, 0, 0 }, .scale = { 1.0, 1.0, 1.0 }, - .translation = { 0, 0, 0 }, + .translation = { 0, 0, 0 } }; vec3_t cube_vertices[N_CUBE_VERTICES] = { @@ -50,60 +45,45 @@ face_t cube_faces[N_CUBE_FACES] = { void load_cube_mesh_data(void) { for (int i = 0; i < N_CUBE_VERTICES; i++) { - array_push(mesh.vertices, cube_vertices[i]); + vec3_t cube_vertex = cube_vertices[i]; + array_push(mesh.vertices, cube_vertex); } for (int i = 0; i < N_CUBE_FACES; i++) { - array_push(mesh.faces, cube_faces[i]); + face_t cube_face = cube_faces[i]; + array_push(mesh.faces, cube_face); } } -void parse_face(const char* buffer, face_t* face) { - char temp_a[64], temp_b[64], temp_c[64]; - sscanf(buffer, "f %63s %63s %63s", temp_a, temp_b, temp_c); +void load_obj_file_data(char* filename) { + FILE* file; + file = fopen(filename, "r"); + char line[1024]; - char* token; - - token = strtok(temp_a, "/"); - face->a = token ? atoi(token) : -1; - - token = strtok(temp_b, "/"); - face->b = token ? atoi(token) : -1; - - token = strtok(temp_c, "/"); - face->c = token ? atoi(token) : -1; -} - -void load_file(const char* filename) { - FILE* fp; - char* tok; - - fp = fopen(filename, "r"); - - if (fp == NULL) { - exit(EXIT_FAILURE); - } - - char buffer[MAX_LEN]; - while (fgets(buffer, MAX_LEN, fp)) { - - if (strncmp(buffer, "v ", 2) == 0) { + while (fgets(line, 1024, file)) { + // Vertex information + if (strncmp(line, "v ", 2) == 0) { vec3_t vertex; - sscanf(buffer, "v %f %f %f", &vertex.x, &vertex.y, &vertex.z); - + sscanf(line, "v %f %f %f", &vertex.x, &vertex.y, &vertex.z); array_push(mesh.vertices, vertex); - - } else if (strncmp(buffer, "f ", 2) == 0) { - face_t face; - - parse_face(buffer, &face); - - array_push(mesh.faces, face); - } - printf("\n"); + // Face information + if (strncmp(line, "f ", 2) == 0) { + int vertex_indices[3]; + int texture_indices[3]; + int normal_indices[3]; + sscanf( + line, "f %d/%d/%d %d/%d/%d %d/%d/%d", + &vertex_indices[0], &texture_indices[0], &normal_indices[0], + &vertex_indices[1], &texture_indices[1], &normal_indices[1], + &vertex_indices[2], &texture_indices[2], &normal_indices[2] + ); + face_t face = { + .a = vertex_indices[0], + .b = vertex_indices[1], + .c = vertex_indices[2], + .color = 0xFFFFFFFF + }; + array_push(mesh.faces, face); + } } - - fflush(stdout); - fclose(fp); - -} \ No newline at end of file +} diff --git a/scripts/mesh.h b/scripts/mesh.h index 5f966c8..f3954a5 100644 --- a/scripts/mesh.h +++ b/scripts/mesh.h @@ -7,40 +7,23 @@ #define N_CUBE_VERTICES 8 #define N_CUBE_FACES (6 * 2) // 6 cube faces, 2 triangles per face -#define MAX_LEN 256 - extern vec3_t cube_vertices[N_CUBE_VERTICES]; extern face_t cube_faces[N_CUBE_FACES]; -typedef enum { - COLOR_PURPLE = 0xFF6A2EFF, - COLOR_SAND_YELLOW = 0xFFE9C46A, - COLOR_TEAL_GREEN = 0xFF2A9D8F, - COLOR_ORANGE = 0xFFF4A261, - COLOR_DARK_BLUE_GREY = 0xFF264653, - COLOR_MAUVE = 0xFFB5838D, - COLOR_RED = 0xFFD7263D, - COLOR_TURQUOISE = 0xFF38A3A5, - COLOR_GREY = 0xFF757575, - COLOR_LIGHT_GREEN_BLUE = 0xFF70C1B3, - COLOR_YELLOW = 0xFFFFC300, - COLOR_DEEP_PURPLE = 0xFF5D2E8C -} color_enum_t; - -typedef struct mesh_t mesh_t; -struct mesh_t { - vec3_t* vertices; - face_t* faces; - vec3_t rotation; - vec3_t scale; - vec3_t translation; -}; +//////////////////////////////////////////////////////////////////////////////// +// Define a struct for dynamic size meshes, with array of vertices and faces +//////////////////////////////////////////////////////////////////////////////// +typedef struct { + vec3_t* vertices; // dynamic array of vertices + face_t* faces; // dynamic array of faces + vec3_t rotation; // rotation with x, y, and z values + vec3_t scale; // scale with x, y, and z values + vec3_t translation; // translation with x, y, and z values +} mesh_t; extern mesh_t mesh; -void parse_face(const char* buffer, face_t* face); - void load_cube_mesh_data(void); -void load_file(const char* filename); +void load_obj_file_data(char* filename); #endif diff --git a/scripts/swap.h b/scripts/swap.h index 72aced2..a8dc570 100644 --- a/scripts/swap.h +++ b/scripts/swap.h @@ -1,2 +1,7 @@ +#ifndef SWAP_H +#define SWAP_H + void int_swap(int* a, int* b); -void float_swap(float* a, float* b); \ No newline at end of file +void float_swap(float* a, float* b); + +#endif diff --git a/scripts/texture.c b/scripts/texture.c index 98d685d..aefbd8b 100644 --- a/scripts/texture.c +++ b/scripts/texture.c @@ -71,4 +71,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/scripts/texture.h b/scripts/texture.h index 9b5cf8c..00c5df6 100644 --- a/scripts/texture.h +++ b/scripts/texture.h @@ -15,4 +15,4 @@ extern const uint8_t REDBRICK_TEXTURE[]; extern uint32_t* mesh_texture; -#endif \ No newline at end of file +#endif diff --git a/scripts/triangle.c b/scripts/triangle.c index 2d8f4ff..5aaa33a 100644 --- a/scripts/triangle.c +++ b/scripts/triangle.c @@ -1,34 +1,6 @@ -#include "triangle.h" - -#include -#include - #include "display.h" - -// TODO: Create implementation for triangle.h functions -int compare_vec2_t(const void* a, const void* b) { - const int_vec2_t* arg1 = (const int_vec2_t*)a; - const int_vec2_t* arg2 = (const int_vec2_t*)b; - if (arg1->y < arg2->y) return -1; - if (arg1->y > arg2->y) return 1; - return 0; -} - -#define FUNC (int)ceilf -#define FUNC2 (int)floorf - -uint32_t invert_rgb(uint32_t color) { - uint32_t a = color & 0xFF000000; // Alpha channel - uint32_t rgb = color & 0x00FFFFFF; // RGB channels - rgb = ~rgb & 0x00FFFFFF; // Invert RGB only - 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); -} +#include "swap.h" +#include "triangle.h" /////////////////////////////////////////////////////////////////////////////// // Draw a filled a triangle with a flat bottom @@ -147,13 +119,37 @@ void draw_filled_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32 } } +/////////////////////////////////////////////////////////////////////////////// +// Draw a triangle using three raw line calls +/////////////////////////////////////////////////////////////////////////////// +void draw_triangle(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); +} + +/////////////////////////////////////////////////////////////////////////////// +// 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_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); + 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 parallegram/triangle ABC using 2D cross product float area_parallelogram_abc = (ac.x * ab.y - ac.y * ab.x); // || AC x AB || @@ -170,62 +166,113 @@ vec3_t barycentric_weights(vec2_t a, vec2_t b, vec2_t c, vec2_t p) { vec3_t weights = { alpha, beta, gamma }; return weights; } -//////////////////////////// -// Function to draw textue at x/y using interpolation + +/////////////////////////////////////////////////////////////////////////////// +// Function to draw the textured pixel at position x and 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); + 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 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); + + // Calculate the barycentric coordinates of our point 'p' inside the triangle + 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 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; + // Variables to store the interpolated values of U, V, and also 1/w for the current pixel + float interpolated_u; + float interpolated_v; + float interpolated_reciprocal_w; + + // Perform the interpolation of all U/w and V/w values using barycentric weights and a factor of 1/w + 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; + + // 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; + + // Now we can 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)); draw_pixel(x, y, texture[(texture_width * tex_y) + tex_x]); - - } +/////////////////////////////////////////////////////////////////////////////// +// Draw a textured triangle based on a texture array of colors. +// We split the original triangle in two, half flat-bottom and half flat-top. +/////////////////////////////////////////////////////////////////////////////// +// +// v0 +// /\ +// / \ +// / \ +// / \ +// v1--------\ +// \_ \ +// \_ \ +// \_ \ +// \_ \ +// \\ +// \ +// v2 +// +/////////////////////////////////////////////////////////////////////////////// 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; - + 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, + uint32_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); } 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); } 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 sorting vertices - vec2_t point_a = { x0, y0 }; - vec2_t point_b = { x1, y1 }; - vec2_t point_c = { x2, y2 }; - - - // FLAT BOTTOM + // 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) + /////////////////////////////////////////////////////// float inv_slope_1 = 0; float inv_slope_2 = 0; @@ -238,18 +285,19 @@ void draw_textured_triangle( int x_end = x0 + (y - y0) * inv_slope_2; if (x_end < x_start) { - int_swap(&x_start, &x_end); + 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 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); + // Draw our pixel with the color that comes from the texture + draw_texel(x, y, texture, point_a, point_b, point_c, a_uv, b_uv, c_uv); } } } - // FLAT TOP + /////////////////////////////////////////////////////// + // Render the bottom part of the triangle (flat-top) + /////////////////////////////////////////////////////// inv_slope_1 = 0; inv_slope_2 = 0; @@ -262,18 +310,13 @@ void draw_textured_triangle( int x_end = x0 + (y - y0) * inv_slope_2; if (x_end < x_start) { - int_swap(&x_start, &x_end); + 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 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); + // Draw our pixel with the color that comes from the texture + draw_texel(x, y, texture, point_a, point_b, point_c, a_uv, b_uv, c_uv); } } } - - - - -} \ No newline at end of file +} diff --git a/scripts/triangle.h b/scripts/triangle.h index a687ab6..69f0b27 100644 --- a/scripts/triangle.h +++ b/scripts/triangle.h @@ -2,13 +2,8 @@ #define TRIANGLE_H #include - #include "texture.h" -#include "swap.h" #include "vector.h" -#include "texture.h" - -typedef uint32_t color_t; typedef struct { int a; @@ -17,31 +12,24 @@ typedef struct { tex2_t a_uv; tex2_t b_uv; tex2_t c_uv; - color_t color; + uint32_t color; } face_t; typedef struct { - int x; - int y; -} int_vec2_t; - -typedef struct { - vec2_t points[3]; + vec4_t points[3]; tex2_t texcoords[3]; - color_t color; - float average_depth; + uint32_t color; + float avg_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_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); +void draw_filled_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, - 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); + 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, + uint32_t* texture +); #endif diff --git a/scripts/vector.c b/scripts/vector.c index 4366948..00ec465 100644 --- a/scripts/vector.c +++ b/scripts/vector.c @@ -1,143 +1,158 @@ +#include #include "vector.h" -#include - -// TODO: Implementation of all vector functions -vec3_t vec3_rotate_x(vec3_t v, float angle) { - return (vec3_t) { - .x = v.x, - .y = v.y * cos(angle) - v.z * sin(angle), - .z = v.y * sin(angle) + v.z * cos(angle), - }; +/////////////////////////////////////////////////////////////////////////////// +// Implementations of Vector 2 functions +/////////////////////////////////////////////////////////////////////////////// +float vec2_length(vec2_t v) { + return sqrt(v.x * v.x + v.y * v.y); } -vec3_t vec3_rotate_y(vec3_t v, float angle) { - return (vec3_t) { - .x = v.x * cos(angle) - v.z * sin(angle), - .y = v.y, - .z = v.x * sin(angle) + v.z * cos(angle), - }; -} - -vec3_t vec3_rotate_z(vec3_t v, float angle) { - return (vec3_t) { - .x = v.x * cos(angle) - v.y * sin(angle), - .y = v.x * sin(angle) + v.y * cos(angle), - .z = v.z, - }; -} - -float vec2_length(const vec2_t vector) { - return sqrt((vector.x * vector.x) + (vector.y * vector.y)); -} - -vec2_t vec2_add(const vec2_t a, const vec2_t b) { - return (vec2_t) { +vec2_t vec2_add(vec2_t a, vec2_t b) { + vec2_t result = { .x = a.x + b.x, - .y = a.y + b.y, + .y = a.y + b.y }; + return result; } -vec2_t vec2_subtract(const vec2_t a, const vec2_t b) { - return (vec2_t) { +vec2_t vec2_sub(vec2_t a, vec2_t b) { + vec2_t result = { .x = a.x - b.x, - .y = a.y - b.y, + .y = a.y - b.y }; + return result; } -vec2_t vec2_multiply(const vec2_t vector, float scalar) { - return (vec2_t) { - .x = vector.x * scalar, - .y = vector.y * scalar, +vec2_t vec2_mul(vec2_t v, float factor) { + vec2_t result = { + .x = v.x * factor, + .y = v.y * factor }; + return result; } -vec2_t vec2_divide(const vec2_t vector, float scalar) { - return (vec2_t) { - .x = vector.x / scalar, - .y = vector.y / scalar, +vec2_t vec2_div(vec2_t v, float factor) { + vec2_t result = { + .x = v.x / factor, + .y = v.y / factor }; + return result; } -float vec2_dot(const vec2_t a, const vec2_t b) { +float vec2_dot(vec2_t a, vec2_t b) { return (a.x * b.x) + (a.y * b.y); } -float vec3_length(const vec3_t vector) { - return sqrtf((vector.x * vector.x) + (vector.y * vector.y) + (vector.z * vector.z)); +void vec2_normalize(vec2_t* v) { + float length = sqrt(v->x * v->x + v->y * v->y); + v->x /= length; + v->y /= length; } -void vec2_normalize(vec2_t* vertex) { - float length = vec2_length(*vertex); - vertex->x /= length; - vertex->y /= length; +/////////////////////////////////////////////////////////////////////////////// +// Implementations of Vector 3 functions +/////////////////////////////////////////////////////////////////////////////// +float vec3_length(vec3_t v) { + return sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } -vec3_t vec3_add(const vec3_t a, const vec3_t b) { - return (vec3_t) { +vec3_t vec3_add(vec3_t a, vec3_t b) { + vec3_t result = { .x = a.x + b.x, .y = a.y + b.y, - .z = a.z + b.z, + .z = a.z + b.z }; + return result; } -vec3_t vec3_subtract(const vec3_t a, const vec3_t b) { - return (vec3_t) { +vec3_t vec3_sub(vec3_t a, vec3_t b) { + vec3_t result = { .x = a.x - b.x, .y = a.y - b.y, - .z = a.z - b.z, + .z = a.z - b.z }; + return result; } -vec3_t vec3_multiply(const vec3_t vector, const float scalar) { - return (vec3_t) { - .x = vector.x * scalar, - .y = vector.y * scalar, - .z = vector.z * scalar, +vec3_t vec3_mul(vec3_t v, float factor) { + vec3_t result = { + .x = v.x * factor, + .y = v.y * factor, + .z = v.z * factor }; + return result; } -vec3_t vec3_divide(const vec3_t vector, const float scalar) { - return (vec3_t) { - .x = vector.x / scalar, - .y = vector.y / scalar, - .z = vector.z / scalar, +vec3_t vec3_div(vec3_t v, float factor) { + vec3_t result = { + .x = v.x / factor, + .y = v.y / factor, + .z = v.z / factor }; + return result; } -vec3_t vec3_cross(const vec3_t a, const vec3_t b) { - return (vec3_t) { +vec3_t vec3_cross(vec3_t a, vec3_t b) { + vec3_t result = { .x = a.y * b.z - a.z * b.y, .y = a.z * b.x - a.x * b.z, - .z = a.x * b.y - a.y * b.x, + .z = a.x * b.y - a.y * b.x }; + return result; } -float vec3_dot(const vec3_t a, const vec3_t b) { +float vec3_dot(vec3_t a, vec3_t b) { return (a.x * b.x) + (a.y * b.y) + (a.z * b.z); } -void vec3_normalize(vec3_t* vertex) { - float length = vec3_length(*vertex); - vertex->x /= length; - vertex->y /= length; - vertex->z /= length; +void vec3_normalize(vec3_t* v) { + float length = sqrt(v->x * v->x + v->y * v->y + v->z * v->z); + v->x /= length; + v->y /= length; + v->z /= length; +} +vec3_t vec3_rotate_x(vec3_t v, float angle) { + vec3_t rotated_vector = { + .x = v.x, + .y = v.y * cos(angle) - v.z * sin(angle), + .z = v.y * sin(angle) + v.z * cos(angle) + }; + return rotated_vector; } -vec4_t vec4_from_vec3(vec3_t vertex) { - vec4_t ret; - ret.x = vertex.x; - ret.y = vertex.y; - ret.z = vertex.z; - ret.w = 1; +vec3_t vec3_rotate_y(vec3_t v, float angle) { + vec3_t rotated_vector = { + .x = v.x * cos(angle) + v.z * sin(angle), + .y = v.y, + .z = -v.x * sin(angle) + v.z * cos(angle) + }; + return rotated_vector; +} - return ret; +vec3_t vec3_rotate_z(vec3_t v, float angle) { + vec3_t rotated_vector = { + .x = v.x * cos(angle) - v.y * sin(angle), + .y = v.x * sin(angle) + v.y * cos(angle), + .z = v.z + }; + return rotated_vector; +} + +/////////////////////////////////////////////////////////////////////////////// +// Implementations of Vector conversion functions +/////////////////////////////////////////////////////////////////////////////// +vec4_t vec4_from_vec3(vec3_t v) { + vec4_t result = { v.x, v.y, v.z, 1.0 }; + return result; } vec3_t vec3_from_vec4(vec4_t v) { - return (vec3_t) { - .x = v.x, - .y = v.y, - .z = v.z, - }; -} \ No newline at end of file + vec3_t result = { v.x, v.y, v.z }; + return result; +} + +vec2_t vec2_from_vec4(vec4_t v) { + vec2_t result = { v.x, v.y }; + return result; +} diff --git a/scripts/vector.h b/scripts/vector.h index eeb85ef..5acaf5b 100644 --- a/scripts/vector.h +++ b/scripts/vector.h @@ -2,45 +2,47 @@ #define VECTOR_H typedef struct { - float x; - float y; + float x, y; } vec2_t; typedef struct { - float x; - float y; - float z; + float x, y, z; } vec3_t; typedef struct { float x, y, z, w; } vec4_t; -// TODO: Add functions to manipulate vectors 2D and 3D -// ... +//////////////////////////////////////////////////////////////////////////////// +// Vector 2 functions +//////////////////////////////////////////////////////////////////////////////// +float vec2_length(vec2_t v); +vec2_t vec2_add(vec2_t a, vec2_t b); +vec2_t vec2_sub(vec2_t a, vec2_t b); +vec2_t vec2_mul(vec2_t v, float factor); +vec2_t vec2_div(vec2_t v, float factor); +void vec2_normalize(vec2_t* v); +//////////////////////////////////////////////////////////////////////////////// +// Vector 3 functions +//////////////////////////////////////////////////////////////////////////////// +float vec3_length(vec3_t v); +vec3_t vec3_add(vec3_t a, vec3_t b); +vec3_t vec3_sub(vec3_t a, vec3_t b); +vec3_t vec3_mul(vec3_t v, float factor); +vec3_t vec3_div(vec3_t v, float factor); +vec3_t vec3_cross(vec3_t a, vec3_t b); +float vec3_dot(vec3_t a, vec3_t b); +void vec3_normalize(vec3_t* v); vec3_t vec3_rotate_x(vec3_t v, float angle); vec3_t vec3_rotate_y(vec3_t v, float angle); vec3_t vec3_rotate_z(vec3_t v, float angle); -vec2_t vec2_add(const vec2_t a, const vec2_t b); -vec2_t vec2_subtract(const vec2_t a, const vec2_t b); -vec2_t vec2_multiply(const vec2_t vector, float scalar); -vec2_t vec2_divide(const vec2_t vector, float scalar); -float vec2_length(const vec2_t vector); -float vec2_dot(const vec2_t a, const vec2_t b); -void vec2_normalize(vec2_t* vertex); - -vec3_t vec3_add(const vec3_t a, const vec3_t b); -vec3_t vec3_subtract(const vec3_t a, const vec3_t b); -vec3_t vec3_multiply(const vec3_t vector, const float scalar); -vec3_t vec3_divide(const vec3_t vector, const float scalar); -vec3_t vec3_cross(const vec3_t a, const vec3_t b); -float vec3_length(const vec3_t vector); -float vec3_dot(const vec3_t a, const vec3_t b); -void vec3_normalize(vec3_t* vertex); - -vec4_t vec4_from_vec3(vec3_t vertex); +//////////////////////////////////////////////////////////////////////////////// +// Vector conversion functions +//////////////////////////////////////////////////////////////////////////////// +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