2020-08-21 00:13:11 -04:00

105 lines
3.1 KiB
C

#include "sphere.h"
#include <math.h>
#include <exceptions.h>
#include <assert.h>
SPHERE_Sphere* SPHERE_new() {
SPHERE_Sphere* s = malloc(sizeof(SPHERE_Sphere));
if (!s)
Throw(E_MALLOC_FAILED);
SPHERE_init(s);
return s;
}
void SPHERE_init(SPHERE_Sphere* sphere) {
assert(sphere);
sphere->origin = TUPLES_point(0, 0 , 0);
sphere->radius = 1.0;
sphere->transform = MATRIX_new_identity(4);
sphere->material = MATERIAL_new();
}
void SPHERE_destroy(SPHERE_Sphere* sphere) {
assert(sphere);
MATRIX_delete(sphere->transform);
MATERIAL_delete(sphere->material);
}
void SPHERE_delete(SPHERE_Sphere* sphere) {
assert(sphere);
SPHERE_destroy(sphere);
free(sphere);
}
RAY_Intersections* SPHERE_intersect(const SPHERE_Sphere* sphere, const RAY_Ray* original_ray, RAY_Intersections* other_intersections) {
assert(sphere);
assert(original_ray);
assert(MATRIX_is_invertible(sphere->transform));
RAY_Ray ray;
MATRIX_Matrix inv_transform;
MATRIX_inverse(&inv_transform, SPHERE_get_transform(sphere));
RAY_transform(&ray, original_ray, &inv_transform);
if (!other_intersections) {
other_intersections = RAY_new_intersections();
}
//compute discriminant
TUPLES_Vector sphere_to_ray = TUPLES_subtract(ray.origin, sphere->origin);
double a = TUPLES_dot(ray.direction, ray.direction);
double b = 2 * TUPLES_dot(ray.direction, sphere_to_ray);
double c = TUPLES_dot(sphere_to_ray, sphere_to_ray) - 1.0;
double discriminant = pow(b, 2.0) - 4.0 * a *c;
if (discriminant < 0) {
//no hit
return other_intersections;
}
double t1 = (-b - sqrt(discriminant)) / (2.0 * a);
double t2 = (-b + sqrt(discriminant)) / (2.0 * a);
RAY_add_intersection(other_intersections, t1, sphere);
RAY_add_intersection(other_intersections, t2, sphere);
RAY_destroy(&ray);
return other_intersections;
}
void SPHERE_set_material(SPHERE_Sphere* sphere, const MATERIAL_Material* material) {
assert(sphere);
assert(material);
MATERIAL_copy(sphere->material, material);
}
const MATERIAL_Material* SPHERE_get_material(const SPHERE_Sphere* sphere) {
assert(sphere);
return sphere->material;
}
void SPHERE_set_transform(SPHERE_Sphere* sphere, const MATRIX_Matrix* matrix) {
assert(sphere);
assert(matrix);
assert(matrix->width == 4);
assert(matrix->height == 4);
MATRIX_destroy(sphere->transform);
MATRIX_copy(sphere->transform, matrix);
}
const MATRIX_Matrix* SPHERE_get_transform(const SPHERE_Sphere* sphere) {
assert(sphere);
return sphere->transform;
}
TUPLES_Vector SPHERE_normal_at(const SPHERE_Sphere* sphere, TUPLES_Point world_point) {
assert(sphere);
MATRIX_Matrix inverse;
MATRIX_inverse(&inverse, SPHERE_get_transform(sphere));
TUPLES_Point object_point = MATRIX_multiply_tuple(&inverse, world_point);
TUPLES_Vector object_normal = TUPLES_subtract(object_point, sphere->origin);
MATRIX_transpose(&inverse);
TUPLES_Vector world_normal = MATRIX_multiply_tuple(&inverse, object_normal);
world_normal.w = 0;
return TUPLES_normalize(world_normal);
}