summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libdimension/color.c56
-rw-r--r--libdimension/dimension/color.h6
-rw-r--r--libdimension/dimension/scene.h1
-rw-r--r--libdimension/raytrace.c66
-rw-r--r--tests/libdimension/tests.c2
5 files changed, 109 insertions, 22 deletions
diff --git a/libdimension/color.c b/libdimension/color.c
index 7fb73ed..374a0a0 100644
--- a/libdimension/color.c
+++ b/libdimension/color.c
@@ -263,17 +263,14 @@ dmnsn_sRGB_from_color(dmnsn_color color)
dmnsn_color
dmnsn_color_add(dmnsn_color color1, dmnsn_color color2)
{
- dmnsn_CIE_Lab Lab, Lab1, Lab2;
- dmnsn_color ret;
-
- Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint);
- Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint);
+ dmnsn_CIE_Lab Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint);
+ dmnsn_CIE_Lab Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint);
- Lab.L = Lab1.L + Lab2.L;
- Lab.a = Lab1.a + Lab2.a;
- Lab.b = Lab1.b + Lab2.b;
+ dmnsn_CIE_Lab Lab = { .L = Lab1.L + Lab2.L,
+ .a = Lab1.a + Lab2.a,
+ .b = Lab1.b + Lab2.b };
- ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint);
+ dmnsn_color ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint);
/* Weighted average of transparencies by intensity */
ret.filter = (Lab1.L*color1.filter + Lab2.L*color2.filter)/Lab.L;
ret.trans = (Lab1.L*color1.trans + Lab2.L*color2.trans)/Lab.L;
@@ -281,6 +278,47 @@ dmnsn_color_add(dmnsn_color color1, dmnsn_color color2)
return ret;
}
+/* Multiply a color by a scalar */
+dmnsn_color
+dmnsn_color_mul(double n, dmnsn_color color)
+{
+ dmnsn_CIE_Lab Lab = dmnsn_Lab_from_color(color, dmnsn_whitepoint);
+ double LabL = Lab.L;
+ Lab.L *= n;
+ Lab.a *= n;
+ Lab.b *= n;
+
+ dmnsn_color ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint);
+ ret.filter = color.filter;
+ ret.trans = color.trans;
+
+ return ret;
+}
+
+/* Illuminates `color' with `light' */
+dmnsn_color
+dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color)
+{
+ dmnsn_CIE_Lab Lab1 = dmnsn_Lab_from_color(light, dmnsn_whitepoint);
+ dmnsn_CIE_Lab Lab2 = dmnsn_Lab_from_color(color, dmnsn_whitepoint);
+
+ double dot = Lab1.L*Lab2.L + Lab1.a*Lab2.a + Lab1.b*Lab2.b;
+ double norm = sqrt(Lab2.L*Lab2.L + Lab2.a*Lab2.a + Lab2.b*Lab2.b);
+
+ if (norm == 0.0)
+ return dmnsn_black;
+
+ dmnsn_CIE_Lab Lab = { .L = dot*Lab2.L/norm/100.0,
+ .a = dot*Lab2.a/norm,
+ .b = dot*Lab2.b/norm };
+
+ dmnsn_color ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint);
+ ret.filter = color.filter;
+ ret.trans = color.trans;
+
+ return ret;
+}
+
/* Find the perceptual difference between two colors, using CIE L*a*b*. */
double
dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2)
diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h
index ab2ea04..a72de98 100644
--- a/libdimension/dimension/color.h
+++ b/libdimension/dimension/color.h
@@ -80,10 +80,10 @@ dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white);
dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white);
dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color);
-/* Perceptually correct color combination */
+/* Perceptual color manipulation */
dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2);
-
-/* Perceptual color difference */
+dmnsn_color dmnsn_color_mul(double n, dmnsn_color color);
+dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color);
double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2);
#endif /* DIMENSION_COLOR_H */
diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h
index 8c9c705..e3f9662 100644
--- a/libdimension/dimension/scene.h
+++ b/libdimension/dimension/scene.h
@@ -29,6 +29,7 @@ typedef enum {
DMNSN_RENDER_NONE,
DMNSN_RENDER_OBJECTS,
DMNSN_RENDER_PIGMENT,
+ DMNSN_RENDER_LIGHTS,
DMNSN_RENDER_FULL
} dmnsn_quality;
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 6cb6d8b..da78411 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -259,11 +259,7 @@ static dmnsn_color
dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
dmnsn_kD_splay_tree *kD_splay_tree, dmnsn_color color)
{
- dmnsn_intersection *intersection;
- const dmnsn_texture *texture;
- const dmnsn_pigment *pigment;
-
- intersection = dmnsn_kD_splay_search(kD_splay_tree, ray);
+ dmnsn_intersection *intersection = dmnsn_kD_splay_search(kD_splay_tree, ray);
if (intersection) {
/* Default to black if we have no texture/pigment */
@@ -271,13 +267,15 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
if (scene->quality >= DMNSN_RENDER_PIGMENT) {
/* Use the default texture if given a NULL texture */
- texture = intersection->texture ? intersection->texture
- : scene->default_texture;
+ const dmnsn_texture *texture
+ = intersection->texture ? intersection->texture
+ : scene->default_texture;
if (texture) {
/* Use the default pigment if given a NULL pigment */
- pigment = texture->pigment ? texture->pigment
- : scene->default_texture->pigment;
+ const dmnsn_pigment *pigment
+ = texture->pigment ? texture->pigment
+ : scene->default_texture->pigment;
if (pigment) {
color = (*pigment->pigment_fn)(
@@ -288,6 +286,56 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene,
}
}
+ if (scene->quality >= DMNSN_RENDER_LIGHTS) {
+ dmnsn_color illum = dmnsn_color_mul(0.3, color);
+
+ const dmnsn_light *light;
+ unsigned int i;
+
+ for (i = 0; i < dmnsn_array_size(scene->lights); ++i) {
+ dmnsn_array_get(scene->lights, i, &light);
+ dmnsn_vector x0 = dmnsn_line_point(ray, intersection->t);
+ dmnsn_line shadow_ray = dmnsn_line_construct(
+ dmnsn_vector_add(
+ x0,
+ dmnsn_vector_mul(1.0e-6, dmnsn_vector_sub(light->x0, x0))
+ ),
+ dmnsn_vector_sub(light->x0, x0)
+ );
+
+ dmnsn_intersection *shadow_caster
+ = dmnsn_kD_splay_search(kD_splay_tree, shadow_ray);
+
+ if (!shadow_caster || shadow_caster->t > 1.0) {
+ dmnsn_vector object_normal = x0;
+ dmnsn_vector normal = dmnsn_vector_normalize(
+ dmnsn_vector_add(
+ dmnsn_vector_normalize(dmnsn_vector_sub(ray.x0, x0)),
+ dmnsn_vector_normalize(dmnsn_vector_sub(light->x0, x0))
+ )
+ );
+
+ illum = dmnsn_color_add(
+ dmnsn_color_mul(
+ dmnsn_vector_dot(normal, object_normal),
+ dmnsn_color_illuminate((*light->light_fn)(light, x0), color)
+ ),
+ illum
+ );
+ illum = dmnsn_color_add(
+ dmnsn_color_mul(
+ 0.1*dmnsn_vector_dot(normal, object_normal),
+ dmnsn_color_illuminate((*light->light_fn)(light, x0), dmnsn_white)
+ ),
+ illum
+ );
+ }
+
+ dmnsn_delete_intersection(shadow_caster);
+ color = illum;
+ }
+ }
+
/* Delete the intersection */
dmnsn_delete_intersection(intersection);
}
diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c
index 5a0b4cf..1257219 100644
--- a/tests/libdimension/tests.c
+++ b/tests/libdimension/tests.c
@@ -116,7 +116,7 @@ dmnsn_new_default_scene()
/* Now make a light */
dmnsn_light *light = dmnsn_new_point_light(
- dmnsn_vector_construct(0.0, 3.0, 0.0),
+ dmnsn_vector_construct(-5.0, 20.0, -5.0),
dmnsn_white
);
if (!light) {