summaryrefslogtreecommitdiffstats
path: root/libdimension
diff options
context:
space:
mode:
Diffstat (limited to 'libdimension')
-rw-r--r--libdimension/dimension/light.h35
-rw-r--r--libdimension/dimension/scene.h7
-rw-r--r--libdimension/light.c11
-rw-r--r--libdimension/point_light.c43
-rw-r--r--libdimension/raytrace.c28
-rw-r--r--libdimension/scene.c7
-rw-r--r--libdimension/tests/render.c2
7 files changed, 99 insertions, 34 deletions
diff --git a/libdimension/dimension/light.h b/libdimension/dimension/light.h
index 03de641..b41a524 100644
--- a/libdimension/dimension/light.h
+++ b/libdimension/dimension/light.h
@@ -23,27 +23,50 @@
* Lights.
*/
+#include <stdbool.h>
+
/* Forward-declar dmnsn_light */
typedef struct dmnsn_light dmnsn_light;
/**
- * Light callback.
+ * Light direction callback.
+ * @param[in] light The light itself.
+ * @param[in] v The point to illuminate.
+ * @return The direction of light rays pointing from \p v
+ */
+typedef dmnsn_line dmnsn_light_direction_fn(const dmnsn_light *light,
+ dmnsn_vector v);
+
+/**
+ * Light illumination callback.
* @param[in] light The light itself.
* @param[in] v The point to illuminate.
* @return The color of the light at \p v.
*/
-typedef dmnsn_color dmnsn_light_fn(const dmnsn_light *light, dmnsn_vector v);
+typedef dmnsn_color dmnsn_light_illumination_fn(const dmnsn_light *light,
+ dmnsn_vector v);
+
+/**
+ * Light shadow callback.
+ * @param[in] light The light itself.
+ * @param[in] t The line index of the closest shadow ray intersection.
+ * @return Whether the point is in shadow.
+ */
+typedef bool dmnsn_light_shadow_fn(const dmnsn_light *light, double t);
/** A light. */
struct dmnsn_light {
- dmnsn_vector x0; /**< Origin of light rays. */
-
/* Callbacks */
- dmnsn_light_fn *light_fn; /**< Light callback. */
- dmnsn_free_fn *free_fn; /**< Desctructor callback. */
+ dmnsn_light_direction_fn *direction_fn; /**< Direction callback. */
+ dmnsn_light_illumination_fn *illumination_fn; /**< Illumination callback. */
+ dmnsn_light_shadow_fn *shadow_fn; /**< Shadow callback. */
+ dmnsn_free_fn *free_fn; /**< Desctructor callback. */
/** Generic pointer for light info. */
void *ptr;
+
+ /** @internal Reference count. */
+ dmnsn_refcount refcount;
};
/**
diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h
index b726a77..bb47ee9 100644
--- a/libdimension/dimension/scene.h
+++ b/libdimension/dimension/scene.h
@@ -100,6 +100,13 @@ void dmnsn_initialize_scene(dmnsn_scene *scene);
void dmnsn_scene_set_canvas(dmnsn_scene *scene, dmnsn_canvas *canvas);
/**
+ * Add a light to a scene.
+ * @param[in,out] scene The scene to which to add the light.
+ * @param[in] object The object to light.
+ */
+void dmnsn_scene_add_light(dmnsn_scene *scene, dmnsn_light *light);
+
+/**
* Set the camera for a scene.
* @param[in,out] scene The scene for which to set the canvas.
* @param[in] camera The camera to set.
diff --git a/libdimension/light.c b/libdimension/light.c
index e1a060c..1103727 100644
--- a/libdimension/light.c
+++ b/libdimension/light.c
@@ -31,9 +31,12 @@ dmnsn_light *
dmnsn_new_light(void)
{
dmnsn_light *light = dmnsn_malloc(sizeof(dmnsn_light));
- light->light_fn = NULL;
- light->free_fn = NULL;
- light->ptr = NULL;
+ light->direction_fn = NULL;
+ light->illumination_fn = NULL;
+ light->shadow_fn = NULL;
+ light->free_fn = NULL;
+ light->ptr = NULL;
+ light->refcount = 0;
return light;
}
@@ -41,7 +44,7 @@ dmnsn_new_light(void)
void
dmnsn_delete_light(dmnsn_light *light)
{
- if (light) {
+ if (light && DMNSN_DECREF(light)) {
if (light->free_fn) {
light->free_fn(light->ptr);
}
diff --git a/libdimension/point_light.c b/libdimension/point_light.c
index 8617791..6ecaa24 100644
--- a/libdimension/point_light.c
+++ b/libdimension/point_light.c
@@ -26,11 +26,33 @@
#include "dimension.h"
#include <stdlib.h>
-/** Point light callback. */
+/** Point light payload type. */
+typedef struct dmnsn_point_light_payload {
+ dmnsn_vector origin;
+ dmnsn_color color;
+} dmnsn_point_light_payload;
+
+/** Point light direction callback. */
+static dmnsn_line
+dmnsn_point_light_direction_fn(const dmnsn_light *light, dmnsn_vector v)
+{
+ dmnsn_point_light_payload *payload = light->ptr;
+ return dmnsn_new_line(v, dmnsn_vector_sub(payload->origin, v));
+}
+
+/** Point light illumination callback. */
static dmnsn_color
-dmnsn_point_light_fn(const dmnsn_light *light, dmnsn_vector v)
+dmnsn_point_light_illumination_fn(const dmnsn_light *light, dmnsn_vector v)
+{
+ dmnsn_point_light_payload *payload = light->ptr;
+ return payload->color;
+}
+
+/** Point light illumination callback. */
+static bool
+dmnsn_point_light_shadow_fn(const dmnsn_light *light, double t)
{
- return *(dmnsn_color *)light->ptr;
+ return t < 1.0;
}
dmnsn_light *
@@ -38,13 +60,16 @@ dmnsn_new_point_light(dmnsn_vector x0, dmnsn_color color)
{
dmnsn_light *light = dmnsn_new_light();
- dmnsn_color *ptr = dmnsn_malloc(sizeof(dmnsn_color));
- *ptr = color;
+ dmnsn_point_light_payload *payload
+ = dmnsn_malloc(sizeof(dmnsn_point_light_payload));
+ payload->origin = x0;
+ payload->color = color;
+ light->ptr = payload;
- light->x0 = x0;
- light->light_fn = dmnsn_point_light_fn;
- light->free_fn = dmnsn_free;
- light->ptr = ptr;
+ light->direction_fn = dmnsn_point_light_direction_fn;
+ light->illumination_fn = dmnsn_point_light_illumination_fn;
+ light->shadow_fn = dmnsn_point_light_shadow_fn;
+ light->free_fn = dmnsn_free;
return light;
}
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index deb0080..e2fd61e 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -113,6 +113,7 @@ typedef struct dmnsn_raytrace_state {
unsigned int reclevel;
dmnsn_vector r;
+ dmnsn_vector light;
dmnsn_vector viewer;
dmnsn_vector reflected;
@@ -240,11 +241,11 @@ dmnsn_raytrace_pigment(dmnsn_raytrace_state *state)
/** Get the color of a light ray at an intersection point. */
static dmnsn_color
-dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state,
+dmnsn_raytrace_light_ray(dmnsn_raytrace_state *state,
const dmnsn_light *light)
{
- dmnsn_line shadow_ray = dmnsn_new_line(state->r,
- dmnsn_vector_sub(light->x0, state->r));
+ dmnsn_line shadow_ray = light->direction_fn(light, state->r);
+ state->light = dmnsn_vector_normalized(shadow_ray.n);
/* Add epsilon to avoid hitting ourselves with the shadow ray */
shadow_ray = dmnsn_line_add_epsilon(shadow_ray);
@@ -253,7 +254,7 @@ dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state,
* dmnsn_vector_dot(state->viewer, state->intersection->normal) < 0.0)
return dmnsn_black;
- dmnsn_color color = light->light_fn(light, state->r);
+ dmnsn_color color = light->illumination_fn(light, state->r);
unsigned int reclevel = state->reclevel;
while (reclevel > 0
@@ -263,7 +264,7 @@ dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state,
bool shadow_casted = dmnsn_prtree_intersection(state->prtree, shadow_ray,
&shadow_caster, false);
- if (!shadow_casted || shadow_caster.t > 1.0) {
+ if (!shadow_casted || !light->shadow_fn(light, shadow_caster.t)) {
break;
}
@@ -276,8 +277,10 @@ dmnsn_raytrace_light_ray(const dmnsn_raytrace_state *state,
&& shadow_state.pigment.trans >= dmnsn_epsilon)
{
color = dmnsn_filter_light(color, shadow_state.pigment);
- shadow_ray.x0 = dmnsn_line_point(shadow_ray, shadow_caster.t);
- shadow_ray.n = dmnsn_vector_sub(light->x0, shadow_ray.x0);
+ shadow_ray = light->direction_fn(
+ light,
+ dmnsn_line_point(shadow_ray, shadow_caster.t)
+ );
shadow_ray = dmnsn_line_add_epsilon(shadow_ray);
} else {
return dmnsn_black;
@@ -310,19 +313,16 @@ dmnsn_raytrace_lighting(dmnsn_raytrace_state *state)
dmnsn_color light_color = dmnsn_raytrace_light_ray(state, *light);
if (!dmnsn_color_is_black(light_color)) {
if (state->scene->quality & DMNSN_RENDER_FINISH) {
- dmnsn_vector ray = dmnsn_vector_normalized(
- dmnsn_vector_sub((*light)->x0, state->r)
- );
-
/* Get this light's color contribution to the object */
dmnsn_color diffuse = TEXTURE_CALLBACK(
state, finish, diffuse_fn, dmnsn_black,
- light_color, state->pigment, ray, state->intersection->normal
+ light_color, state->pigment, state->light,
+ state->intersection->normal
);
dmnsn_color specular = TEXTURE_CALLBACK(
state, finish, specular_fn, dmnsn_black,
- light_color, state->pigment, ray, state->intersection->normal,
- state->viewer
+ light_color, state->pigment, state->light,
+ state->intersection->normal, state->viewer
);
state->diffuse = dmnsn_color_add(diffuse, state->diffuse);
state->additional = dmnsn_color_add(specular, state->additional);
diff --git a/libdimension/scene.c b/libdimension/scene.c
index ec9fdbd..8462203 100644
--- a/libdimension/scene.c
+++ b/libdimension/scene.c
@@ -92,6 +92,13 @@ dmnsn_scene_set_canvas(dmnsn_scene *scene, dmnsn_canvas *canvas)
}
void
+dmnsn_scene_add_light(dmnsn_scene *scene, dmnsn_light *light)
+{
+ DMNSN_INCREF(light);
+ dmnsn_array_push(scene->lights, &light);
+}
+
+void
dmnsn_scene_set_camera(dmnsn_scene *scene, dmnsn_camera *camera)
{
DMNSN_INCREF(camera);
diff --git a/libdimension/tests/render.c b/libdimension/tests/render.c
index de5b6a4..85742d0 100644
--- a/libdimension/tests/render.c
+++ b/libdimension/tests/render.c
@@ -88,7 +88,7 @@ dmnsn_new_test_scene(void)
dmnsn_new_vector(-15.0, 20.0, 10.0),
dmnsn_white
);
- dmnsn_array_push(scene->lights, &light);
+ dmnsn_scene_add_light(scene, light);
/* Now make our objects */