From cec7699ea5f377df838b4280a214e210c8318756 Mon Sep 17 00:00:00 2001 From: Tyrel Souza Date: Fri, 19 Apr 2024 00:02:54 -0400 Subject: [PATCH] wireframe cube --- CMakeLists.txt | 2 +- Makefile | 2 +- src/display.c | 22 +++++++ src/display.h | 4 ++ src/main.c | 167 +++++++++++++++++++++++++++---------------------- src/mesh.c | 33 ++++++++++ src/mesh.h | 11 ++++ src/triangle.c | 3 + src/triangle.h | 16 +++++ src/vector.c | 25 ++++++++ src/vector.h | 3 + 11 files changed, 211 insertions(+), 77 deletions(-) create mode 100644 src/mesh.c create mode 100644 src/mesh.h create mode 100644 src/triangle.c create mode 100644 src/triangle.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 743c15e..e92009a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ file(GLOB SOURCES "src/*.c") add_executable(renderer ${SOURCES}) # Link SDL2 library to the executable -target_link_libraries(renderer PRIVATE ${SDL2_LIBRARIES}) +target_link_libraries(renderer PRIVATE ${SDL2_LIBRARIES} m) # Set compiler options target_compile_options(renderer PRIVATE -Wall -g) # -g adds debugging information diff --git a/Makefile b/Makefile index 3700046..d623073 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ SRCS = $(shell find ./src -type f -name *.c) build: - gcc -Wall -std=c99 $(SRCS) -lSDL2 -o renderer + gcc -Wall -std=c99 $(SRCS) -lSDL2 -lm -o renderer ./renderer run: build diff --git a/src/display.c b/src/display.c index abb1f84..57fd941 100644 --- a/src/display.c +++ b/src/display.c @@ -105,3 +105,25 @@ void destroy_window(void) { SDL_Quit(); } + +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); + + float xInc = delta_x / (float)longest_side_length; + float yInc = delta_y / (float)longest_side_length; + float current_x = x0; + float current_y = y0; + for (int i = 0; i < longest_side_length; i++) { + draw_pixel(round(current_x), round(current_y), color); + current_x += xInc; + current_y += yInc; + } +} + +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); +} diff --git a/src/display.h b/src/display.h index 0358166..2b7a037 100644 --- a/src/display.h +++ b/src/display.h @@ -12,6 +12,8 @@ extern uint32_t *color_buffer; extern SDL_Texture *color_buffer_texture; extern int window_width; extern int window_height; +#define FPS 60 +#define FRAME_TARGET_TIME (1000/FPS) bool initialize_window(void); @@ -19,6 +21,8 @@ void draw_grid(); 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_triangle(int x0, int y0, int x1, int y1, int x2, int y2, uint32_t color); void draw_rect(int x, int y, int width, int height, uint32_t color); void clear_color_buffer(uint32_t color); diff --git a/src/main.c b/src/main.c index ca5944c..c255487 100644 --- a/src/main.c +++ b/src/main.c @@ -3,112 +3,129 @@ #include #include "display.h" #include "vector.h" - -//////////////////////////////////////////////////////////// -// Declare an array of points -//////////////////////////////////////////////////////////// -#define N_POINTS (9 * 9 * 9) -vec3_t cube_points[N_POINTS]; -vec2_t projected_points[N_POINTS]; +#include "mesh.h" vec3_t camera_position = {0, 0, -5}; +vec3_t cube_rotation = {.x = 0, .y = 0, .z = 0}; +triangle_t triangles_to_render[N_MESH_FACES]; float fov_factor = 640; - - bool is_running = false; +uint32_t previous_frame_time = 0; + void setup(void) { - // Allocate the required memory in bytes to hold color buffer - color_buffer = (uint32_t *) malloc(sizeof(uint32_t) * window_width * window_height); + // Allocate the required memory in bytes to hold color buffer + color_buffer = (uint32_t *) malloc(sizeof(uint32_t) * window_width * window_height); - // Creating the SDL Texture that is uses to display the color buffer - color_buffer_texture = SDL_CreateTexture( - renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - window_width, - window_height - ); - int point_count = 0; - for (float x = -1; x <= 1; x += 0.25) { - for (float y = -1; y <= 1; y += 0.25) { - for (float z = -1; z <= 1; z += 0.25) { - vec3_t new_point = { .x = x, .y = y, .z = z }; - cube_points[point_count++] = new_point; - } - } - } + // Creating the SDL Texture that is uses 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); + 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; - } + switch (event.type) { + case SDL_QUIT: + is_running = false; + break; + case SDL_KEYDOWN: + if (event.key.keysym.sym == SDLK_ESCAPE) { + is_running = false; + } + break; + } } //////////////////////////////////////////////////////////////////////////////// // Function that receives a 3d Vector and returns a 2d projected point //////////////////////////////////////////////////////////////////////////////// vec2_t project(vec3_t point) { - vec2_t projected_point = { - .x = (fov_factor * point.x) / point.z, - .y = (fov_factor * point.y) / point.z, - }; - return projected_point; + vec2_t projected_point = { + .x = (fov_factor * point.x) / point.z, + .y = (fov_factor * point.y) / point.z, + }; + return projected_point; } - void update(void) { - for (int i = 0; i < N_POINTS; i++){ - vec3_t point = cube_points[i]; - point.z -= camera_position.z; - vec2_t projected_point = project(point); + // lock execution to the next tick + uint32_t time_to_wait = FRAME_TARGET_TIME - (SDL_GetTicks() - previous_frame_time); + if (time_to_wait > 0 && time_to_wait <= FRAME_TARGET_TIME) { + SDL_Delay(time_to_wait); + } + previous_frame_time = SDL_GetTicks(); + + cube_rotation.y += 0.01f; + cube_rotation.z += 0.01f; + cube_rotation.x += 0.01f; + + for (int i = 0; i < N_MESH_FACES; i++) { + face_t mesh_face = mesh_faces[i]; + vec3_t face_vertices[3]; + face_vertices[0] = mesh_vertices[mesh_face.a - 1]; + face_vertices[1] = mesh_vertices[mesh_face.b - 1]; + face_vertices[2] = mesh_vertices[mesh_face.c - 1]; + //loop all three vertices + triangle_t projected_triangle; + for (int j = 0; j < 3; j++) { + vec3_t transformed_vertex = face_vertices[j]; + transformed_vertex = vec3_rotate_y(transformed_vertex, cube_rotation.y); + transformed_vertex = vec3_rotate_x(transformed_vertex, cube_rotation.x); + transformed_vertex = vec3_rotate_z(transformed_vertex, cube_rotation.z); + transformed_vertex.z -= camera_position.z; + vec2_t projected_point = project(transformed_vertex); + + projected_point.x += (window_width / 2); + projected_point.y += (window_height / 2); + + projected_triangle.points[j] = projected_point; + } + // save projected triangle in array of triangles to render + triangles_to_render[i] = projected_triangle; + } - projected_points[i] = projected_point; - } } void render(void) { - draw_grid(); + draw_grid(); - for (int i = 0; i < N_POINTS; i++){ - vec2_t projected_point = projected_points[i]; - draw_rect( - projected_point.x + (window_width/2), - projected_point.y + (window_height/2), - 4, - 4, - 0xFFFFFF00 - ); - } + for (int i = 0; i < N_MESH_FACES; i++) { + triangle_t triangle = triangles_to_render[i]; + uint32_t color = 0xFFFFFF00; + for (int j = 0; j < 3; j++) { + draw_rect(triangle.points[j].x, triangle.points[j].y, 3, 3, color); + } + draw_triangle(triangle.points[0].x, triangle.points[0].y, + triangle.points[1].x, triangle.points[1].y, + triangle.points[2].x, triangle.points[2].y, + color); - render_color_buffer(); - clear_color_buffer(0xFF000000); + } - SDL_RenderPresent(renderer); + render_color_buffer(); + clear_color_buffer(0xFF000000); + + SDL_RenderPresent(renderer); } int main(void) { - is_running = initialize_window(); - setup(); + is_running = initialize_window(); + setup(); - while (is_running) { - process_input(); - update(); - render(); - } - destroy_window(); - return 0; + while (is_running) { + process_input(); + update(); + render(); + } + destroy_window(); + return 0; } diff --git a/src/mesh.c b/src/mesh.c new file mode 100644 index 0000000..01846d0 --- /dev/null +++ b/src/mesh.c @@ -0,0 +1,33 @@ +#include "mesh.h" + +vec3_t mesh_vertices[N_MESH_VERTICES] = { + {.x = -1, .y = -1, .z = -1}, + {.x = -1, .y = 1, .z = -1}, + {.x = 1, .y = 1, .z = -1}, + {.x = 1, .y = -1, .z = -1}, + {.x = 1, .y = 1, .z = 1}, + {.x = 1, .y = -1, .z = 1}, + {.x = -1, .y = 1, .z = 1}, + {.x = -1, .y = -1, .z = 1}, +}; + +face_t mesh_faces[N_MESH_FACES] = { + // Front + {.a = 1, .b = 2, .c = 3}, + {.a = 1, .b = 3, .c = 4}, + // right + {.a = 4, .b = 3, .c = 5}, + {.a = 4, .b = 5, .c = 6}, + // back + {.a = 6, .b = 5, .c = 7}, + {.a = 6, .b = 7, .c = 8}, + // left + {.a = 8, .b = 7, .c = 2}, + {.a = 8, .b = 2, .c = 1}, + // top + {.a = 2, .b = 7, .c = 5}, + {.a = 2, .b = 5, .c = 3}, + // bottom + {.a = 6, .b = 8, .c = 1}, + {.a = 6, .b = 1, .c = 4}, +}; \ No newline at end of file diff --git a/src/mesh.h b/src/mesh.h new file mode 100644 index 0000000..396cd7e --- /dev/null +++ b/src/mesh.h @@ -0,0 +1,11 @@ +#ifndef RENDERER_MESH_H +#define RENDERER_MESH_H +#include "vector.h" +#include "triangle.h" +#define N_MESH_VERTICES 8 +#define N_MESH_FACES (6 * 2 ) + +extern vec3_t mesh_vertices[N_MESH_VERTICES]; +extern face_t mesh_faces[N_MESH_FACES]; + +#endif //RENDERER_MESH_H \ No newline at end of file diff --git a/src/triangle.c b/src/triangle.c new file mode 100644 index 0000000..07025ac --- /dev/null +++ b/src/triangle.c @@ -0,0 +1,3 @@ +#include "triangle.h" + +// TODO \ No newline at end of file diff --git a/src/triangle.h b/src/triangle.h new file mode 100644 index 0000000..4592cba --- /dev/null +++ b/src/triangle.h @@ -0,0 +1,16 @@ +#ifndef RENDERER_TRIANGLE_H +#define RENDERER_TRIANGLE_H + +#include "vector.h" + +typedef struct { + int a; + int b; + int c; +} face_t; + +typedef struct { + vec2_t points[3]; +} triangle_t; + +#endif //RENDERER_TRIANGLE_H diff --git a/src/vector.c b/src/vector.c index db96a88..5b64cf2 100644 --- a/src/vector.c +++ b/src/vector.c @@ -1,3 +1,28 @@ +#include #include "vector.h" // Implement all vector functons +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; +} +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; +} +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; +} \ No newline at end of file diff --git a/src/vector.h b/src/vector.h index 0b54d31..45a5993 100644 --- a/src/vector.h +++ b/src/vector.h @@ -13,6 +13,9 @@ typedef struct { float z; } vec3_t; +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); #endif