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

136 lines
3.8 KiB
C

#include <assert.h>
#include "exceptions.h"
#include "world.h"
typedef struct WORLD_World {
const LIGHTS_PointLight* light;
SPHERE_Sphere** objects;
unsigned int object_count;
} WORLD_World;
void WORLD_init(WORLD_World* world, const LIGHTS_PointLight* light) {
assert(world);
assert(light);
world->light = light;
world->objects = NULL;
world->object_count = 0;
}
WORLD_World* WORLD_new(const LIGHTS_PointLight* light) {
assert(light);
WORLD_World* world = malloc(sizeof(WORLD_World));
if (!world)
Throw(E_MALLOC_FAILED);
WORLD_init(world, light);
return world;
}
void WORLD_destroy(WORLD_World* world) {
assert(world);
free(world->objects);
world->objects = NULL;
world->object_count = 0;
}
void WORLD_delete(WORLD_World* world) {
assert(world);
WORLD_destroy(world);
free(world);
}
void WORLD_set_light(WORLD_World* world, const LIGHTS_PointLight* light) {
assert(world);
assert(light);
world->light = light;
}
inline const LIGHTS_PointLight* WORLD_get_light(const WORLD_World* world) {
assert(world);
return world->light;
}
void WORLD_add_object(WORLD_World* world, SPHERE_Sphere* sphere) {
assert(world);
assert(sphere);
SPHERE_Sphere** tmpptr = reallocarray(world->objects, sizeof(SPHERE_Sphere*), world->object_count + 1);
if (!tmpptr) {
Throw(E_MALLOC_FAILED);
} else {
world->objects = tmpptr;
}
world->objects[world->object_count] = sphere;
world->object_count++;
}
inline SPHERE_Sphere* WORLD_get_object(const WORLD_World* world, unsigned int index) {
assert(world);
assert(index < world->object_count);
return world->objects[index];
}
inline unsigned int WORLD_get_object_count(const WORLD_World* world) {
assert(world);
return world->object_count;
}
RAY_Intersections* WORLD_intersect(const WORLD_World* world, const RAY_Ray* ray) {
assert(world);
assert(ray);
RAY_Intersections* intersections = RAY_new_intersections();
for (unsigned int i=0; i<world->object_count; i++) {
SPHERE_intersect(WORLD_get_object(world, i), ray, intersections);
}
RAY_sort_intersections(intersections);
return intersections;
}
void WORLD_shade_hit(TUPLES_Color* dest, const WORLD_World* world, const INTERSECTION_Intersection* computation) {
assert(world);
assert(computation);
bool shadowed = WORLD_is_shadowed(world, computation->over_point);
*dest = MATERIAL_lighting(
SPHERE_get_material(computation->object),
world->light,
computation->point,
computation->eyev,
computation->normalv,
shadowed);
}
void WORLD_color_at(TUPLES_Color* dest, const WORLD_World* world, const RAY_Ray* ray) {
assert(dest);
assert(world);
assert(ray);
RAY_Intersections* intersections = WORLD_intersect(world, ray);
RAY_Xs* hit = RAY_hit(intersections);
if (!hit) {
*dest = TUPLES_color(0, 0, 0);
} else {
INTERSECTION_Intersection* comps = INTERSECTION_prepare_computations(hit, ray);
WORLD_shade_hit(dest, world, comps);
INTERSECTION_delete(comps);
}
RAY_delete_intersections(intersections);
}
bool WORLD_is_shadowed(const WORLD_World* world, TUPLES_Point point) {
TUPLES_Vector direction = TUPLES_subtract(LIGHTS_get_origin(WORLD_get_light(world)), point);
double distance = TUPLES_magnitude(direction);
direction = TUPLES_normalize(direction);
RAY_Ray ray;
RAY_init_from_tuples(&ray, point, direction);
struct RAY_Intersections* intersections = WORLD_intersect(world, &ray);
RAY_Xs* hit = RAY_hit(intersections);
bool is_shadowed = false;
if (hit && hit->t < distance) {
is_shadowed = true;
}
RAY_delete_intersections(intersections);
return is_shadowed;
}