Compare commits
	
		
			80 Commits
		
	
	
		
			c5cc8643e1
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b35a7d9cbe | |||
| ade35f3940 | |||
| e96400f74e | |||
| 70dfb5d5ee | |||
| 51099ae97e | |||
| 5a3b143762 | |||
| 83fa308a4b | |||
| 94287ff081 | |||
| 48735adf7b | |||
| f6848b5f4f | |||
| 77edf714bb | |||
| 5d61e8a616 | |||
| e236cd8bbe | |||
| b0bf4f593b | |||
| f6f2483b61 | |||
| 00e7293b28 | |||
| 3c293198bb | |||
| ae072ec70e | |||
| c3e1aac779 | |||
| 4430ea872c | |||
| df1620319c | |||
| 26fc513d4a | |||
| 9d929c22ba | |||
| 44c7b6ac1b | |||
| 7823e92861 | |||
| b7101108a4 | |||
| 39f198e342 | |||
| b81304e759 | |||
| 9ba7a8c414 | |||
| 01c5def71f | |||
| 0911b33981 | |||
| 946ea9c307 | |||
| 7f251e7704 | |||
| fa5453d399 | |||
| 7c192d5edf | |||
| 33b89a9e44 | |||
| d5a18828c5 | |||
| c9f3c6ab01 | |||
| 96c5d21f79 | |||
| f922980232 | |||
| 6dc609be14 | |||
| 52dbae227d | |||
| 5636fa57fc | |||
| e3c463d2f1 | |||
| 01ece119ed | |||
| 1c1b611bbb | |||
| e622923e19 | |||
| f72568c135 | |||
| ab469b8f37 | |||
| 058dba9276 | |||
| 65dcd66f76 | |||
| 5908cf3063 | |||
| 9f4137dac9 | |||
| 05eb1723ee | |||
| 3c21e2c471 | |||
| fc79cb1906 | |||
| 8fc3a2577a | |||
| fbe4513a14 | |||
| 0323fa2a8f | |||
| 1cebb9d29f | |||
| a7dda028aa | |||
| c2560ccbdd | |||
| 6d8f332500 | |||
| 4914f8eb71 | |||
| 56959990e4 | |||
| 1f5568b63e | |||
| bfdea0fd0c | |||
| f2fdc0d084 | |||
| 451aa48b3a | |||
| 8b9ac28402 | |||
| f34e234609 | |||
| 0b7ca65967 | |||
| a4e67ebc18 | |||
| 9b22ce61d5 | |||
| 0345f90405 | |||
| 2ec654774e | |||
| 6b0732980a | |||
| 36913bf365 | |||
| 25ff01b815 | |||
| f0b6771255 | 
							
								
								
									
										7
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.gitmodules
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,3 @@
 | 
			
		||||
[submodule "include/c_cpp_aliases"]
 | 
			
		||||
	path = include/c_cpp_aliases
 | 
			
		||||
	url = https://git.thewizardapprentice.com/abdelrahman/c-cpp-aliases.git
 | 
			
		||||
	branch = main
 | 
			
		||||
[submodule "intern/wapp"]
 | 
			
		||||
	path = intern/wapp
 | 
			
		||||
	url = https://git.thewizardapprentice.com/abdelrahman/wizapp-stdlib.git
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,7 @@
 | 
			
		||||
# Computer Graphics from Scratch
 | 
			
		||||
 | 
			
		||||
Following along with [Gabriel Gambetta](https://gabrielgambetta.com/index.html)'s [Computer Graphics From Scratch](https://gabrielgambetta.com/computer-graphics-from-scratch/)
 | 
			
		||||
 | 
			
		||||
## Raytracer
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								compile
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										22
									
								
								compile
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -1,16 +1,34 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
WAPP_INCLUDE="$(find ./intern/wapp/src -type d | xargs -I{} echo -n "-I{} ")"
 | 
			
		||||
WAPP_SRC="$(find ./intern/wapp/src -type f -name "*.c" | xargs -I{} echo -n "{} ")"
 | 
			
		||||
 | 
			
		||||
CC=clang
 | 
			
		||||
CFLAGS="-g -Wall -Werror -pedantic -Iinclude $(pkg-config --cflags sdl2)"
 | 
			
		||||
LIBS="$(pkg-config --libs sdl2)"
 | 
			
		||||
CFLAGS="-g -Wall -Werror -pedantic -Iinclude $WAPP_INCLUDE $(pkg-config --cflags sdl2)"
 | 
			
		||||
LIBS="$(pkg-config --libs sdl2) -lm"
 | 
			
		||||
 | 
			
		||||
RAYTRACER_SRC="src/window/*.c \
 | 
			
		||||
	src/vector/*.c \
 | 
			
		||||
	src/raytracer/*.c \
 | 
			
		||||
	src/math/*.c \
 | 
			
		||||
	src/camera/*.c \
 | 
			
		||||
	$WAPP_SRC \
 | 
			
		||||
"
 | 
			
		||||
 | 
			
		||||
RASTERISER_SRC="src/window/*.c \
 | 
			
		||||
	src/vector/*.c \
 | 
			
		||||
	src/list/*.c \
 | 
			
		||||
	src/rasteriser/*.c \
 | 
			
		||||
	src/math/*.c \
 | 
			
		||||
	src/camera/*.c \
 | 
			
		||||
	$WAPP_SRC \
 | 
			
		||||
"
 | 
			
		||||
 | 
			
		||||
BUILD=build_dir
 | 
			
		||||
RAYTRACER_OUT="$BUILD/raytracer"
 | 
			
		||||
RASTERISER_OUT="$BUILD/rasteriser"
 | 
			
		||||
 | 
			
		||||
mkdir -p $BUILD
 | 
			
		||||
 | 
			
		||||
(set -x ; $CC $CFLAGS $LIBS $RAYTRACER_SRC -o $RAYTRACER_OUT)
 | 
			
		||||
(set -x ; $CC $CFLAGS $LIBS $RASTERISER_SRC -o $RASTERISER_OUT)
 | 
			
		||||
 
 | 
			
		||||
 Submodule include/c_cpp_aliases deleted from f95f3aa499
									
								
							
							
								
								
									
										15
									
								
								include/camera/camera.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								include/camera/camera.h
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										79
									
								
								include/list/typed_list.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								include/list/typed_list.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
#ifndef TYPED_LIST_H
 | 
			
		||||
#define TYPED_LIST_H
 | 
			
		||||
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define BASE_LIST_CAPACITY 1024
 | 
			
		||||
 | 
			
		||||
#define CONCAT(A, B) A##B
 | 
			
		||||
#define LIST_TYPE_NAME(T) CONCAT(list_, T)
 | 
			
		||||
 | 
			
		||||
#define MAKE_LIST_TYPE(T)                                                      \
 | 
			
		||||
  typedef struct {                                                             \
 | 
			
		||||
    T *items;                                                                  \
 | 
			
		||||
    u64 capacity;                                                              \
 | 
			
		||||
    u64 count;                                                                 \
 | 
			
		||||
  } LIST_TYPE_NAME(T)
 | 
			
		||||
 | 
			
		||||
#define list_create(T, ARENA)                                                  \
 | 
			
		||||
  (LIST_TYPE_NAME(T) *)_create_list(ARENA, sizeof(T), BASE_LIST_CAPACITY)
 | 
			
		||||
#define list_create_with_capacity(T, ARENA, CAPACITY)                          \
 | 
			
		||||
  (LIST_TYPE_NAME(T) *)_create_list(ARENA, sizeof(T), CAPACITY)
 | 
			
		||||
 | 
			
		||||
#define _increase_list_capacity(T, ARENA, LP, CAP)                             \
 | 
			
		||||
  do {                                                                         \
 | 
			
		||||
    u64 new_capacity = LP->capacity * 2;                                       \
 | 
			
		||||
    T *tmp = _alloc_for_list(ARENA, sizeof(T) * new_capacity);                 \
 | 
			
		||||
    assert(tmp != NULL && "Failed to increase capacity");                      \
 | 
			
		||||
                                                                               \
 | 
			
		||||
    memcpy(tmp, LP->items, sizeof(T) * LP->count);                             \
 | 
			
		||||
                                                                               \
 | 
			
		||||
    LP->capacity = new_capacity;                                               \
 | 
			
		||||
    LP->items = tmp;                                                           \
 | 
			
		||||
  } while (0)
 | 
			
		||||
 | 
			
		||||
#define list_append(T, ARENA, LP, ITEM)                                        \
 | 
			
		||||
  do {                                                                         \
 | 
			
		||||
    if (LP->count + 1 >= LP->capacity) {                                       \
 | 
			
		||||
      _increase_list_capacity(T, ARENA, LP, LP->capacity * 2);                 \
 | 
			
		||||
    }                                                                          \
 | 
			
		||||
                                                                               \
 | 
			
		||||
    LP->items[(LP->count)++] = ITEM;                                           \
 | 
			
		||||
  } 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_set(LP, IDX, ITEM) LP->items[IDX] = ITEM
 | 
			
		||||
#define list_get(LP, IDX) LP->items[IDX]
 | 
			
		||||
 | 
			
		||||
#define list_merge(T, ARENA, DST, LP1, LP2)                                    \
 | 
			
		||||
  do {                                                                         \
 | 
			
		||||
    u64 new_count = LP1->count + LP2->count;                                   \
 | 
			
		||||
    u64 capacity =                                                             \
 | 
			
		||||
        new_count < BASE_LIST_CAPACITY ? BASE_LIST_CAPACITY : new_count * 2;   \
 | 
			
		||||
                                                                               \
 | 
			
		||||
    DST = (LIST_TYPE_NAME(T) *)_create_list(ARENA, new_count, capacity);       \
 | 
			
		||||
    assert(DST != NULL && "Failed to allocate new list");                      \
 | 
			
		||||
                                                                               \
 | 
			
		||||
    u64 lp1_copy_size = sizeof(T) * LP1->count;                                \
 | 
			
		||||
    u64 lp2_copy_size = sizeof(T) * LP2->count;                                \
 | 
			
		||||
    memcpy(DST->items, LP1->items, lp1_copy_size);                             \
 | 
			
		||||
    T *dst = &(DST->items[LP1->count]);                                        \
 | 
			
		||||
    memcpy(dst, LP2->items, lp2_copy_size);                                    \
 | 
			
		||||
    DST->capacity = capacity;                                                  \
 | 
			
		||||
    DST->count = new_count;                                                    \
 | 
			
		||||
  } while (0)
 | 
			
		||||
 | 
			
		||||
MAKE_LIST_TYPE(void);
 | 
			
		||||
 | 
			
		||||
list_void *_create_list(Arena *arena, u64 size, u64 count);
 | 
			
		||||
void *_alloc_for_list(Arena *arena, u64 size);
 | 
			
		||||
 | 
			
		||||
#endif // !TYPED_LIST_H
 | 
			
		||||
							
								
								
									
										17
									
								
								include/math/math_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								include/math/math_utils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
#ifndef MATH_UTILS_H
 | 
			
		||||
#define MATH_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#define RADIANS(DEG) (DEG * (f32)M_PI / 180.0f)
 | 
			
		||||
#define swap(T, v1, v2)                                                        \
 | 
			
		||||
  {                                                                            \
 | 
			
		||||
    T tmp = v1;                                                                \
 | 
			
		||||
    v1 = v2;                                                                   \
 | 
			
		||||
    v2 = tmp;                                                                  \
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
f32 clamp(f32 value, f32 min, f32 max);
 | 
			
		||||
 | 
			
		||||
#endif // !MATH_UTILS_H
 | 
			
		||||
							
								
								
									
										6
									
								
								include/misc/misc_utils.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								include/misc/misc_utils.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
#ifndef MISC_UTILS_H
 | 
			
		||||
#define MISC_UTILS_H
 | 
			
		||||
 | 
			
		||||
#define ARR_LEN(ARR) sizeof(ARR) / sizeof(ARR[0])
 | 
			
		||||
 | 
			
		||||
#endif // !MISC_UTILS_H
 | 
			
		||||
							
								
								
									
										103
									
								
								include/rasteriser/rasteriser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								include/rasteriser/rasteriser.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
#ifndef RASTERISER_H
 | 
			
		||||
#define RASTERISER_H
 | 
			
		||||
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "camera/camera.h"
 | 
			
		||||
#include "list/typed_list.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "vector/vec.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(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 {
 | 
			
		||||
  vec2i_t p0;
 | 
			
		||||
  vec2i_t p1;
 | 
			
		||||
} line_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  vec2i_t p0;
 | 
			
		||||
  vec2i_t p1;
 | 
			
		||||
  vec2i_t p2;
 | 
			
		||||
  f32 h0;
 | 
			
		||||
  f32 h1;
 | 
			
		||||
  f32 h2;
 | 
			
		||||
  f32 z0;
 | 
			
		||||
  f32 z1;
 | 
			
		||||
  f32 z2;
 | 
			
		||||
  colour_t colour;
 | 
			
		||||
} triangle_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  list_vertex_t *vertices;
 | 
			
		||||
  list_scene_triangle_t *triangles;
 | 
			
		||||
} model_t;
 | 
			
		||||
#define NULL_MODEL ((model_t){0})
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
bool is_null_model(const model_t *model);
 | 
			
		||||
 | 
			
		||||
#endif // !RASTERISER_H
 | 
			
		||||
							
								
								
									
										55
									
								
								include/raytracer/raytracer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								include/raytracer/raytracer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
#ifndef RAYTRACER_H
 | 
			
		||||
#define RAYTRACER_H
 | 
			
		||||
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include "window/window.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  f32 t1;
 | 
			
		||||
  f32 t2;
 | 
			
		||||
} solutions_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  f32 radius;
 | 
			
		||||
  vec3f_t centre;
 | 
			
		||||
  colour_t colour;
 | 
			
		||||
  f32 specular;
 | 
			
		||||
  f32 reflective;
 | 
			
		||||
} sphere_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  f32 closest_t;
 | 
			
		||||
  const sphere_t *closest_sphere;
 | 
			
		||||
} 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,
 | 
			
		||||
                   const raytracer_scene_t *scene, colour_t default_colour,
 | 
			
		||||
                   u32 recursion_depth);
 | 
			
		||||
 | 
			
		||||
#endif // !RAYTRACER_H
 | 
			
		||||
							
								
								
									
										137
									
								
								include/vector/vec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								include/vector/vec.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,137 @@
 | 
			
		||||
#ifndef VEC_H
 | 
			
		||||
#define VEC_H
 | 
			
		||||
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  i32 x;
 | 
			
		||||
  i32 y;
 | 
			
		||||
} vec2i_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  f32 x;
 | 
			
		||||
  f32 y;
 | 
			
		||||
} vec2f_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  i32 x;
 | 
			
		||||
  i32 y;
 | 
			
		||||
  i32 z;
 | 
			
		||||
} vec3i_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  f32 x;
 | 
			
		||||
  f32 y;
 | 
			
		||||
  f32 z;
 | 
			
		||||
} 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_sub(T, v1, v2) vec_sub_##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_div_num(T, v1, num) vec_div_num_##T(v1, num)
 | 
			
		||||
#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_unit(T, v) vec_unit_##T(v)
 | 
			
		||||
 | 
			
		||||
vec2i_t vec_add_vec2i_t(vec2i_t v1, vec2i_t v2);
 | 
			
		||||
vec2i_t vec_sub_vec2i_t(vec2i_t v1, vec2i_t v2);
 | 
			
		||||
vec2i_t vec_mul_vec2i_t(vec2i_t v1, vec2i_t v2);
 | 
			
		||||
vec2i_t vec_mul_num_vec2i_t(vec2i_t v1, i32 num);
 | 
			
		||||
vec2i_t vec_div_num_vec2i_t(vec2i_t v1, i32 num);
 | 
			
		||||
i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2);
 | 
			
		||||
i32 vec_magnitude_vec2i_t(vec2i_t v);
 | 
			
		||||
vec2i_t vec_unit_vec2i_t(vec2i_t v);
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_add_vec2f_t(vec2f_t v1, vec2f_t v2);
 | 
			
		||||
vec2f_t vec_sub_vec2f_t(vec2f_t v1, vec2f_t v2);
 | 
			
		||||
vec2f_t vec_mul_vec2f_t(vec2f_t v1, vec2f_t v2);
 | 
			
		||||
vec2f_t vec_mul_num_vec2f_t(vec2f_t v1, f32 num);
 | 
			
		||||
vec2f_t vec_div_num_vec2f_t(vec2f_t v1, f32 num);
 | 
			
		||||
f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2);
 | 
			
		||||
f32 vec_magnitude_vec2f_t(vec2f_t v);
 | 
			
		||||
vec2f_t vec_unit_vec2f_t(vec2f_t v);
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_add_vec3i_t(vec3i_t v1, vec3i_t v2);
 | 
			
		||||
vec3i_t vec_sub_vec3i_t(vec3i_t v1, vec3i_t v2);
 | 
			
		||||
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_div_num_vec3i_t(vec3i_t v1, i32 num);
 | 
			
		||||
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);
 | 
			
		||||
vec3i_t vec_unit_vec3i_t(vec3i_t v);
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_add_vec3f_t(vec3f_t v1, vec3f_t v2);
 | 
			
		||||
vec3f_t vec_sub_vec3f_t(vec3f_t v1, vec3f_t v2);
 | 
			
		||||
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_div_num_vec3f_t(vec3f_t v1, f32 num);
 | 
			
		||||
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);
 | 
			
		||||
vec3f_t vec_unit_vec3f_t(vec3f_t v);
 | 
			
		||||
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
 | 
			
		||||
@@ -1,15 +1,24 @@
 | 
			
		||||
#ifndef WINDOW_H
 | 
			
		||||
#define WINDOW_H
 | 
			
		||||
 | 
			
		||||
#include "c_cpp_aliases/aliases.h"
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include <SDL2/SDL_video.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  u8 r;
 | 
			
		||||
  u8 g;
 | 
			
		||||
  u8 b;
 | 
			
		||||
  u8 a;
 | 
			
		||||
  u8 b;
 | 
			
		||||
  u8 g;
 | 
			
		||||
  u8 r;
 | 
			
		||||
} rgba_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  union {
 | 
			
		||||
    rgba_t rgba;
 | 
			
		||||
    u32 colour;
 | 
			
		||||
  };
 | 
			
		||||
} colour_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
@@ -21,13 +30,23 @@ 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);
 | 
			
		||||
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_mul(colour_t colour, f32 scalar);
 | 
			
		||||
 | 
			
		||||
#endif // !WINDOW_H
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								intern/wapp
									
									
									
									
									
										Submodule
									
								
							
							
								
								
								
								
								
							
						
						
									
										1
									
								
								intern/wapp
									
									
									
									
									
										Submodule
									
								
							 Submodule intern/wapp added at 8ed372d938
									
								
							
							
								
								
									
										
											BIN
										
									
								
								raytracer.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								raytracer.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 184 KiB  | 
							
								
								
									
										10
									
								
								run
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										10
									
								
								run
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -3,8 +3,8 @@
 | 
			
		||||
USAGE="Usage: run (raytracer | rasteriser)"
 | 
			
		||||
 | 
			
		||||
if [[ $# == 0 ]]; then
 | 
			
		||||
	echo $USAGE
 | 
			
		||||
	exit 1
 | 
			
		||||
  echo $USAGE
 | 
			
		||||
  exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
while [[ $# -gt 0 ]]; do
 | 
			
		||||
@@ -13,8 +13,12 @@ while [[ $# -gt 0 ]]; do
 | 
			
		||||
      RENDERER="raytracer"
 | 
			
		||||
      shift # past argument
 | 
			
		||||
      ;;
 | 
			
		||||
    rasteriser)
 | 
			
		||||
      RENDERER="rasteriser"
 | 
			
		||||
      shift # past argument
 | 
			
		||||
      ;;
 | 
			
		||||
    -*|--*|*)
 | 
			
		||||
			echo $USAGE
 | 
			
		||||
      echo $USAGE
 | 
			
		||||
      exit 1
 | 
			
		||||
      ;;
 | 
			
		||||
  esac
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								src/camera/camera.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/camera/camera.c
									
									
									
									
									
										Normal 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								src/list/typed_list.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/list/typed_list.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
#include "list/typed_list.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
 | 
			
		||||
list_void *_create_list(Arena *arena, u64 size, u64 count) {
 | 
			
		||||
  list_void *list = (list_void *)_alloc_for_list(arena, sizeof(list_void));
 | 
			
		||||
  if (!list) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  list->items = (void *)_alloc_for_list(arena, size * count);
 | 
			
		||||
  if (!list->items) {
 | 
			
		||||
    munmap(list, sizeof(list_void));
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
  memset(list->items, 0, sizeof(size * count));
 | 
			
		||||
 | 
			
		||||
  list->capacity = count;
 | 
			
		||||
  list->count = 0;
 | 
			
		||||
 | 
			
		||||
  return list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void *_alloc_for_list(Arena *arena, u64 size) {
 | 
			
		||||
  return wapp_mem_arena_alloc(arena, size);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								src/math/math_utils.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/math/math_utils.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
			
		||||
#include "math/math_utils.h"
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
 | 
			
		||||
f32 clamp(f32 value, f32 min, f32 max) {
 | 
			
		||||
  if (value < min) {
 | 
			
		||||
    return min;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (value > max) {
 | 
			
		||||
    return max;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return value;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										202
									
								
								src/rasteriser/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								src/rasteriser/main.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
			
		||||
#include "camera/camera.h"
 | 
			
		||||
#include "list/typed_list.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "mem_utils.h"
 | 
			
		||||
#include "misc/misc_utils.h"
 | 
			
		||||
#include "rasteriser/rasteriser.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include "window/window.h"
 | 
			
		||||
#include <SDL2/SDL_events.h>
 | 
			
		||||
#include <SDL2/SDL_keycode.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
int main(void) {
 | 
			
		||||
  colour_t bg =
 | 
			
		||||
      (colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255};
 | 
			
		||||
  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};
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  SDL_Event event = {0};
 | 
			
		||||
 | 
			
		||||
  // i32 w_min = ((i32)window.half_width) * -1;
 | 
			
		||||
  // i32 w_max = (i32)window.half_width;
 | 
			
		||||
  // i32 h_min = ((i32)window.half_height) * -1;
 | 
			
		||||
  // i32 h_max = (i32)window.half_height;
 | 
			
		||||
 | 
			
		||||
  Arena *frame_arena = NULL;
 | 
			
		||||
  u64 frame_arena_capacity = 32ull * 1024ull * 1024ull * 1024ull;
 | 
			
		||||
  if (!wapp_mem_arena_init(&frame_arena, frame_arena_capacity,
 | 
			
		||||
                           WAPP_MEM_ALLOC_RESERVE, false)) {
 | 
			
		||||
    return EXIT_FAILURE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render_type_t type = RASTERISER_RENDER_FILLED;
 | 
			
		||||
 | 
			
		||||
  while (running) {
 | 
			
		||||
    while (SDL_PollEvent(&event)) {
 | 
			
		||||
      switch (event.type) {
 | 
			
		||||
      case SDL_QUIT:
 | 
			
		||||
        running = false;
 | 
			
		||||
        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);
 | 
			
		||||
 | 
			
		||||
    render_scene(&window, frame_arena, &scene, type);
 | 
			
		||||
 | 
			
		||||
    swap_buffers(&window);
 | 
			
		||||
 | 
			
		||||
    wapp_mem_arena_clear(frame_arena);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  wapp_mem_arena_destroy(&frame_arena);
 | 
			
		||||
  wapp_mem_arena_destroy(&arena);
 | 
			
		||||
  close_window(&window);
 | 
			
		||||
 | 
			
		||||
  return EXIT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										683
									
								
								src/rasteriser/rasteriser.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										683
									
								
								src/rasteriser/rasteriser.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,683 @@
 | 
			
		||||
#include "rasteriser/rasteriser.h"
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "list/typed_list.h"
 | 
			
		||||
#include "math/math_utils.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include "window/window.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <sys/mman.h>
 | 
			
		||||
 | 
			
		||||
#define CULL_ENABLED 0
 | 
			
		||||
 | 
			
		||||
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 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 render_scene(window_t *wnd, Arena *arena, const rasteriser_scene_t *scene,
 | 
			
		||||
                  render_type_t type) {
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  for (u64 i = 0; i < scene->instance_count; ++i) {
 | 
			
		||||
    render_instance(wnd, scene, arena, cam_matrix, *(scene->proj_matrix),
 | 
			
		||||
                    &(scene->instances[i]), type);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
  list_vertex_t *transformed = list_create_with_capacity(
 | 
			
		||||
      vertex_t, arena, instance->model->vertices->count + 10);
 | 
			
		||||
  list_scene_triangle_t *triangles = list_create_with_capacity(
 | 
			
		||||
      scene_triangle_t, arena, instance->model->triangles->count + 10);
 | 
			
		||||
  if (!transformed || !triangles) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  copy_triangles(arena, triangles, instance->model->triangles);
 | 
			
		||||
 | 
			
		||||
  mat4x4f_t t_mat = get_translation_matrix(instance->transform.position);
 | 
			
		||||
  mat4x4f_t r_mat = get_rotation_matrix(instance->transform.rotation);
 | 
			
		||||
  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_wireframe_triangle(window_t *wnd, Arena *arena, triangle_t triangle) {
 | 
			
		||||
  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);
 | 
			
		||||
 | 
			
		||||
  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_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_merge(f32, arena, x012, x01, x12);
 | 
			
		||||
 | 
			
		||||
  f32 h0 = triangle.h0;
 | 
			
		||||
  f32 h1 = triangle.h1;
 | 
			
		||||
  f32 h2 = triangle.h2;
 | 
			
		||||
  list_float *h01 = interpolate(arena, y0, h0, y1, h1);
 | 
			
		||||
  list_float *h12 = interpolate(arena, y1, h1, y2, h2);
 | 
			
		||||
  list_float *h02 = interpolate(arena, y0, h0, y2, h2);
 | 
			
		||||
  list_float *h012 = NULL;
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
    index = y - y0;
 | 
			
		||||
    xl = (i64)list_get(x_left, index);
 | 
			
		||||
    xr = (i64)list_get(x_right, index);
 | 
			
		||||
    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));
 | 
			
		||||
 | 
			
		||||
      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) {
 | 
			
		||||
  list_float *values = NULL;
 | 
			
		||||
 | 
			
		||||
  if (abs(line.p1.x - line.p0.x) > abs(line.p1.y - line.p0.y)) {
 | 
			
		||||
    if (line.p1.x < line.p0.x) {
 | 
			
		||||
      swap(vec2i_t, line.p0, line.p1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    i32 x0 = line.p0.x;
 | 
			
		||||
    i32 y0 = line.p0.y;
 | 
			
		||||
    i32 x1 = line.p1.x;
 | 
			
		||||
    i32 y1 = line.p1.y;
 | 
			
		||||
 | 
			
		||||
    values = interpolate(arena, x0, y0, x1, y1);
 | 
			
		||||
    if (!values) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i32 x = x0; x <= x1; ++x) {
 | 
			
		||||
      set_pixel(wnd, x, (i32)(list_get(values, x - x0)), colour);
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    if (line.p1.y < line.p0.y) {
 | 
			
		||||
      swap(vec2i_t, line.p0, line.p1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    i32 x0 = line.p0.x;
 | 
			
		||||
    i32 y0 = line.p0.y;
 | 
			
		||||
    i32 x1 = line.p1.x;
 | 
			
		||||
    i32 y1 = line.p1.y;
 | 
			
		||||
 | 
			
		||||
    values = interpolate(arena, y0, x0, y1, x1);
 | 
			
		||||
    if (!values) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i32 y = y0; y <= y1; ++y) {
 | 
			
		||||
      set_pixel(wnd, (i32)(list_get(values, y - y0)), y, colour);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool is_null_model(const model_t *model) {
 | 
			
		||||
  return model->vertices == NULL && model->triangles == NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
    values = list_create_with_capacity(f32, arena, 20);
 | 
			
		||||
    if (values) {
 | 
			
		||||
      list_append(f32, arena, values, d0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return values;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  values = list_create(f32, arena);
 | 
			
		||||
  if (!values) {
 | 
			
		||||
    return NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  f32 a = (d1 - d0) / ((f32)i1 - i0);
 | 
			
		||||
  f32 d = d0;
 | 
			
		||||
 | 
			
		||||
  for (i32 i = i0; i <= i1; ++i) {
 | 
			
		||||
    list_append(f32, arena, values, d);
 | 
			
		||||
    d += a;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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) {
 | 
			
		||||
  if (triangle->p1.y < triangle->p0.y) {
 | 
			
		||||
    swap(vec2i_t, triangle->p0, triangle->p1);
 | 
			
		||||
    swap(f32, triangle->h0, triangle->h1);
 | 
			
		||||
  }
 | 
			
		||||
  if (triangle->p2.y < triangle->p0.y) {
 | 
			
		||||
    swap(vec2i_t, triangle->p0, triangle->p2);
 | 
			
		||||
    swap(f32, triangle->h0, triangle->h2);
 | 
			
		||||
  }
 | 
			
		||||
  if (triangle->p2.y < triangle->p1.y) {
 | 
			
		||||
    swap(vec2i_t, triangle->p1, triangle->p2);
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,22 +1,41 @@
 | 
			
		||||
#include "SDL_events.h"
 | 
			
		||||
#include "c_cpp_aliases/aliases.h"
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "camera/camera.h"
 | 
			
		||||
#include "raytracer/raytracer.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include "window/window.h"
 | 
			
		||||
#include <SDL2/SDL_events.h>
 | 
			
		||||
#include <SDL2/SDL_keycode.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[]) {
 | 
			
		||||
  colour_t bg = (colour_t){.r = 128, .g = 128, .b = 128, .a = 255};
 | 
			
		||||
#define RECURSION_DEPTH 3
 | 
			
		||||
 | 
			
		||||
i32 main(i32 argc, char *argv[]) {
 | 
			
		||||
  colour_t bg =
 | 
			
		||||
      (colour_t){.rgba.r = 27, .rgba.g = 38, .rgba.b = 79, .rgba.a = 255};
 | 
			
		||||
  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};
 | 
			
		||||
 | 
			
		||||
  window_t window = {0};
 | 
			
		||||
 | 
			
		||||
  if (!init_window(&window, 1000, 800, "CG From Scratch")) {
 | 
			
		||||
  if (!init_window(NULL, &window, 800, 800, "CG From Scratch Raytracer")) {
 | 
			
		||||
    return EXIT_FAILURE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const raytracer_scene_t *scene = build_test_scene();
 | 
			
		||||
 | 
			
		||||
  bool running = true;
 | 
			
		||||
  SDL_Event event = {0};
 | 
			
		||||
 | 
			
		||||
  i32 w_min = ((i32)window.half_width) * -1;
 | 
			
		||||
  i32 w_max = (i32)window.half_width;
 | 
			
		||||
  i32 h_min = ((i32)window.half_height) * -1;
 | 
			
		||||
  i32 h_max = (i32)window.half_height;
 | 
			
		||||
 | 
			
		||||
  while (running) {
 | 
			
		||||
    while (SDL_PollEvent(&event)) {
 | 
			
		||||
      switch (event.type) {
 | 
			
		||||
@@ -28,6 +47,16 @@ int main(int argc, char *argv[]) {
 | 
			
		||||
 | 
			
		||||
    clear_window(&window, bg);
 | 
			
		||||
 | 
			
		||||
    for (i32 y = h_min; y < h_max; ++y) {
 | 
			
		||||
      for (i32 x = w_min; x < w_max; ++x) {
 | 
			
		||||
        vec3f_t direction = window_to_viewport(&window, x, y, viewport);
 | 
			
		||||
        vec3f_t rotated = vec_rotate_vec3f_t(direction, camera.rotation);
 | 
			
		||||
        colour_t colour = trace_ray(camera.position, rotated, 1, INFINITY,
 | 
			
		||||
                                    scene, bg, RECURSION_DEPTH);
 | 
			
		||||
        set_pixel(&window, x, y, colour);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    swap_buffers(&window);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										265
									
								
								src/raytracer/raytracer.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										265
									
								
								src/raytracer/raytracer.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,265 @@
 | 
			
		||||
#include "raytracer/raytracer.h"
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "misc/misc_utils.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include "window/window.h"
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
#define SPECULAR_EPSILON 0.001f
 | 
			
		||||
#define REFLECTIVE_EPSILON 0.1f
 | 
			
		||||
 | 
			
		||||
internal intersection_t
 | 
			
		||||
find_closest_intersection(vec3f_t origin, vec3f_t direction, f32 t_min,
 | 
			
		||||
                          f32 t_max, const raytracer_scene_t *scene);
 | 
			
		||||
internal solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
 | 
			
		||||
                                           sphere_t sphere);
 | 
			
		||||
internal f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
 | 
			
		||||
                              vec3f_t view_vector, f32 specular_exponent,
 | 
			
		||||
                              const raytracer_scene_t *scene);
 | 
			
		||||
internal f32 light_diffuse(f32 light_intensity, vec3f_t light_direction,
 | 
			
		||||
                           vec3f_t surface_normal);
 | 
			
		||||
internal f32 light_specular(f32 light_intensity, vec3f_t light_direction,
 | 
			
		||||
                            vec3f_t surface_normal, vec3f_t view_vector,
 | 
			
		||||
                            f32 specular_exponent);
 | 
			
		||||
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 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,
 | 
			
		||||
                   const raytracer_scene_t *scene, colour_t default_colour,
 | 
			
		||||
                   u32 recursion_depth) {
 | 
			
		||||
  intersection_t intersection =
 | 
			
		||||
      find_closest_intersection(origin, direction, t_min, t_max, scene);
 | 
			
		||||
 | 
			
		||||
  if (!intersection.closest_sphere) {
 | 
			
		||||
    return default_colour;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  vec3f_t _direction = vec_mul_num(vec3f_t, direction, intersection.closest_t);
 | 
			
		||||
  vec3f_t position = vec_add(vec3f_t, origin, _direction);
 | 
			
		||||
 | 
			
		||||
  vec3f_t surface_normal =
 | 
			
		||||
      vec_sub(vec3f_t, position, intersection.closest_sphere->centre);
 | 
			
		||||
 | 
			
		||||
  f32 normal_magnitude = vec_magnitude(vec3f_t, surface_normal);
 | 
			
		||||
  surface_normal = vec_div_num(vec3f_t, surface_normal, normal_magnitude);
 | 
			
		||||
 | 
			
		||||
  vec3f_t view_vector = vec_mul_num(vec3f_t, direction, -1.0f);
 | 
			
		||||
 | 
			
		||||
  f32 light = compute_lighting(position, surface_normal, view_vector,
 | 
			
		||||
                               intersection.closest_sphere->specular, scene);
 | 
			
		||||
 | 
			
		||||
  colour_t local_colour =
 | 
			
		||||
      colour_mul(intersection.closest_sphere->colour, light);
 | 
			
		||||
 | 
			
		||||
  f32 reflective = intersection.closest_sphere->reflective;
 | 
			
		||||
  if (recursion_depth <= 0 || reflective <= 0) {
 | 
			
		||||
    return local_colour;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  vec3f_t R = reflect_ray(view_vector, surface_normal);
 | 
			
		||||
  colour_t reflected_colour =
 | 
			
		||||
      trace_ray(position, R, REFLECTIVE_EPSILON, INFINITY, scene,
 | 
			
		||||
                default_colour, recursion_depth - 1);
 | 
			
		||||
 | 
			
		||||
  local_colour = colour_mul(local_colour, 1.0f - reflective);
 | 
			
		||||
  reflected_colour = colour_mul(reflected_colour, reflective);
 | 
			
		||||
 | 
			
		||||
  return colour_add_colour(local_colour, reflected_colour);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal intersection_t
 | 
			
		||||
find_closest_intersection(vec3f_t origin, vec3f_t direction, f32 t_min,
 | 
			
		||||
                          f32 t_max, const raytracer_scene_t *scene) {
 | 
			
		||||
  f32 closest_t = INFINITY;
 | 
			
		||||
  const sphere_t *closest_sphere = NULL;
 | 
			
		||||
 | 
			
		||||
  for (u32 i = 0; i < scene->spheres_count; ++i) {
 | 
			
		||||
    solutions_t solutions =
 | 
			
		||||
        ray_intersects_sphere(origin, direction, scene->spheres[i]);
 | 
			
		||||
 | 
			
		||||
    if (solutions.t1 >= t_min && solutions.t1 <= t_max &&
 | 
			
		||||
        solutions.t1 < closest_t) {
 | 
			
		||||
      closest_t = solutions.t1;
 | 
			
		||||
      closest_sphere = &(scene->spheres[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (solutions.t2 >= t_min && solutions.t2 <= t_max &&
 | 
			
		||||
        solutions.t2 < closest_t) {
 | 
			
		||||
      closest_t = solutions.t2;
 | 
			
		||||
      closest_sphere = &(scene->spheres[i]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (intersection_t){closest_t, closest_sphere};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
 | 
			
		||||
                                           sphere_t sphere) {
 | 
			
		||||
  f32 r = sphere.radius;
 | 
			
		||||
  vec3f_t CO = vec_sub(vec3f_t, origin, sphere.centre);
 | 
			
		||||
 | 
			
		||||
  f32 a = vec_dot(vec3f_t, direction, direction);
 | 
			
		||||
  f32 b = 2.0f * vec_dot(vec3f_t, CO, direction);
 | 
			
		||||
  f32 c = vec_dot(vec3f_t, CO, CO) - r * r;
 | 
			
		||||
 | 
			
		||||
  f32 discriminant = b * b - 4 * a * c;
 | 
			
		||||
  if (discriminant < 0) {
 | 
			
		||||
    return (solutions_t){INFINITY, INFINITY};
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  f32 t1 = (-b + sqrtf(discriminant)) / (2 * a);
 | 
			
		||||
  f32 t2 = (-b - sqrtf(discriminant)) / (2 * a);
 | 
			
		||||
 | 
			
		||||
  return (solutions_t){t1, t2};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal f32 compute_lighting(vec3f_t position, vec3f_t surface_normal,
 | 
			
		||||
                              vec3f_t view_vector, f32 specular_exponent,
 | 
			
		||||
                              const raytracer_scene_t *scene) {
 | 
			
		||||
  f32 I = 0.0f;
 | 
			
		||||
  light_t light = {0};
 | 
			
		||||
 | 
			
		||||
  for (u32 i = 0; i < scene->lights_count; ++i) {
 | 
			
		||||
    light = scene->lights[i];
 | 
			
		||||
 | 
			
		||||
    if (light.type == LIGHT_TYPE_AMBIENT) {
 | 
			
		||||
      I += light.intensity;
 | 
			
		||||
    } else {
 | 
			
		||||
      vec3f_t light_direction = {0};
 | 
			
		||||
      f32 t_max = SPECULAR_EPSILON;
 | 
			
		||||
 | 
			
		||||
      switch (light.type) {
 | 
			
		||||
      case LIGHT_TYPE_POINT:
 | 
			
		||||
        light_direction = vec_sub(vec3f_t, light.position, position);
 | 
			
		||||
        t_max = 1;
 | 
			
		||||
        break;
 | 
			
		||||
      case LIGHT_TYPE_DIRECTIONAL:
 | 
			
		||||
        light_direction = light.direction;
 | 
			
		||||
        t_max = INFINITY;
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      intersection_t shadow = find_closest_intersection(
 | 
			
		||||
          position, light_direction, SPECULAR_EPSILON, t_max, scene);
 | 
			
		||||
      if (shadow.closest_sphere != NULL) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      I += light_diffuse(light.intensity, light_direction, surface_normal);
 | 
			
		||||
 | 
			
		||||
      if (specular_exponent != -1.0f) {
 | 
			
		||||
        I += light_specular(light.intensity, light_direction, surface_normal,
 | 
			
		||||
                            view_vector, specular_exponent);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return I;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal f32 light_diffuse(f32 light_intensity, vec3f_t light_direction,
 | 
			
		||||
                           vec3f_t surface_normal) {
 | 
			
		||||
  return light_intensity *
 | 
			
		||||
         cos_angle_between_vectors(light_direction, surface_normal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal f32 light_specular(f32 light_intensity, vec3f_t light_direction,
 | 
			
		||||
                            vec3f_t surface_normal, vec3f_t view_vector,
 | 
			
		||||
                            f32 specular_exponent) {
 | 
			
		||||
  vec3f_t R = reflect_ray(light_direction, surface_normal);
 | 
			
		||||
 | 
			
		||||
  return light_intensity *
 | 
			
		||||
         powf(cos_angle_between_vectors(R, view_vector), specular_exponent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal vec3f_t reflect_ray(vec3f_t light_direction, vec3f_t surface_normal) {
 | 
			
		||||
  vec3f_t _2N = vec_mul_num(vec3f_t, surface_normal, 2.0f);
 | 
			
		||||
  f32 dot_product = vec_dot(vec3f_t, light_direction, surface_normal);
 | 
			
		||||
 | 
			
		||||
  vec3f_t _2N_mul_dot = vec_mul_num(vec3f_t, _2N, dot_product);
 | 
			
		||||
 | 
			
		||||
  return vec_sub(vec3f_t, _2N_mul_dot, light_direction);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
internal f32 cos_angle_between_vectors(vec3f_t v1, vec3f_t v2) {
 | 
			
		||||
  f32 dot_product = vec_dot(vec3f_t, v1, v2);
 | 
			
		||||
 | 
			
		||||
  if (dot_product < 0.0f) {
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  f32 divisor = vec_magnitude(vec3f_t, v1) * vec_magnitude(vec3f_t, v2);
 | 
			
		||||
 | 
			
		||||
  if (divisor == 0.0f) {
 | 
			
		||||
    return 0.0f;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return dot_product / divisor;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										417
									
								
								src/vector/vec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										417
									
								
								src/vector/vec.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,417 @@
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include "math/math_utils.h"
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
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};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2i_t vec_sub_vec2i_t(vec2i_t v1, vec2i_t v2) {
 | 
			
		||||
  return (vec2i_t){.x = v1.x - v2.x, .y = v1.y - v2.y};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2i_t vec_mul_vec2i_t(vec2i_t v1, vec2i_t v2) {
 | 
			
		||||
  return (vec2i_t){.x = v1.x * v2.x, .y = v1.y * v2.y};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2i_t vec_mul_num_vec2i_t(vec2i_t v1, i32 num) {
 | 
			
		||||
  return (vec2i_t){.x = v1.x * num, .y = v1.y * num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2i_t vec_div_num_vec2i_t(vec2i_t v1, i32 num) {
 | 
			
		||||
  return (vec2i_t){.x = v1.x / num, .y = v1.y / num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2) {
 | 
			
		||||
  return v1.x * v2.x + v1.y * v2.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
i32 vec_magnitude_vec2i_t(vec2i_t v) {
 | 
			
		||||
  i32 dot_product = vec_dot_vec2i_t(v, v);
 | 
			
		||||
  return (i32)sqrtf((f32)dot_product);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2i_t vec_unit_vec2i_t(vec2i_t v) {
 | 
			
		||||
  i32 magnitude = vec_magnitude_vec2i_t(v);
 | 
			
		||||
  return (vec2i_t){v.x / magnitude, v.y / magnitude};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_add_vec2f_t(vec2f_t v1, vec2f_t v2) {
 | 
			
		||||
  return (vec2f_t){.x = v1.x + v2.x, .y = v1.y + v2.y};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_sub_vec2f_t(vec2f_t v1, vec2f_t v2) {
 | 
			
		||||
  return (vec2f_t){.x = v1.x - v2.x, .y = v1.y - v2.y};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_mul_vec2f_t(vec2f_t v1, vec2f_t v2) {
 | 
			
		||||
  return (vec2f_t){.x = v1.x * v2.x, .y = v1.y * v2.y};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_mul_num_vec2f_t(vec2f_t v1, f32 num) {
 | 
			
		||||
  return (vec2f_t){.x = v1.x * num, .y = v1.y * num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_div_num_vec2f_t(vec2f_t v1, f32 num) {
 | 
			
		||||
  return (vec2f_t){.x = v1.x / num, .y = v1.y / num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2) {
 | 
			
		||||
  return v1.x * v2.x + v1.y * v2.y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
f32 vec_magnitude_vec2f_t(vec2f_t v) {
 | 
			
		||||
  f32 dot_product = vec_dot_vec2f_t(v, v);
 | 
			
		||||
  return sqrtf(dot_product);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2f_t vec_unit_vec2f_t(vec2f_t v) {
 | 
			
		||||
  f32 magnitude = vec_magnitude_vec2f_t(v);
 | 
			
		||||
  return (vec2f_t){v.x / magnitude, v.y / magnitude};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_add_vec3i_t(vec3i_t v1, vec3i_t v2) {
 | 
			
		||||
  return (vec3i_t){.x = v1.x + v2.x, .y = v1.y + v2.y, .z = v1.z + v2.z};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_sub_vec3i_t(vec3i_t v1, vec3i_t v2) {
 | 
			
		||||
  return (vec3i_t){.x = v1.x - v2.x, .y = v1.y - v2.y, .z = v1.z - v2.z};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_mul_vec3i_t(vec3i_t v1, vec3i_t v2) {
 | 
			
		||||
  return (vec3i_t){.x = v1.x * v2.x, .y = v1.y * v2.y, .z = v1.z * v2.z};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_mul_num_vec3i_t(vec3i_t v1, i32 num) {
 | 
			
		||||
  return (vec3i_t){.x = v1.x * num, .y = v1.y * num, .z = v1.z * num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_div_num_vec3i_t(vec3i_t v1, i32 num) {
 | 
			
		||||
  return (vec3i_t){.x = v1.x / num, .y = v1.y / num, .z = v1.z / num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2) {
 | 
			
		||||
  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 dot_product = vec_dot_vec3i_t(v, v);
 | 
			
		||||
  return (i32)sqrtf((f32)dot_product);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3i_t vec_unit_vec3i_t(vec3i_t v) {
 | 
			
		||||
  i32 magnitude = vec_magnitude_vec3i_t(v);
 | 
			
		||||
  return (vec3i_t){v.x / magnitude, v.y / magnitude, v.z / magnitude};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_add_vec3f_t(vec3f_t v1, vec3f_t v2) {
 | 
			
		||||
  return (vec3f_t){.x = v1.x + v2.x, .y = v1.y + v2.y, .z = v1.z + v2.z};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_sub_vec3f_t(vec3f_t v1, vec3f_t v2) {
 | 
			
		||||
  return (vec3f_t){.x = v1.x - v2.x, .y = v1.y - v2.y, .z = v1.z - v2.z};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_mul_num_vec3f_t(vec3f_t v1, f32 num) {
 | 
			
		||||
  return (vec3f_t){.x = v1.x * num, .y = v1.y * num, .z = v1.z * num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_div_num_vec3f_t(vec3f_t v1, f32 num) {
 | 
			
		||||
  return (vec3f_t){.x = v1.x / num, .y = v1.y / num, .z = v1.z / num};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_mul_vec3f_t(vec3f_t v1, vec3f_t v2) {
 | 
			
		||||
  return (vec3f_t){.x = v1.x * v2.x, .y = v1.y * v2.y, .z = v1.z * v2.z};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2) {
 | 
			
		||||
  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 dot_product = vec_dot_vec3f_t(v, v);
 | 
			
		||||
  return sqrtf(dot_product);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec3f_t vec_unit_vec3f_t(vec3f_t v) {
 | 
			
		||||
  f32 magnitude = vec_magnitude_vec3f_t(v);
 | 
			
		||||
  return (vec3f_t){v.x / magnitude, v.y / magnitude, v.z / magnitude};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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 y_rad = RADIANS(rotation.y);
 | 
			
		||||
  f32 z_rad = RADIANS(rotation.z);
 | 
			
		||||
 | 
			
		||||
  f32 cos_x = cosf(x_rad);
 | 
			
		||||
  f32 sin_x = sinf(x_rad);
 | 
			
		||||
 | 
			
		||||
  f32 cos_y = cosf(y_rad);
 | 
			
		||||
  f32 sin_y = sinf(y_rad);
 | 
			
		||||
 | 
			
		||||
  f32 cos_z = cosf(z_rad);
 | 
			
		||||
  f32 sin_z = sinf(z_rad);
 | 
			
		||||
 | 
			
		||||
  f32 row0_col0 = cos_z * cos_y;
 | 
			
		||||
  f32 row0_col1 = cos_z * sin_y * sin_x - sin_z * cos_x;
 | 
			
		||||
  f32 row0_col2 = cos_z * sin_y * cos_x + sin_z * sin_x;
 | 
			
		||||
 | 
			
		||||
  f32 row1_col0 = sin_z * cos_y;
 | 
			
		||||
  f32 row1_col1 = sin_z * sin_y * sin_x + cos_z * cos_x;
 | 
			
		||||
  f32 row1_col2 = sin_z * sin_y * cos_x - cos_z * sin_x;
 | 
			
		||||
 | 
			
		||||
  f32 row2_col0 = -sin_y;
 | 
			
		||||
  f32 row2_col1 = cos_y * sin_x;
 | 
			
		||||
  f32 row2_col2 = cos_y * cos_x;
 | 
			
		||||
 | 
			
		||||
  return (mat3x3f_t){
 | 
			
		||||
      .row0 = {row0_col0, row0_col1, row0_col2},
 | 
			
		||||
      .row1 = {row1_col0, row1_col1, row1_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
 | 
			
		||||
  return (mat4x4f_t){
 | 
			
		||||
      (vec4f_t){mat.row0.x, mat.row0.y, mat.row0.z, 0.0f},
 | 
			
		||||
      (vec4f_t){mat.row1.x, mat.row1.y, mat.row1.z, 0.0f},
 | 
			
		||||
      (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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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},
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +1,24 @@
 | 
			
		||||
#include "window/window.h"
 | 
			
		||||
#include "c_cpp_aliases/aliases.h"
 | 
			
		||||
#include "aliases.h"
 | 
			
		||||
#include "math/math_utils.h"
 | 
			
		||||
#include "mem_arena.h"
 | 
			
		||||
#include "vector/vec.h"
 | 
			
		||||
#include <SDL2/SDL.h>
 | 
			
		||||
#include <SDL2/SDL_error.h>
 | 
			
		||||
#include <SDL2/SDL_pixels.h>
 | 
			
		||||
#include <SDL2/SDL_surface.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
u32 colour_to_u32(colour_t colour);
 | 
			
		||||
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());
 | 
			
		||||
 | 
			
		||||
@@ -61,6 +67,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;
 | 
			
		||||
}
 | 
			
		||||
@@ -82,6 +91,8 @@ void close_window(window_t *wnd) {
 | 
			
		||||
 | 
			
		||||
      wnd->back_buffer = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    wnd->z_buffer = NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SDL_Quit();
 | 
			
		||||
@@ -90,45 +101,59 @@ void close_window(window_t *wnd) {
 | 
			
		||||
void clear_window(window_t *wnd, colour_t colour) {
 | 
			
		||||
  SDL_LockSurface(wnd->back_buffer);
 | 
			
		||||
 | 
			
		||||
  u32 c = colour_to_u32(colour);
 | 
			
		||||
 | 
			
		||||
  u32 *pixels = (u32 *)(wnd->back_buffer->pixels);
 | 
			
		||||
  u32 count = wnd->back_buffer->w * wnd->back_buffer->h;
 | 
			
		||||
 | 
			
		||||
  for (u32 i = 0; i < count; ++i) {
 | 
			
		||||
    pixels[i] = c;
 | 
			
		||||
    pixels[i] = colour.colour;
 | 
			
		||||
    wnd->z_buffer[i] = 0.0f;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SDL_UnlockSurface(wnd->back_buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_pixel(window_t *wnd, i32 x, i32 y, colour_t colour) {
 | 
			
		||||
  i32 screen_x = denormalise(x, wnd->width, wnd->half_width);
 | 
			
		||||
  i32 screen_y = denormalise(-y, wnd->height, wnd->half_height);
 | 
			
		||||
  vec2i_t coords = denormalised_coords(wnd, x, y);
 | 
			
		||||
 | 
			
		||||
  if (screen_x < 0 || screen_y < 0) {
 | 
			
		||||
  if (coords.x < 0 || coords.y < 0) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  SDL_LockSurface(wnd->back_buffer);
 | 
			
		||||
 | 
			
		||||
  set_screen_pixel(wnd, (u32)screen_x, (u32)screen_y, colour);
 | 
			
		||||
  set_screen_pixel(wnd, (u32)(coords.x), (u32)(coords.y), 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 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) {
 | 
			
		||||
  SDL_BlitSurface(wnd->back_buffer, NULL, wnd->front_buffer, NULL);
 | 
			
		||||
 | 
			
		||||
  SDL_UpdateWindowSurface(wnd->window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u32 colour_to_u32(colour_t colour) {
 | 
			
		||||
  return ((u32)(colour.r) << 24) | ((u32)(colour.g) << 16) |
 | 
			
		||||
         ((u32)(colour.b) << 8) | (u32)(colour.a);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -150,11 +175,61 @@ i32 denormalise(i32 value, u32 max, u32 abs_half) {
 | 
			
		||||
  return denormalised;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vec2i_t denormalised_coords(const window_t *wnd, i32 x, i32 y) {
 | 
			
		||||
  i32 screen_x = denormalise(x, wnd->width, wnd->half_width);
 | 
			
		||||
  i32 screen_y = denormalise(-y, wnd->height, wnd->half_height);
 | 
			
		||||
 | 
			
		||||
  return (vec2i_t){.x = screen_x, .y = screen_y};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour) {
 | 
			
		||||
  u32 index = index_from_coordinates(wnd, x, y);
 | 
			
		||||
  u32 c = colour_to_u32(colour);
 | 
			
		||||
 | 
			
		||||
  u32 *pixels = (u32 *)(wnd->back_buffer->pixels);
 | 
			
		||||
 | 
			
		||||
  pixels[index] = c;
 | 
			
		||||
  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){
 | 
			
		||||
      .x = x * viewport.x / wnd->width,
 | 
			
		||||
      .y = y * viewport.y / wnd->height,
 | 
			
		||||
      .z = viewport.z,
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
  f32 alpha = clamp((f32)(a.rgba.a + b.rgba.a), 0.0f, (f32)UINT8_MAX);
 | 
			
		||||
 | 
			
		||||
  return (colour_t){.rgba.r = a.rgba.r + b.rgba.r,
 | 
			
		||||
                    .rgba.g = a.rgba.g + b.rgba.g,
 | 
			
		||||
                    .rgba.b = a.rgba.b + b.rgba.b,
 | 
			
		||||
                    .rgba.a = (u8)alpha};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
colour_t colour_mul(colour_t colour, f32 scalar) {
 | 
			
		||||
  f32 r = (f32)colour.rgba.r * scalar;
 | 
			
		||||
  r = clamp(r, 0.0f, (f32)UINT8_MAX);
 | 
			
		||||
  f32 g = (f32)colour.rgba.g * scalar;
 | 
			
		||||
  g = clamp(g, 0.0f, (f32)UINT8_MAX);
 | 
			
		||||
  f32 b = (f32)colour.rgba.b * scalar;
 | 
			
		||||
  b = clamp(b, 0.0f, (f32)UINT8_MAX);
 | 
			
		||||
 | 
			
		||||
  return (colour_t){.rgba.r = (u8)r,
 | 
			
		||||
                    .rgba.g = (u8)g,
 | 
			
		||||
                    .rgba.b = (u8)b,
 | 
			
		||||
                    .rgba.a = colour.rgba.a};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user