Start implementing drawing order

This commit is contained in:
Abdelrahman Said 2024-07-14 00:49:41 +01:00
parent 77edf714bb
commit f6848b5f4f
7 changed files with 142 additions and 22 deletions

View File

@ -12,6 +12,7 @@ RAYTRACER_SRC="src/window/*.c \
src/raytracer/*.c \ src/raytracer/*.c \
src/math/*.c \ src/math/*.c \
src/camera/*.c \ src/camera/*.c \
$WAPP_SRC \
" "
RASTERISER_SRC="src/window/*.c \ RASTERISER_SRC="src/window/*.c \

View File

@ -31,7 +31,8 @@ MAKE_LIST_TYPE(scene_triangle_t);
typedef enum { typedef enum {
RASTERISER_RENDER_WIREFRAME, RASTERISER_RENDER_WIREFRAME,
RASTERISER_RENDER_SOLID, RASTERISER_RENDER_FILLED,
RASTERISER_RENDER_SHADED,
} render_type_t; } render_type_t;
typedef struct { typedef struct {
@ -46,6 +47,9 @@ typedef struct {
f32 h0; f32 h0;
f32 h1; f32 h1;
f32 h2; f32 h2;
f32 z0;
f32 z1;
f32 z2;
colour_t colour; colour_t colour;
} triangle_t; } triangle_t;

View File

@ -2,6 +2,7 @@
#define WINDOW_H #define WINDOW_H
#include "aliases.h" #include "aliases.h"
#include "mem_arena.h"
#include "vector/vec.h" #include "vector/vec.h"
#include <SDL2/SDL_video.h> #include <SDL2/SDL_video.h>
#include <stdbool.h> #include <stdbool.h>
@ -29,13 +30,17 @@ typedef struct {
SDL_Window *window; SDL_Window *window;
SDL_Surface *front_buffer; SDL_Surface *front_buffer;
SDL_Surface *back_buffer; SDL_Surface *back_buffer;
f32 *z_buffer;
} window_t; } 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 close_window(window_t *wnd);
void clear_window(window_t *wnd, colour_t colour); void clear_window(window_t *wnd, colour_t colour);
void set_pixel(window_t *wnd, i32 x, i32 y, 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); void swap_buffers(window_t *wnd);
vec3f_t window_to_viewport(const window_t *wnd, i32 x, i32 y, vec3f_t viewport); vec3f_t window_to_viewport(const window_t *wnd, i32 x, i32 y, vec3f_t viewport);

View File

@ -20,12 +20,6 @@ int main(void) {
}; };
vec3f_t viewport = {.x = 1.0f, .y = 1.0f, .z = 1.0f}; 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; Arena *arena = NULL;
u64 main_arena_capacity = 64ull * 1024ull * 1024ull * 1024ull; u64 main_arena_capacity = 64ull * 1024ull * 1024ull * 1024ull;
if (!wapp_mem_arena_init(&arena, main_arena_capacity, WAPP_MEM_ALLOC_RESERVE, if (!wapp_mem_arena_init(&arena, main_arena_capacity, WAPP_MEM_ALLOC_RESERVE,
@ -33,6 +27,12 @@ int main(void) {
return EXIT_FAILURE; 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); list_vertex_t *vertices = list_create(vertex_t, arena);
if (!vertices) { if (!vertices) {
return EXIT_FAILURE; return EXIT_FAILURE;
@ -181,7 +181,7 @@ int main(void) {
clear_window(&window, bg); 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); swap_buffers(&window);

View File

@ -121,16 +121,23 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
list_append(vec2i_t, arena, projected, point); list_append(vec2i_t, arena, projected, point);
} }
vertex_t v0, v1, v2;
for (u64 i = 0; i < triangles->count; ++i) { for (u64 i = 0; i < triangles->count; ++i) {
scene_triangle_t triangle = list_get(triangles, 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 = { triangle_t tri = {
.p0 = list_get(projected, triangle.idx0), .p0 = list_get(projected, triangle.idx0),
.p1 = list_get(projected, triangle.idx1), .p1 = list_get(projected, triangle.idx1),
.p2 = list_get(projected, triangle.idx2), .p2 = list_get(projected, triangle.idx2),
.h0 = list_get(transformed, triangle.idx0).h, .h0 = v0.h,
.h1 = list_get(transformed, triangle.idx1).h, .h1 = v1.h,
.h2 = list_get(transformed, triangle.idx2).h, .h2 = v2.h,
.z0 = v0.position.z,
.z1 = v1.position.z,
.z2 = v2.position.z,
.colour = triangle.colour, .colour = triangle.colour,
}; };
@ -143,9 +150,12 @@ internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
case RASTERISER_RENDER_WIREFRAME: case RASTERISER_RENDER_WIREFRAME:
draw_wireframe_triangle(wnd, arena, tri); draw_wireframe_triangle(wnd, arena, tri);
break; break;
case RASTERISER_RENDER_SOLID: case RASTERISER_RENDER_FILLED:
draw_filled_triangle(wnd, arena, tri); draw_filled_triangle(wnd, arena, tri);
break; break;
case RASTERISER_RENDER_SHADED:
draw_shaded_triangle(wnd, arena, tri);
break;
} }
} }
} }
@ -176,25 +186,60 @@ 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_pop(x01); // Last element of x01 is a duplicate of first element in x12
list_merge(f32, arena, x012, x01, 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_left;
list_float *x_right; list_float *x_right;
list_float *z_left;
list_float *z_right;
u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f)); u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f));
if (list_get(x02, middle) < list_get(x012, middle)) { if (list_get(x02, middle) < list_get(x012, middle)) {
x_left = x02; x_left = x02;
z_left = z02;
x_right = x012; x_right = x012;
z_right = z012;
} else { } else {
x_left = x012; x_left = x012;
z_left = z012;
x_right = x02; 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) { for (i64 y = y0; y <= y2; ++y) {
i32 index = y - y0; index = y - y0;
for (i64 x = (i64)list_get(x_left, index); x < list_get(x_right, index); xl = (i64)list_get(x_left, index);
++x) { 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); set_pixel(wnd, x, y, triangle.colour);
} }
} }
} }
}
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) { void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
order_triangle_points(&triangle); order_triangle_points(&triangle);
@ -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_pop(h01); // Last element of h01 is a duplicate of first element in h12
list_merge(f32, arena, h012, h01, 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_left;
list_float *x_right; list_float *x_right;
list_float *h_left; list_float *h_left;
list_float *h_right; list_float *h_right;
list_float *z_left;
list_float *z_right;
u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f)); u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f));
if (list_get(x02, middle) < list_get(x012, middle)) { if (list_get(x02, middle) < list_get(x012, middle)) {
x_left = x02; x_left = x02;
h_left = h02; h_left = h02;
z_left = z02;
x_right = x012; x_right = x012;
h_right = h012; h_right = h012;
z_right = z012;
} else { } else {
x_left = x012; x_left = x012;
h_left = h012; h_left = h012;
z_left = z012;
x_right = x02; x_right = x02;
h_right = h02; h_right = h02;
z_right = z02;
} }
list_float *h_segment = NULL; list_float *h_segment = NULL;
list_float *z_segment = NULL;
i32 index = -1; i32 index = -1;
i64 xl = -1; i64 xl = -1;
i64 xr = -1; i64 xr = -1;
f32 current_z = INFINITY;
f32 new_z = INFINITY;
colour_t shaded_colour = (colour_t){0}; colour_t shaded_colour = (colour_t){0};
for (i64 y = y0; y <= y2; ++y) { for (i64 y = y0; y <= y2; ++y) {
@ -255,11 +320,20 @@ void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
for (i64 x = xl; x < xr; ++x) { for (i64 x = xl; x < xr; ++x) {
h_segment = interpolate(arena, xl, list_get(h_left, index), xr, h_segment = interpolate(arena, xl, list_get(h_left, index), xr,
list_get(h_right, index)); 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)); shaded_colour = colour_mul(triangle.colour, list_get(h_segment, x - xl));
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); set_pixel(wnd, x, y, shaded_colour);
} }
} }
} }
}
void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) { void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) {
list_float *values = NULL; list_float *values = NULL;

View File

@ -22,7 +22,7 @@ i32 main(i32 argc, char *argv[]) {
window_t window = {0}; 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; return EXIT_FAILURE;
} }

View File

@ -1,21 +1,25 @@
#include "window/window.h" #include "window/window.h"
#include "aliases.h" #include "aliases.h"
#include "math/math_utils.h" #include "math/math_utils.h"
#include "mem_arena.h"
#include "vector/vec.h" #include "vector/vec.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <SDL2/SDL_error.h> #include <SDL2/SDL_error.h>
#include <SDL2/SDL_pixels.h> #include <SDL2/SDL_pixels.h>
#include <SDL2/SDL_surface.h> #include <SDL2/SDL_surface.h>
#include <math.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
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); i32 denormalise(i32 value, u32 max, u32 abs_half);
vec2i_t denormalised_coords(const window_t *wnd, i32 x, i32 y); 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_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) { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
printf("Failed to initialise SDL: %s\n", SDL_GetError()); 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_width = width / 2;
wnd->half_height = height / 2; wnd->half_height = height / 2;
wnd->title = title; wnd->title = title;
if (arena) {
wnd->z_buffer = wapp_mem_arena_alloc(arena, width * height * sizeof(f32));
}
return true; return true;
} }
@ -85,6 +92,8 @@ void close_window(window_t *wnd) {
wnd->back_buffer = NULL; wnd->back_buffer = NULL;
} }
wnd->z_buffer = NULL;
} }
SDL_Quit(); SDL_Quit();
@ -98,6 +107,7 @@ void clear_window(window_t *wnd, colour_t colour) {
for (u32 i = 0; i < count; ++i) { for (u32 i = 0; i < count; ++i) {
pixels[i] = colour.colour; pixels[i] = colour.colour;
wnd->z_buffer[i] = INFINITY;
} }
SDL_UnlockSurface(wnd->back_buffer); 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); 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) { void swap_buffers(window_t *wnd) {
SDL_BlitSurface(wnd->back_buffer, NULL, wnd->front_buffer, NULL); SDL_BlitSurface(wnd->back_buffer, NULL, wnd->front_buffer, NULL);
SDL_UpdateWindowSurface(wnd->window); 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; 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; 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 window_to_viewport(const window_t *wnd, i32 x, i32 y,
vec3f_t viewport) { vec3f_t viewport) {
return (vec3f_t){ return (vec3f_t){