Compare commits

...

41 Commits

Author SHA1 Message Date
b35a7d9cbe Save projected vertex 2024-07-14 23:28:41 +01:00
ade35f3940 Add list_set function 2024-07-14 23:28:21 +01:00
e96400f74e Minor changes to depth buffering 2024-07-14 22:36:36 +01:00
70dfb5d5ee Calculate the triangle normal from midpoint 2024-07-14 17:56:01 +01:00
51099ae97e Incomplete implementation of back face culling 2024-07-14 16:02:37 +01:00
5a3b143762 Add list_remove function 2024-07-14 16:02:19 +01:00
83fa308a4b Add cross product for 3D vectors 2024-07-14 16:01:55 +01:00
94287ff081 Switch to 1/z for depth buffering 2024-07-14 01:19:12 +01:00
48735adf7b Remove unused data type 2024-07-14 00:50:45 +01:00
f6848b5f4f Start implementing drawing order 2024-07-14 00:49:41 +01:00
77edf714bb Switch to rendering solid objects 2024-07-13 22:44:16 +01:00
5d61e8a616 Add wireframe and solid render types 2024-07-13 22:43:00 +01:00
e236cd8bbe Create vertex_t and move h data to it 2024-07-13 22:00:48 +01:00
b0bf4f593b Add h values for scene_triangle_t 2024-07-13 19:32:02 +01:00
f6f2483b61 Finalise implementing triangle clipping 2024-07-13 18:26:15 +01:00
00e7293b28 Reformat 2024-07-10 00:19:11 +01:00
3c293198bb Start implementing clipping triangles 2024-07-10 00:18:10 +01:00
ae072ec70e Initial implementation of bounding sphere clipping 2024-07-09 23:31:54 +01:00
c3e1aac779 Move scene to raytracer 2024-07-09 19:44:19 +01:00
4430ea872c Increase arena and frame arena capacities 2024-07-07 23:33:36 +01:00
df1620319c Flip camera x rotation controls 2024-07-07 23:30:46 +01:00
26fc513d4a Apply transformation first then project the points 2024-07-07 23:19:29 +01:00
9d929c22ba Add clipping planes to the scene 2024-07-07 23:19:12 +01:00
44c7b6ac1b Add function to multiply 4x4 matrix by 4D vector 2024-07-07 23:18:00 +01:00
7823e92861 Apply projection matrix last to allow for clipping 2024-07-07 22:06:35 +01:00
b7101108a4 Add rasteriser_scene_t struct and render_scene function 2024-07-07 21:58:16 +01:00
39f198e342 Add camera controls 2024-06-30 14:52:29 +01:00
b81304e759 Switch to using transformation matrices 2024-06-30 02:40:04 +01:00
9ba7a8c414 Add vec4 types and functions 2024-06-30 00:09:22 +01:00
01c5def71f Fix project_point function 2024-06-30 00:08:38 +01:00
0911b33981 Add another cube instance 2024-06-29 20:13:30 +01:00
946ea9c307 Add model and instance data types 2024-06-29 20:04:52 +01:00
7f251e7704 Draw cube using vertices and triangles lists 2024-06-29 19:28:57 +01:00
fa5453d399 Add render_object function 2024-06-29 19:28:41 +01:00
7c192d5edf Include vector 2024-06-29 19:28:21 +01:00
33b89a9e44 Fix list type naming 2024-06-29 18:28:41 +01:00
d5a18828c5 Rename arena to frame_arena 2024-06-29 17:47:04 +01:00
c9f3c6ab01 Add colour field to triangle 2024-06-29 17:46:50 +01:00
96c5d21f79 Adjust cube colours 2024-06-29 17:16:48 +01:00
f922980232 Projection equation and first cube 2024-06-29 17:11:31 +01:00
6dc609be14 Update wireframe triangle colour 2024-06-29 15:54:54 +01:00
17 changed files with 1272 additions and 244 deletions

View File

@@ -9,17 +9,18 @@ LIBS="$(pkg-config --libs sdl2) -lm"
RAYTRACER_SRC="src/window/*.c \ RAYTRACER_SRC="src/window/*.c \
src/vector/*.c \ src/vector/*.c \
src/scene/*.c \
src/raytracer/*.c \ src/raytracer/*.c \
src/math/*.c \ src/math/*.c \
src/camera/*.c \
$WAPP_SRC \
" "
RASTERISER_SRC="src/window/*.c \ RASTERISER_SRC="src/window/*.c \
src/vector/*.c \ src/vector/*.c \
src/scene/*.c \
src/list/*.c \ src/list/*.c \
src/rasteriser/*.c \ src/rasteriser/*.c \
src/math/*.c \ src/math/*.c \
src/camera/*.c \
$WAPP_SRC \ $WAPP_SRC \
" "

15
include/camera/camera.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef CAMERA_H
#define CAMERA_H
#include "vector/vec.h"
#include "window/window.h"
typedef struct {
vec3f_t position;
vec3f_t rotation;
} camera_t;
mat4x4f_t inverse_camera_translation_matrix(const camera_t *camera);
mat4x4f_t inverse_camera_rotation_matrix(const camera_t *camera);
#endif // !CAMERA_H

View File

@@ -8,8 +8,8 @@
#define BASE_LIST_CAPACITY 1024 #define BASE_LIST_CAPACITY 1024
#define CONCAT(A, B, C) A##B##C #define CONCAT(A, B) A##B
#define LIST_TYPE_NAME(T) CONCAT(list_, T, _t) #define LIST_TYPE_NAME(T) CONCAT(list_, T)
#define MAKE_LIST_TYPE(T) \ #define MAKE_LIST_TYPE(T) \
typedef struct { \ typedef struct { \
@@ -44,8 +44,13 @@
LP->items[(LP->count)++] = ITEM; \ LP->items[(LP->count)++] = ITEM; \
} while (0) } while (0)
#define list_remove(LP, IDX) \
do { \
LP->items[IDX] = LP->items[(LP->count)--]; \
} while (0)
#define list_pop(LP) (LP->count -= 1) #define list_pop(LP) (LP->count -= 1)
#define list_set(LP, IDX, ITEM) LP->items[IDX] = ITEM
#define list_get(LP, IDX) LP->items[IDX] #define list_get(LP, IDX) LP->items[IDX]
#define list_merge(T, ARENA, DST, LP1, LP2) \ #define list_merge(T, ARENA, DST, LP1, LP2) \
@@ -68,7 +73,7 @@
MAKE_LIST_TYPE(void); MAKE_LIST_TYPE(void);
list_void_t *_create_list(Arena *arena, u64 size, u64 count); list_void *_create_list(Arena *arena, u64 size, u64 count);
void *_alloc_for_list(Arena *arena, u64 size); void *_alloc_for_list(Arena *arena, u64 size);
#endif // !TYPED_LIST_H #endif // !TYPED_LIST_H

View File

@@ -2,12 +2,41 @@
#define RASTERISER_H #define RASTERISER_H
#include "aliases.h" #include "aliases.h"
#include "camera/camera.h"
#include "list/typed_list.h" #include "list/typed_list.h"
#include "mem_arena.h" #include "mem_arena.h"
#include "vector/vec.h" #include "vector/vec.h"
#include "window/window.h" #include "window/window.h"
#define INVALID_VERTEX -1
typedef struct {
vec3f_t position;
f32 h;
} vertex_t;
typedef struct {
i64 idx0;
i64 idx1;
i64 idx2;
colour_t colour;
} scene_triangle_t;
MAKE_LIST_TYPE(u64);
MAKE_LIST_TYPE(f32); MAKE_LIST_TYPE(f32);
MAKE_LIST_TYPE(vec2i_t);
MAKE_LIST_TYPE(vec3f_t);
MAKE_LIST_TYPE(vec4f_t);
MAKE_LIST_TYPE(vertex_t);
MAKE_LIST_TYPE(scene_triangle_t);
typedef enum {
RASTERISER_RENDER_WIREFRAME,
RASTERISER_RENDER_FILLED,
RASTERISER_RENDER_SHADED,
COUNT_RASTERISER_RENDER,
} render_type_t;
typedef struct { typedef struct {
vec2i_t p0; vec2i_t p0;
@@ -21,14 +50,54 @@ typedef struct {
f32 h0; f32 h0;
f32 h1; f32 h1;
f32 h2; f32 h2;
f32 z0;
f32 z1;
f32 z2;
colour_t colour;
} triangle_t; } triangle_t;
void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle, typedef struct {
colour_t colour); list_vertex_t *vertices;
void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle, list_scene_triangle_t *triangles;
colour_t colour); } model_t;
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle, #define NULL_MODEL ((model_t){0})
colour_t colour);
typedef struct {
f32 scale;
vec3f_t rotation;
vec3f_t position;
} transform_t;
typedef struct {
vec3f_t centre;
f32 radius;
} bounding_sphere_t;
typedef struct {
model_t *model;
transform_t transform;
} instance_t;
typedef struct {
vec3f_t normal;
f32 distance;
} clipping_plane_t;
#define CLIPPING_PLANE_COUNT 5
typedef struct {
u64 instance_count;
instance_t *instances;
camera_t *camera;
const mat3x4f_t *proj_matrix;
clipping_plane_t planes[CLIPPING_PLANE_COUNT];
} rasteriser_scene_t;
void render_scene(window_t *wnd, Arena *arena, const rasteriser_scene_t *scene,
render_type_t type);
void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle);
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);
bool is_null_model(const model_t *model);
#endif // !RASTERISER_H #endif // !RASTERISER_H

View File

@@ -2,7 +2,6 @@
#define RAYTRACER_H #define RAYTRACER_H
#include "aliases.h" #include "aliases.h"
#include "scene/scene.h"
#include "vector/vec.h" #include "vector/vec.h"
#include "window/window.h" #include "window/window.h"
@@ -11,13 +10,46 @@ typedef struct {
f32 t2; f32 t2;
} solutions_t; } solutions_t;
typedef struct {
f32 radius;
vec3f_t centre;
colour_t colour;
f32 specular;
f32 reflective;
} sphere_t;
typedef struct { typedef struct {
f32 closest_t; f32 closest_t;
const sphere_t *closest_sphere; const sphere_t *closest_sphere;
} intersection_t; } intersection_t;
typedef enum {
LIGHT_TYPE_POINT,
LIGHT_TYPE_DIRECTIONAL,
LIGHT_TYPE_AMBIENT,
COUNT_LIGHT_TYPE,
} light_type_t;
typedef struct {
light_type_t type;
f32 intensity;
union {
vec3f_t position;
vec3f_t direction;
};
} light_t;
typedef struct {
const sphere_t *spheres;
const light_t *lights;
u32 spheres_count;
u32 lights_count;
} raytracer_scene_t;
const raytracer_scene_t *build_test_scene(void);
colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max, colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
const scene_t *scene, colour_t default_colour, const raytracer_scene_t *scene, colour_t default_colour,
u32 recursion_depth); u32 recursion_depth);
#endif // !RAYTRACER_H #endif // !RAYTRACER_H

View File

@@ -1,41 +0,0 @@
#ifndef SCENE_H
#define SCENE_H
#include "aliases.h"
#include "window/window.h"
typedef struct {
f32 radius;
vec3f_t centre;
colour_t colour;
f32 specular;
f32 reflective;
} sphere_t;
typedef enum {
LIGHT_TYPE_POINT,
LIGHT_TYPE_DIRECTIONAL,
LIGHT_TYPE_AMBIENT,
COUNT_LIGHT_TYPE,
} light_type_t;
typedef struct {
light_type_t type;
f32 intensity;
union {
vec3f_t position;
vec3f_t direction;
};
} light_t;
typedef struct {
const sphere_t *spheres;
const light_t *lights;
u32 spheres_count;
u32 lights_count;
} scene_t;
const scene_t *build_test_scene(void);
#endif // !SCENE_H

View File

@@ -25,12 +25,46 @@ typedef struct {
f32 z; f32 z;
} vec3f_t; } vec3f_t;
typedef struct {
i32 x;
i32 y;
i32 z;
i32 w;
} vec4i_t;
typedef struct {
f32 x;
f32 y;
f32 z;
f32 w;
} vec4f_t;
typedef struct {
vec3f_t row0;
vec3f_t row1;
vec3f_t row2;
} mat3x3f_t;
typedef struct {
vec4f_t row0;
vec4f_t row1;
vec4f_t row2;
} mat3x4f_t;
typedef struct {
vec4f_t row0;
vec4f_t row1;
vec4f_t row2;
vec4f_t row3;
} mat4x4f_t;
#define vec_add(T, v1, v2) vec_add_##T(v1, v2) #define vec_add(T, v1, v2) vec_add_##T(v1, v2)
#define vec_sub(T, v1, v2) vec_sub_##T(v1, v2) #define vec_sub(T, v1, v2) vec_sub_##T(v1, v2)
#define vec_mul(T, v1, v2) vec_mul_##T(v1, v2) #define vec_mul(T, v1, v2) vec_mul_##T(v1, v2)
#define vec_mul_num(T, v1, num) vec_mul_num_##T(v1, num) #define vec_mul_num(T, v1, num) vec_mul_num_##T(v1, num)
#define vec_div_num(T, v1, num) vec_div_num_##T(v1, num) #define vec_div_num(T, v1, num) vec_div_num_##T(v1, num)
#define vec_dot(T, v1, v2) vec_dot_##T(v1, v2) #define vec_dot(T, v1, v2) vec_dot_##T(v1, v2)
#define vec_cross(T, v1, v2) vec_cross_##T(v1, v2)
#define vec_magnitude(T, v) vec_magnitude_##T(v) #define vec_magnitude(T, v) vec_magnitude_##T(v)
#define vec_unit(T, v) vec_unit_##T(v) #define vec_unit(T, v) vec_unit_##T(v)
@@ -58,6 +92,7 @@ vec3i_t vec_mul_vec3i_t(vec3i_t v1, vec3i_t v2);
vec3i_t vec_mul_num_vec3i_t(vec3i_t v1, i32 num); vec3i_t vec_mul_num_vec3i_t(vec3i_t v1, i32 num);
vec3i_t vec_div_num_vec3i_t(vec3i_t v1, i32 num); vec3i_t vec_div_num_vec3i_t(vec3i_t v1, i32 num);
i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2); i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2);
vec3i_t vec_cross_vec3i_t(vec3i_t v1, vec3i_t v2);
i32 vec_magnitude_vec3i_t(vec3i_t v); i32 vec_magnitude_vec3i_t(vec3i_t v);
vec3i_t vec_unit_vec3i_t(vec3i_t v); vec3i_t vec_unit_vec3i_t(vec3i_t v);
@@ -67,8 +102,36 @@ vec3f_t vec_mul_vec3f_t(vec3f_t v1, vec3f_t v2);
vec3f_t vec_mul_num_vec3f_t(vec3f_t v1, f32 num); vec3f_t vec_mul_num_vec3f_t(vec3f_t v1, f32 num);
vec3f_t vec_div_num_vec3f_t(vec3f_t v1, f32 num); vec3f_t vec_div_num_vec3f_t(vec3f_t v1, f32 num);
f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2); f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2);
vec3f_t vec_cross_vec3f_t(vec3f_t v1, vec3f_t v2);
f32 vec_magnitude_vec3f_t(vec3f_t v); f32 vec_magnitude_vec3f_t(vec3f_t v);
vec3f_t vec_unit_vec3f_t(vec3f_t v); vec3f_t vec_unit_vec3f_t(vec3f_t v);
vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation); vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation);
vec4i_t vec_add_vec4i_t(vec4i_t v1, vec4i_t v2);
vec4i_t vec_sub_vec4i_t(vec4i_t v1, vec4i_t v2);
vec4i_t vec_mul_vec4i_t(vec4i_t v1, vec4i_t v2);
vec4i_t vec_mul_num_vec4i_t(vec4i_t v1, i32 num);
vec4i_t vec_div_num_vec4i_t(vec4i_t v1, i32 num);
i32 vec_dot_vec4i_t(vec4i_t v1, vec4i_t v2);
i32 vec_magnitude_vec4i_t(vec4i_t v);
vec4i_t vec_unit_vec4i_t(vec4i_t v);
vec4f_t vec_add_vec4f_t(vec4f_t v1, vec4f_t v2);
vec4f_t vec_sub_vec4f_t(vec4f_t v1, vec4f_t v2);
vec4f_t vec_mul_vec4f_t(vec4f_t v1, vec4f_t v2);
vec4f_t vec_mul_num_vec4f_t(vec4f_t v1, f32 num);
vec4f_t vec_div_num_vec4f_t(vec4f_t v1, f32 num);
f32 vec_dot_vec4f_t(vec4f_t v1, vec4f_t v2);
f32 vec_magnitude_vec4f_t(vec4f_t v);
vec4f_t vec_unit_vec4f_t(vec4f_t v);
mat4x4f_t get_translation_matrix(vec3f_t translation);
mat4x4f_t get_rotation_matrix(vec3f_t rotation);
mat4x4f_t get_scaling_matrix(vec3f_t scale);
mat3x3f_t get_rotation_mat3x3f(vec3f_t rotation);
vec3f_t mul_mat3x4f_by_vec4f(mat3x4f_t mat, vec4f_t vec);
mat3x4f_t mul_mat3x4f_by_mat4x4f(mat3x4f_t mat1, mat4x4f_t mat2);
vec4f_t mul_mat4x4f_by_vec4f(mat4x4f_t mat, vec4f_t vec);
mat4x4f_t mul_mat4x4f(mat4x4f_t mat1, mat4x4f_t mat2);
#endif // !VEC_H #endif // !VEC_H

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,16 +30,21 @@ 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(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);
vec2i_t viewport_to_window(const window_t *wnd, f32 x, f32 y, vec3f_t viewport);
colour_t colour_add_colour(colour_t a, colour_t b); colour_t colour_add_colour(colour_t a, colour_t b);
colour_t colour_mul(colour_t colour, f32 scalar); colour_t colour_mul(colour_t colour, f32 scalar);

12
src/camera/camera.c Normal file
View File

@@ -0,0 +1,12 @@
#include "camera/camera.h"
#include "vector/vec.h"
mat4x4f_t inverse_camera_translation_matrix(const camera_t *camera) {
vec3f_t inverse_translation = vec_mul_num(vec3f_t, camera->position, -1.0f);
return get_translation_matrix(inverse_translation);
}
mat4x4f_t inverse_camera_rotation_matrix(const camera_t *camera) {
vec3f_t inverse_rotation = vec_mul_num(vec3f_t, camera->rotation, -1.0f);
return get_rotation_matrix(inverse_rotation);
}

View File

@@ -5,16 +5,15 @@
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
list_void_t *_create_list(Arena *arena, u64 size, u64 count) { list_void *_create_list(Arena *arena, u64 size, u64 count) {
list_void_t *list = list_void *list = (list_void *)_alloc_for_list(arena, sizeof(list_void));
(list_void_t *)_alloc_for_list(arena, sizeof(list_void_t));
if (!list) { if (!list) {
return NULL; return NULL;
} }
list->items = (void *)_alloc_for_list(arena, size * count); list->items = (void *)_alloc_for_list(arena, size * count);
if (!list->items) { if (!list->items) {
munmap(list, sizeof(list_void_t)); munmap(list, sizeof(list_void));
return NULL; return NULL;
} }
memset(list->items, 0, sizeof(size * count)); memset(list->items, 0, sizeof(size * count));

View File

@@ -1,3 +1,5 @@
#include "camera/camera.h"
#include "list/typed_list.h"
#include "mem_arena.h" #include "mem_arena.h"
#include "mem_utils.h" #include "mem_utils.h"
#include "misc/misc_utils.h" #include "misc/misc_utils.h"
@@ -6,17 +8,144 @@
#include "window/window.h" #include "window/window.h"
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
#include <SDL2/SDL_keycode.h> #include <SDL2/SDL_keycode.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
int main(void) { int main(void) {
colour_t bg = colour_t bg =
(colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255}; (colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255};
window_t window = {0}; camera_t camera = {
.position = {.x = 0.0f, .y = 0.0f, .z = 0.0f},
.rotation = {.x = 0.0f, .y = 0.0f, .z = 0.0f},
};
vec3f_t viewport = {.x = 1.0f, .y = 1.0f, .z = 1.0f};
if (!init_window(&window, 800, 800, "CG From Scratch Rasteriser")) { Arena *arena = NULL;
u64 main_arena_capacity = 64ull * 1024ull * 1024ull * 1024ull;
if (!wapp_mem_arena_init(&arena, main_arena_capacity, WAPP_MEM_ALLOC_RESERVE,
false)) {
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);
if (!vertices) {
return EXIT_FAILURE;
}
// Vertices
vertex_t verts[] = {
(vertex_t){.position = {1, 1, 1}, .h = 1.0f},
(vertex_t){.position = {-1, 1, 1}, .h = 1.0f},
(vertex_t){.position = {-1, -1, 1}, .h = 1.0f},
(vertex_t){.position = {1, -1, 1}, .h = 1.0f},
(vertex_t){.position = {1, 1, -1}, .h = 1.0f},
(vertex_t){.position = {-1, 1, -1}, .h = 1.0f},
(vertex_t){.position = {-1, -1, -1}, .h = 1.0f},
(vertex_t){.position = {1, -1, -1}, .h = 1.0f},
};
for (u64 i = 0; i < ARR_LEN(verts); ++i) {
list_append(vertex_t, arena, vertices, verts[i]);
}
list_scene_triangle_t *triangles = list_create(scene_triangle_t, arena);
if (!triangles) {
return EXIT_FAILURE;
}
// Triangles
scene_triangle_t tris[] = {
(scene_triangle_t){0, 1, 2, (colour_t){.colour = 0xff0000ff}},
(scene_triangle_t){0, 2, 3, (colour_t){.colour = 0xff0000ff}},
(scene_triangle_t){4, 0, 3, (colour_t){.colour = 0x00ff00ff}},
(scene_triangle_t){4, 3, 7, (colour_t){.colour = 0x00ff00ff}},
(scene_triangle_t){5, 4, 7, (colour_t){.colour = 0x0000ffff}},
(scene_triangle_t){5, 7, 6, (colour_t){.colour = 0x0000ffff}},
(scene_triangle_t){1, 5, 6, (colour_t){.colour = 0xffff00ff}},
(scene_triangle_t){1, 6, 2, (colour_t){.colour = 0xffff00ff}},
(scene_triangle_t){4, 5, 1, (colour_t){.colour = 0xff00ffff}},
(scene_triangle_t){4, 1, 0, (colour_t){.colour = 0xff00ffff}},
(scene_triangle_t){2, 6, 7, (colour_t){.colour = 0x00ffffff}},
(scene_triangle_t){2, 7, 3, (colour_t){.colour = 0x00ffffff}},
};
for (u64 i = 0; i < ARR_LEN(tris); ++i) {
list_append(scene_triangle_t, arena, triangles, tris[i]);
}
model_t cube = {.vertices = vertices, .triangles = triangles};
instance_t instances[] = {
(instance_t){
.model = &cube,
.transform =
{
.scale = 1.0f,
.rotation = (vec3f_t){0},
.position = (vec3f_t){-1.5f, 0.0f, 8.0f},
},
},
(instance_t){
.model = &cube,
.transform =
{
.scale = 1.0f,
.rotation = {0},
.position = (vec3f_t){1.7f, 1.5f, 7.0f},
},
},
};
mat3x4f_t proj_matrix = {
(vec4f_t){viewport.z * window.width / viewport.x, 0.0f, 0.0f, 0.0f},
(vec4f_t){0.0f, viewport.z * window.height / viewport.y, 0.0f, 0.0f},
(vec4f_t){0.0f, 0.0f, 1.0f, 0.0f},
};
f32 sqrt_2 = sqrtf(2.0f);
f32 one_div_sqrt_2 = 1.0f / sqrt_2;
f32 neg_one_div_sqrt_2 = -1.0f / sqrt_2;
rasteriser_scene_t scene = {
.instance_count = ARR_LEN(instances),
.instances = instances,
.camera = &camera,
.proj_matrix = &proj_matrix,
.planes =
{
[0] =
(clipping_plane_t){
.normal = (vec3f_t){0.0f, 0.0f, 1.0f},
.distance = viewport.z,
},
[1] =
(clipping_plane_t){
.normal = (vec3f_t){one_div_sqrt_2, 0.0f, one_div_sqrt_2},
.distance = 0.0f,
},
[2] =
(clipping_plane_t){
.normal =
(vec3f_t){neg_one_div_sqrt_2, 0.0f, one_div_sqrt_2},
.distance = 0.0f,
},
[3] =
(clipping_plane_t){
.normal = (vec3f_t){0.0f, one_div_sqrt_2, one_div_sqrt_2},
.distance = 0.0f,
},
[4] =
(clipping_plane_t){
.normal =
(vec3f_t){0.0f, neg_one_div_sqrt_2, one_div_sqrt_2},
.distance = 0.0f,
},
},
};
bool running = true; bool running = true;
SDL_Event event = {0}; SDL_Event event = {0};
@@ -25,42 +154,47 @@ int main(void) {
// i32 h_min = ((i32)window.half_height) * -1; // i32 h_min = ((i32)window.half_height) * -1;
// i32 h_max = (i32)window.half_height; // i32 h_max = (i32)window.half_height;
triangle_t triangle = { Arena *frame_arena = NULL;
.p0 = {-200, -250}, u64 frame_arena_capacity = 32ull * 1024ull * 1024ull * 1024ull;
.p1 = {200, 50}, if (!wapp_mem_arena_init(&frame_arena, frame_arena_capacity,
.p2 = {20, 250}, WAPP_MEM_ALLOC_RESERVE, false)) {
.h0 = 0,
.h1 = 0,
.h2 = 1,
};
Arena *arena = NULL;
u64 capacity = 10ull * 1024ull * 1024ull * 1024ull;
if (!wapp_mem_arena_init(&arena, capacity, WAPP_MEM_ALLOC_RESERVE, false)) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
render_type_t type = RASTERISER_RENDER_FILLED;
while (running) { while (running) {
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
running = false; running = false;
break; break;
case SDL_KEYDOWN:
if (event.key.keysym.sym == SDLK_w) {
camera.rotation.x -= 1.0f;
} else if (event.key.keysym.sym == SDLK_s) {
camera.rotation.x += 1.0f;
} else if (event.key.keysym.sym == SDLK_d) {
camera.rotation.y += 1.0f;
} else if (event.key.keysym.sym == SDLK_a) {
camera.rotation.y -= 1.0f;
} else if (event.key.keysym.sym == SDLK_e) {
type = (type + 1) % COUNT_RASTERISER_RENDER;
}
break;
} }
} }
clear_window(&window, bg); clear_window(&window, bg);
draw_shaded_triangle(&window, arena, triangle, render_scene(&window, frame_arena, &scene, type);
(colour_t){.colour = 0x00ff00ff});
draw_wireframe_triangle(&window, arena, triangle,
(colour_t){.colour = 0x000000ff});
swap_buffers(&window); swap_buffers(&window);
wapp_mem_arena_clear(arena); wapp_mem_arena_clear(frame_arena);
} }
wapp_mem_arena_destroy(&frame_arena);
wapp_mem_arena_destroy(&arena); wapp_mem_arena_destroy(&arena);
close_window(&window); close_window(&window);

View File

@@ -7,65 +7,184 @@
#include "window/window.h" #include "window/window.h"
#include <assert.h> #include <assert.h>
#include <math.h> #include <math.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
internal list_float_t *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, #define CULL_ENABLED 0
f32 d1);
internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
Arena *arena, mat4x4f_t camera_matrix,
mat3x4f_t projection_matrix,
const instance_t *instance, render_type_t type);
internal void clip_instance(Arena *arena, model_t *model,
const rasteriser_scene_t *scene);
#if CULL_ENABLED
internal void cull_back_faces(Arena *arena, const rasteriser_scene_t *scene,
model_t *model);
#endif
internal void clip_instance_against_plane(Arena *arena, model_t *model,
const bounding_sphere_t *sphere,
const clipping_plane_t *plane);
internal void clip_triangles_against_plane(Arena *arena, model_t *model,
const clipping_plane_t *plane);
internal void clip_triangle_against_plane(Arena *arena, model_t *model,
i64 triangle_index,
const clipping_plane_t *plane);
internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1);
#if CULL_ENABLED
internal inline vec3f_t
calculate_triangle_normal(const model_t *model,
const scene_triangle_t *triangle);
#endif
internal inline void order_triangle_points(triangle_t *triangle); internal inline void order_triangle_points(triangle_t *triangle);
internal inline bounding_sphere_t
get_bounding_sphere(const list_vertex_t *vertices);
internal inline vertex_t segment_intersection(const vertex_t *a,
const vertex_t *b,
const clipping_plane_t *plane);
internal inline void copy_triangles(Arena *arena, list_scene_triangle_t *dst,
const list_scene_triangle_t *src);
internal inline f32 signed_distance(const vec3f_t *vertex,
const clipping_plane_t *plane);
void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle, void render_scene(window_t *wnd, Arena *arena, const rasteriser_scene_t *scene,
colour_t colour) { render_type_t type) {
order_triangle_points(&triangle); mat4x4f_t cam_inverse_rotation =
inverse_camera_rotation_matrix(scene->camera);
mat4x4f_t cam_inverse_translation =
inverse_camera_translation_matrix(scene->camera);
mat4x4f_t cam_matrix =
mul_mat4x4f(cam_inverse_rotation, cam_inverse_translation);
draw_line(wnd, arena, (line_t){triangle.p0, triangle.p1}, colour); for (u64 i = 0; i < scene->instance_count; ++i) {
draw_line(wnd, arena, (line_t){triangle.p1, triangle.p2}, colour); render_instance(wnd, scene, arena, cam_matrix, *(scene->proj_matrix),
draw_line(wnd, arena, (line_t){triangle.p2, triangle.p0}, colour); &(scene->instances[i]), type);
}
} }
void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle, internal void render_instance(window_t *wnd, const rasteriser_scene_t *scene,
colour_t colour) { Arena *arena, mat4x4f_t camera_matrix,
order_triangle_points(&triangle); mat3x4f_t projection_matrix,
const instance_t *instance, render_type_t type) {
i32 x0 = triangle.p0.x; list_vertex_t *transformed = list_create_with_capacity(
i32 y0 = triangle.p0.y; vertex_t, arena, instance->model->vertices->count + 10);
i32 x1 = triangle.p1.x; list_scene_triangle_t *triangles = list_create_with_capacity(
i32 y1 = triangle.p1.y; scene_triangle_t, arena, instance->model->triangles->count + 10);
i32 x2 = triangle.p2.x; if (!transformed || !triangles) {
i32 y2 = triangle.p2.y; return;
list_float_t *x01 = interpolate(arena, y0, x0, y1, x1);
list_float_t *x12 = interpolate(arena, y1, x1, y2, x2);
list_float_t *x02 = interpolate(arena, y0, x0, y2, x2);
list_float_t *x012 = NULL;
list_pop(x01); // Last element of x01 is a duplicate of first element in x12
list_merge(f32, arena, x012, x01, x12);
list_float_t *x_left;
list_float_t *x_right;
u64 middle = (u64)(floorf((f32)(x02->count) / 2.0f));
if (list_get(x02, middle) < list_get(x012, middle)) {
x_left = x02;
x_right = x012;
} else {
x_left = x012;
x_right = x02;
} }
for (i64 y = y0; y <= y2; ++y) { copy_triangles(arena, triangles, instance->model->triangles);
i32 index = y - y0;
for (i64 x = (i64)list_get(x_left, index); x < list_get(x_right, index); mat4x4f_t t_mat = get_translation_matrix(instance->transform.position);
++x) { mat4x4f_t r_mat = get_rotation_matrix(instance->transform.rotation);
set_pixel(wnd, x, y, colour); mat4x4f_t s_mat = get_scaling_matrix((vec3f_t){instance->transform.scale,
instance->transform.scale,
instance->transform.scale});
mat4x4f_t tr_mat = mul_mat4x4f(t_mat, r_mat);
mat4x4f_t trs_mat = mul_mat4x4f(tr_mat, s_mat);
mat4x4f_t xf_cam_mat = mul_mat4x4f(camera_matrix, trs_mat);
vertex_t vertex = {0};
vec4f_t xf_vertex = {0};
for (u64 i = 0; i < instance->model->vertices->count; ++i) {
vertex = list_get(instance->model->vertices, i);
xf_vertex = mul_mat4x4f_by_vec4f(
xf_cam_mat, (vec4f_t){vertex.position.x, vertex.position.y,
vertex.position.z, 1.0f});
xf_vertex = vec_div_num(vec4f_t, xf_vertex, xf_vertex.w);
vertex.position = (vec3f_t){xf_vertex.x, xf_vertex.y, xf_vertex.z};
list_append(vertex_t, arena, transformed, vertex);
}
model_t model = {transformed, triangles};
#if CULL_ENABLED
cull_back_faces(arena, scene, &model);
#endif
clip_instance(arena, &model, scene);
if (is_null_model(&model)) {
return;
}
list_vec2i_t *projected = list_create_with_capacity(
vec2i_t, arena, instance->model->vertices->count);
if (!projected) {
return;
}
vec2i_t point = {0};
vertex_t *vp = NULL;
for (u64 i = 0; i < transformed->count; ++i) {
vp = &(list_get(transformed, i));
vp->position = mul_mat3x4f_by_vec4f(
projection_matrix,
(vec4f_t){vp->position.x, vp->position.y, vp->position.z, 1.0f});
point = (vec2i_t){(i32)(vp->position.x / vp->position.z),
(i32)(vp->position.y / vp->position.z)};
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 = v0.h,
.h1 = v1.h,
.h2 = v2.h,
.z0 = 1.0f / v0.position.z,
.z1 = 1.0f / v1.position.z,
.z2 = 1.0f / v2.position.z,
.colour = triangle.colour,
};
if ((tri.p0.x == tri.p1.x && tri.p0.x == tri.p2.x) &&
(tri.p0.y == tri.p1.y && tri.p0.y == tri.p2.y)) {
continue;
}
switch (type) {
case RASTERISER_RENDER_WIREFRAME:
draw_wireframe_triangle(wnd, arena, tri);
break;
case RASTERISER_RENDER_FILLED:
draw_filled_triangle(wnd, arena, tri);
break;
case RASTERISER_RENDER_SHADED:
draw_shaded_triangle(wnd, arena, tri);
break;
default:
return;
} }
} }
} }
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle, void draw_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
colour_t colour) { order_triangle_points(&triangle);
draw_line(wnd, arena, (line_t){triangle.p0, triangle.p1}, triangle.colour);
draw_line(wnd, arena, (line_t){triangle.p1, triangle.p2}, triangle.colour);
draw_line(wnd, arena, (line_t){triangle.p2, triangle.p0}, triangle.colour);
}
void draw_filled_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
order_triangle_points(&triangle); order_triangle_points(&triangle);
i32 x0 = triangle.p0.x; i32 x0 = triangle.p0.x;
@@ -75,10 +194,83 @@ void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle,
i32 x2 = triangle.p2.x; i32 x2 = triangle.p2.x;
i32 y2 = triangle.p2.y; i32 y2 = triangle.p2.y;
list_float_t *x01 = interpolate(arena, y0, x0, y1, x1); list_float *x01 = interpolate(arena, y0, x0, y1, x1);
list_float_t *x12 = interpolate(arena, y1, x1, y2, x2); list_float *x12 = interpolate(arena, y1, x1, y2, x2);
list_float_t *x02 = interpolate(arena, y0, x0, y2, x2); list_float *x02 = interpolate(arena, y0, x0, y2, x2);
list_float_t *x012 = NULL; list_float *x012 = NULL;
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 = 0.0f;
f32 new_z = 0.0f;
for (i64 y = y0; y <= y2; ++y) {
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);
}
}
}
}
void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
order_triangle_points(&triangle);
i32 x0 = triangle.p0.x;
i32 y0 = triangle.p0.y;
i32 x1 = triangle.p1.x;
i32 y1 = triangle.p1.y;
i32 x2 = triangle.p2.x;
i32 y2 = triangle.p2.y;
list_float *x01 = interpolate(arena, y0, x0, y1, x1);
list_float *x12 = interpolate(arena, y1, x1, y2, x2);
list_float *x02 = interpolate(arena, y0, x0, y2, x2);
list_float *x012 = NULL;
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);
@@ -86,35 +278,55 @@ void draw_shaded_triangle(window_t *wnd, Arena *arena, triangle_t triangle,
f32 h0 = triangle.h0; f32 h0 = triangle.h0;
f32 h1 = triangle.h1; f32 h1 = triangle.h1;
f32 h2 = triangle.h2; f32 h2 = triangle.h2;
list_float_t *h01 = interpolate(arena, y0, h0, y1, h1); list_float *h01 = interpolate(arena, y0, h0, y1, h1);
list_float_t *h12 = interpolate(arena, y1, h1, y2, h2); list_float *h12 = interpolate(arena, y1, h1, y2, h2);
list_float_t *h02 = interpolate(arena, y0, h0, y2, h2); list_float *h02 = interpolate(arena, y0, h0, y2, h2);
list_float_t *h012 = NULL; list_float *h012 = NULL;
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);
list_float_t *x_left; f32 z0 = triangle.z0;
list_float_t *x_right; f32 z1 = triangle.z1;
list_float_t *h_left; f32 z2 = triangle.z2;
list_float_t *h_right; 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)); 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_t *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) {
@@ -124,14 +336,23 @@ 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));
shaded_colour = colour_mul(colour, list_get(h_segment, x - xl)); z_segment = interpolate(arena, xl, list_get(z_left, index), xr,
set_pixel(wnd, x, y, shaded_colour); list_get(z_right, index));
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);
}
} }
} }
} }
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_t *values = NULL; list_float *values = NULL;
if (abs(line.p1.x - line.p0.x) > abs(line.p1.y - line.p0.y)) { if (abs(line.p1.x - line.p0.x) > abs(line.p1.y - line.p0.y)) {
if (line.p1.x < line.p0.x) { if (line.p1.x < line.p0.x) {
@@ -172,9 +393,187 @@ void draw_line(window_t *wnd, Arena *arena, line_t line, colour_t colour) {
} }
} }
internal list_float_t *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, bool is_null_model(const model_t *model) {
f32 d1) { return model->vertices == NULL && model->triangles == NULL;
list_float_t *values; }
internal void clip_instance(Arena *arena, model_t *model,
const rasteriser_scene_t *scene) {
bounding_sphere_t sphere = get_bounding_sphere(model->vertices);
const clipping_plane_t *plane = NULL;
for (u64 i = 0; i < CLIPPING_PLANE_COUNT; ++i) {
plane = &(scene->planes[i]);
clip_instance_against_plane(arena, model, &sphere, plane);
if (is_null_model(model)) {
return;
}
}
}
#if CULL_ENABLED
internal void cull_back_faces(Arena *arena, const rasteriser_scene_t *scene,
model_t *model) {
list_uint64_t *to_remove =
list_create_with_capacity(u64, arena, model->triangles->count);
vec3f_t normal;
scene_triangle_t *triangle;
vertex_t v0;
vertex_t v1;
vertex_t v2;
vec3f_t sum;
vec3f_t midpoint;
vec3f_t viewing_vector;
f32 dot_product;
for (u64 i = 0; i < model->triangles->count; ++i) {
triangle = &(list_get(model->triangles, i));
v0 = list_get(model->vertices, triangle->idx0);
v1 = list_get(model->vertices, triangle->idx1);
v2 = list_get(model->vertices, triangle->idx2);
sum = vec_add(vec3f_t, v0.position,
vec_add(vec3f_t, v1.position, v2.position));
midpoint = vec_div_num(vec3f_t, sum, 3);
normal = calculate_triangle_normal(model, triangle);
viewing_vector = vec_sub(vec3f_t, midpoint, scene->camera->position);
dot_product = vec_dot(vec3f_t, normal, viewing_vector);
if (dot_product <= 0.0f) {
list_append(u64, arena, to_remove, i);
}
}
for (u64 i = 0; i < to_remove->count; ++i) {
u64 idx = list_get(to_remove, i);
list_remove(model->triangles, idx);
}
}
#endif
internal void clip_instance_against_plane(Arena *arena, model_t *model,
const bounding_sphere_t *sphere,
const clipping_plane_t *plane) {
f32 distance = signed_distance(&(sphere->centre), plane);
f32 neg_radius = -1.0f * sphere->radius;
if (distance > sphere->radius) {
return;
} else if (distance < neg_radius) {
*model = NULL_MODEL;
} else {
clip_triangles_against_plane(arena, model, plane);
}
}
internal void clip_triangles_against_plane(Arena *arena, model_t *model,
const clipping_plane_t *plane) {
u64 count = model->triangles->count;
for (u64 i = 0; i < count; ++i) {
clip_triangle_against_plane(arena, model, i, plane);
}
}
internal void clip_triangle_against_plane(Arena *arena, model_t *model,
i64 triangle_index,
const clipping_plane_t *plane) {
scene_triangle_t *triangle = &(list_get(model->triangles, triangle_index));
vertex_t *v0 = &(list_get(model->vertices, triangle->idx0));
vertex_t *v1 = &(list_get(model->vertices, triangle->idx1));
vertex_t *v2 = &(list_get(model->vertices, triangle->idx2));
f32 d0 = signed_distance(&(v0->position), plane);
f32 d1 = signed_distance(&(v1->position), plane);
f32 d2 = signed_distance(&(v2->position), plane);
if (d0 >= 0.0f && d1 >= 0.0f && d2 >= 0.0f) {
return;
} else if (d0 < 0.0f && d1 < 0.0f && d2 < 0.0f) {
triangle->idx0 = INVALID_VERTEX;
triangle->idx1 = INVALID_VERTEX;
triangle->idx2 = INVALID_VERTEX;
} else if ((d0 < 0.0f && d1 < 0.0f) || (d0 < 0.0f && d2 < 0.0f) ||
(d1 < 0.0f && d2 < 0.0f)) {
vertex_t *vp;
vertex_t *vn0;
vertex_t *vn1;
i64 *in0;
i64 *in1;
if (d0 > 0.0f) {
vp = v0;
vn0 = v1;
vn1 = v2;
in0 = &(triangle->idx1);
in1 = &(triangle->idx2);
} else if (d1 > 0.0f) {
vp = v1;
vn0 = v0;
vn1 = v2;
in0 = &(triangle->idx0);
in1 = &(triangle->idx2);
} else {
vp = v2;
vn0 = v0;
vn1 = v1;
in0 = &(triangle->idx0);
in1 = &(triangle->idx1);
}
vertex_t r0 = segment_intersection(vp, vn0, plane);
vertex_t r1 = segment_intersection(vp, vn1, plane);
list_append(vertex_t, arena, model->vertices, r0);
list_append(vertex_t, arena, model->vertices, r1);
*in0 = model->vertices->count - 2;
*in1 = model->vertices->count - 1;
} else {
vertex_t *vn;
vertex_t *vp0;
vertex_t *vp1;
i64 *in;
i64 *ip;
if (d0 < 0.0f) {
vn = v0;
vp0 = v1;
vp1 = v2;
in = &(triangle->idx0);
ip = &(triangle->idx2);
} else if (d1 < 0.0f) {
vn = v1;
vp0 = v0;
vp1 = v2;
in = &(triangle->idx1);
ip = &(triangle->idx2);
} else {
vn = v2;
vp0 = v0;
vp1 = v1;
in = &(triangle->idx2);
ip = &(triangle->idx1);
}
vertex_t r0 = segment_intersection(vp0, vn, plane);
vertex_t r1 = segment_intersection(vp1, vn, plane);
list_append(vertex_t, arena, model->vertices, r0);
list_append(vertex_t, arena, model->vertices, r1);
*in = model->vertices->count - 2;
scene_triangle_t tri = {
.idx0 = *in,
.idx1 = *ip,
.idx2 = model->vertices->count - 1,
.colour = triangle->colour,
};
list_append(scene_triangle_t, arena, model->triangles, tri);
}
}
internal list_float *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1, f32 d1) {
list_float *values;
if (i0 == i1) { if (i0 == i1) {
values = list_create_with_capacity(f32, arena, 20); values = list_create_with_capacity(f32, arena, 20);
if (values) { if (values) {
@@ -200,6 +599,21 @@ internal list_float_t *interpolate(Arena *arena, i32 i0, f32 d0, i32 i1,
return values; return values;
} }
#if CULL_ENABLED
internal inline vec3f_t
calculate_triangle_normal(const model_t *model,
const scene_triangle_t *triangle) {
vertex_t v0 = list_get(model->vertices, triangle->idx0);
vertex_t v1 = list_get(model->vertices, triangle->idx1);
vertex_t v2 = list_get(model->vertices, triangle->idx2);
vec3f_t ba = vec_sub(vec3f_t, v1.position, v0.position);
vec3f_t ca = vec_sub(vec3f_t, v2.position, v0.position);
return vec_cross(vec3f_t, ba, ca);
}
#endif
internal inline void order_triangle_points(triangle_t *triangle) { internal inline void order_triangle_points(triangle_t *triangle) {
if (triangle->p1.y < triangle->p0.y) { if (triangle->p1.y < triangle->p0.y) {
swap(vec2i_t, triangle->p0, triangle->p1); swap(vec2i_t, triangle->p0, triangle->p1);
@@ -214,3 +628,56 @@ internal inline void order_triangle_points(triangle_t *triangle) {
swap(f32, triangle->h1, triangle->h2); swap(f32, triangle->h1, triangle->h2);
} }
} }
internal inline bounding_sphere_t
get_bounding_sphere(const list_vertex_t *vertices) {
vec3f_t sum = {0};
for (u64 i = 0; i < vertices->count; ++i) {
sum = vec_add(vec3f_t, list_get(vertices, i).position, sum);
}
vec3f_t centre = vec_div_num(vec3f_t, sum, vertices->count);
f32 radius = 0.0f;
f32 tmp = 0.0f;
vec3f_t dst = {0};
for (u64 i = 0; i < vertices->count; ++i) {
dst = vec_sub(vec3f_t, list_get(vertices, i).position, centre);
tmp = vec_magnitude(vec3f_t, dst);
radius = tmp > radius ? tmp : radius;
}
return (bounding_sphere_t){
.centre = centre,
.radius = radius,
};
}
internal inline vertex_t segment_intersection(const vertex_t *a,
const vertex_t *b,
const clipping_plane_t *plane) {
f32 neg_d = plane->distance * -1.0f;
f32 na_dot = vec_dot(vec3f_t, plane->normal, a->position);
vec3f_t ba = vec_sub(vec3f_t, b->position, a->position);
f32 nba_dot = vec_dot(vec3f_t, plane->normal, ba);
f32 t = (neg_d - na_dot) / nba_dot;
return (vertex_t){
.position = vec_add(vec3f_t, a->position, vec_mul_num(vec3f_t, ba, t)),
.h = a->h + t * (b->h - a->h),
};
}
internal inline void copy_triangles(Arena *arena, list_scene_triangle_t *dst,
const list_scene_triangle_t *src) {
for (u64 i = 0; i < src->count; ++i) {
scene_triangle_t tri = list_get(src, i);
list_append(scene_triangle_t, arena, dst, tri);
}
}
internal inline f32 signed_distance(const vec3f_t *vertex,
const clipping_plane_t *plane) {
return (vertex->x * plane->normal.x) + (vertex->y * plane->normal.y) +
(vertex->z * plane->normal.z) + plane->distance;
}

View File

@@ -1,6 +1,6 @@
#include "aliases.h" #include "aliases.h"
#include "camera/camera.h"
#include "raytracer/raytracer.h" #include "raytracer/raytracer.h"
#include "scene/scene.h"
#include "vector/vec.h" #include "vector/vec.h"
#include "window/window.h" #include "window/window.h"
#include <SDL2/SDL_events.h> #include <SDL2/SDL_events.h>
@@ -11,11 +11,6 @@
#define RECURSION_DEPTH 3 #define RECURSION_DEPTH 3
typedef struct {
vec3f_t position;
vec3f_t rotation;
} camera_t;
i32 main(i32 argc, char *argv[]) { i32 main(i32 argc, char *argv[]) {
colour_t bg = colour_t bg =
(colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255}; (colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255};
@@ -27,11 +22,11 @@ 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;
} }
const scene_t *scene = build_test_scene(); const raytracer_scene_t *scene = build_test_scene();
bool running = true; bool running = true;
SDL_Event event = {0}; SDL_Event event = {0};

View File

@@ -1,5 +1,6 @@
#include "raytracer/raytracer.h" #include "raytracer/raytracer.h"
#include "aliases.h" #include "aliases.h"
#include "misc/misc_utils.h"
#include "vector/vec.h" #include "vector/vec.h"
#include "window/window.h" #include "window/window.h"
#include <math.h> #include <math.h>
@@ -7,15 +8,14 @@
#define SPECULAR_EPSILON 0.001f #define SPECULAR_EPSILON 0.001f
#define REFLECTIVE_EPSILON 0.1f #define REFLECTIVE_EPSILON 0.1f
internal intersection_t find_closest_intersection(vec3f_t origin, internal intersection_t
vec3f_t direction, f32 t_min, find_closest_intersection(vec3f_t origin, vec3f_t direction, f32 t_min,
f32 t_max, f32 t_max, const raytracer_scene_t *scene);
const scene_t *scene);
internal solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction, internal solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
sphere_t sphere); sphere_t sphere);
internal f32 compute_lighting(vec3f_t position, vec3f_t surface_normal, internal f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
vec3f_t view_vector, f32 specular_exponent, vec3f_t view_vector, f32 specular_exponent,
const scene_t *scene); const raytracer_scene_t *scene);
internal f32 light_diffuse(f32 light_intensity, vec3f_t light_direction, internal f32 light_diffuse(f32 light_intensity, vec3f_t light_direction,
vec3f_t surface_normal); vec3f_t surface_normal);
internal f32 light_specular(f32 light_intensity, vec3f_t light_direction, internal f32 light_specular(f32 light_intensity, vec3f_t light_direction,
@@ -24,8 +24,73 @@ internal f32 light_specular(f32 light_intensity, vec3f_t light_direction,
internal vec3f_t reflect_ray(vec3f_t light_direction, vec3f_t surface_normal); internal vec3f_t reflect_ray(vec3f_t light_direction, vec3f_t surface_normal);
internal f32 cos_angle_between_vectors(vec3f_t v1, vec3f_t v2); internal f32 cos_angle_between_vectors(vec3f_t v1, vec3f_t v2);
internal const sphere_t spheres[] = {
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 0.0f, .y = -1.0f, .z = 3.0f},
.colour =
(colour_t){
.rgba.r = 245, .rgba.g = 238, .rgba.b = 158, .rgba.a = 255},
.specular = 500.0f,
.reflective = 0.3f,
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = -2.0f, .y = 0.0f, .z = 4.0f},
.colour =
(colour_t){
.rgba.r = 59, .rgba.g = 142, .rgba.b = 165, .rgba.a = 255},
.specular = 10.0f,
.reflective = 0.1f,
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 2.0f, .y = 0.0f, .z = 4.0f},
.colour =
(colour_t){
.rgba.r = 171, .rgba.g = 52, .rgba.b = 40, .rgba.a = 255},
.specular = 500.0f,
.reflective = 0.4f,
},
(sphere_t){
.radius = 5000.0f,
.centre = (vec3f_t){.x = 0.0f, .y = -5001.0f, .z = 0.0f},
.colour =
(colour_t){
.rgba.r = 255, .rgba.g = 255, .rgba.b = 0, .rgba.a = 255},
.specular = 1000.0f,
.reflective = 0.5f,
},
};
internal const light_t lights[] = {
(light_t){
.type = LIGHT_TYPE_AMBIENT,
.intensity = 0.2f,
},
(light_t){
.type = LIGHT_TYPE_POINT,
.intensity = 0.6f,
.position = (vec3f_t){.x = 2.0f, .y = 1.0f, .z = 0.0f},
},
(light_t){
.type = LIGHT_TYPE_DIRECTIONAL,
.intensity = 0.2f,
.direction = (vec3f_t){.x = 1.0f, .y = 4.0f, .z = 4.0f},
},
};
internal raytracer_scene_t scene = (raytracer_scene_t){
.spheres = spheres,
.lights = lights,
.spheres_count = ARR_LEN(spheres),
.lights_count = ARR_LEN(lights),
};
const raytracer_scene_t *build_test_scene(void) { return &scene; }
colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max, colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
const scene_t *scene, colour_t default_colour, const raytracer_scene_t *scene, colour_t default_colour,
u32 recursion_depth) { u32 recursion_depth) {
intersection_t intersection = intersection_t intersection =
find_closest_intersection(origin, direction, t_min, t_max, scene); find_closest_intersection(origin, direction, t_min, t_max, scene);
@@ -67,10 +132,9 @@ colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
return colour_add_colour(local_colour, reflected_colour); return colour_add_colour(local_colour, reflected_colour);
} }
internal intersection_t find_closest_intersection(vec3f_t origin, internal intersection_t
vec3f_t direction, f32 t_min, find_closest_intersection(vec3f_t origin, vec3f_t direction, f32 t_min,
f32 t_max, f32 t_max, const raytracer_scene_t *scene) {
const scene_t *scene) {
f32 closest_t = INFINITY; f32 closest_t = INFINITY;
const sphere_t *closest_sphere = NULL; const sphere_t *closest_sphere = NULL;
@@ -116,7 +180,7 @@ internal solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
internal f32 compute_lighting(vec3f_t position, vec3f_t surface_normal, internal f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
vec3f_t view_vector, f32 specular_exponent, vec3f_t view_vector, f32 specular_exponent,
const scene_t *scene) { const raytracer_scene_t *scene) {
f32 I = 0.0f; f32 I = 0.0f;
light_t light = {0}; light_t light = {0};

View File

@@ -1,68 +0,0 @@
#include "scene/scene.h"
#include "aliases.h"
#include "misc/misc_utils.h"
internal const sphere_t spheres[] = {
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 0.0f, .y = -1.0f, .z = 3.0f},
.colour =
(colour_t){
.rgba.r = 245, .rgba.g = 238, .rgba.b = 158, .rgba.a = 255},
.specular = 500.0f,
.reflective = 0.3f,
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = -2.0f, .y = 0.0f, .z = 4.0f},
.colour =
(colour_t){
.rgba.r = 59, .rgba.g = 142, .rgba.b = 165, .rgba.a = 255},
.specular = 10.0f,
.reflective = 0.1f,
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 2.0f, .y = 0.0f, .z = 4.0f},
.colour =
(colour_t){
.rgba.r = 171, .rgba.g = 52, .rgba.b = 40, .rgba.a = 255},
.specular = 500.0f,
.reflective = 0.4f,
},
(sphere_t){
.radius = 5000.0f,
.centre = (vec3f_t){.x = 0.0f, .y = -5001.0f, .z = 0.0f},
.colour =
(colour_t){
.rgba.r = 255, .rgba.g = 255, .rgba.b = 0, .rgba.a = 255},
.specular = 1000.0f,
.reflective = 0.5f,
},
};
internal const light_t lights[] = {
(light_t){
.type = LIGHT_TYPE_AMBIENT,
.intensity = 0.2f,
},
(light_t){
.type = LIGHT_TYPE_POINT,
.intensity = 0.6f,
.position = (vec3f_t){.x = 2.0f, .y = 1.0f, .z = 0.0f},
},
(light_t){
.type = LIGHT_TYPE_DIRECTIONAL,
.intensity = 0.2f,
.direction = (vec3f_t){.x = 1.0f, .y = 4.0f, .z = 4.0f},
},
};
internal scene_t scene = (scene_t){
.spheres = spheres,
.lights = lights,
.spheres_count = ARR_LEN(spheres),
.lights_count = ARR_LEN(lights),
};
const scene_t *build_test_scene(void) { return &scene; }

View File

@@ -2,12 +2,6 @@
#include "math/math_utils.h" #include "math/math_utils.h"
#include <math.h> #include <math.h>
typedef struct {
vec3f_t row0;
vec3f_t row1;
vec3f_t row2;
} mat3x3f_t;
vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2) { vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2) {
return (vec2i_t){.x = v1.x + v2.x, .y = v1.y + v2.y}; return (vec2i_t){.x = v1.x + v2.x, .y = v1.y + v2.y};
} }
@@ -100,6 +94,14 @@ i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
} }
vec3i_t vec_cross_vec3i_t(vec3i_t v1, vec3i_t v2) {
return (vec3i_t){
.x = v1.y * v2.z - v1.z * v2.y,
.y = v1.z * v2.x - v1.x * v2.z,
.z = v1.x * v2.y - v1.y * v2.x,
};
}
i32 vec_magnitude_vec3i_t(vec3i_t v) { i32 vec_magnitude_vec3i_t(vec3i_t v) {
i32 dot_product = vec_dot_vec3i_t(v, v); i32 dot_product = vec_dot_vec3i_t(v, v);
return (i32)sqrtf((f32)dot_product); return (i32)sqrtf((f32)dot_product);
@@ -134,6 +136,14 @@ f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z; return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
} }
vec3f_t vec_cross_vec3f_t(vec3f_t v1, vec3f_t v2) {
return (vec3f_t){
.x = v1.y * v2.z - v1.z * v2.y,
.y = v1.z * v2.x - v1.x * v2.z,
.z = v1.x * v2.y - v1.y * v2.x,
};
}
f32 vec_magnitude_vec3f_t(vec3f_t v) { f32 vec_magnitude_vec3f_t(vec3f_t v) {
f32 dot_product = vec_dot_vec3f_t(v, v); f32 dot_product = vec_dot_vec3f_t(v, v);
return sqrtf(dot_product); return sqrtf(dot_product);
@@ -145,6 +155,109 @@ vec3f_t vec_unit_vec3f_t(vec3f_t v) {
} }
vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation) { vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation) {
mat3x3f_t matrix = get_rotation_mat3x3f(rotation);
// clang-format off
return (vec3f_t){
.x = matrix.row0.x * original.x + matrix.row0.y * original.y + matrix.row0.z * original.z,
.y = matrix.row1.x * original.x + matrix.row1.y * original.y + matrix.row1.z * original.z,
.z = matrix.row2.x * original.x + matrix.row2.y * original.y + matrix.row2.z * original.z,
};
// clang-format on
}
vec4i_t vec_add_vec4i_t(vec4i_t v1, vec4i_t v2) {
return (vec4i_t){
.x = v1.x + v2.x, .y = v1.y + v2.y, .z = v1.z + v2.z, .w = v1.w + v2.w};
}
vec4i_t vec_sub_vec4i_t(vec4i_t v1, vec4i_t v2) {
return (vec4i_t){
.x = v1.x - v2.x, .y = v1.y - v2.y, .z = v1.z - v2.z, .w = v1.w - v2.w};
}
vec4i_t vec_mul_vec4i_t(vec4i_t v1, vec4i_t v2) {
return (vec4i_t){
.x = v1.x * v2.x, .y = v1.y * v2.y, .z = v1.z * v2.z, .w = v1.w * v2.w};
}
vec4i_t vec_mul_num_vec4i_t(vec4i_t v1, i32 num) {
return (vec4i_t){
.x = v1.x * num, .y = v1.y * num, .z = v1.z * num, .w = v1.w * num};
}
vec4i_t vec_div_num_vec4i_t(vec4i_t v1, i32 num) {
return (vec4i_t){
.x = v1.x / num, .y = v1.y / num, .z = v1.z / num, .w = v1.w / num};
}
i32 vec_dot_vec4i_t(vec4i_t v1, vec4i_t v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
}
i32 vec_magnitude_vec4i_t(vec4i_t v) {
i32 dot_product = vec_dot_vec4i_t(v, v);
return (i32)sqrtf((f32)dot_product);
}
vec4i_t vec_unit_vec4i_t(vec4i_t v) {
i32 magnitude = vec_magnitude_vec4i_t(v);
return (vec4i_t){v.x / magnitude, v.y / magnitude, v.z / magnitude,
v.w / magnitude};
}
vec4f_t vec_add_vec4f_t(vec4f_t v1, vec4f_t v2) {
return (vec4f_t){
.x = v1.x + v2.x, .y = v1.y + v2.y, .z = v1.z + v2.z, .w = v1.w + v2.w};
}
vec4f_t vec_sub_vec4f_t(vec4f_t v1, vec4f_t v2) {
return (vec4f_t){
.x = v1.x - v2.x, .y = v1.y - v2.y, .z = v1.z - v2.z, .w = v1.w - v2.w};
}
vec4f_t vec_mul_num_vec4f_t(vec4f_t v1, f32 num) {
return (vec4f_t){
.x = v1.x * num, .y = v1.y * num, .z = v1.z * num, .w = v1.w * num};
}
vec4f_t vec_div_num_vec4f_t(vec4f_t v1, f32 num) {
return (vec4f_t){
.x = v1.x / num, .y = v1.y / num, .z = v1.z / num, .w = v1.w / num};
}
vec4f_t vec_mul_vec4f_t(vec4f_t v1, vec4f_t v2) {
return (vec4f_t){
.x = v1.x * v2.x, .y = v1.y * v2.y, .z = v1.z * v2.z, .w = v1.w * v2.w};
}
f32 vec_dot_vec4f_t(vec4f_t v1, vec4f_t v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w;
}
f32 vec_magnitude_vec4f_t(vec4f_t v) {
f32 dot_product = vec_dot_vec4f_t(v, v);
return sqrtf(dot_product);
}
vec4f_t vec_unit_vec4f_t(vec4f_t v) {
f32 magnitude = vec_magnitude_vec4f_t(v);
return (vec4f_t){v.x / magnitude, v.y / magnitude, v.z / magnitude,
v.w / magnitude};
}
mat4x4f_t get_scaling_matrix(vec3f_t scale) {
// clang-format off
return (mat4x4f_t){
(vec4f_t){scale.x, 0.0f, 0.0f, 0.0f},
(vec4f_t){0.0f, scale.y, 0.0f, 0.0f},
(vec4f_t){0.0f, 0.0f, scale.z, 0.0f},
(vec4f_t){0.0f, 0.0f, 0.0f, 1.0f},
};
// clang-format on
}
mat3x3f_t get_rotation_mat3x3f(vec3f_t rotation) {
f32 x_rad = RADIANS(rotation.x); f32 x_rad = RADIANS(rotation.x);
f32 y_rad = RADIANS(rotation.y); f32 y_rad = RADIANS(rotation.y);
f32 z_rad = RADIANS(rotation.z); f32 z_rad = RADIANS(rotation.z);
@@ -170,17 +283,135 @@ vec3f_t vec_rotate_vec3f_t(vec3f_t original, vec3f_t rotation) {
f32 row2_col1 = cos_y * sin_x; f32 row2_col1 = cos_y * sin_x;
f32 row2_col2 = cos_y * cos_x; f32 row2_col2 = cos_y * cos_x;
mat3x3f_t matrix = { return (mat3x3f_t){
.row0 = {row0_col0, row0_col1, row0_col2}, .row0 = {row0_col0, row0_col1, row0_col2},
.row1 = {row1_col0, row1_col1, row1_col2}, .row1 = {row1_col0, row1_col1, row1_col2},
.row2 = {row2_col0, row2_col1, row2_col2}, .row2 = {row2_col0, row2_col1, row2_col2},
}; };
}
mat4x4f_t get_translation_matrix(vec3f_t translation) {
return (mat4x4f_t){
(vec4f_t){1.0f, 0.0f, 0.0f, translation.x},
(vec4f_t){0.0f, 1.0f, 0.0f, translation.y},
(vec4f_t){0.0f, 0.0f, 1.0f, translation.z},
(vec4f_t){0.0f, 0.0f, 0.0f, 1.0f},
};
}
mat4x4f_t get_rotation_matrix(vec3f_t rotation) {
mat3x3f_t mat = get_rotation_mat3x3f(rotation);
// clang-format off // clang-format off
return (vec3f_t){ return (mat4x4f_t){
.x = matrix.row0.x * original.x + matrix.row0.y * original.y + matrix.row0.z * original.z, (vec4f_t){mat.row0.x, mat.row0.y, mat.row0.z, 0.0f},
.y = matrix.row1.x * original.x + matrix.row1.y * original.y + matrix.row1.z * original.z, (vec4f_t){mat.row1.x, mat.row1.y, mat.row1.z, 0.0f},
.z = matrix.row2.x * original.x + matrix.row2.y * original.y + matrix.row2.z * original.z, (vec4f_t){mat.row2.x, mat.row2.y, mat.row2.z, 0.0f},
}; (vec4f_t){ 0.0f, 0.0f, 0.0f, 1.0f},
};
// clang-format on // clang-format on
} }
vec3f_t mul_mat3x4f_by_vec4f(mat3x4f_t mat, vec4f_t vec) {
f32 x = mat.row0.x * vec.x + mat.row0.y * vec.y + mat.row0.z * vec.z +
mat.row0.w * vec.w;
f32 y = mat.row1.x * vec.x + mat.row1.y * vec.y + mat.row1.z * vec.z +
mat.row1.w * vec.w;
f32 z = mat.row2.x * vec.x + mat.row2.y * vec.y + mat.row2.z * vec.z +
mat.row2.w * vec.w;
return (vec3f_t){x, y, z};
}
mat3x4f_t mul_mat3x4f_by_mat4x4f(mat3x4f_t mat1, mat4x4f_t mat2) {
f32 row0_col0 = mat1.row0.x * mat2.row0.x + mat1.row0.y * mat2.row1.x +
mat1.row0.z * mat2.row2.x + mat1.row0.w * mat2.row3.x;
f32 row0_col1 = mat1.row0.x * mat2.row0.y + mat1.row0.y * mat2.row1.y +
mat1.row0.z * mat2.row2.y + mat1.row0.w * mat2.row3.y;
f32 row0_col2 = mat1.row0.x * mat2.row0.z + mat1.row0.y * mat2.row1.z +
mat1.row0.z * mat2.row2.z + mat1.row0.w * mat2.row3.z;
f32 row0_col3 = mat1.row0.x * mat2.row0.w + mat1.row0.y * mat2.row1.w +
mat1.row0.z * mat2.row2.w + mat1.row0.w * mat2.row3.w;
f32 row1_col0 = mat1.row1.x * mat2.row0.x + mat1.row1.y * mat2.row1.x +
mat1.row1.z * mat2.row2.x + mat1.row1.w * mat2.row3.x;
f32 row1_col1 = mat1.row1.x * mat2.row0.y + mat1.row1.y * mat2.row1.y +
mat1.row1.z * mat2.row2.y + mat1.row1.w * mat2.row3.y;
f32 row1_col2 = mat1.row1.x * mat2.row0.z + mat1.row1.y * mat2.row1.z +
mat1.row1.z * mat2.row2.z + mat1.row1.w * mat2.row3.z;
f32 row1_col3 = mat1.row1.x * mat2.row0.w + mat1.row1.y * mat2.row1.w +
mat1.row1.z * mat2.row2.w + mat1.row1.w * mat2.row3.w;
f32 row2_col0 = mat1.row2.x * mat2.row0.x + mat1.row2.y * mat2.row1.x +
mat1.row2.z * mat2.row2.x + mat1.row2.w * mat2.row3.x;
f32 row2_col1 = mat1.row2.x * mat2.row0.y + mat1.row2.y * mat2.row1.y +
mat1.row2.z * mat2.row2.y + mat1.row2.w * mat2.row3.y;
f32 row2_col2 = mat1.row2.x * mat2.row0.z + mat1.row2.y * mat2.row1.z +
mat1.row2.z * mat2.row2.z + mat1.row2.w * mat2.row3.z;
f32 row2_col3 = mat1.row2.x * mat2.row0.w + mat1.row2.y * mat2.row1.w +
mat1.row2.z * mat2.row2.w + mat1.row2.w * mat2.row3.w;
return (mat3x4f_t){
(vec4f_t){row0_col0, row0_col1, row0_col2, row0_col3},
(vec4f_t){row1_col0, row1_col1, row1_col2, row1_col3},
(vec4f_t){row2_col0, row2_col1, row2_col2, row2_col3},
};
}
vec4f_t mul_mat4x4f_by_vec4f(mat4x4f_t mat, vec4f_t vec) {
f32 x = mat.row0.x * vec.x + mat.row0.y * vec.y + mat.row0.z * vec.z +
mat.row0.w * vec.w;
f32 y = mat.row1.x * vec.x + mat.row1.y * vec.y + mat.row1.z * vec.z +
mat.row1.w * vec.w;
f32 z = mat.row2.x * vec.x + mat.row2.y * vec.y + mat.row2.z * vec.z +
mat.row2.w * vec.w;
f32 w = mat.row3.x * vec.x + mat.row3.y * vec.y + mat.row3.z * vec.z +
mat.row3.w * vec.w;
return (vec4f_t){x, y, z, w};
}
mat4x4f_t mul_mat4x4f(mat4x4f_t mat1, mat4x4f_t mat2) {
f32 row0_col0 = mat1.row0.x * mat2.row0.x + mat1.row0.y * mat2.row1.x +
mat1.row0.z * mat2.row2.x + mat1.row0.w * mat2.row3.x;
f32 row0_col1 = mat1.row0.x * mat2.row0.y + mat1.row0.y * mat2.row1.y +
mat1.row0.z * mat2.row2.y + mat1.row0.w * mat2.row3.y;
f32 row0_col2 = mat1.row0.x * mat2.row0.z + mat1.row0.y * mat2.row1.z +
mat1.row0.z * mat2.row2.z + mat1.row0.w * mat2.row3.z;
f32 row0_col3 = mat1.row0.x * mat2.row0.w + mat1.row0.y * mat2.row1.w +
mat1.row0.z * mat2.row2.w + mat1.row0.w * mat2.row3.w;
f32 row1_col0 = mat1.row1.x * mat2.row0.x + mat1.row1.y * mat2.row1.x +
mat1.row1.z * mat2.row2.x + mat1.row1.w * mat2.row3.x;
f32 row1_col1 = mat1.row1.x * mat2.row0.y + mat1.row1.y * mat2.row1.y +
mat1.row1.z * mat2.row2.y + mat1.row1.w * mat2.row3.y;
f32 row1_col2 = mat1.row1.x * mat2.row0.z + mat1.row1.y * mat2.row1.z +
mat1.row1.z * mat2.row2.z + mat1.row1.w * mat2.row3.z;
f32 row1_col3 = mat1.row1.x * mat2.row0.w + mat1.row1.y * mat2.row1.w +
mat1.row1.z * mat2.row2.w + mat1.row1.w * mat2.row3.w;
f32 row2_col0 = mat1.row2.x * mat2.row0.x + mat1.row2.y * mat2.row1.x +
mat1.row2.z * mat2.row2.x + mat1.row2.w * mat2.row3.x;
f32 row2_col1 = mat1.row2.x * mat2.row0.y + mat1.row2.y * mat2.row1.y +
mat1.row2.z * mat2.row2.y + mat1.row2.w * mat2.row3.y;
f32 row2_col2 = mat1.row2.x * mat2.row0.z + mat1.row2.y * mat2.row1.z +
mat1.row2.z * mat2.row2.z + mat1.row2.w * mat2.row3.z;
f32 row2_col3 = mat1.row2.x * mat2.row0.w + mat1.row2.y * mat2.row1.w +
mat1.row2.z * mat2.row2.w + mat1.row2.w * mat2.row3.w;
f32 row3_col0 = mat1.row3.x * mat2.row0.x + mat1.row3.y * mat2.row1.x +
mat1.row3.z * mat2.row2.x + mat1.row3.w * mat2.row3.x;
f32 row3_col1 = mat1.row3.x * mat2.row0.y + mat1.row3.y * mat2.row1.y +
mat1.row3.z * mat2.row2.y + mat1.row3.w * mat2.row3.y;
f32 row3_col2 = mat1.row3.x * mat2.row0.z + mat1.row3.y * mat2.row1.z +
mat1.row3.z * mat2.row2.z + mat1.row3.w * mat2.row3.z;
f32 row3_col3 = mat1.row3.x * mat2.row0.w + mat1.row3.y * mat2.row1.w +
mat1.row3.z * mat2.row2.w + mat1.row3.w * mat2.row3.w;
return (mat4x4f_t){
(vec4f_t){row0_col0, row0_col1, row0_col2, row0_col3},
(vec4f_t){row1_col0, row1_col1, row1_col2, row1_col3},
(vec4f_t){row2_col0, row2_col1, row2_col2, row2_col3},
(vec4f_t){row3_col0, row3_col1, row3_col2, row3_col3},
};
}

View File

@@ -1,6 +1,7 @@
#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>
@@ -10,12 +11,14 @@
#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 +67,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 +91,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 +106,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] = 0.0f;
} }
SDL_UnlockSurface(wnd->back_buffer); SDL_UnlockSurface(wnd->back_buffer);
@@ -117,13 +126,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 0.0f;
}
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,7 +189,13 @@ void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour) {
pixels[index] = colour.colour; pixels[index] = colour.colour;
} }
vec3f_t window_to_viewport(window_t *wnd, i32 x, i32 y, vec3f_t viewport) { 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){ return (vec3f_t){
.x = x * viewport.x / wnd->width, .x = x * viewport.x / wnd->width,
.y = y * viewport.y / wnd->height, .y = y * viewport.y / wnd->height,
@@ -167,6 +203,14 @@ vec3f_t window_to_viewport(window_t *wnd, i32 x, i32 y, vec3f_t viewport) {
}; };
} }
vec2i_t viewport_to_window(const window_t *wnd, f32 x, f32 y,
vec3f_t viewport) {
return (vec2i_t){
.x = x / viewport.x * wnd->width,
.y = y / viewport.y * wnd->height,
};
}
colour_t colour_add_colour(colour_t a, colour_t b) { colour_t colour_add_colour(colour_t a, colour_t b) {
f32 alpha = clamp((f32)(a.rgba.a + b.rgba.a), 0.0f, (f32)UINT8_MAX); f32 alpha = clamp((f32)(a.rgba.a + b.rgba.a), 0.0f, (f32)UINT8_MAX);