--- /dev/null
+#include "miniRT.h"
+#include "libft.h"
+#include <math.h>
+
+#ifndef INFINITY
+# error "This platform does not support INFINITY macro!"
+#endif // INFINITY
+
+#ifndef NAN
+# error "This platform does not support NAN macro!"
+#endif // NAN
+
+static const t_color DEFAULT_COLOR = {0, 0, 0};
+
+static int is_bounded(const t_object *object)
+{
+ enum e_object_type type;
+
+ type = object->type;
+ return (type == PLANE);
+}
+
+double get_cylinder_circumsphere_radius(const t_cylinder *cylinder)
+{
+ double base_radius;
+ double height;
+
+ base_radius = cylinder->radius;
+ height = cylinder->height;
+ return (sqrt(base_radius * base_radius + height * height / 4));
+}
+
+t_vec3 vec_add(t_vec3 v, t_vec3 u)
+{
+ t_vec3 res;
+
+ res.x = v.x + u.x;
+ res.y = v.y + u.y;
+ res.z = v.z + u.z;
+ return (res);
+}
+
+t_vec3 vec_diff(t_vec3 v, t_vec3 u)
+{
+ t_vec3 res;
+
+ res.x = v.x - u.x;
+ res.y = v.y - u.y;
+ res.z = v.z - u.z;
+ return (res);
+}
+
+t_vec3 vec_real_mul(t_vec3 vec, double real)
+{
+ t_vec3 res;
+
+ res.x = real * vec.x;
+ res.y = real * vec.y;
+ res.z = real * vec.z;
+ return (res);
+}
+
+double vec_scalar_mul(t_vec3 v, t_vec3 u)
+{
+ return (v.x * u.x + v.y * u.y + v.z * u.z);
+}
+
+double vec_norm(t_vec3 vec)
+{
+ return (sqrt(vec_scalar_mul(vec, vec)));
+}
+
+double dist_point_from_line(const t_ray *ray, t_vec3 point)
+{
+ t_vec3 start;
+ t_vec3 projection;
+
+ start = vec_diff(point, ray->start);
+ projection = vec_real_mul(ray->direction,
+ vec_scalar_mul(ray->direction, start));
+ return (vec_norm(projection));
+}
+
+int is_behind_ray(const t_ray *ray, t_vec3 point)
+{
+ return (0 > vec_scalar_mul(ray->direction, vec_diff(point, ray->start)));
+}
+
+int intersects_circumsphere(const t_ray *ray, const t_object *object)
+{
+ double radius;
+ t_vec3 center;
+ double distance;
+
+ if (object->type == SPHERE)
+ {
+ radius = object->object.sphere.radius;
+ center = object->object.sphere.center;
+ }
+ else if (object->type == CYLINDER)
+ {
+ radius = get_cylinder_circumsphere_radius(&object->object.cylinder);
+ center = object->object.cylinder.center;
+ }
+ if (is_behind_ray(ray, center))
+ return (0);
+ distance = dist_point_from_line(ray, center);
+ return (distance < radius);
+}
+
+double get_intersection_arg_plane(const t_ray *ray, const t_plane *plane)
+{
+ t_vec3 start;
+
+ start = vec_diff(plane->point, ray->start);
+ return (vec_scalar_mul(plane->normal, start)
+ / vec_scalar_mul(plane->normal, ray->direction));
+}
+
+double get_intersection_arg_nonbounded(const t_ray *ray, const t_object *object)
+{
+ if (object->type == PLANE)
+ return (get_intersection_arg_plane(ray, &object->object.plane));
+ else
+ return (NAN);
+}
+
+double get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere)
+{
+ t_vec3 start;
+ double a;
+ double b;
+ double c;
+ double det;
+
+ start = vec_diff(ray->start, sphere->center);
+ a = vec_scalar_mul(ray->direction, ray->direction);
+ b = 2 * vec_scalar_mul(ray->direction, start);
+ c = vec_scalar_mul(start, start) - sphere->radius * sphere->radius;
+ det = b * b - 4 * a * c;
+ if (det < 0)
+ return (NAN);
+ return ((-b - sqrt(det)) / (2 * a));
+}
+
+double get_intersection_arg_bounded(const t_ray *ray, const t_object *object)
+{
+ if (object->type == SPHERE)
+ return (get_intersection_arg_sphere(ray, &object->object.sphere));
+ else if (object->type == CYLINDER)
+ return (get_intersection_arg_cylinder(ray, &object->object.cylinder));
+ else
+ return (NAN);
+}
+
+double get_intersection_arg(const t_ray *ray, const t_object *object)
+{
+ if (!is_bounded(object))
+ return (get_intersection_arg_nonbounded(ray, object));
+ else if (!intersects_circumsphere(ray, object))
+ return (NAN);
+ else
+ return (get_intersection_arg_bounded(ray, object));
+}
+
+t_color trace_ray(const t_ray *ray, const t_scene *scene)
+{
+ size_t i;
+ const t_object *object_found;
+ double distance_found;
+ double distance;
+
+ object_found = NULL;
+ distance_found = INFINITY;
+ i = 0;
+ while (i < scene->objects.size)
+ {
+ distance = get_intersection_arg(ray, ft_vec_caccess(&scene->objects, i));
+ if (0 < distance && distance < distance_found)
+ {
+ distance_found = distance;
+ object_found = ft_vec_caccess(&scene->objects, i);
+ }
+ ++i;
+ }
+ if (object_found)
+ return (get_object_color(ray, object_found));
+ else
+ return (DEFAULT_COLOR);
+}