Make scene.c completely Norm compliant
authorLukas Jiriste <ljiriste@student.42prague.com>
Tue, 14 Jan 2025 15:45:21 +0000 (16:45 +0100)
committerLukas Jiriste <ljiriste@student.42prague.com>
Tue, 14 Jan 2025 15:45:21 +0000 (16:45 +0100)
Makefile
inc/miniRT.h
src/circumsphere.c [new file with mode: 0644]
src/cylinder.c [new file with mode: 0644]
src/intersect.c [new file with mode: 0644]
src/object_color.c [new file with mode: 0644]
src/plane.c [new file with mode: 0644]
src/scene.c
src/scene_helpers.c [new file with mode: 0644]
src/sphere.c [new file with mode: 0644]

index 7ad1e6b3fdf7707507ae7dd27bc39cfb51a0885a..8363fde0a617465e28f8603fdf5fc5cfb4eaacfa 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -21,13 +21,20 @@ INCLUDE := $(addprefix -I, $(INCDIR))
 SRCDIR := src
 
 SOURCES :=     main.c                          \
-                       scene.c                         \
                        manipulation.c          \
                        tokenize.c                      \
                        parse.c                         \
                        parse_rt.c                      \
                        parse_small.c           \
                        parse_elements.c        \
+                       scene.c                         \
+                       scene_helpers.c         \
+                       intersect.c                     \
+                       circumsphere.c          \
+                       cylinder.c                      \
+                       sphere.c                        \
+                       plane.c                         \
+                       object_color.c          \
                        vec3.c                          \
 
 SOURCES := $(addprefix $(SRCDIR)/, $(SOURCES))
index 6144fd922f3f0c0a44d826e81ea866c3654dbca7..28532a5b9fcec61d271f9648a7f808dae759bc71 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2025/01/13 19:51:09 by ljiriste          #+#    #+#             */
-/*   Updated: 2025/01/14 15:13:53 by ljiriste         ###   ########.fr       */
+/*   Updated: 2025/01/14 16:44:53 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
 
 # include "vec3.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
 
 typedef t_vec3         t_color;
 
@@ -154,6 +163,8 @@ double                      node_to_double(const t_parse_tree_node *double_node);
 t_color                        node_to_linear_rgb(const t_parse_tree_node *rgb_node);
 t_vec3                 node_to_vec3(const t_parse_tree_node *vec3_node);
 
+int                            parse_rt_file(const char *filename, t_scene *scene);
+int                            parse_args(int argc, char **argv, t_session *s);
 int                            add_light(const t_parse_tree_node *light_node, t_vec *lights);
 int                            add_camera(
                                        const t_parse_tree_node *camera_node, t_vec *cameras);
@@ -163,7 +174,11 @@ int                                add_sphere(
 int                            add_cylinder(
                                        const t_parse_tree_node *cylinder_node, t_vec *objects);
 
-int                            parse_rt_file(const char *filename, t_scene *scene);
+double                 dist_point_from_line(const t_ray *ray, t_vec3 point);
+double                 dist_point_from_plane(const t_plane *plane, t_vec3 point);
+int                            is_behind_ray(const t_ray *ray, t_vec3 point);
+t_vec3                 ray_point(const t_ray *ray, double arg);
+t_pair                 solve_quadratic(double a, double b, double c);
 
 t_color                        trace_ray(const t_ray *ray, t_scene *scene);
 t_color                        color_srgb_to_lin(t_color_srgb srgb);
@@ -171,7 +186,22 @@ t_color                    color_srgb_to_lin(t_color_srgb srgb);
 t_obstruction  find_nearest_obstruction(
                                        const t_ray *ray, t_vec *objects, const t_object *ignored);
 
-int                            parse_args(int argc, char **argv, t_session *s);
+t_sphere               get_circumsphere(const t_object *object);
+int                            intersects_circumsphere(
+                                       const t_ray *ray, const t_object *object);
+t_vec3                 get_cylinder_normal(t_vec3 point, const t_cylinder *cylinder);
+t_vec                  get_intersection_arg_cylinder(
+                                       const t_ray *ray, const t_cylinder *cylinder);
+t_vec                  get_intersection_arg_sphere(
+                                       const t_ray *ray, const t_sphere *sphere);
+double                 get_intersection_arg_plane(
+                                       const t_ray *ray, const t_plane *plane);
+t_vec                  get_intersection_args(const t_ray *ray, const t_object *object);
+double                 get_intersection_arg_min(
+                                       const t_ray *ray, const t_object *object);
+
+t_color                        get_object_color(const t_ray *ray, const t_object *object,
+                                       t_scene *scene);
 
 int                            rotate(t_element *element, t_vec3 rot_axis, double angle);
 void                   translate(
diff --git a/src/circumsphere.c b/src/circumsphere.c
new file mode 100644 (file)
index 0000000..11b379c
--- /dev/null
@@ -0,0 +1,63 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   circumsphere.c                                     :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 15:55:54 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 16:07:27 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+#include "libft.h"
+#include <math.h>
+
+static 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_sphere       get_circumsphere(const t_object *object)
+{
+       t_sphere        circumsphere;
+
+       if (object->type == SPHERE)
+       {
+               circumsphere.radius = object->object.sphere.radius;
+               circumsphere.center = object->object.sphere.center;
+       }
+       else if (object->type == CYLINDER)
+       {
+               circumsphere.radius
+                       = get_cylinder_circumsphere_radius(&object->object.cylinder);
+               circumsphere.center = object->object.cylinder.center;
+       }
+       else if (object->type == PLANE)
+       {
+               circumsphere.radius = INFINITY;
+               circumsphere.center = object->object.plane.point;
+       }
+       return (circumsphere);
+}
+
+int    intersects_circumsphere(const t_ray *ray, const t_object *object)
+{
+       t_sphere        circumsphere;
+       double          distance;
+
+       circumsphere = get_circumsphere(object);
+       if (is_behind_ray(ray, vec_add(
+                               circumsphere.center,
+                               vec_real_mul(ray->direction, circumsphere.radius))))
+               return (0);
+       distance = dist_point_from_line(ray, circumsphere.center);
+       return (distance < circumsphere.radius);
+}
diff --git a/src/cylinder.c b/src/cylinder.c
new file mode 100644 (file)
index 0000000..d92a8d7
--- /dev/null
@@ -0,0 +1,113 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   cylinder.c                                         :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 15:42:58 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 16:08:21 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+#include "libft.h"
+
+static t_vec   get_intersection_arg_cylinder_base(
+                       const t_ray *ray, const t_cylinder *cylinder)
+{
+       t_vec   res;
+       double  arg;
+       t_plane base;
+
+       ft_vec_init(&res, sizeof(double));
+       base.point = vec_add(
+                       cylinder->center,
+                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
+       base.normal = cylinder->rot_axis;
+       arg = get_intersection_arg_plane(ray, &base);
+       if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius)
+               ft_vec_append(&res, &arg);
+       base.point = vec_diff(
+                       cylinder->center,
+                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
+       arg = get_intersection_arg_plane(ray, &base);
+       if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius)
+               ft_vec_append(&res, &arg);
+       return (res);
+}
+
+static t_vec   get_intersection_arg_cylinder_around(
+                       const t_ray *ray, const t_cylinder *cylinder)
+{
+       t_vec   res;
+       t_pair  args;
+       t_vec3  v;
+       t_vec3  u;
+       t_vec3  intersect;
+
+       ft_vec_init(&res, sizeof(double));
+       v = vec_vec_mul(cylinder->rot_axis, ray->direction);
+       u = vec_vec_mul(cylinder->rot_axis, vec_diff(ray->start, cylinder->center));
+       args = solve_quadratic(vec_scalar_mul(v, v), 2 * vec_scalar_mul(v, u),
+                       vec_scalar_mul(u, u) - cylinder->radius * cylinder->radius);
+       intersect = ray_point(ray, args.first);
+       if (fabs(vec_scalar_mul(
+                               cylinder->rot_axis, vec_diff(intersect, cylinder->center)))
+               < cylinder->height / 2)
+               ft_vec_append(&res, &args.first);
+       intersect = ray_point(ray, args.second);
+       if (fabs(vec_scalar_mul(
+                               cylinder->rot_axis, vec_diff(intersect, cylinder->center)))
+               < cylinder->height / 2)
+               ft_vec_append(&res, &args.second);
+       return (res);
+}
+
+t_vec  get_intersection_arg_cylinder(
+                       const t_ray *ray, const t_cylinder *cylinder)
+{
+       size_t                  i;
+       t_vec                   res;
+       t_vec                   res2;
+       const double    *el;
+
+       res = get_intersection_arg_cylinder_base(ray, cylinder);
+       res2 = get_intersection_arg_cylinder_around(ray, cylinder);
+       i = 0;
+       while (i < res2.size)
+       {
+               el = ft_vec_caccess(&res2, i);
+               ft_vec_append(&res, el);
+               ++i;
+       }
+       ft_vec_free(&res2, NULL);
+       return (res);
+}
+
+t_vec3 get_cylinder_normal(t_vec3 point, const t_cylinder *cylinder)
+{
+       t_vec3  radial_vec;
+       double  dist_from_round;
+       double  dist_from_top;
+       double  dist_from_bottom;
+       t_plane base;
+
+       radial_vec = vec_vec_mul(cylinder->rot_axis,
+                       vec_diff(point, cylinder->center));
+       radial_vec = vec_vec_mul(radial_vec, cylinder->rot_axis);
+       dist_from_round = fabs(vec_norm(radial_vec) - cylinder->radius);
+       base.normal = cylinder->rot_axis;
+       base.point = vec_add(cylinder->center,
+                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
+       dist_from_top = dist_point_from_plane(&base, point);
+       base.point = vec_diff(cylinder->center,
+                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
+       dist_from_bottom = dist_point_from_plane(&base, point);
+       if (dist_from_round < dist_from_top && dist_from_round < dist_from_bottom)
+               return (radial_vec);
+       if (dist_from_top < dist_from_bottom)
+               return (cylinder->rot_axis);
+       return (vec_real_mul(cylinder->rot_axis, -1));
+}
diff --git a/src/intersect.c b/src/intersect.c
new file mode 100644 (file)
index 0000000..f047934
--- /dev/null
@@ -0,0 +1,85 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   intersect.c                                        :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 15:58:23 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 16:04:08 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+#include "libft.h"
+
+static int     is_bounded(const t_object *object)
+{
+       enum e_object_type      type;
+
+       type = object->type;
+       return (type != PLANE);
+}
+
+static t_vec   get_intersection_arg_nonbounded(
+                       const t_ray *ray, const t_object *object)
+{
+       t_vec   res;
+       double  tmp;
+
+       ft_vec_init(&res, sizeof(double));
+       if (object->type == PLANE)
+       {
+               tmp = get_intersection_arg_plane(ray, &object->object.plane);
+               ft_vec_append(&res, &tmp);
+       }
+       return (res);
+}
+
+static t_vec   get_intersection_arg_bounded(
+                                       const t_ray *ray, const t_object *object)
+{
+       t_vec   res;
+
+       if (object->type == SPHERE)
+               res = get_intersection_arg_sphere(ray, &object->object.sphere);
+       else if (object->type == CYLINDER)
+               res = get_intersection_arg_cylinder(ray, &object->object.cylinder);
+       else
+               ft_vec_init(&res, sizeof(double));
+       return (res);
+}
+
+t_vec  get_intersection_args(const t_ray *ray, const t_object *object)
+{
+       t_vec   res;
+
+       if (!is_bounded(object))
+               res = get_intersection_arg_nonbounded(ray, object);
+       else if (intersects_circumsphere(ray, object))
+               res = get_intersection_arg_bounded(ray, object);
+       else
+               ft_vec_init(&res, sizeof(double));
+       return (res);
+}
+
+double get_intersection_arg_min(const t_ray *ray, const t_object *object)
+{
+       t_vec   args;
+       double  arg;
+       double  res;
+       size_t  i;
+
+       args = get_intersection_args(ray, object);
+       res = INFINITY;
+       i = 0;
+       while (i < args.size)
+       {
+               arg = *(const double *)ft_vec_caccess(&args, i++);
+               if (arg > 0 && arg < res)
+                       res = arg;
+       }
+       ft_vec_free(&args, NULL);
+       return (res);
+}
diff --git a/src/object_color.c b/src/object_color.c
new file mode 100644 (file)
index 0000000..7594c73
--- /dev/null
@@ -0,0 +1,89 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   object_color.c                                     :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 16:00:18 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 16:15:13 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+#include "libft.h"
+
+static t_vec3  get_object_normal(const t_object *object, t_vec3 point)
+{
+       if (object->type == PLANE)
+               return (object->object.plane.normal);
+       if (object->type == SPHERE)
+               return (vec_diff(point, object->object.sphere.center));
+       if (object->type == CYLINDER)
+               return (get_cylinder_normal(point, &object->object.cylinder));
+       return ((t_vec3){.x = 0, .y = 0, .z = 0});
+}
+
+static t_color get_ambient_color(
+                                       const t_object *object, const t_ambient_light *amb)
+{
+       return (vec_real_mul(
+                       vec_elwise_mul(amb->color, object->object.plane.color),
+                       amb->brightness));
+}
+
+static t_color get_light_contribution(t_ray normal, const t_object *object,
+                       const t_light *light, t_scene *scene)
+{
+       t_ray                   new_ray;
+       t_obstruction   obstruction;
+       double                  angle_multiplier;
+       double                  distance;
+
+       new_ray.start = normal.start;
+       new_ray.direction = vec_diff(light->position, new_ray.start);
+       distance = vec_norm(new_ray.direction);
+       new_ray.direction = vec_real_mul(new_ray.direction, 1 / distance);
+       obstruction = find_nearest_obstruction(&new_ray, &scene->objects, object);
+       angle_multiplier = vec_scalar_mul(normal.direction, new_ray.direction)
+               / (vec_norm(normal.direction) * vec_norm(new_ray.direction));
+       if (object->type == PLANE)
+               angle_multiplier = fabs(angle_multiplier);
+       if (angle_multiplier > 0 && (!obstruction.object
+                       || distance < obstruction.distance
+                       ||obstruction.distance < 0))
+               return (vec_real_mul(
+                               vec_elwise_mul(light->color, object->object.plane.color),
+                               light->brightness * angle_multiplier / distance / distance));
+       else
+               return ((t_color){.x = 0, .y = 0, .z = 0});
+}
+
+t_color        get_object_color(const t_ray *ray, const t_object *object,
+                       t_scene *scene)
+{
+       t_color                 result;
+       t_ray                   object_normal;
+       const t_light   *light;
+       size_t                  i;
+
+       result = (t_color){.x = 0, .y = 0, .z = 0};
+       object_normal.start = ray_point(ray, get_intersection_arg_min(ray, object));
+       object_normal.direction = get_object_normal(object, object_normal.start);
+       if (vec_scalar_mul(object_normal.direction, ray->direction) > 0)
+               object_normal.direction = vec_real_mul(object_normal.direction, -1);
+       i = 0;
+       while (i < scene->lights.size)
+       {
+               light = &((const t_element *)
+                               ft_vec_caccess(&scene->lights, i++))->object.light;
+               if (vec_scalar_mul(object_normal.direction,
+                               vec_diff(light->position, object_normal.start)) > 0)
+                       result = vec_add(result, get_light_contribution(
+                                               object_normal,
+                                               object, light, scene));
+       }
+       result = vec_add(result, get_ambient_color(object, &scene->ambient_light));
+       return (result);
+}
diff --git a/src/plane.c b/src/plane.c
new file mode 100644 (file)
index 0000000..f6bd22f
--- /dev/null
@@ -0,0 +1,26 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   plane.c                                            :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 15:50:09 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 15:50:25 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+#include "libft.h"
+
+double get_intersection_arg_plane(const t_ray *ray, const t_plane *plane)
+{
+       t_vec3  start;
+       t_vec   res;
+
+       ft_vec_init(&res, sizeof(double));
+       start = vec_diff(plane->point, ray->start);
+       return (vec_scalar_mul(plane->normal, start)
+               / vec_scalar_mul(plane->normal, ray->direction));
+}
index 15f69882553dc357bae04a4e9aa6661ad899a137..8b4d260e1788656df0e9d17eb58193b74eb89fb1 100644 (file)
@@ -6,7 +6,7 @@
 /*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
 /*                                                +#+#+#+#+#+   +#+           */
 /*   Created: 2025/01/13 19:41:36 by ljiriste          #+#    #+#             */
-/*   Updated: 2025/01/13 19:43:04 by ljiriste         ###   ########.fr       */
+/*   Updated: 2025/01/14 16:15:13 by ljiriste         ###   ########.fr       */
 /*                                                                            */
 /* ************************************************************************** */
 
 #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   g_default_color = {0, 0, 0};
 
 static const double            g_self_obstruction_multiplier = 1e-8;
 
-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));
-}
-
-double dist_point_from_line(const t_ray *ray, t_vec3 point)
-{
-       t_vec3  start;
-       t_vec3  projection;
-
-       start = vec_diff(ray->start, point);
-       projection = vec_real_mul(ray->direction,
-                       vec_scalar_mul(ray->direction, start));
-       return (vec_norm(vec_diff(start, projection)));
-}
-
-double dist_point_from_plane(const t_plane *plane, t_vec3 point)
-{
-       return (fabs(vec_scalar_mul(plane->normal,
-                               vec_diff(point, plane->point))));
-}
-
-int    is_behind_ray(const t_ray *ray, t_vec3 point)
-{
-       return (0 > vec_scalar_mul(ray->direction, vec_diff(point, ray->start)));
-}
-
-t_sphere       get_circumsphere(const t_object *object)
-{
-       t_sphere        circumsphere;
-
-       if (object->type == SPHERE)
-       {
-               circumsphere.radius = object->object.sphere.radius;
-               circumsphere.center = object->object.sphere.center;
-       }
-       else if (object->type == CYLINDER)
-       {
-               circumsphere.radius
-                       = get_cylinder_circumsphere_radius(&object->object.cylinder);
-               circumsphere.center = object->object.cylinder.center;
-       }
-       else if (object->type == PLANE)
-       {
-               circumsphere.radius = INFINITY;
-               circumsphere.center = object->object.plane.point;
-       }
-       return (circumsphere);
-}
-
-int    intersects_circumsphere(const t_ray *ray, const t_object *object)
-{
-       t_sphere        circumsphere;
-       double          distance;
-
-       circumsphere = get_circumsphere(object);
-       if (is_behind_ray(ray, vec_add(
-                               circumsphere.center,
-                               vec_real_mul(ray->direction, circumsphere.radius))))
-               return (0);
-       distance = dist_point_from_line(ray, circumsphere.center);
-       return (distance < circumsphere.radius);
-}
-
-double get_intersection_arg_plane(const t_ray *ray, const t_plane *plane)
-{
-       t_vec3  start;
-       t_vec   res;
-
-       ft_vec_init(&res, sizeof(double));
-       start = vec_diff(plane->point, ray->start);
-       return (vec_scalar_mul(plane->normal, start)
-               / vec_scalar_mul(plane->normal, ray->direction));
-}
-
-t_vec  get_intersection_arg_nonbounded(
-                       const t_ray *ray, const t_object *object)
-{
-       t_vec   res;
-       double  tmp;
-
-       ft_vec_init(&res, sizeof(double));
-       if (object->type == PLANE)
-       {
-               tmp = get_intersection_arg_plane(ray, &object->object.plane);
-               ft_vec_append(&res, &tmp);
-       }
-       return (res);
-}
-
-t_vec3 ray_point(const t_ray *ray, double arg)
-{
-       return (vec_add(ray->start, vec_real_mul(ray->direction, arg)));
-}
-
-t_vec  get_intersection_arg_cylinder_base(
-                       const t_ray *ray, const t_cylinder *cylinder)
-{
-       t_vec   res;
-       double  arg;
-       t_plane base;
-
-       ft_vec_init(&res, sizeof(double));
-       base.point = vec_add(
-                       cylinder->center,
-                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
-       base.normal = cylinder->rot_axis;
-       arg = get_intersection_arg_plane(ray, &base);
-       if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius)
-               ft_vec_append(&res, &arg);
-       base.point = vec_diff(
-                       cylinder->center,
-                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
-       arg = get_intersection_arg_plane(ray, &base);
-       if (vec_norm(vec_diff(base.point, ray_point(ray, arg))) <= cylinder->radius)
-               ft_vec_append(&res, &arg);
-       return (res);
-}
-
-t_pair solve_quadratic(double a, double b, double c)
-{
-       t_pair  res;
-       double  det;
-
-       det = b * b - 4 * a * c;
-       if (det < 0)
-       {
-               res.first = NAN;
-               res.second = NAN;
-               return (res);
-       }
-       det = sqrt(det);
-       res.first = (-b - det) / (2 * a);
-       res.second = (-b + det) / (2 * a);
-       return (res);
-}
-
-t_vec  get_intersection_arg_cylinder_around(
-                       const t_ray *ray, const t_cylinder *cylinder)
-{
-       t_vec   res;
-       t_pair  args;
-       t_vec3  v;
-       t_vec3  u;
-       t_vec3  intersect;
-
-       ft_vec_init(&res, sizeof(double));
-       v = vec_vec_mul(cylinder->rot_axis, ray->direction);
-       u = vec_vec_mul(cylinder->rot_axis, vec_diff(ray->start, cylinder->center));
-       args = solve_quadratic(vec_scalar_mul(v, v), 2 * vec_scalar_mul(v, u),
-                       vec_scalar_mul(u, u) - cylinder->radius * cylinder->radius);
-       intersect = ray_point(ray, args.first);
-       if (fabs(vec_scalar_mul(
-                               cylinder->rot_axis, vec_diff(intersect, cylinder->center)))
-               < cylinder->height / 2)
-               ft_vec_append(&res, &args.first);
-       intersect = ray_point(ray, args.second);
-       if (fabs(vec_scalar_mul(
-                               cylinder->rot_axis, vec_diff(intersect, cylinder->center)))
-               < cylinder->height / 2)
-               ft_vec_append(&res, &args.second);
-       return (res);
-}
-
-t_vec  get_intersection_arg_cylinder(
-                       const t_ray *ray, const t_cylinder *cylinder)
-{
-       size_t                  i;
-       t_vec                   res;
-       t_vec                   res2;
-       const double    *el;
-
-       res = get_intersection_arg_cylinder_base(ray, cylinder);
-       res2 = get_intersection_arg_cylinder_around(ray, cylinder);
-       i = 0;
-       while (i < res2.size)
-       {
-               el = ft_vec_caccess(&res2, i);
-               ft_vec_append(&res, el);
-               ++i;
-       }
-       ft_vec_free(&res2, NULL);
-       return (res);
-}
-
-t_vec  get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere)
-{
-       t_vec3  start;
-       t_pair  intersection_args;
-       t_vec   res;
-
-       ft_vec_init(&res, sizeof(double));
-       start = vec_diff(ray->start, sphere->center);
-       intersection_args = solve_quadratic(
-                       vec_scalar_mul(ray->direction, ray->direction),
-                       2 * vec_scalar_mul(ray->direction, start),
-                       vec_scalar_mul(start, start) - sphere->radius * sphere->radius);
-       if (!isnan(intersection_args.first))
-               ft_vec_append(&res, &intersection_args.first);
-       if (!isnan(intersection_args.second))
-               ft_vec_append(&res, &intersection_args.second);
-       return (res);
-}
-
-t_vec  get_intersection_arg_bounded(const t_ray *ray, const t_object *object)
-{
-       t_vec   res;
-
-       if (object->type == SPHERE)
-               res = get_intersection_arg_sphere(ray, &object->object.sphere);
-       else if (object->type == CYLINDER)
-               res = get_intersection_arg_cylinder(ray, &object->object.cylinder);
-       else
-               ft_vec_init(&res, sizeof(double));
-       return (res);
-}
-
-t_vec  get_intersection_args(const t_ray *ray, const t_object *object)
+double get_self_obstruction_limit(const t_object *object)
 {
-       t_vec   res;
-
-       if (!is_bounded(object))
-               res = get_intersection_arg_nonbounded(ray, object);
-       else if (intersects_circumsphere(ray, object))
-               res = get_intersection_arg_bounded(ray, object);
-       else
-               ft_vec_init(&res, sizeof(double));
-       return (res);
+       return (get_circumsphere(object).radius * g_self_obstruction_multiplier);
 }
 
-double get_intersection_arg_min(const t_ray *ray, const t_object *object)
+void   update_nearest(t_obstruction *obstruction, t_vec *distances,
+                       t_object *object, const t_object *ignored)
 {
-       t_vec   args;
-       double  arg;
-       double  res;
-       size_t  i;
+       size_t  j;
+       double  ignored_dist;
+       double  distance;
 
-       args = get_intersection_args(ray, object);
-       res = INFINITY;
-       i = 0;
-       while (i < args.size)
+       if (ignored)
+               ignored_dist = get_self_obstruction_limit(ignored);
+       j = 0;
+       while (j < distances->size)
        {
-               arg = *(const double *)ft_vec_caccess(&args, i++);
-               if (arg > 0 && arg < res)
-                       res = arg;
+               distance = *(const double *)ft_vec_caccess(distances, j++);
+               if (object == ignored && distance > 0 && distance < ignored_dist)
+                       continue ;
+               if (0 < distance && distance < obstruction->distance)
+               {
+                       obstruction->distance = distance;
+                       obstruction->object = object;
+               }
        }
-       ft_vec_free(&args, NULL);
-       return (res);
-}
-
-double get_self_obstruction_limit(const t_object *object)
-{
-       return (get_circumsphere(object).radius * g_self_obstruction_multiplier);
 }
 
 t_obstruction  find_nearest_obstruction(const t_ray *ray, t_vec *objects,
                                        const t_object *ignored)
 {
        size_t                  i;
-       size_t                  j;
        t_obstruction   obstruction_found;
        t_object                *object;
-       double                  distance;
-       double                  ignored_dist;
        t_vec                   distances;
 
-       if (ignored)
-               ignored_dist = get_self_obstruction_limit(ignored);
        obstruction_found.object = NULL;
        obstruction_found.distance = INFINITY;
        i = 0;
@@ -315,126 +62,12 @@ t_obstruction     find_nearest_obstruction(const t_ray *ray, t_vec *objects,
        {
                object = ft_vec_access(objects, i++);
                distances = get_intersection_args(ray, object);
-               j = 0;
-               while (j < distances.size)
-               {
-                       distance = *(const double *)ft_vec_caccess(&distances, j++);
-                       if (object == ignored && distance > 0 && distance < ignored_dist)
-                               continue ;
-                       if (0 < distance && distance < obstruction_found.distance)
-                       {
-                               obstruction_found.distance = distance;
-                               obstruction_found.object = object;
-                       }
-               }
+               update_nearest(&obstruction_found, &distances, object, ignored);
                ft_vec_free(&distances, NULL);
        }
        return (obstruction_found);
 }
 
-t_color        get_ambient_color(const t_object *object, const t_ambient_light *amb)
-{
-       return (vec_real_mul(
-                       vec_elwise_mul(amb->color, object->object.plane.color),
-                       amb->brightness));
-}
-
-t_vec3 get_cylinder_normal(t_vec3 point, const t_cylinder *cylinder)
-{
-       t_vec3  radial_vec;
-       double  dist_from_round;
-       double  dist_from_top;
-       double  dist_from_bottom;
-       t_plane base;
-
-       radial_vec = vec_vec_mul(cylinder->rot_axis,
-                       vec_diff(point, cylinder->center));
-       radial_vec = vec_vec_mul(radial_vec, cylinder->rot_axis);
-       dist_from_round = fabs(vec_norm(radial_vec) - cylinder->radius);
-       base.normal = cylinder->rot_axis;
-       base.point = vec_add(cylinder->center,
-                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
-       dist_from_top = dist_point_from_plane(&base, point);
-       base.point = vec_diff(cylinder->center,
-                       vec_real_mul(cylinder->rot_axis, cylinder->height / 2));
-       dist_from_bottom = dist_point_from_plane(&base, point);
-       if (dist_from_round < dist_from_top && dist_from_round < dist_from_bottom)
-               return (radial_vec);
-       if (dist_from_top < dist_from_bottom)
-               return (cylinder->rot_axis);
-       return (vec_real_mul(cylinder->rot_axis, -1));
-}
-
-t_vec3 get_object_normal(const t_object *object, t_vec3 point)
-{
-       if (object->type == PLANE)
-               return (object->object.plane.normal);
-       if (object->type == SPHERE)
-               return (vec_diff(point, object->object.sphere.center));
-       if (object->type == CYLINDER)
-               return (get_cylinder_normal(point, &object->object.cylinder));
-       return ((t_vec3){.x = 0, .y = 0, .z = 0});
-}
-
-t_color        get_light_contribution(t_ray normal, const t_object *object,
-                       const t_light *light, t_scene *scene)
-{
-       t_ray                   new_ray;
-       t_obstruction   obstruction;
-       double                  angle_multiplier;
-       double                  distance;
-
-       new_ray.start = normal.start;
-       new_ray.direction = vec_diff(light->position, new_ray.start);
-       distance = vec_norm(new_ray.direction);
-       new_ray.direction = vec_real_mul(new_ray.direction, 1 / distance);
-       obstruction = find_nearest_obstruction(&new_ray, &scene->objects, object);
-       angle_multiplier = vec_scalar_mul(normal.direction, new_ray.direction)
-               / (vec_norm(normal.direction) * vec_norm(new_ray.direction));
-       if (object->type == PLANE)
-               angle_multiplier = fabs(angle_multiplier);
-       if (angle_multiplier > 0 && (!obstruction.object
-                       || distance < obstruction.distance
-                       ||obstruction.distance < 0))
-               return (vec_real_mul(
-                               vec_elwise_mul(light->color, object->object.plane.color),
-                               light->brightness * angle_multiplier / distance / distance));
-       else
-               return ((t_color){.x = 0, .y = 0, .z = 0});
-}
-
-t_color        get_object_color(const t_ray *ray, const t_object *object,
-                       t_scene *scene)
-{
-       t_color                 result;
-       t_ray                   normal_at_intersect;
-       const t_light   *light;
-       size_t                  i;
-
-       result = (t_color){.x = 0, .y = 0, .z = 0};
-       normal_at_intersect.start
-               = ray_point(ray, get_intersection_arg_min(ray, object));
-       normal_at_intersect.direction
-               = get_object_normal(object, normal_at_intersect.start);
-       if (vec_scalar_mul(normal_at_intersect.direction, ray->direction) > 0)
-               normal_at_intersect.direction
-                       = vec_real_mul(normal_at_intersect.direction, -1);
-       i = 0;
-       while (i < scene->lights.size)
-       {
-               light = &((const t_element *)
-                               ft_vec_caccess(&scene->lights, i))->object.light;
-               if (vec_scalar_mul(normal_at_intersect.direction,
-                               vec_diff(light->position, normal_at_intersect.start)) > 0)
-                       result = vec_add(result, get_light_contribution(
-                                               normal_at_intersect,
-                                               object, light, scene));
-               ++i;
-       }
-       result = vec_add(result, get_ambient_color(object, &scene->ambient_light));
-       return (result);
-}
-
 t_color        trace_ray(const t_ray *ray, t_scene *scene)
 {
        const t_object  *object_found;
diff --git a/src/scene_helpers.c b/src/scene_helpers.c
new file mode 100644 (file)
index 0000000..de8e950
--- /dev/null
@@ -0,0 +1,59 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   scene_helpers.c                                    :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 16:01:26 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 16:02:10 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+
+double dist_point_from_line(const t_ray *ray, t_vec3 point)
+{
+       t_vec3  start;
+       t_vec3  projection;
+
+       start = vec_diff(ray->start, point);
+       projection = vec_real_mul(ray->direction,
+                       vec_scalar_mul(ray->direction, start));
+       return (vec_norm(vec_diff(start, projection)));
+}
+
+double dist_point_from_plane(const t_plane *plane, t_vec3 point)
+{
+       return (fabs(vec_scalar_mul(plane->normal,
+                               vec_diff(point, plane->point))));
+}
+
+int    is_behind_ray(const t_ray *ray, t_vec3 point)
+{
+       return (0 > vec_scalar_mul(ray->direction, vec_diff(point, ray->start)));
+}
+
+t_vec3 ray_point(const t_ray *ray, double arg)
+{
+       return (vec_add(ray->start, vec_real_mul(ray->direction, arg)));
+}
+
+t_pair solve_quadratic(double a, double b, double c)
+{
+       t_pair  res;
+       double  det;
+
+       det = b * b - 4 * a * c;
+       if (det < 0)
+       {
+               res.first = NAN;
+               res.second = NAN;
+               return (res);
+       }
+       det = sqrt(det);
+       res.first = (-b - det) / (2 * a);
+       res.second = (-b + det) / (2 * a);
+       return (res);
+}
diff --git a/src/sphere.c b/src/sphere.c
new file mode 100644 (file)
index 0000000..a69f94b
--- /dev/null
@@ -0,0 +1,34 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   sphere.c                                           :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: ljiriste <ljiriste@student.42prague.com>   +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2025/01/14 15:49:12 by ljiriste          #+#    #+#             */
+/*   Updated: 2025/01/14 15:49:37 by ljiriste         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+#include "vec3.h"
+#include "miniRT.h"
+#include "libft.h"
+
+t_vec  get_intersection_arg_sphere(const t_ray *ray, const t_sphere *sphere)
+{
+       t_vec3  start;
+       t_pair  intersection_args;
+       t_vec   res;
+
+       ft_vec_init(&res, sizeof(double));
+       start = vec_diff(ray->start, sphere->center);
+       intersection_args = solve_quadratic(
+                       vec_scalar_mul(ray->direction, ray->direction),
+                       2 * vec_scalar_mul(ray->direction, start),
+                       vec_scalar_mul(start, start) - sphere->radius * sphere->radius);
+       if (!isnan(intersection_args.first))
+               ft_vec_append(&res, &intersection_args.first);
+       if (!isnan(intersection_args.second))
+               ft_vec_append(&res, &intersection_args.second);
+       return (res);
+}