Compare commits

..

5 Commits

6 changed files with 257 additions and 7 deletions

View File

@ -2,9 +2,10 @@
CC=clang
CFLAGS="-g -Wall -Werror -pedantic -Iinclude $(pkg-config --cflags sdl2)"
LIBS="$(pkg-config --libs sdl2)"
LIBS="$(pkg-config --libs sdl2) -lm"
RAYTRACER_SRC="src/window/*.c \
src/vector/*.c \
src/raytracer/*.c \
"

53
include/vector/vec.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef VEC_H
#define VEC_H
#include "c_cpp_aliases/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;
#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_dot(T, v1, v2) vec_dot_##T(v1, v2)
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);
i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2);
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);
f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2);
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);
i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2);
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);
f32 vec_dot_vec3f_t(vec3f_t v1, vec3f_t v2);
#endif // !VEC_H

View File

@ -2,6 +2,7 @@
#define WINDOW_H
#include "c_cpp_aliases/aliases.h"
#include "vector/vec.h"
#include <SDL2/SDL_video.h>
#include <stdbool.h>
@ -30,4 +31,6 @@ void clear_window(window_t *wnd, colour_t colour);
void set_pixel(window_t *wnd, i32 x, i32 y, colour_t colour);
void swap_buffers(window_t *wnd);
vec3f_t window_to_viewport(window_t *wnd, i32 x, i32 y, vec3f_t viewport);
#endif // !WINDOW_H

View File

@ -1,22 +1,77 @@
#include "SDL_events.h"
#include "c_cpp_aliases/aliases.h"
#include "vector/vec.h"
#include "window/window.h"
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define ARR_LEN(ARR) sizeof(ARR) / sizeof(ARR[0])
typedef struct {
f32 radius;
vec3f_t centre;
colour_t colour;
} sphere_t;
typedef struct {
sphere_t *spheres;
u32 count;
} scene_t;
typedef struct {
f32 t1;
f32 t2;
} solutions_t;
solutions_t ray_intersects_sphere(vec3f_t origin, vec3f_t direction,
sphere_t sphere);
colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
const scene_t *scene, colour_t default_colour);
int main(int argc, char *argv[]) {
colour_t bg = (colour_t){.r = 128, .g = 128, .b = 128, .a = 255};
colour_t bg = (colour_t){.r = 27, .g = 38, .b = 79, .a = 255};
vec3f_t camera = {.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(&window, 800, 800, "CG From Scratch")) {
return EXIT_FAILURE;
}
bool running = true;
SDL_Event event = {0};
sphere_t spheres[] = {
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 0.0f, .y = -1.0f, .z = 3.0f},
.colour = (colour_t){.r = 245, .g = 238, .b = 158, .a = 255},
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = -2.0f, .y = 0.0f, .z = 4.0f},
.colour = (colour_t){.r = 59, .g = 142, .b = 165, .a = 255},
},
(sphere_t){
.radius = 1.0f,
.centre = (vec3f_t){.x = 2.0f, .y = 0.0f, .z = 4.0f},
.colour = (colour_t){.r = 171, .g = 52, .b = 40, .a = 255},
},
};
scene_t scene = {
.spheres = spheres,
.count = ARR_LEN(spheres),
};
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 +83,14 @@ 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);
colour_t colour = trace_ray(camera, direction, 1, INFINITY, &scene, bg);
set_pixel(&window, x, y, colour);
}
}
swap_buffers(&window);
}
@ -35,3 +98,52 @@ int main(int argc, char *argv[]) {
return EXIT_SUCCESS;
}
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};
}
colour_t trace_ray(vec3f_t origin, vec3f_t direction, f32 t_min, f32 t_max,
const scene_t *scene, colour_t default_colour) {
f32 closest_t = INFINITY;
sphere_t *closest_sphere = NULL;
for (u32 i = 0; i < scene->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]);
}
}
if (!closest_sphere) {
return default_colour;
}
return closest_sphere->colour;
}

65
src/vector/vec.c Normal file
View File

@ -0,0 +1,65 @@
#include "vector/vec.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};
}
i32 vec_dot_vec2i_t(vec2i_t v1, vec2i_t v2) {
return v1.x * v2.x + v1.y * v2.y;
}
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};
}
f32 vec_dot_vec2f_t(vec2f_t v1, vec2f_t v2) {
return v1.x * v2.x + v1.y * v2.y;
}
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};
}
i32 vec_dot_vec3i_t(vec3i_t v1, vec3i_t v2) {
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
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_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;
}

View File

@ -1,5 +1,6 @@
#include "window/window.h"
#include "c_cpp_aliases/aliases.h"
#include "vector/vec.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_error.h>
#include <SDL2/SDL_pixels.h>
@ -10,6 +11,7 @@
u32 colour_to_u32(colour_t colour);
u32 index_from_coordinates(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);
bool init_window(window_t *wnd, u32 width, u32 height, const char *title) {
@ -103,16 +105,15 @@ void clear_window(window_t *wnd, colour_t colour) {
}
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);
}
@ -150,6 +151,13 @@ 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);
@ -158,3 +166,11 @@ void set_screen_pixel(window_t *wnd, u32 x, u32 y, colour_t colour) {
pixels[index] = c;
}
vec3f_t window_to_viewport(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,
};
}