From f6848b5f4fadd74e86dc110eced5830cc203b5cc Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sun, 14 Jul 2024 00:49:41 +0100 Subject: [PATCH] Start implementing drawing order --- compile | 1 + include/rasteriser/rasteriser.h | 6 ++- include/window/window.h | 7 ++- src/rasteriser/main.c | 14 ++--- src/rasteriser/rasteriser.c | 92 +++++++++++++++++++++++++++++---- src/raytracer/main.c | 2 +- src/window/window.c | 42 +++++++++++++-- 7 files changed, 142 insertions(+), 22 deletions(-) diff --git a/compile b/compile index 742ecd0..43fce83 100755 --- a/compile +++ b/compile @@ -12,6 +12,7 @@ RAYTRACER_SRC="src/window/*.c \ src/raytracer/*.c \ src/math/*.c \ src/camera/*.c \ + $WAPP_SRC \ " RASTERISER_SRC="src/window/*.c \ diff --git a/include/rasteriser/rasteriser.h b/include/rasteriser/rasteriser.h index 44d3840..012a4ea 100644 --- a/include/rasteriser/rasteriser.h +++ b/include/rasteriser/rasteriser.h @@ -31,7 +31,8 @@ MAKE_LIST_TYPE(scene_triangle_t); typedef enum { RASTERISER_RENDER_WIREFRAME, - RASTERISER_RENDER_SOLID, + RASTERISER_RENDER_FILLED, + RASTERISER_RENDER_SHADED, } render_type_t; typedef struct { @@ -46,6 +47,9 @@ typedef struct { f32 h0; f32 h1; f32 h2; + f32 z0; + f32 z1; + f32 z2; colour_t colour; } triangle_t; diff --git a/include/window/window.h b/include/window/window.h index ba9f134..fae131d 100644 --- a/include/window/window.h +++ b/include/window/window.h @@ -2,6 +2,7 @@ #define WINDOW_H #include "aliases.h" +#include "mem_arena.h" #include "vector/vec.h" #include #include @@ -29,13 +30,17 @@ typedef struct { SDL_Window *window; SDL_Surface *front_buffer; SDL_Surface *back_buffer; + f32 *z_buffer; } window_t; -bool init_window(window_t *wnd, u32 width, u32 height, const char *title); +bool init_window(Arena *arena, window_t *wnd, u32 width, u32 height, + const char *title); void close_window(window_t *wnd); void clear_window(window_t *wnd, colour_t colour); void set_pixel(window_t *wnd, i32 x, i32 y, colour_t colour); +void set_z_pixel(window_t *wnd, i32 x, i32 y, f32 value); +f32 get_z_pixel(const window_t *wnd, i32 x, i32 y); void swap_buffers(window_t *wnd); vec3f_t window_to_viewport(const window_t *wnd, i32 x, i32 y, vec3f_t viewport); diff --git a/src/rasteriser/main.c b/src/rasteriser/main.c index 0ae6da1..10b2d5f 100644 --- a/src/rasteriser/main.c +++ b/src/rasteriser/main.c @@ -20,12 +20,6 @@ int main(void) { }; vec3f_t viewport = {.x = 1.0f, .y = 1.0f, .z = 1.0f}; - window_t window = {0}; - - if (!init_window(&window, 800, 800, "CG From Scratch Rasteriser")) { - return EXIT_FAILURE; - } - Arena *arena = NULL; u64 main_arena_capacity = 64ull * 1024ull * 1024ull * 1024ull; if (!wapp_mem_arena_init(&arena, main_arena_capacity, WAPP_MEM_ALLOC_RESERVE, @@ -33,6 +27,12 @@ int main(void) { return EXIT_FAILURE; } + window_t window = {0}; + + if (!init_window(arena, &window, 800, 800, "CG From Scratch Rasteriser")) { + return EXIT_FAILURE; + } + list_vertex_t *vertices = list_create(vertex_t, arena); if (!vertices) { return EXIT_FAILURE; @@ -181,7 +181,7 @@ int main(void) { clear_window(&window, bg); - render_scene(&window, frame_arena, &scene, RASTERISER_RENDER_SOLID); + render_scene(&window, frame_arena, &scene, RASTERISER_RENDER_FILLED); swap_buffers(&window); diff --git a/src/rasteriser/rasteriser.c b/src/rasteriser/rasteriser.c index f0a7b72..9c9a8a7 100644 --- a/src/rasteriser/rasteriser.c +++ b/src/rasteriser/rasteriser.c @@ -121,16 +121,23 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, list_append(vec2i_t, arena, projected, point); } + vertex_t v0, v1, v2; for (u64 i = 0; i < triangles->count; ++i) { scene_triangle_t triangle = list_get(triangles, i); + v0 = list_get(transformed, triangle.idx0); + v1 = list_get(transformed, triangle.idx1); + v2 = list_get(transformed, triangle.idx2); triangle_t tri = { .p0 = list_get(projected, triangle.idx0), .p1 = list_get(projected, triangle.idx1), .p2 = list_get(projected, triangle.idx2), - .h0 = list_get(transformed, triangle.idx0).h, - .h1 = list_get(transformed, triangle.idx1).h, - .h2 = list_get(transformed, triangle.idx2).h, + .h0 = v0.h, + .h1 = v1.h, + .h2 = v2.h, + .z0 = v0.position.z, + .z1 = v1.position.z, + .z2 = v2.position.z, .colour = triangle.colour, }; @@ -143,9 +150,12 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene, case RASTERISER_RENDER_WIREFRAME: draw_wireframe_triangle(wnd, arena, tri); break; - case RASTERISER_RENDER_SOLID: + case RASTERISER_RENDER_FILLED: draw_filled_triangle(wnd, arena, tri); break; + case RASTERISER_RENDER_SHADED: + draw_shaded_triangle(wnd, arena, tri); + break; } } } @@ -176,22 +186,57 @@ void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle) { list_pop(x01); // Last element of x01 is a duplicate of first element in x12 list_merge(f32, arena, x012, x01, x12); + f32 z0 = triangle.z0; + f32 z1 = triangle.z1; + f32 z2 = triangle.z2; + list_float *z01 = interpolate(arena, y0, z0, y1, z1); + list_float *z12 = interpolate(arena, y1, z1, y2, z2); + list_float *z02 = interpolate(arena, y0, z0, y2, z2); + list_float *z012 = NULL; + + list_pop(z01); // Last element of z01 is a duplicate of first element in z12 + list_merge(f32, arena, z012, z01, z12); + list_float *x_left; list_float *x_right; + list_float *z_left; + list_float *z_right; u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f)); if (list_get(x02, middle) < list_get(x012, middle)) { x_left = x02; + z_left = z02; x_right = x012; + z_right = z012; } else { x_left = x012; + z_left = z012; x_right = x02; + z_right = z02; } + list_float *z_segment = NULL; + i32 index = -1; + i64 xl = -1; + i64 xr = -1; + f32 current_z = INFINITY; + f32 new_z = INFINITY; + for (i64 y = y0; y <= y2; ++y) { - i32 index = y - y0; - for (i64 x = (i64)list_get(x_left, index); x < list_get(x_right, index); - ++x) { - set_pixel(wnd, x, y, triangle.colour); + index = y - y0; + xl = (i64)list_get(x_left, index); + xr = (i64)list_get(x_right, index); + + for (i64 x = xl; x < xr; ++x) { + z_segment = interpolate(arena, xl, list_get(z_left, index), xr, + list_get(z_right, index)); + + current_z = get_z_pixel(wnd, x, y); + new_z = list_get(z_segment, x - xl); + + if (new_z <= current_z) { + set_z_pixel(wnd, x, y, new_z); + set_pixel(wnd, x, y, triangle.colour); + } } } } @@ -225,27 +270,47 @@ void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) { list_pop(h01); // Last element of h01 is a duplicate of first element in h12 list_merge(f32, arena, h012, h01, h12); + f32 z0 = triangle.z0; + f32 z1 = triangle.z1; + f32 z2 = triangle.z2; + list_float *z01 = interpolate(arena, y0, z0, y1, z1); + list_float *z12 = interpolate(arena, y1, z1, y2, z2); + list_float *z02 = interpolate(arena, y0, z0, y2, z2); + list_float *z012 = NULL; + + list_pop(z01); // Last element of z01 is a duplicate of first element in z12 + list_merge(f32, arena, z012, z01, z12); + list_float *x_left; list_float *x_right; list_float *h_left; list_float *h_right; + list_float *z_left; + list_float *z_right; u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f)); if (list_get(x02, middle) < list_get(x012, middle)) { x_left = x02; h_left = h02; + z_left = z02; x_right = x012; h_right = h012; + z_right = z012; } else { x_left = x012; h_left = h012; + z_left = z012; x_right = x02; h_right = h02; + z_right = z02; } list_float *h_segment = NULL; + list_float *z_segment = NULL; i32 index = -1; i64 xl = -1; i64 xr = -1; + f32 current_z = INFINITY; + f32 new_z = INFINITY; colour_t shaded_colour = (colour_t){0}; for (i64 y = y0; y <= y2; ++y) { @@ -255,8 +320,17 @@ void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) { for (i64 x = xl; x < xr; ++x) { h_segment = interpolate(arena, xl, list_get(h_left, index), xr, list_get(h_right, index)); + z_segment = interpolate(arena, xl, list_get(z_left, index), xr, + list_get(z_right, index)); shaded_colour = colour_mul(triangle.colour, list_get(h_segment, x - xl)); - set_pixel(wnd, x, y, shaded_colour); + + current_z = get_z_pixel(wnd, x, y); + new_z = list_get(z_segment, x - xl); + + if (new_z <= current_z) { + set_z_pixel(wnd, x, y, new_z); + set_pixel(wnd, x, y, shaded_colour); + } } } } diff --git a/src/raytracer/main.c b/src/raytracer/main.c index 67ba71a..e2612b6 100644 --- a/src/raytracer/main.c +++ b/src/raytracer/main.c @@ -22,7 +22,7 @@ i32 main(i32 argc, char *argv[]) { window_t window = {0}; - if (!init_window(&window, 800, 800, "CG From Scratch Raytracer")) { + if (!init_window(NULL, &window, 800, 800, "CG From Scratch Raytracer")) { return EXIT_FAILURE; } diff --git a/src/window/window.c b/src/window/window.c index 559949d..5724b13 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -1,21 +1,25 @@ #include "window/window.h" #include "aliases.h" #include "math/math_utils.h" +#include "mem_arena.h" #include "vector/vec.h" #include #include #include #include +#include #include #include #include -u32 index_from_coordinates(window_t *wnd, u32 x, u32 y); +u32 index_from_coordinates(const window_t *wnd, u32 x, u32 y); i32 denormalise(i32 value, u32 max, u32 abs_half); vec2i_t denormalised_coords(const window_t *wnd, i32 x, i32 y); void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour); +void set_z_buffer_pixel(window_t *wnd, u32 x, u32 y, f32 value); -bool init_window(window_t *wnd, u32 width, u32 height, const char *title) { +bool init_window(Arena *arena, window_t *wnd, u32 width, u32 height, + const char *title) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { printf("Failed to initialise SDL: %s\n", SDL_GetError()); @@ -64,6 +68,9 @@ bool init_window(window_t *wnd, u32 width, u32 height, const char *title) { wnd->half_width = width / 2; wnd->half_height = height / 2; wnd->title = title; + if (arena) { + wnd->z_buffer = wapp_mem_arena_alloc(arena, width * height * sizeof(f32)); + } return true; } @@ -85,6 +92,8 @@ void close_window(window_t *wnd) { wnd->back_buffer = NULL; } + + wnd->z_buffer = NULL; } SDL_Quit(); @@ -98,6 +107,7 @@ void clear_window(window_t *wnd, colour_t colour) { for (u32 i = 0; i < count; ++i) { pixels[i] = colour.colour; + wnd->z_buffer[i] = INFINITY; } SDL_UnlockSurface(wnd->back_buffer); @@ -117,13 +127,34 @@ void set_pixel(window_t *wnd, i32 x, i32 y, colour_t colour) { SDL_UnlockSurface(wnd->back_buffer); } +void set_z_pixel(window_t *wnd, i32 x, i32 y, f32 value) { + vec2i_t coords = denormalised_coords(wnd, x, y); + + if (coords.x < 0 || coords.y < 0) { + return; + } + + set_z_buffer_pixel(wnd, (u32)(coords.x), (u32)(coords.y), value); +} + +f32 get_z_pixel(const window_t *wnd, i32 x, i32 y) { + vec2i_t coords = denormalised_coords(wnd, x, y); + + if (coords.x < 0 || coords.y < 0) { + return INFINITY; + } + + u32 index = index_from_coordinates(wnd, (u32)(coords.x), (u32)(coords.y)); + return wnd->z_buffer[index]; +} + void swap_buffers(window_t *wnd) { SDL_BlitSurface(wnd->back_buffer, NULL, wnd->front_buffer, NULL); SDL_UpdateWindowSurface(wnd->window); } -u32 index_from_coordinates(window_t *wnd, u32 x, u32 y) { +u32 index_from_coordinates(const window_t *wnd, u32 x, u32 y) { return y * wnd->width + x; } @@ -159,6 +190,11 @@ void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour) { pixels[index] = colour.colour; } +void set_z_buffer_pixel(window_t *wnd, u32 x, u32 y, f32 value) { + u32 index = index_from_coordinates(wnd, x, y); + wnd->z_buffer[index] = value; +} + vec3f_t window_to_viewport(const window_t *wnd, i32 x, i32 y, vec3f_t viewport) { return (vec3f_t){