#pragma once #include #include #include "spheres.h" #include "rays.h" struct intersection { float t; struct sphere const * object; }; struct intersection intersection(float t, struct sphere const * const object) { return (struct intersection){ t, object }; } #define MAX_INTERSECTIONS 1024 struct intersections { int count; struct intersection i[MAX_INTERSECTIONS]; }; inline static void intersections(struct intersections * intersections, int count, ...) { va_list ap; va_start(ap, count); for (int i = 0; i < count; i++) { intersections->i[i] = va_arg(ap, struct intersection); } va_end(ap); 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; }; 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); } return (struct computations){ intersection.t, intersection.object, point, eyev, normalv, inside }; }