diff --git a/.gitignore b/.gitignore index 657a0dd..fd8c240 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,8 @@ test/test_materials test/test_spheres test/test_world test/test_camera +test/test_shapes +test/test_planes raytracer *.ppm *.png diff --git a/camera.h b/camera.h index 91e49fc..93bb93b 100644 --- a/camera.h +++ b/camera.h @@ -50,11 +50,11 @@ struct ray camera_ray_for_pixel(struct camera * camera, float px, float py) float world_x = camera->half_width - xoffset; float world_y = camera->half_height - yoffset; - struct mat4x4 t_inverse = mat4x4_inverse(&camera->transform); + struct mat4x4 t_inverse = mat4x4_inverse(camera->transform); struct tuple world_point = point(world_x, world_y, -1.0f); - struct tuple pixel = mat4x4_mul_t(&t_inverse, &world_point); + struct tuple pixel = mat4x4_mul_t(t_inverse, world_point); struct tuple world_origin = point(0.0f, 0.0f, 0.0f); - struct tuple origin = mat4x4_mul_t(&t_inverse, &world_origin); + struct tuple origin = mat4x4_mul_t(t_inverse, world_origin); struct tuple direction = tuple_normalize(tuple_sub(pixel, origin)); return ray(origin, direction); diff --git a/intersections.h b/intersections.h index d4185ab..b93ab63 100644 --- a/intersections.h +++ b/intersections.h @@ -1,29 +1,26 @@ #pragma once #include -#include -#include - -#include "spheres.h" -#include "rays.h" struct intersection { float t; - struct sphere const * object; + struct shape const * object; }; -struct intersection intersection(float t, struct sphere const * const object) -{ - return (struct intersection){ t, object }; -} - -#define MAX_INTERSECTIONS 1024 +#ifndef INTERSECTIONS_MAX +#define INTERSECTIONS_MAX 1024 +#endif struct intersections { int count; - struct intersection i[MAX_INTERSECTIONS]; + struct intersection i[INTERSECTIONS_MAX]; }; +struct intersection intersection(float t, struct shape const * const object) +{ + return (struct intersection){ t, object }; +} + inline static void intersections(struct intersections * intersections, int count, ...) { va_list ap; @@ -35,113 +32,3 @@ inline static void intersections(struct intersections * intersections, int count intersections->count = count; } - -inline static void intersect(struct sphere const * const s, struct ray r, struct intersections * intersections) -{ - struct mat4x4 m = mat4x4_inverse(&s->transform); - struct ray r2 = ray_transform(r, &m); - struct tuple sphere_to_ray = tuple_sub(r2.origin, point(0.0f, 0.0f, 0.0f)); - - float a = tuple_dot(r2.direction, r2.direction); - float b = 2 * tuple_dot(r2.direction, sphere_to_ray); - float c = tuple_dot(sphere_to_ray, sphere_to_ray) - 1; - - float discriminant = b * b - 4 * a * c; - - if (discriminant < 0) { - return; - } else { - float root = sqrtf(discriminant); - float t1 = (-b - root) / (2 * a); - float t2 = (-b + root) / (2 * a); - - intersections->i[intersections->count++] = intersection(t1, s); - intersections->i[intersections->count++] = intersection(t2, s); - assert(intersections->count < MAX_INTERSECTIONS); - return; - } -} - -inline static struct intersection * hit(struct intersections * xs) -{ - struct intersection * i = NULL; - for (int n = 0; n < xs->count; n++) { - if (xs->i[n].t >= 0) { - if (i == NULL || i->t > xs->i[n].t) - i = &xs->i[n]; - } - } - return i; -} - - -inline static void intersections_sort(struct intersections * xs) -{ -#define left_child(i) (2 * i + 1) - - int start = xs->count / 2; - int end = xs->count; - while (end > 1) { - if (start > 0) { - start = start - 1; - } else { - end = end - 1; - struct intersection tmp = xs->i[0]; - xs->i[0] = xs->i[end]; - xs->i[end] = tmp; - } - - int root = start; - while (left_child(root) < end) { - int child = left_child(root); - if (child + 1 < end && xs->i[child].t < xs->i[child+1].t) { - child = child + 1; - } - if (xs->i[root].t < xs->i[child].t) { - struct intersection tmp = xs->i[root]; - xs->i[root] = xs->i[child]; - xs->i[child] = tmp; - root = child; - } else { - break; - } - } - } - -#undef left_child -} - -struct computations { - float t; - struct sphere const * object; - struct tuple point; - struct tuple eyev; - struct tuple normalv; - bool inside; - struct tuple over_point; -}; - -inline static struct computations prepare_computations(struct intersection intersection, struct ray ray) -{ - struct tuple point = ray_position(ray, intersection.t); - struct tuple eyev = tuple_neg(ray.direction); - struct tuple normalv = sphere_normal_at(intersection.object, point); - - bool inside = false; - if (tuple_dot(normalv, eyev) < 0.0f) { - inside = true; - normalv = tuple_neg(normalv); - } - - struct tuple over_point = tuple_add(point, tuple_mul(normalv, epsilon * 100)); - - return (struct computations){ - intersection.t, - intersection.object, - point, - eyev, - normalv, - inside, - over_point - }; -} diff --git a/intersections_shapes.h b/intersections_shapes.h new file mode 100644 index 0000000..9464b5d --- /dev/null +++ b/intersections_shapes.h @@ -0,0 +1,153 @@ +#pragma once + +#include +#include + +#include "rays.h" +#include "shapes.h" +#include "intersections.h" +#include "spheres.h" +#include "planes.h" + +#ifdef TEST +struct ray intersections_saved_ray; +#endif + +inline static void intersect(struct shape const * const s, struct ray r, struct intersections * intersections) +{ + struct mat4x4 m = mat4x4_inverse(s->transform); + struct ray local_ray = ray_transform(r, m); + + switch (s->type) { +#ifdef TEST + case SHAPE_TEST: + intersections_saved_ray = local_ray; + break; +#endif + case SHAPE_SPHERE: + sphere_intersect(s, local_ray, intersections); + break; + case SHAPE_PLANE: + plane_intersect(s, local_ray, intersections); + break; + default: + assert(false); + break; + } + assert(intersections->count < INTERSECTIONS_MAX); +} + +inline static struct intersection * hit(struct intersections * xs) +{ + struct intersection * i = NULL; + for (int n = 0; n < xs->count; n++) { + if (xs->i[n].t >= 0) { + if (i == NULL || i->t > xs->i[n].t) + i = &xs->i[n]; + } + } + return i; +} + + +inline static void intersections_sort(struct intersections * xs) +{ +#define left_child(i) (2 * i + 1) + + int start = xs->count / 2; + int end = xs->count; + while (end > 1) { + if (start > 0) { + start = start - 1; + } else { + end = end - 1; + struct intersection tmp = xs->i[0]; + xs->i[0] = xs->i[end]; + xs->i[end] = tmp; + } + + int root = start; + while (left_child(root) < end) { + int child = left_child(root); + if (child + 1 < end && xs->i[child].t < xs->i[child+1].t) { + child = child + 1; + } + if (xs->i[root].t < xs->i[child].t) { + struct intersection tmp = xs->i[root]; + xs->i[root] = xs->i[child]; + xs->i[child] = tmp; + root = child; + } else { + break; + } + } + } + +#undef left_child +} + +struct computations { + float t; + struct shape const * object; + struct tuple point; + struct tuple eyev; + struct tuple normalv; + bool inside; + struct tuple over_point; +}; + +inline static struct tuple normal_at(struct shape const * const s, struct tuple world_point) +{ + struct mat4x4 inv = mat4x4_inverse(s->transform); + struct mat4x4 inv_t = mat4x4_transpose(inv); + + struct tuple local_point = mat4x4_mul_t(inv, world_point); + struct tuple local_normal; + + switch (s->type) { +#ifdef TEST + case SHAPE_TEST: + local_normal = vector(local_point.x, local_point.y, local_point.z); + break; +#endif + case SHAPE_SPHERE: + local_normal = sphere_normal_at(local_point); + break; + case SHAPE_PLANE: + local_normal = plane_normal_at(local_point); + break; + default: + assert(false); + break; + } + + struct tuple world_normal = mat4x4_mul_t(inv_t, local_normal); + world_normal.w = 0.0f; + + return tuple_normalize(world_normal); +} + +inline static struct computations prepare_computations(struct intersection intersection, struct ray ray) +{ + struct tuple point = ray_position(ray, intersection.t); + struct tuple eyev = tuple_neg(ray.direction); + struct tuple normalv = normal_at(intersection.object, point); + + bool inside = false; + if (tuple_dot(normalv, eyev) < 0.0f) { + inside = true; + normalv = tuple_neg(normalv); + } + + struct tuple over_point = tuple_add(point, tuple_mul(normalv, epsilon * 100)); + + return (struct computations){ + intersection.t, + intersection.object, + point, + eyev, + normalv, + inside, + over_point + }; +} diff --git a/math.h b/math.h index 166cd90..698e9d0 100644 --- a/math.h +++ b/math.h @@ -6,6 +6,7 @@ #define sinf __builtin_sinf #define powf __builtin_powf #define tanf __builtin_tanf +#define fabsf __builtin_fabsf static const float tau = 6.283185307179586f; static const float pi = tau / 2.0f; diff --git a/matrices.h b/matrices.h index 4041818..73a065e 100644 --- a/matrices.h +++ b/matrices.h @@ -48,61 +48,61 @@ inline static struct mat2x2 mat2x2(float a1, float a2, }}; } -inline static bool mat4x4_equal(struct mat4x4 const * const a, - struct mat4x4 const * const b) +inline static bool mat4x4_equal(struct mat4x4 a, + struct mat4x4 b) { return - float_equal(a->e[0][0], b->e[0][0]) && - float_equal(a->e[0][1], b->e[0][1]) && - float_equal(a->e[0][2], b->e[0][2]) && - float_equal(a->e[0][3], b->e[0][3]) && - float_equal(a->e[1][0], b->e[1][0]) && - float_equal(a->e[1][1], b->e[1][1]) && - float_equal(a->e[1][2], b->e[1][2]) && - float_equal(a->e[1][3], b->e[1][3]) && - float_equal(a->e[2][0], b->e[2][0]) && - float_equal(a->e[2][1], b->e[2][1]) && - float_equal(a->e[2][2], b->e[2][2]) && - float_equal(a->e[2][3], b->e[2][3]) && - float_equal(a->e[3][0], b->e[3][0]) && - float_equal(a->e[3][1], b->e[3][1]) && - float_equal(a->e[3][2], b->e[3][2]) && - float_equal(a->e[3][3], b->e[3][3]); + float_equal(a.e[0][0], b.e[0][0]) && + float_equal(a.e[0][1], b.e[0][1]) && + float_equal(a.e[0][2], b.e[0][2]) && + float_equal(a.e[0][3], b.e[0][3]) && + float_equal(a.e[1][0], b.e[1][0]) && + float_equal(a.e[1][1], b.e[1][1]) && + float_equal(a.e[1][2], b.e[1][2]) && + float_equal(a.e[1][3], b.e[1][3]) && + float_equal(a.e[2][0], b.e[2][0]) && + float_equal(a.e[2][1], b.e[2][1]) && + float_equal(a.e[2][2], b.e[2][2]) && + float_equal(a.e[2][3], b.e[2][3]) && + float_equal(a.e[3][0], b.e[3][0]) && + float_equal(a.e[3][1], b.e[3][1]) && + float_equal(a.e[3][2], b.e[3][2]) && + float_equal(a.e[3][3], b.e[3][3]); } -inline static bool mat3x3_equal(struct mat3x3 * a, - struct mat3x3 * b) +inline static bool mat3x3_equal(struct mat3x3 a, + struct mat3x3 b) { return - float_equal(a->e[0][0], b->e[0][0]) && - float_equal(a->e[0][1], b->e[0][1]) && - float_equal(a->e[0][2], b->e[0][2]) && - float_equal(a->e[1][0], b->e[1][0]) && - float_equal(a->e[1][1], b->e[1][1]) && - float_equal(a->e[1][2], b->e[1][2]) && - float_equal(a->e[2][0], b->e[2][0]) && - float_equal(a->e[2][1], b->e[2][1]) && - float_equal(a->e[2][2], b->e[2][2]); + float_equal(a.e[0][0], b.e[0][0]) && + float_equal(a.e[0][1], b.e[0][1]) && + float_equal(a.e[0][2], b.e[0][2]) && + float_equal(a.e[1][0], b.e[1][0]) && + float_equal(a.e[1][1], b.e[1][1]) && + float_equal(a.e[1][2], b.e[1][2]) && + float_equal(a.e[2][0], b.e[2][0]) && + float_equal(a.e[2][1], b.e[2][1]) && + float_equal(a.e[2][2], b.e[2][2]); } -inline static bool mat2x2_equal(struct mat2x2 * a, - struct mat2x2 * b) +inline static bool mat2x2_equal(struct mat2x2 a, + struct mat2x2 b) { return - float_equal(a->e[0][0], b->e[0][0]) && - float_equal(a->e[0][1], b->e[0][1]) && - float_equal(a->e[1][0], b->e[1][0]) && - float_equal(a->e[1][1], b->e[1][1]); + float_equal(a.e[0][0], b.e[0][0]) && + float_equal(a.e[0][1], b.e[0][1]) && + float_equal(a.e[1][0], b.e[1][0]) && + float_equal(a.e[1][1], b.e[1][1]); } -inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 const * const a, - struct mat4x4 const * const b) +inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 a, + struct mat4x4 b) { #define dot(row, col) \ - a->e[row][0] * b->e[0][col] + \ - a->e[row][1] * b->e[1][col] + \ - a->e[row][2] * b->e[2][col] + \ - a->e[row][3] * b->e[3][col] + a.e[row][0] * b.e[0][col] + \ + a.e[row][1] * b.e[1][col] + \ + a.e[row][2] * b.e[2][col] + \ + a.e[row][3] * b.e[3][col] return mat4x4(dot(0, 0), dot(0, 1), dot(0, 2), dot(0, 3), dot(1, 0), dot(1, 1), dot(1, 2), dot(1, 3), @@ -112,14 +112,14 @@ inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 const * const a, #undef dot } -inline static struct tuple mat4x4_mul_t(struct mat4x4 const * const a, - struct tuple * b) +inline static struct tuple mat4x4_mul_t(struct mat4x4 a, + struct tuple b) { #define dot(row) \ - a->e[row][0] * b->e[0] + \ - a->e[row][1] * b->e[1] + \ - a->e[row][2] * b->e[2] + \ - a->e[row][3] * b->e[3] + a.e[row][0] * b.e[0] + \ + a.e[row][1] * b.e[1] + \ + a.e[row][2] * b.e[2] + \ + a.e[row][3] * b.e[3] return tuple(dot(0), dot(1), dot(2), dot(3)); #undef dot @@ -133,20 +133,20 @@ inline static struct mat4x4 mat4x4_identity() 0.0f, 0.0f, 0.0f, 1.0f); } -inline static struct mat4x4 mat4x4_transpose(struct mat4x4 const * const a) +inline static struct mat4x4 mat4x4_transpose(struct mat4x4 a) { - return mat4x4(a->e[0][0], a->e[1][0], a->e[2][0], a->e[3][0], - a->e[0][1], a->e[1][1], a->e[2][1], a->e[3][1], - a->e[0][2], a->e[1][2], a->e[2][2], a->e[3][2], - a->e[0][3], a->e[1][3], a->e[2][3], a->e[3][3]); + return mat4x4(a.e[0][0], a.e[1][0], a.e[2][0], a.e[3][0], + a.e[0][1], a.e[1][1], a.e[2][1], a.e[3][1], + a.e[0][2], a.e[1][2], a.e[2][2], a.e[3][2], + a.e[0][3], a.e[1][3], a.e[2][3], a.e[3][3]); } -inline static float mat2x2_determinant(struct mat2x2 * a) +inline static float mat2x2_determinant(struct mat2x2 a) { - return a->e[0][0] * a->e[1][1] - a->e[0][1] * a->e[1][0]; + return a.e[0][0] * a.e[1][1] - a.e[0][1] * a.e[1][0]; } -inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c) +inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 a, int r, int c) { struct mat2x2 b; int row2 = 0; @@ -155,7 +155,7 @@ inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c) int col2 = 0; for (int col3 = 0; col3 < 3; col3++) { if (col3 == c) continue; - b.e[row2][col2] = a->e[row3][col3]; + b.e[row2][col2] = a.e[row3][col3]; col2++; } row2++; @@ -163,7 +163,7 @@ inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c) return b; } -inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int r, int c) +inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 a, int r, int c) { struct mat3x3 b; int row3 = 0; @@ -172,7 +172,7 @@ inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int int col3 = 0; for (int col4 = 0; col4 < 4; col4++) { if (col4 == c) continue; - b.e[row3][col3] = a->e[row4][col4]; + b.e[row3][col3] = a.e[row4][col4]; col3++; } row3++; @@ -180,14 +180,14 @@ inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int return b; } -inline static float mat3x3_minor(struct mat3x3 * a, int r, int c) +inline static float mat3x3_minor(struct mat3x3 a, int r, int c) { struct mat2x2 s = mat3x3_submatrix(a, r, c); - float ret = mat2x2_determinant(&s); + float ret = mat2x2_determinant(s); return ret; } -inline static float mat3x3_cofactor(struct mat3x3 * a, int r, int c) +inline static float mat3x3_cofactor(struct mat3x3 a, int r, int c) { float minor = mat3x3_minor(a, r, c); if ((r + c) & 1) @@ -196,25 +196,25 @@ inline static float mat3x3_cofactor(struct mat3x3 * a, int r, int c) return minor; } -inline static float mat3x3_determinant(struct mat3x3 * a) +inline static float mat3x3_determinant(struct mat3x3 a) { float f0 = mat3x3_cofactor(a, 0, 0); float f1 = mat3x3_cofactor(a, 0, 1); float f2 = mat3x3_cofactor(a, 0, 2); return - a->e[0][0] * f0 + - a->e[0][1] * f1 + - a->e[0][2] * f2; + a.e[0][0] * f0 + + a.e[0][1] * f1 + + a.e[0][2] * f2; } -inline static float mat4x4_minor(struct mat4x4 const * const a, int r, int c) +inline static float mat4x4_minor(struct mat4x4 a, int r, int c) { struct mat3x3 s = mat4x4_submatrix(a, r, c); - float ret = mat3x3_determinant(&s); + float ret = mat3x3_determinant(s); return ret; } -inline static float mat4x4_cofactor(struct mat4x4 const * const a, int r, int c) +inline static float mat4x4_cofactor(struct mat4x4 a, int r, int c) { float minor = mat4x4_minor(a, r, c); if ((r + c) & 1) @@ -223,25 +223,25 @@ inline static float mat4x4_cofactor(struct mat4x4 const * const a, int r, int c) return minor; } -inline static float mat4x4_determinant(struct mat4x4 const * const a) +inline static float mat4x4_determinant(struct mat4x4 a) { float f0 = mat4x4_cofactor(a, 0, 0); float f1 = mat4x4_cofactor(a, 0, 1); float f2 = mat4x4_cofactor(a, 0, 2); float f3 = mat4x4_cofactor(a, 0, 3); return - a->e[0][0] * f0 + - a->e[0][1] * f1 + - a->e[0][2] * f2 + - a->e[0][3] * f3; + a.e[0][0] * f0 + + a.e[0][1] * f1 + + a.e[0][2] * f2 + + a.e[0][3] * f3; } -inline static bool mat4x4_is_invertible(struct mat4x4 const * const a) +inline static bool mat4x4_is_invertible(struct mat4x4 a) { return !float_equal(mat4x4_determinant(a), 0.f); } -inline static struct mat4x4 mat4x4_inverse(struct mat4x4 const * const a) +inline static struct mat4x4 mat4x4_inverse(struct mat4x4 a) { struct mat4x4 m; float det = mat4x4_determinant(a); diff --git a/planes.h b/planes.h new file mode 100644 index 0000000..cfefecc --- /dev/null +++ b/planes.h @@ -0,0 +1,35 @@ +#pragma once + +#include "math.h" +#include "matrices.h" +#include "materials.h" +#include "shapes.h" +#include "rays.h" +#include "intersections.h" + +inline static struct shape plane() +{ + return (struct shape){ + mat4x4_identity(), + material(), + SHAPE_PLANE, + }; +} + +inline static struct tuple plane_normal_at(struct tuple local_point) +{ + return vector(0.0f, 1.0f, 0.0f); +} + +inline static void plane_intersect(struct shape const * const s, struct ray local_ray, struct intersections * intersections) +{ + if (fabsf(local_ray.direction.y) < epsilon) { + return; + } + + float t = -local_ray.origin.y / local_ray.direction.y; + + intersections->i[intersections->count++] = intersection(t, s); + + return; +} diff --git a/rays.h b/rays.h index 7d814f2..788bee7 100644 --- a/rays.h +++ b/rays.h @@ -1,6 +1,5 @@ #pragma once -#include "spheres.h" #include "tuples.h" #include "matrices.h" @@ -19,8 +18,8 @@ inline static struct tuple ray_position(struct ray ray, float t) return tuple_add(ray.origin, tuple_mul(ray.direction, t)); } -inline static struct ray ray_transform(struct ray r, struct mat4x4 const * const m) +inline static struct ray ray_transform(struct ray r, struct mat4x4 m) { - return ray(mat4x4_mul_t(m, &r.origin), - mat4x4_mul_t(m, &r.direction)); + return ray(mat4x4_mul_t(m, r.origin), + mat4x4_mul_t(m, r.direction)); } diff --git a/raytracer.c b/raytracer.c index faaab52..f830ced 100644 --- a/raytracer.c +++ b/raytracer.c @@ -22,59 +22,60 @@ int main() float pixel_size = wall_size / (float)canvas_pixels; float half = wall_size / 2.0f; - struct sphere floor = sphere(); - floor.transform = scaling(10.0f, 0.01f, 10.0f); + struct shape floor = plane(); floor.material.color = color(1.0f, 0.9f, 0.9f); floor.material.specular = 0.0f; - struct sphere left_wall = sphere(); + /* + struct shape left_wall = sphere(); { struct mat4x4 _translation = translation(0.0f, 0.0f, 5.0f); struct mat4x4 _rotation_y = rotation_y(-pi / 4.0f); struct mat4x4 _rotation_x = rotation_x(pi / 2.0f); struct mat4x4 _scaling = scaling(10.0f, 0.05f, 10.0f); - struct mat4x4 t0 = mat4x4_mul_m(&_rotation_x, &_scaling); - struct mat4x4 t1 = mat4x4_mul_m(&_rotation_y, &t0); - struct mat4x4 t2 = mat4x4_mul_m(&_translation, &t1); + struct mat4x4 t0 = mat4x4_mul_m(_rotation_x, _scaling); + struct mat4x4 t1 = mat4x4_mul_m(_rotation_y, t0); + struct mat4x4 t2 = mat4x4_mul_m(_translation, t1); left_wall.transform = t2; } left_wall.material = floor.material; - struct sphere right_wall = sphere(); + struct shape right_wall = sphere(); { struct mat4x4 _translation = translation(0.0f, 0.0f, 5.0f); struct mat4x4 _rotation_y = rotation_y(pi / 4.0f); struct mat4x4 _rotation_x = rotation_x(pi / 2.0f); struct mat4x4 _scaling = scaling(10.0f, 0.05f, 10.0f); - struct mat4x4 t0 = mat4x4_mul_m(&_rotation_x, &_scaling); - struct mat4x4 t1 = mat4x4_mul_m(&_rotation_y, &t0); - struct mat4x4 t2 = mat4x4_mul_m(&_translation, &t1); + struct mat4x4 t0 = mat4x4_mul_m(_rotation_x, _scaling); + struct mat4x4 t1 = mat4x4_mul_m(_rotation_y, t0); + struct mat4x4 t2 = mat4x4_mul_m(_translation, t1); right_wall.transform = t2; } right_wall.material = floor.material; + */ - struct sphere middle = sphere(); + struct shape middle = sphere(); middle.transform = translation(-0.5f, 1.0f, 0.5f); middle.material.color = color((float)0xfc / 255.f , (float)0x6d / 255.f, (float)0x09 / 255.f); middle.material.diffuse = 0.7; middle.material.specular = 0.3; - struct sphere right = sphere(); + struct shape right = sphere(); struct mat4x4 right_t = translation(1.5f, 0.5f, -0.5f); struct mat4x4 right_s = scaling(0.5f, 0.5f, 0.5f); - right.transform = mat4x4_mul_m(&right_t, &right_s); + right.transform = mat4x4_mul_m(right_t, right_s); right.material.color = color(0.5f, 1.0f, 0.1f); right.material.diffuse = 0.7; right.material.specular = 0.3; - struct sphere left = sphere(); + struct shape left = sphere(); struct mat4x4 left_t = translation(-1.5f, 0.33f, -0.75f); struct mat4x4 left_s = scaling(0.33f, 0.33f, 0.33f); - left.transform = mat4x4_mul_m(&left_t, &left_s); + left.transform = mat4x4_mul_m(left_t, left_s); left.material.color = color((float)0x12 / 255.f, (float)0xc9 / 255.f, (float)0xcc / 255.f); left.material.diffuse = 0.7; left.material.specular = 0.3; @@ -83,42 +84,104 @@ int main() struct tuple light_color = color(1.0f, 1.0f, 1.0f); struct light light = point_light(light_position, light_color); + + struct shape h1 = plane(); + struct shape h2 = plane(); + struct shape h3 = plane(); + struct shape h4 = plane(); + struct shape h5 = plane(); + struct shape h6 = plane(); + struct mat4x4 h1_t = translation(0, 8, 8); + struct mat4x4 h2_t = translation(4, 0, 6.9282); + struct mat4x4 h3_t = translation(-4, 0, 6.9282); + struct mat4x4 h4_t = translation(0, -8, 8); + struct mat4x4 h5_t = translation(-4, 0, -6.9282); + struct mat4x4 h6_t = translation(4, 0, -6.9282); + struct mat4x4 h1_r = rotation_x(tau / 4.0f); + struct mat4x4 h2_r = rotation_x(tau / 4.0f); + struct mat4x4 h3_r = rotation_x(tau / 4.0f); + struct mat4x4 h4_r = rotation_x(tau / 4.0f); + struct mat4x4 h5_r = rotation_x(tau / 4.0f); + struct mat4x4 h6_r = rotation_x(tau / 4.0f); + + struct mat4x4 h1_rr = rotation_y(tau / 4.0f * 0); + h1.transform = mat4x4_mul_m(h1_t, h1_r); + h1.transform = mat4x4_mul_m(h1_rr, h1.transform); + + struct mat4x4 h2_rr = rotation_y(tau / 4.0f * 1); + h2.transform = mat4x4_mul_m(h2_t, h2_r); + h2.transform = mat4x4_mul_m(h2_rr, h2.transform); + + struct mat4x4 h3_rr = rotation_y(tau / 4.0f * 2); + h3.transform = mat4x4_mul_m(h3_t, h3_r); + h3.transform = mat4x4_mul_m(h3_rr, h3.transform); + + struct mat4x4 h4_rr = rotation_y(tau / 4.0f * 3); + h4.transform = mat4x4_mul_m(h4_t, h4_r); + h4.transform = mat4x4_mul_m(h4_rr, h4.transform); + + struct mat4x4 h5_rr = rotation_y(tau / 4.0f); + h5.transform = mat4x4_mul_m(h5_rr, h5_r); + h5.transform = mat4x4_mul_m(h5_t, h5.transform); + + struct mat4x4 h6_rr = rotation_y(tau / 4.0f); + h6.transform = mat4x4_mul_m(h6_rr, h6_r); + h6.transform = mat4x4_mul_m(h6_t, h6.transform); + + h1.material = floor.material; + h1.material.color = color(1.0f, 0.0f, 0.0f); + h2.material = floor.material; + h2.material.color = color(0.0f, 1.0f, 0.0f); + h3.material = floor.material; + h3.material.color = color(0.0f, 0.0f, 1.0f); + h4.material = floor.material; + h4.material.color = color(1.0f, 1.0f, 0.0f); + h5.material = floor.material; + h5.material.color = color(0.0f, 1.0f, 1.0f); + h6.material = floor.material; + h6.material.color = color(1.0f, 0.0f, 1.0f); + struct world world; world.light = light; - world.object_count = 6; + world.object_count = 4 + 4; world.objects[0] = floor; - world.objects[1] = left_wall; - world.objects[2] = right_wall; - world.objects[3] = middle; - world.objects[4] = right; - world.objects[5] = left; + world.objects[1] = middle; + world.objects[2] = right; + world.objects[3] = left; - struct camera _camera = camera(1600.0f, 800.0f, pi / 3.0f); + world.objects[4] = h1; + world.objects[5] = h2; + world.objects[6] = h3; + world.objects[7] = h4; + world.objects[8] = h5; + world.objects[9] = h6; + + struct camera _camera = camera(1600.0f, 800.0f, pi / 4.f); _camera.transform = view_transform(point(0.0f, 1.5f, -5.0f), point(0.0f, 1.0f, 0.0f), vector(0.0f, 1.0f, 0.0f)); - struct mat4x4 middle_t = world.objects[3].transform; + struct mat4x4 middle_t = world.objects[1].transform; for (int i = 0; i < 360; i++) { - _camera.transform = view_transform(point(5.0f * cosf(pi / 360 * (float)i / 10), - 1.5f, - -5.0f * sinf(pi / 360 * (float)i / 10)), + _camera.transform = view_transform(point(2.0f * cosf(pi / 360 * (float)i * 0.5), + 8.5f, + 1.0f * sinf(pi / 360 * (float)i * 0.5)), point(0.0f, 1.0f, 0.0f), vector(0.0f, 1.0f, 0.0f)); - struct tuple light_position = point(-10.0f * cosf(pi / 360 * (float)i), + struct tuple light_position = point(-6.0f * cosf(pi / 360 * (float)i * 3), 10.0f, - -10.0f * sinf(pi / 360 * (float)i)); + -6.0f * sinf(pi / 360 * (float)i * 3)); world.light.position = light_position; struct mat4x4 middle_s = scaling(1.0f, 0.4f, 1.0f); struct mat4x4 middle_rz = rotation_z(tau / 360.f * (float)i); struct mat4x4 middle_ry = rotation_y(tau / 360.f * (float)i); - struct mat4x4 middle_r = mat4x4_mul_m(&middle_rz, &middle_ry); - struct mat4x4 middle_transform = mat4x4_mul_m(&middle_r, &middle_s); - world.objects[3].transform = mat4x4_mul_m(&middle_t, &middle_transform); + struct mat4x4 middle_r = mat4x4_mul_m(middle_rz, middle_ry); + struct mat4x4 middle_transform = mat4x4_mul_m(middle_r, middle_s); + world.objects[1].transform = mat4x4_mul_m(middle_t, middle_transform); camera_render(&_camera, &world, &_canvas); diff --git a/shapes.h b/shapes.h new file mode 100644 index 0000000..61a95d3 --- /dev/null +++ b/shapes.h @@ -0,0 +1,25 @@ +#pragma once + +#include "matrices.h" +#include "materials.h" + +enum shape_type { + SHAPE_TEST, + SHAPE_SPHERE, + SHAPE_PLANE, +}; + +struct shape { + struct mat4x4 transform; + struct material material; + enum shape_type type; +}; + +inline static struct shape shape() +{ + return (struct shape){ + mat4x4_identity(), + material(), + SHAPE_TEST, + }; +} diff --git a/spheres.h b/spheres.h index d912c29..4428c3d 100644 --- a/spheres.h +++ b/spheres.h @@ -2,27 +2,43 @@ #include "matrices.h" #include "materials.h" +#include "shapes.h" +#include "rays.h" +#include "intersections.h" -struct sphere { - struct mat4x4 transform; - struct material material; -}; - -inline static struct sphere sphere() +inline static struct shape sphere() { - return (struct sphere){ + return (struct shape){ mat4x4_identity(), - material() + material(), + SHAPE_SPHERE, }; } -inline static struct tuple sphere_normal_at(struct sphere const * const s, struct tuple world_point) +inline static struct tuple sphere_normal_at(struct tuple local_point) { - struct mat4x4 inv = mat4x4_inverse(&s->transform); - struct tuple object_point = mat4x4_mul_t(&inv, &world_point); - struct tuple object_normal = tuple_sub(object_point, point(0.0f, 0.0f, 0.0f)); - struct mat4x4 inv_t = mat4x4_transpose(&inv); - struct tuple world_normal = mat4x4_mul_t(&inv_t, &object_normal); - world_normal.w = 0.0f; - return tuple_normalize(world_normal); + return tuple_sub(local_point, point(0.0f, 0.0f, 0.0f)); +} + +inline static void sphere_intersect(struct shape const * const s, struct ray local_ray, struct intersections * intersections) +{ + struct tuple sphere_to_ray = tuple_sub(local_ray.origin, point(0.0f, 0.0f, 0.0f)); + + float a = tuple_dot(local_ray.direction, local_ray.direction); + float b = 2 * tuple_dot(local_ray.direction, sphere_to_ray); + float c = tuple_dot(sphere_to_ray, sphere_to_ray) - 1; + + float discriminant = b * b - 4 * a * c; + + if (discriminant < 0) { + return; + } else { + float root = sqrtf(discriminant); + float t1 = (-b - root) / (2 * a); + float t2 = (-b + root) / (2 * a); + + intersections->i[intersections->count++] = intersection(t1, s); + intersections->i[intersections->count++] = intersection(t2, s); + return; + } } diff --git a/test/run.sh b/test/run.sh index ce50151..54db03e 100644 --- a/test/run.sh +++ b/test/run.sh @@ -2,10 +2,13 @@ set -eux -for name in tuples canvas matrices transformations rays intersections spheres lights materials world camera; do + +for name in tuples canvas matrices transformations rays intersections shapes spheres planes lights materials world camera; do gcc -g -gdwarf-5 \ -Wall -Werror -Wfatal-errors \ + -Wno-error=unused-variable \ -I. \ + -DTEST \ test/test_${name}.c -o test/test_${name} -O0 -lm ./test/test_${name} done diff --git a/test/test_camera.c b/test/test_camera.c index 9820d9c..af7f402 100644 --- a/test/test_camera.c +++ b/test/test_camera.c @@ -21,7 +21,7 @@ static bool camera_test_0(const char ** scenario) float_equal(c.hsize, 160.0f) && float_equal(c.vsize, 120.0f) && float_equal(c.field_of_view, pi / 2.0f) && - mat4x4_equal(&c.transform, &identity_matrix); + mat4x4_equal(c.transform, identity_matrix); } static bool camera_test_1(const char ** scenario) @@ -73,7 +73,7 @@ static bool camera_test_5(const char ** scenario) struct camera c = camera(201.0f, 101.0f, pi / 2.0f); struct mat4x4 rotate = rotation_y(pi / 4.0f); struct mat4x4 translate = translation(0.0f, -2.0f, 5.0f); - c.transform = mat4x4_mul_m(&rotate, &translate); + c.transform = mat4x4_mul_m(rotate, translate); struct ray r = camera_ray_for_pixel(&c, 100.0f, 50.0f); return diff --git a/test/test_intersections.c b/test/test_intersections.c index 98025dd..a42ff2a 100644 --- a/test/test_intersections.c +++ b/test/test_intersections.c @@ -1,7 +1,7 @@ #include #include -#include "intersections.h" +#include "intersections_shapes.h" #include "transformations.h" #include "runner.h" @@ -9,7 +9,7 @@ static bool intersections_test_0(const char ** scenario) { *scenario = "An intersection encapsulates t and object"; - struct sphere s = sphere(); + struct shape s = sphere(); struct intersection i = intersection(3.5f, &s); return @@ -21,7 +21,7 @@ static bool intersections_test_1(const char ** scenario) { *scenario = "Aggregating intersections"; - struct sphere s = sphere(); + struct shape s = sphere(); struct intersection i1 = intersection(1.0f, &s); struct intersection i2 = intersection(2.0f, &s); struct intersections xs; @@ -37,7 +37,7 @@ static bool intersections_test_2(const char ** scenario) { *scenario = "The hit, when all intersections have positive t"; - struct sphere s = sphere(); + struct shape s = sphere(); struct intersection i1 = intersection(1.0f, &s); struct intersection i2 = intersection(2.0f, &s); struct intersections xs; @@ -55,7 +55,7 @@ static bool intersections_test_3(const char ** scenario) { *scenario = "The hit, when some intersections have negative t"; - struct sphere s = sphere(); + struct shape s = sphere(); struct intersection i1 = intersection(-1.0f, &s); struct intersection i2 = intersection( 1.0f, &s); struct intersections xs; @@ -73,7 +73,7 @@ static bool intersections_test_4(const char ** scenario) { *scenario = "The hit, when all intersections have negative t"; - struct sphere s = sphere(); + struct shape s = sphere(); struct intersection i1 = intersection(-2.0f, &s); struct intersection i2 = intersection(-1.0f, &s); struct intersections xs; @@ -88,7 +88,7 @@ static bool intersections_test_5(const char ** scenario) { *scenario = "The hit is always the lowest nonnegative intersection"; - struct sphere s = sphere(); + struct shape s = sphere(); struct intersection i1 = intersection( 5.0f, &s); struct intersection i2 = intersection( 7.0f, &s); struct intersection i3 = intersection(-3.0f, &s); @@ -108,13 +108,13 @@ static bool intersections_test_6(const char ** scenario) { *scenario = "In-place ascending sort of intersections"; - struct sphere s1 = sphere(); + struct shape s1 = sphere(); s1.material.ambient = 1.0f; - struct sphere s2 = sphere(); + struct shape s2 = sphere(); s2.material.ambient = 2.0f; - struct sphere s3 = sphere(); + struct shape s3 = sphere(); s3.material.ambient = 3.0f; - struct sphere s4 = sphere(); + struct shape s4 = sphere(); s4.material.ambient = 4.0f; struct intersection i1 = intersection( 5.0f, &s1); struct intersection i2 = intersection( 7.0f, &s2); @@ -141,7 +141,7 @@ static bool intersections_test_7(const char ** scenario) *scenario = "Precomputing the state of an intersection"; struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere shape = sphere(); + struct shape shape = sphere(); struct intersection i = intersection(4.0f, &shape); struct computations comps = prepare_computations(i, r); @@ -158,7 +158,7 @@ static bool intersections_test_8(const char ** scenario) *scenario = "The hit, when an intersection occurs on the outside"; struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere shape = sphere(); + struct shape shape = sphere(); struct intersection i = intersection(4.0f, &shape); struct computations comps = prepare_computations(i, r); @@ -171,7 +171,7 @@ static bool intersections_test_9(const char ** scenario) *scenario = "The hit, when an intersection occurs on the inside"; struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere shape = sphere(); + struct shape shape = sphere(); struct intersection i = intersection(1.0f, &shape); struct computations comps = prepare_computations(i, r); @@ -187,7 +187,7 @@ static bool intersections_test_10(const char ** scenario) *scenario = "The hit should offset the point"; struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere shape = sphere(); + struct shape shape = sphere(); shape.transform = translation(0.0f, 0.0f, 1.0f); struct intersection i = intersection(5.0f, &shape); struct computations comps = prepare_computations(i, r); diff --git a/test/test_matrices.c b/test/test_matrices.c index 7071abf..fdc31c0 100644 --- a/test/test_matrices.c +++ b/test/test_matrices.c @@ -58,7 +58,7 @@ static bool matrices_test_3(const char ** scenario) 9.0f, 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f); - return mat4x4_equal(&a, &b); + return mat4x4_equal(a, b); } static bool matrices_test_4(const char ** scenario) @@ -75,7 +75,7 @@ static bool matrices_test_4(const char ** scenario) 8.0f, 7.0f, 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 1.0f); - return !mat4x4_equal(&a, &b); + return !mat4x4_equal(a, b); } static bool matrices_test_5(const char ** scenario) @@ -92,12 +92,12 @@ static bool matrices_test_5(const char ** scenario) 4.0f, 3.0f, 6.0f, 5.0f, 1.0f, 2.0f, 7.0f, 8.0f); - struct mat4x4 m1 = mat4x4_mul_m(&a, &b); + struct mat4x4 m1 = mat4x4_mul_m(a, b); struct mat4x4 m2 = mat4x4(20.0f, 22.0f, 50.0f, 48.0f, 44.0f, 54.0f, 114.0f, 108.0f, 40.0f, 58.0f, 110.0f, 102.0f, 16.0f, 26.0f, 46.0f, 42.0f); - return mat4x4_equal(&m1, &m2); + return mat4x4_equal(m1, m2); } static bool matrices_test_6(const char ** scenario) @@ -110,7 +110,7 @@ static bool matrices_test_6(const char ** scenario) 0.0f, 0.0f, 0.0f, 1.0f); struct tuple b = tuple(1.0f, 2.0f, 3.0f, 1.0f); - struct tuple c = mat4x4_mul_t(&a, &b); + struct tuple c = mat4x4_mul_t(a, b); return tuple_equal(c, tuple(18, 24, 33, 1)); } @@ -124,8 +124,8 @@ static bool matrices_test_7(const char ** scenario) 4.0f, 8.0f, 16.0f, 32.0f); struct mat4x4 id = mat4x4_identity(); - struct mat4x4 c = mat4x4_mul_m(&a, &id); - return mat4x4_equal(&a, &c); + struct mat4x4 c = mat4x4_mul_m(a, id); + return mat4x4_equal(a, c); } static bool matrices_test_8(const char ** scenario) @@ -135,7 +135,7 @@ static bool matrices_test_8(const char ** scenario) struct tuple a = tuple(1.0f, 2.0f, 3.0f, 4.0f); struct mat4x4 id = mat4x4_identity(); - struct tuple c = mat4x4_mul_t(&id, &a); + struct tuple c = mat4x4_mul_t(id, a); return tuple_equal(a, c); } @@ -153,9 +153,9 @@ static bool matrices_test_9(const char ** scenario) 3.0f, 0.0f, 5.0f, 5.0f, 0.0f, 8.0f, 3.0f, 8.0f); - struct mat4x4 c = mat4x4_transpose(&a); + struct mat4x4 c = mat4x4_transpose(a); - return mat4x4_equal(&c, &b); + return mat4x4_equal(c, b); } static bool matrices_test_10(const char ** scenario) @@ -164,9 +164,9 @@ static bool matrices_test_10(const char ** scenario) struct mat4x4 a = mat4x4_identity(); - struct mat4x4 c = mat4x4_transpose(&a); + struct mat4x4 c = mat4x4_transpose(a); - return mat4x4_equal(&a, &c); + return mat4x4_equal(a, c); } static bool matrices_test_11(const char ** scenario) @@ -176,7 +176,7 @@ static bool matrices_test_11(const char ** scenario) struct mat2x2 a = mat2x2( 1.0f, 5.0f, -3.0f, 2.0f); - return float_equal(mat2x2_determinant(&a), 17); + return float_equal(mat2x2_determinant(a), 17); } static bool matrices_test_12(const char ** scenario) @@ -187,11 +187,11 @@ static bool matrices_test_12(const char ** scenario) -3.0f, 2.0f, 7.0f, 0.0f, 6.0f, -3.0f); - struct mat2x2 b = mat3x3_submatrix(&a, 0, 2); + struct mat2x2 b = mat3x3_submatrix(a, 0, 2); struct mat2x2 c = mat2x2(-3.0f, 2.0f, 0.0f, 6.0f); - return mat2x2_equal(&b, &c); + return mat2x2_equal(b, c); } static bool matrices_test_13(const char ** scenario) @@ -203,12 +203,12 @@ static bool matrices_test_13(const char ** scenario) -1.0f, 0.0f, 8.0f, 2.0f, -7.0f, 1.0f, -1.0f, 1.0f); - struct mat3x3 b = mat4x4_submatrix(&a, 2, 1); + struct mat3x3 b = mat4x4_submatrix(a, 2, 1); struct mat3x3 c = mat3x3(-6.0f, 1.0f, 6.0f, -8.0f, 8.0f, 6.0f, -7.0f, -1.0f, 1.0f); - return mat3x3_equal(&b, &c); + return mat3x3_equal(b, c); } static bool matrices_test_14(const char ** scenario) @@ -218,11 +218,11 @@ static bool matrices_test_14(const char ** scenario) struct mat3x3 a = mat3x3(3, 5, 0, 2, -1, -7, 6, -1, 5); - struct mat2x2 b = mat3x3_submatrix(&a, 1, 0); + struct mat2x2 b = mat3x3_submatrix(a, 1, 0); return - float_equal(mat2x2_determinant(&b), 25.0f) && - float_equal(mat3x3_minor(&a, 1, 0), 25.0f); + float_equal(mat2x2_determinant(b), 25.0f) && + float_equal(mat3x3_minor(a, 1, 0), 25.0f); } static bool matrices_test_15(const char ** scenario) @@ -234,11 +234,11 @@ static bool matrices_test_15(const char ** scenario) 6, -1, 5); return - float_equal(mat3x3_minor(&a, 0, 0), -12.0f) && - float_equal(mat3x3_cofactor(&a, 0, 0), -12.0f) && - float_equal(mat3x3_minor(&a, 1, 0), 25.0f) && - float_equal(mat3x3_cofactor(&a, 1, 0), -25.0f) && - float_equal(mat3x3_cofactor(&a, 2, 1), 21.0f); + float_equal(mat3x3_minor(a, 0, 0), -12.0f) && + float_equal(mat3x3_cofactor(a, 0, 0), -12.0f) && + float_equal(mat3x3_minor(a, 1, 0), 25.0f) && + float_equal(mat3x3_cofactor(a, 1, 0), -25.0f) && + float_equal(mat3x3_cofactor(a, 2, 1), 21.0f); } @@ -251,10 +251,10 @@ static bool matrices_test_16(const char ** scenario) 2.0f, 6.0f, 4.0f); return - float_equal(mat3x3_cofactor(&a, 0, 0), 56.0f) && - float_equal(mat3x3_cofactor(&a, 0, 1), 12.0f) && - float_equal(mat3x3_cofactor(&a, 0, 2), -46.0f) && - float_equal(mat3x3_determinant(&a), -196.0f); + float_equal(mat3x3_cofactor(a, 0, 0), 56.0f) && + float_equal(mat3x3_cofactor(a, 0, 1), 12.0f) && + float_equal(mat3x3_cofactor(a, 0, 2), -46.0f) && + float_equal(mat3x3_determinant(a), -196.0f); } static bool matrices_test_17(const char ** scenario) @@ -267,11 +267,11 @@ static bool matrices_test_17(const char ** scenario) -6.0f, 7.0f, 7.0f, -9.0f); return - float_equal(mat4x4_cofactor(&a, 0, 0), 690.0f) && - float_equal(mat4x4_cofactor(&a, 0, 1), 447.0f) && - float_equal(mat4x4_cofactor(&a, 0, 2), 210.0f) && - float_equal(mat4x4_cofactor(&a, 0, 3), 51.0f) && - float_equal(mat4x4_determinant(&a), -4071.0f); + float_equal(mat4x4_cofactor(a, 0, 0), 690.0f) && + float_equal(mat4x4_cofactor(a, 0, 1), 447.0f) && + float_equal(mat4x4_cofactor(a, 0, 2), 210.0f) && + float_equal(mat4x4_cofactor(a, 0, 3), 51.0f) && + float_equal(mat4x4_determinant(a), -4071.0f); } static bool matrices_test_18(const char ** scenario) @@ -284,8 +284,8 @@ static bool matrices_test_18(const char ** scenario) 9.0f, 1.0f, 7.0f, -6.0f); return - float_equal(mat4x4_determinant(&a), -2120.0f) && - mat4x4_is_invertible(&a); + float_equal(mat4x4_determinant(a), -2120.0f) && + mat4x4_is_invertible(a); } static bool matrices_test_19(const char ** scenario) @@ -298,8 +298,8 @@ static bool matrices_test_19(const char ** scenario) 0.0f, 0.0f, 0.0f, 0.0f); return - float_equal(mat4x4_determinant(&a), 0.0f) && - !mat4x4_is_invertible(&a); + float_equal(mat4x4_determinant(a), 0.0f) && + !mat4x4_is_invertible(a); } static bool matrices_test_20(const char ** scenario) @@ -310,7 +310,7 @@ static bool matrices_test_20(const char ** scenario) 1.0, -5.0, 1.0, 8.0, 7.0, 7.0, -6.0, -7.0, 1.0, -3.0, 7.0, 4.0); - struct mat4x4 b = mat4x4_inverse(&a); + struct mat4x4 b = mat4x4_inverse(a); struct mat4x4 c = mat4x4( 0.218045f, 0.451128f, 0.240602f, -0.045113f, -0.808271f, -1.456767f, -0.443609f, 0.520677f, @@ -318,12 +318,12 @@ static bool matrices_test_20(const char ** scenario) -0.522564f, -0.813910f, -0.300752f, 0.306391f); return - float_equal(mat4x4_determinant(&a), 532.0f) && - float_equal(mat4x4_cofactor(&a, 2, 3), -160.0f) && + float_equal(mat4x4_determinant(a), 532.0f) && + float_equal(mat4x4_cofactor(a, 2, 3), -160.0f) && float_equal(b.e[3][2], -160.0f/532.0f) && - float_equal(mat4x4_cofactor(&a, 3, 2), 105.0f) && + float_equal(mat4x4_cofactor(a, 3, 2), 105.0f) && float_equal(b.e[2][3], 105.0f/532.0f) && - mat4x4_equal(&b, &c); + mat4x4_equal(b, c); } static bool matrices_test_21(const char ** scenario) @@ -335,14 +335,14 @@ static bool matrices_test_21(const char ** scenario) -6.0f, 0.0f, 9.0f, 6.0f, -3.0f, 0.0f, -9.0f, -4.0f); - struct mat4x4 b = mat4x4_inverse(&a); + struct mat4x4 b = mat4x4_inverse(a); struct mat4x4 c = mat4x4(-0.15385f, -0.15385f, -0.28205f, -0.53846f, -0.07692f, 0.12308f, 0.02564f, 0.03077f, 0.35897f, 0.35897f, 0.43590f, 0.92308f, -0.69231f, -0.69231f, -0.76923f, -1.92308f); - return mat4x4_equal(&b, &c); + return mat4x4_equal(b, c); } static bool matrices_test_22(const char ** scenario) @@ -354,14 +354,14 @@ static bool matrices_test_22(const char ** scenario) -4.0f, 9.0f, 6.0f, 4.0f, -7.0f, 6.0f, 6.0f, 2.0f); - struct mat4x4 b = mat4x4_inverse(&a); + struct mat4x4 b = mat4x4_inverse(a); struct mat4x4 c = mat4x4(-0.04074f, -0.07778f, 0.14444f, -0.22222f, -0.07778f, 0.03333f, 0.36667f, -0.33333f, -0.02901f, -0.14630f, -0.10926f, 0.12963f, 0.17778f, 0.06667f, -0.26667f, 0.33333f); - return mat4x4_equal(&b, &c); + return mat4x4_equal(b, c); } static bool matrices_test_23(const char ** scenario) @@ -378,12 +378,12 @@ static bool matrices_test_23(const char ** scenario) 7.0f, 0.0f, 5.0f, 4.0f, 6.0f, -2.0f, 0.0f, 5.0f); - struct mat4x4 c = mat4x4_mul_m(&a, &b); + struct mat4x4 c = mat4x4_mul_m(a, b); - struct mat4x4 b_i = mat4x4_inverse(&b); - struct mat4x4 d = mat4x4_mul_m(&c, &b_i); + struct mat4x4 b_i = mat4x4_inverse(b); + struct mat4x4 d = mat4x4_mul_m(c, b_i); - return mat4x4_equal(&d, &a); + return mat4x4_equal(d, a); } test_t matrices_tests[] = { diff --git a/test/test_planes.c b/test/test_planes.c new file mode 100644 index 0000000..a6e5863 --- /dev/null +++ b/test/test_planes.c @@ -0,0 +1,86 @@ +#include +#include + +#include "rays.h" +#include "planes.h" +#include "intersections_shapes.h" +#include "runner.h" +#include "matrices.h" +#include "transformations.h" + +static bool planes_test_0(const char ** scenario) +{ + *scenario = "The normal of a plane is constant everywhere"; + + struct tuple n1 = plane_normal_at(point(0.0f, 0.0f, 0.0f)); + struct tuple n2 = plane_normal_at(point(10.0f, 0.0f, -10.0f)); + struct tuple n3 = plane_normal_at(point(-5.0f, 0.0f, 150.0f)); + return + tuple_equal(n1, vector(0.0f, 1.0f, 0.0f)) && + tuple_equal(n2, vector(0.0f, 1.0f, 0.0f)) && + tuple_equal(n3, vector(0.0f, 1.0f, 0.0f)); +} + +static bool planes_test_1(const char ** scenario) +{ + *scenario = "Intersect with a ray parallel to the plane"; + + struct shape p = plane(); + struct ray r = ray(point(0.0f, 10.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); + struct intersections xs; + xs.count = 0; + plane_intersect(&p, r, &xs); + return xs.count == 0; +} + +static bool planes_test_2(const char ** scenario) +{ + *scenario = "Intersect with a coplanar ray"; + + struct shape p = plane(); + struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); + struct intersections xs; + xs.count = 0; + plane_intersect(&p, r, &xs); + return xs.count == 0; +} + +static bool planes_test_3(const char ** scenario) +{ + *scenario = "A ray intersecting a plane from above"; + + struct shape p = plane(); + struct ray r = ray(point(0.0f, 1.0f, 0.0f), vector(0.0f, -1.0f, 0.0f)); + struct intersections xs; + xs.count = 0; + plane_intersect(&p, r, &xs); + return + xs.count == 1 && + float_equal(xs.i[0].t, 1.0f) && + xs.i[0].object == &p; +} + +static bool planes_test_4(const char ** scenario) +{ + *scenario = "A ray intersecting a plane from below"; + + struct shape p = plane(); + struct ray r = ray(point(0.0f, -1.0f, 0.0f), vector(0.0f, 1.0f, 1.0f)); + struct intersections xs; + xs.count = 0; + plane_intersect(&p, r, &xs); + return + xs.count == 1 && + float_equal(xs.i[0].t, 1.0f) && + xs.i[0].object == &p; +} + +test_t planes_tests[] = { + planes_test_0, + planes_test_1, + planes_test_2, + planes_test_3, + planes_test_4, +}; + +RUNNER(planes_tests); diff --git a/test/test_rays.c b/test/test_rays.c index d861a42..49740a5 100644 --- a/test/test_rays.c +++ b/test/test_rays.c @@ -38,7 +38,7 @@ static bool rays_test_2(const char ** scenario) struct ray r = ray(point(1.0f, 2.0f, 3.0f), vector(0.0f, 1.0f, 0.0f)); struct mat4x4 m = translation(3.0f, 4.0f, 5.0f); - struct ray r2 = ray_transform(r, &m); + struct ray r2 = ray_transform(r, m); return tuple_equal(r2.origin, point(4.0f, 6.0f, 8.0f)) && @@ -51,7 +51,7 @@ static bool rays_test_3(const char ** scenario) struct ray r = ray(point(1.0f, 2.0f, 3.0f), vector(0.0f, 1.0f, 0.0f)); struct mat4x4 m = scaling(2.0f, 3.0f, 4.0f); - struct ray r2 = ray_transform(r, &m); + struct ray r2 = ray_transform(r, m); return tuple_equal(r2.origin, point(2.0f, 6.0f, 12.0f)) && diff --git a/test/test_shapes.c b/test/test_shapes.c new file mode 100644 index 0000000..09a13b4 --- /dev/null +++ b/test/test_shapes.c @@ -0,0 +1,121 @@ +#include +#include + +#include "shapes.h" +#include "intersections_shapes.h" +#include "transformations.h" +#include "runner.h" +#include "rays.h" +#include "spheres.h" + +static bool shapes_test_0(const char ** scenario) +{ + *scenario = "A shape's default transformation"; + + struct shape s = shape(); + struct mat4x4 identity = mat4x4_identity(); + + return mat4x4_equal(s.transform, identity); +} + +static bool shapes_test_1(const char ** scenario) +{ + *scenario = "Changing a shape's transformation"; + + struct shape s = shape(); + struct mat4x4 t = translation(2.0f, 3.0f, 4.0f); + s.transform = t; + + return mat4x4_equal(s.transform, t); +} + +static bool shapes_test_2(const char ** scenario) +{ + *scenario = "A shape has a default material"; + + struct shape s = shape(); + struct material m = s.material; + return material_equal(m, material()); +} + +static bool shapes_test_3(const char ** scenario) +{ + *scenario = "A shape may be assigned a material"; + + struct shape s = shape(); + struct material m = material(); + m.ambient = 1.0f; + s.material = m; + return material_equal(s.material, m); +} + +static bool shapes_test_4(const char ** scenario) +{ + *scenario = "Intersecting a scaled shape with a ray"; + + struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); + struct shape s = shape(); + s.transform = scaling(2.0f, 2.0f, 2.0f); + struct intersections xs; + xs.count = 0; + intersect(&s, r, &xs); + + return + tuple_equal(intersections_saved_ray.origin, point(0.0f, 0.0f, -2.5f)) && + tuple_equal(intersections_saved_ray.direction, vector(0.0f, 0.0f, 0.5f)); +} + +static bool shapes_test_5(const char ** scenario) +{ + *scenario = "Intersecting a translated shape with a ray"; + + struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); + struct shape s = shape(); + s.transform = translation(5.0f, 0.0f, 0.0f); + struct intersections xs; + xs.count = 0; + intersect(&s, r, &xs); + + return + tuple_equal(intersections_saved_ray.origin, point(-5.0f, 0.0f, -5.0f)) && + tuple_equal(intersections_saved_ray.direction, vector(0.0f, 0.0f, 1.0f)); +} + +static bool shapes_test_6(const char ** scenario) +{ + *scenario = "Computing the normal on a translated shape"; + + struct shape s = shape(); + s.transform = translation(0.0f, 1.0f, 0.0f); + + struct tuple n = normal_at(&s, point(0.0f, 1.70711f, -0.70711)); + + return tuple_equal(n, vector(0.0f, 0.70711f, -0.70711f)); +} + +static bool shapes_test_7(const char ** scenario) +{ + *scenario = "Computing the normal on a transformed shape"; + struct shape s = shape(); + struct mat4x4 scale = scaling(1.0f, 0.5f, 1.0f); + struct mat4x4 rotate = rotation_z(pi / 5.0f); + struct mat4x4 m = mat4x4_mul_m(scale, rotate); + s.transform = m; + + struct tuple n = normal_at(&s, point(0.0f, 0.7071067811865476, -0.7071067811865476)); + + return tuple_equal(n, vector(0.0f, 0.97014f, -0.24254f)); +} + +test_t shape_tests[] = { + shapes_test_0, + shapes_test_1, + shapes_test_2, + shapes_test_3, + shapes_test_4, + shapes_test_5, + shapes_test_6, + shapes_test_7, +}; + +RUNNER(shape_tests) diff --git a/test/test_spheres.c b/test/test_spheres.c index 0a0afb5..2495806 100644 --- a/test/test_spheres.c +++ b/test/test_spheres.c @@ -3,7 +3,7 @@ #include "rays.h" #include "spheres.h" -#include "intersections.h" +#include "intersections_shapes.h" #include "runner.h" #include "matrices.h" #include "transformations.h" @@ -13,7 +13,7 @@ static bool spheres_test_0(const char ** scenario) *scenario = "A ray intersects a sphere at two points"; struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); struct intersections xs; xs.count = 0; intersect(&s, r, &xs); @@ -29,7 +29,7 @@ static bool spheres_test_1(const char ** scenario) *scenario = "A ray intersects a sphere at a tangent"; struct ray r = ray(point(0.0f, 1.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); struct intersections xs; xs.count = 0; intersect(&s, r, &xs); @@ -45,7 +45,7 @@ static bool spheres_test_2(const char ** scenario) *scenario = "A ray misses a sphere"; struct ray r = ray(point(0.0f, 2.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); struct intersections xs; xs.count = 0; intersect(&s, r, &xs); @@ -58,7 +58,7 @@ static bool spheres_test_3(const char ** scenario) *scenario = "A ray originates in a sphere"; struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); struct intersections xs; xs.count = 0; intersect(&s, r, &xs); @@ -74,7 +74,7 @@ static bool spheres_test_4(const char ** scenario) *scenario = "A sphere is behind a ray"; struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); struct intersections xs; xs.count = 0; intersect(&s, r, &xs); @@ -90,7 +90,7 @@ static bool spheres_test_5(const char ** scenario) *scenario = "Intersect sets the object on the intersection"; struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); struct intersections xs; xs.count = 0; intersect(&s, r, &xs); @@ -102,32 +102,11 @@ static bool spheres_test_5(const char ** scenario) } static bool spheres_test_6(const char ** scenario) -{ - *scenario = "A sphere's default transformation"; - - struct sphere s = sphere(); - struct mat4x4 identity = mat4x4_identity(); - - return mat4x4_equal(&s.transform, &identity); -} - -static bool spheres_test_7(const char ** scenario) -{ - *scenario = "Changing a sphere's transformation"; - - struct sphere s = sphere(); - struct mat4x4 t = translation(2.0f, 3.0f, 4.0f); - s.transform = t; - - return mat4x4_equal(&s.transform, &t); -} - -static bool spheres_test_8(const char ** scenario) { *scenario = "Intersecting a scaled sphere with a ray"; struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); s.transform = scaling(2.0f, 2.0f, 2.0f); struct intersections xs; xs.count = 0; @@ -139,12 +118,12 @@ static bool spheres_test_8(const char ** scenario) float_equal(xs.i[1].t, 7.0f); } -static bool spheres_test_9(const char ** scenario) +static bool spheres_test_7(const char ** scenario) { *scenario = "Intersecting a translated sphere with a ray"; struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere s = sphere(); + struct shape s = sphere(); s.transform = translation(5.0f, 0.0f, 0.0f); struct intersections xs; xs.count = 0; @@ -153,103 +132,83 @@ static bool spheres_test_9(const char ** scenario) return xs.count == 0; } -static bool spheres_test_10(const char ** scenario) +static bool spheres_test_8(const char ** scenario) { *scenario = "The normal on a sphere at a point on the x axis"; - struct sphere s = sphere(); - struct tuple n = sphere_normal_at(&s, point(1.0f, 0.0f, 0.0f)); + struct shape s = sphere(); + struct tuple n = normal_at(&s, point(1.0f, 0.0f, 0.0f)); return tuple_equal(n, vector(1.0f, 0.0f, 0.0f)); } +static bool spheres_test_9(const char ** scenario) +{ + *scenario = "The normal on a sphere at a point on the y axis"; + + struct shape s = sphere(); + struct tuple n = normal_at(&s, point(0.0f, 1.0f, 0.0f)); + return tuple_equal(n, vector(0.0f, 1.0f, 0.0f)); +} + +static bool spheres_test_10(const char ** scenario) +{ + *scenario = "The normal on a sphere at a point on the z axis"; + + struct shape s = sphere(); + struct tuple n = normal_at(&s, point(0.0f, 0.0f, 1.0f)); + return tuple_equal(n, vector(0.0f, 0.0f, 1.0f)); +} + static bool spheres_test_11(const char ** scenario) -{ - *scenario = "The normal on a sphere at a point on the y axis"; - - struct sphere s = sphere(); - struct tuple n = sphere_normal_at(&s, point(0.0f, 1.0f, 0.0f)); - return tuple_equal(n, vector(0.0f, 1.0f, 0.0f)); -} - -static bool spheres_test_12(const char ** scenario) -{ - *scenario = "The normal on a sphere at a point on the z axis"; - - struct sphere s = sphere(); - struct tuple n = sphere_normal_at(&s, point(0.0f, 0.0f, 1.0f)); - return tuple_equal(n, vector(0.0f, 0.0f, 1.0f)); -} - -static bool spheres_test_13(const char ** scenario) { *scenario = "The normal on a sphere at a nonaxial point"; - struct sphere s = sphere(); - struct tuple n = sphere_normal_at(&s, point(0.5773502691896257, - 0.5773502691896257, - 0.5773502691896257)); + struct shape s = sphere(); + struct tuple n = normal_at(&s, point(0.5773502691896257, + 0.5773502691896257, + 0.5773502691896257)); return tuple_equal(n, vector(0.5773502691896257, 0.5773502691896257, 0.5773502691896257)); } -static bool spheres_test_14(const char ** scenario) +static bool spheres_test_12(const char ** scenario) { *scenario = "The normal is a normalized vector"; - struct sphere s = sphere(); - struct tuple n = sphere_normal_at(&s, point(0.5773502691896257, - 0.5773502691896257, - 0.5773502691896257)); + struct shape s = sphere(); + struct tuple n = normal_at(&s, point(0.5773502691896257, + 0.5773502691896257, + 0.5773502691896257)); return tuple_equal(n, tuple_normalize(n)); } -static bool spheres_test_15(const char ** scenario) +static bool spheres_test_13(const char ** scenario) { *scenario = "Computing the normal on a translated sphere"; - struct sphere s = sphere(); + struct shape s = sphere(); s.transform = translation(0.0f, 1.0f, 0.0f); - struct tuple n = sphere_normal_at(&s, point(0.0f, 1.70711f, -0.70711)); + struct tuple n = normal_at(&s, point(0.0f, 1.70711f, -0.70711)); return tuple_equal(n, vector(0.0f, 0.70711f, -0.70711f)); } -static bool spheres_test_16(const char ** scenario) +static bool spheres_test_14(const char ** scenario) { *scenario = "Computing the normal on a transformed sphere"; - struct sphere s = sphere(); + struct shape s = sphere(); struct mat4x4 scale = scaling(1.0f, 0.5f, 1.0f); struct mat4x4 rotate = rotation_z(pi / 5.0f); - struct mat4x4 m = mat4x4_mul_m(&scale, &rotate); + struct mat4x4 m = mat4x4_mul_m(scale, rotate); s.transform = m; - struct tuple n = sphere_normal_at(&s, point(0.0f, 0.7071067811865476, -0.7071067811865476)); + struct tuple n = normal_at(&s, point(0.0f, 0.7071067811865476, -0.7071067811865476)); return tuple_equal(n, vector(0.0f, 0.97014f, -0.24254f)); } -static bool spheres_test_17(const char ** scenario) -{ - *scenario = "A sphere has a default material"; - - struct sphere s = sphere(); - struct material m = s.material; - return material_equal(m, material()); -} - -static bool spheres_test_18(const char ** scenario) -{ - *scenario = "A sphere may be assigned a material"; - - struct sphere s = sphere(); - struct material m = material(); - m.ambient = 1.0f; - s.material = m; - return material_equal(s.material, m); -} - test_t spheres_tests[] = { spheres_test_0, spheres_test_1, @@ -266,10 +225,6 @@ test_t spheres_tests[] = { spheres_test_12, spheres_test_13, spheres_test_14, - spheres_test_15, - spheres_test_16, - spheres_test_17, - spheres_test_18, }; RUNNER(spheres_tests); diff --git a/test/test_transformations.c b/test/test_transformations.c index e0442e0..b1aec7e 100644 --- a/test/test_transformations.c +++ b/test/test_transformations.c @@ -11,7 +11,7 @@ static bool transformations_test_0(const char ** scenario) struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct tuple p = point(-3.0f, 4.0f, 5.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 1.0f, 7.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 1.0f, 7.0f)); } static bool transformations_test_1(const char ** scenario) @@ -19,10 +19,10 @@ static bool transformations_test_1(const char ** scenario) *scenario = "Multiplying by the inverse of a translation matrix"; struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); - struct mat4x4 inv = mat4x4_inverse(&transform); + struct mat4x4 inv = mat4x4_inverse(transform); struct tuple p = point(-3.0f, 4.0f, 5.0f); - return tuple_equal(mat4x4_mul_t(&inv, &p), point(-8.0f, 7.0f, 3.0f)); + return tuple_equal(mat4x4_mul_t(inv, p), point(-8.0f, 7.0f, 3.0f)); } static bool transformations_test_2(const char ** scenario) @@ -32,7 +32,7 @@ static bool transformations_test_2(const char ** scenario) struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct tuple v = vector(-3.0f, 4.0f, 5.0f); - return tuple_equal(mat4x4_mul_t(&transform, &v), v); + return tuple_equal(mat4x4_mul_t(transform, v), v); } static bool transformations_test_3(const char ** scenario) @@ -42,7 +42,7 @@ static bool transformations_test_3(const char ** scenario) struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct tuple p = point(-4.0f, 6.0f, 8.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(-8.0f, 18.0f, 32.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(-8.0f, 18.0f, 32.0f)); } static bool transformations_test_4(const char ** scenario) @@ -52,7 +52,7 @@ static bool transformations_test_4(const char ** scenario) struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct tuple v = vector(-4.0f, 6.0f, 8.0f); - return tuple_equal(mat4x4_mul_t(&transform, &v), vector(-8.0f, 18.0f, 32.0f)); + return tuple_equal(mat4x4_mul_t(transform, v), vector(-8.0f, 18.0f, 32.0f)); } static bool transformations_test_5(const char ** scenario) @@ -60,10 +60,10 @@ static bool transformations_test_5(const char ** scenario) *scenario = "Multiplying by the inverse of a scaling matrix"; struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); - struct mat4x4 inv = mat4x4_inverse(&transform); + struct mat4x4 inv = mat4x4_inverse(transform); struct tuple v = vector(-4.0f, 6.0f, 8.0f); - return tuple_equal(mat4x4_mul_t(&inv, &v), vector(-2.0f, 2.0f, 2.0f)); + return tuple_equal(mat4x4_mul_t(inv, v), vector(-2.0f, 2.0f, 2.0f)); } static bool transformations_test_6(const char ** scenario) @@ -73,7 +73,7 @@ static bool transformations_test_6(const char ** scenario) struct mat4x4 transform = scaling(-1.0f, 1.0f, 1.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(-2.0f, 3.0f, 4.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(-2.0f, 3.0f, 4.0f)); } static bool transformations_test_7(const char ** scenario) @@ -85,8 +85,8 @@ static bool transformations_test_7(const char ** scenario) struct mat4x4 full_quarter = rotation_x(tau / 4); return - tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(0.0f, 0.7071067811865476, 0.7071067811865476)) && - tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(0.0f, 0.0f, 1.0f)); + tuple_equal(mat4x4_mul_t(half_quarter, p), point(0.0f, 0.7071067811865476, 0.7071067811865476)) && + tuple_equal(mat4x4_mul_t(full_quarter, p), point(0.0f, 0.0f, 1.0f)); } static bool transformations_test_8(const char ** scenario) @@ -98,8 +98,8 @@ static bool transformations_test_8(const char ** scenario) struct mat4x4 full_quarter = rotation_y(tau / 4); return - tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(0.7071067811865476, 0.0f, 0.7071067811865476)) && - tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(1.0f, 0.0f, 0.0f)); + tuple_equal(mat4x4_mul_t(half_quarter, p), point(0.7071067811865476, 0.0f, 0.7071067811865476)) && + tuple_equal(mat4x4_mul_t(full_quarter, p), point(1.0f, 0.0f, 0.0f)); } static bool transformations_test_9(const char ** scenario) @@ -111,8 +111,8 @@ static bool transformations_test_9(const char ** scenario) struct mat4x4 full_quarter = rotation_z(tau / 4); return - tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(-0.7071067811865476, 0.7071067811865476, 0.0f)) && - tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(-1.0f, 0.0f, 0.0f)); + tuple_equal(mat4x4_mul_t(half_quarter, p), point(-0.7071067811865476, 0.7071067811865476, 0.0f)) && + tuple_equal(mat4x4_mul_t(full_quarter, p), point(-1.0f, 0.0f, 0.0f)); } static bool transformations_test_10(const char ** scenario) @@ -122,7 +122,7 @@ static bool transformations_test_10(const char ** scenario) struct mat4x4 transform = shearing(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(5.0f, 3.0f, 4.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(5.0f, 3.0f, 4.0f)); } static bool transformations_test_11(const char ** scenario) @@ -132,7 +132,7 @@ static bool transformations_test_11(const char ** scenario) struct mat4x4 transform = shearing(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(6.0f, 3.0f, 4.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(6.0f, 3.0f, 4.0f)); } static bool transformations_test_12(const char ** scenario) @@ -142,7 +142,7 @@ static bool transformations_test_12(const char ** scenario) struct mat4x4 transform = shearing(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 5.0f, 4.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 5.0f, 4.0f)); } static bool transformations_test_13(const char ** scenario) @@ -152,7 +152,7 @@ static bool transformations_test_13(const char ** scenario) struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 7.0f, 4.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 7.0f, 4.0f)); } static bool transformations_test_14(const char ** scenario) @@ -162,7 +162,7 @@ static bool transformations_test_14(const char ** scenario) struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 3.0f, 6.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 3.0f, 6.0f)); } static bool transformations_test_15(const char ** scenario) @@ -172,7 +172,7 @@ static bool transformations_test_15(const char ** scenario) struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); - return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 3.0f, 7.0f)); + return tuple_equal(mat4x4_mul_t(transform, p), point(2.0f, 3.0f, 7.0f)); } static bool transformations_test_16(const char ** scenario) @@ -184,9 +184,9 @@ static bool transformations_test_16(const char ** scenario) struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f); struct mat4x4 c = translation(10.0f, 5.0f, 7.0f); - struct tuple p2 = mat4x4_mul_t(&a, &p); - struct tuple p3 = mat4x4_mul_t(&b, &p2); - struct tuple p4 = mat4x4_mul_t(&c, &p3); + struct tuple p2 = mat4x4_mul_t(a, p); + struct tuple p3 = mat4x4_mul_t(b, p2); + struct tuple p4 = mat4x4_mul_t(c, p3); return tuple_equal(p2, point(1.0f, -1.0f, 0.0f)) && @@ -203,9 +203,9 @@ static bool transformations_test_17(const char ** scenario) struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f); struct mat4x4 c = translation(10.0f, 5.0f, 7.0f); - struct mat4x4 t1 = mat4x4_mul_m(&c, &b); - struct mat4x4 t2 = mat4x4_mul_m(&t1, &a); - struct tuple p1 = mat4x4_mul_t(&t2, &p); + struct mat4x4 t1 = mat4x4_mul_m(c, b); + struct mat4x4 t2 = mat4x4_mul_m(t1, a); + struct tuple p1 = mat4x4_mul_t(t2, p); return tuple_equal(p1, point(15.0f, 0.0f, 7.0f)); } @@ -220,7 +220,7 @@ static bool transformations_test_18(const char ** scenario) struct mat4x4 t = view_transform(from, to, up); struct mat4x4 identity_matrix = mat4x4_identity(); - return mat4x4_equal(&t, &identity_matrix); + return mat4x4_equal(t, identity_matrix); } static bool transformations_test_19(const char ** scenario) @@ -233,7 +233,7 @@ static bool transformations_test_19(const char ** scenario) struct mat4x4 t = view_transform(from, to, up); struct mat4x4 scaled = scaling(-1.0f, 1.0f, -1.0f); - return mat4x4_equal(&t, &scaled); + return mat4x4_equal(t, scaled); } static bool transformations_test_20(const char ** scenario) @@ -246,7 +246,7 @@ static bool transformations_test_20(const char ** scenario) struct mat4x4 t = view_transform(from, to, up); struct mat4x4 translated = translation(0.0f, 0.0f, -8.0f); - return mat4x4_equal(&t, &translated); + return mat4x4_equal(t, translated); } static bool transformations_test_21(const char ** scenario) @@ -263,7 +263,7 @@ static bool transformations_test_21(const char ** scenario) -0.35857f, 0.59761f, -0.71714f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f ); - return mat4x4_equal(&t, &expected); + return mat4x4_equal(t, expected); } test_t transformations_tests[] = { diff --git a/test/test_world.c b/test/test_world.c index c099367..76f5cc6 100644 --- a/test/test_world.c +++ b/test/test_world.c @@ -20,11 +20,11 @@ static bool world_test_1(const char ** scenario) *scenario = "The default world"; struct light light = point_light(point(-10.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f)); - struct sphere s1 = sphere(); + struct shape s1 = sphere(); s1.material.color = color(0.8f, 1.0f, 0.6f); s1.material.diffuse = 0.7f; s1.material.specular = 0.2f; - struct sphere s2 = sphere(); + struct shape s2 = sphere(); s2.transform = scaling(0.5f, 0.5f, 0.5f); struct world w = world_default(); return @@ -34,7 +34,7 @@ static bool world_test_1(const char ** scenario) tuple_equal(w.objects[0].material.color, s1.material.color) && float_equal(w.objects[0].material.diffuse, s1.material.diffuse) && float_equal(w.objects[0].material.specular, s1.material.specular) && - mat4x4_equal(&w.objects[1].transform, &s2.transform); + mat4x4_equal(w.objects[1].transform, s2.transform); } static bool world_test_2(const char ** scenario) @@ -61,7 +61,7 @@ static bool world_test_3(const char ** scenario) struct world w = world_default(); struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere * shape = &w.objects[0]; + struct shape * shape = &w.objects[0]; struct intersection i = intersection(4.0f, shape); struct computations comps = prepare_computations(i, r); struct tuple c = world_shade_hit(&w, &comps); @@ -76,7 +76,7 @@ static bool world_test_4(const char ** scenario) struct world w = world_default(); w.light = point_light(point(0.0f, 0.25f, 0.0f), color(1.0f, 1.0f, 1.0f)); struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f)); - struct sphere * shape = &w.objects[1]; + struct shape * shape = &w.objects[1]; struct intersection i = intersection(0.5f, shape); struct computations comps = prepare_computations(i, r); struct tuple c = world_shade_hit(&w, &comps); @@ -111,9 +111,9 @@ static bool world_test_7(const char ** scenario) *scenario = "The color with an intersection behind the ray"; struct world w = world_default(); - struct sphere * outer = &w.objects[0]; + struct shape * outer = &w.objects[0]; outer->material.ambient = 1.0f; - struct sphere * inner = &w.objects[1]; + struct shape * inner = &w.objects[1]; inner->material.ambient = 1.0f; struct ray r = ray(point(0.0f, 0.0f, 0.75f), vector(0.0f, 0.0f, -1.0f)); struct tuple c = world_color_at(&w, r); @@ -167,9 +167,9 @@ static bool world_test_12(const char ** scenario) struct world w = world(); w.light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f)); - struct sphere s1 = sphere(); + struct shape s1 = sphere(); w.objects[0] = s1; - struct sphere s2 = sphere(); + struct shape s2 = sphere(); s2.transform = translation(0.0f, 0.0f, 10.0f); w.objects[1] = s2; w.object_count = 2; diff --git a/transformations.h b/transformations.h index c07c9ec..1d4802b 100644 --- a/transformations.h +++ b/transformations.h @@ -70,5 +70,5 @@ inline static struct mat4x4 view_transform(struct tuple from, 0.0f, 0.0f, 0.0f, 1.0f); struct mat4x4 translate = translation(-from.x, -from.y, -from.z); - return mat4x4_mul_m(&orientation, &translate); + return mat4x4_mul_m(orientation, translate); } diff --git a/world.h b/world.h index 700ffe9..39922fe 100644 --- a/world.h +++ b/world.h @@ -3,7 +3,7 @@ #include "lights.h" #include "spheres.h" #include "transformations.h" -#include "intersections.h" +#include "intersections_shapes.h" #include "rays.h" #include "materials.h" @@ -12,7 +12,7 @@ struct world { struct light light; int object_count; - struct sphere objects[WORLD_MAX_OBJECTS]; + struct shape objects[WORLD_MAX_OBJECTS]; }; inline static struct world world() @@ -25,11 +25,11 @@ inline static struct world world() inline static struct world world_default() { - struct sphere s1 = sphere(); + struct shape s1 = sphere(); s1.material.color = color(0.8f, 1.0f, 0.6f); s1.material.diffuse = 0.7f; s1.material.specular = 0.2f; - struct sphere s2 = sphere(); + struct shape s2 = sphere(); s2.transform = scaling(0.5f, 0.5f, 0.5f); return (struct world){