summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-12-23 02:04:32 -0500
committerTavian Barnes <tavianator@gmail.com>2009-12-23 02:04:32 -0500
commita9ce26a1cd786690b4b8f4b54fc7077b3d3569e5 (patch)
tree1d6e3676224699d828180a15edbca8a3ed39d75a
parentff44d1b89812c1c7ef86c848937f17a59c64a66e (diff)
downloaddimension-a9ce26a1cd786690b4b8f4b54fc7077b3d3569e5.tar.xz
Separate finishes into single-purpose finishes.
-rw-r--r--dimension/realize.c18
-rw-r--r--libdimension/dimension/finishes.h11
-rw-r--r--libdimension/dimension/texture.h6
-rw-r--r--libdimension/finishes.c174
-rw-r--r--libdimension/raytrace.c8
-rw-r--r--libdimension/texture.c4
-rw-r--r--tests/libdimension/tests.c36
7 files changed, 218 insertions, 39 deletions
diff --git a/dimension/realize.c b/dimension/realize.c
index f795d0f..6ebcdd1 100644
--- a/dimension/realize.c
+++ b/dimension/realize.c
@@ -547,12 +547,26 @@ dmnsn_realize_astree(const dmnsn_astree *astree)
}
/* Default finish */
- scene->default_texture->finish = dmnsn_new_phong_finish(1.0, 0.0, 1.0);
+ dmnsn_finish *ambient = dmnsn_new_ambient_finish(
+ dmnsn_color_mul(0.1, dmnsn_white)
+ );
+ dmnsn_finish *diffuse = dmnsn_new_diffuse_finish(0.6);
+ if (!ambient || !diffuse) {
+ dmnsn_delete_finish(diffuse);
+ dmnsn_delete_finish(ambient);
+ dmnsn_delete_scene(scene);
+ return NULL;
+ }
+ scene->default_texture->finish = dmnsn_new_finish_combination(
+ ambient,
+ diffuse
+ );
if (!scene->default_texture->finish) {
+ dmnsn_delete_finish(diffuse);
+ dmnsn_delete_finish(ambient);
dmnsn_delete_scene(scene);
return NULL;
}
- scene->default_texture->finish->ambient = 0.1;
/* Background color */
scene->background = dmnsn_black;
diff --git a/libdimension/dimension/finishes.h b/libdimension/dimension/finishes.h
index e3d0597..b836e51 100644
--- a/libdimension/dimension/finishes.h
+++ b/libdimension/dimension/finishes.h
@@ -25,8 +25,13 @@
#ifndef DIMENSION_FINISHES_H
#define DIMENSION_FINISHES_H
-/* A phong finish */
-dmnsn_finish *dmnsn_new_phong_finish(double diffuse, double specular,
- double exp);
+/* Add two finishes */
+dmnsn_finish *dmnsn_new_finish_combination(dmnsn_finish *f1, dmnsn_finish *f2);
+
+dmnsn_finish *dmnsn_new_ambient_finish(dmnsn_color ambient);
+dmnsn_finish *dmnsn_new_diffuse_finish(double diffuse);
+
+/* A phong specular highlight */
+dmnsn_finish *dmnsn_new_phong_finish(double specular, double exp);
#endif /* DIMENSION_FINISHES_H */
diff --git a/libdimension/dimension/texture.h b/libdimension/dimension/texture.h
index e5a1bfd..c5f4b3f 100644
--- a/libdimension/dimension/texture.h
+++ b/libdimension/dimension/texture.h
@@ -61,14 +61,14 @@ typedef dmnsn_color dmnsn_finish_fn(const dmnsn_finish *finish,
dmnsn_color light, dmnsn_color color,
dmnsn_vector ray, dmnsn_vector normal,
dmnsn_vector viewer);
+typedef dmnsn_color dmnsn_ambient_fn(const dmnsn_finish *finish,
+ dmnsn_color pigment);
/* dmnsn_finish definition */
struct dmnsn_finish {
- /* Ambient contribution factor */
- double ambient;
-
/* Callbacks */
dmnsn_finish_fn *finish_fn;
+ dmnsn_ambient_fn *ambient_fn;
dmnsn_free_fn *free_fn;
/* Generic pointer */
diff --git a/libdimension/finishes.c b/libdimension/finishes.c
index a7cfaea..a8347bd 100644
--- a/libdimension/finishes.c
+++ b/libdimension/finishes.c
@@ -22,7 +22,151 @@
#include <stdlib.h> /* For malloc */
#include <math.h>
-dmnsn_color
+/*
+ * Finish combinations
+ */
+
+static dmnsn_color
+dmnsn_finish_combination_fn(const dmnsn_finish *finish,
+ dmnsn_color light, dmnsn_color color,
+ dmnsn_vector ray, dmnsn_vector normal,
+ dmnsn_vector viewer)
+{
+ dmnsn_finish **params = finish->ptr;
+ if (params[0]->finish_fn && params[1]->finish_fn) {
+ return dmnsn_color_add((*params[0]->finish_fn)(params[0], light, color, ray,
+ normal, viewer),
+ (*params[1]->finish_fn)(params[1], light, color, ray,
+ normal, viewer));
+ } else if (params[0]->finish_fn) {
+ return (*params[0]->finish_fn)(params[0], light, color, ray,
+ normal, viewer);
+ } else if (params[1]->finish_fn) {
+ return (*params[1]->finish_fn)(params[1], light, color, ray,
+ normal, viewer);
+ } else {
+ return dmnsn_black;
+ }
+}
+
+static dmnsn_color
+dmnsn_finish_combination_ambient_fn(const dmnsn_finish *finish,
+ dmnsn_color pigment)
+{
+ dmnsn_finish **params = finish->ptr;
+ if (params[0]->ambient_fn && params[1]->ambient_fn) {
+ return dmnsn_color_add((*params[0]->ambient_fn)(params[0], pigment),
+ (*params[1]->ambient_fn)(params[1], pigment));
+ } else if (params[0]->ambient_fn) {
+ return (*params[0]->ambient_fn)(params[0], pigment);
+ } else if (params[1]->ambient_fn) {
+ return (*params[1]->ambient_fn)(params[1], pigment);
+ } else {
+ return dmnsn_black;
+ }
+}
+
+static void
+dmnsn_finish_combination_free_fn(void *ptr)
+{
+ dmnsn_finish **params = ptr;
+ dmnsn_delete_finish(params[0]);
+ dmnsn_delete_finish(params[1]);
+ free(ptr);
+}
+
+dmnsn_finish *
+dmnsn_new_finish_combination(dmnsn_finish *f1, dmnsn_finish *f2)
+{
+ dmnsn_finish *finish = dmnsn_new_finish();
+ if (finish) {
+ dmnsn_finish **params = malloc(2*sizeof(dmnsn_finish *));
+ if (!params) {
+ dmnsn_delete_finish(finish);
+ return NULL;
+ }
+
+ params[0] = f1;
+ params[1] = f2;
+
+ finish->ptr = params;
+ finish->finish_fn = &dmnsn_finish_combination_fn;
+ finish->ambient_fn = &dmnsn_finish_combination_ambient_fn;
+ finish->free_fn = &dmnsn_finish_combination_free_fn;
+ }
+ return finish;
+}
+
+/*
+ * Ambient finish
+ */
+
+static dmnsn_color
+dmnsn_ambient_finish_fn(const dmnsn_finish *finish, dmnsn_color pigment)
+{
+ dmnsn_color *ambient = finish->ptr;
+ return dmnsn_color_illuminate(*ambient, pigment);
+}
+
+dmnsn_finish *
+dmnsn_new_ambient_finish(dmnsn_color ambient)
+{
+ dmnsn_finish *finish = dmnsn_new_finish();
+ if (finish) {
+ dmnsn_color *param = malloc(sizeof(dmnsn_color));
+ if (!param) {
+ dmnsn_delete_finish(finish);
+ return NULL;
+ }
+
+ *param = ambient;
+ finish->ptr = param;
+ finish->ambient_fn = &dmnsn_ambient_finish_fn;
+ finish->free_fn = &free;
+ }
+ return finish;
+}
+
+/*
+ * Diffuse finish
+ */
+
+static dmnsn_color
+dmnsn_diffuse_finish_fn(const dmnsn_finish *finish,
+ dmnsn_color light, dmnsn_color color,
+ dmnsn_vector ray, dmnsn_vector normal,
+ dmnsn_vector viewer)
+{
+ double *diffuse = finish->ptr;
+ double diffuse_factor = (*diffuse)*dmnsn_vector_dot(ray, normal);
+ return dmnsn_color_mul(diffuse_factor, dmnsn_color_illuminate(light, color));
+}
+
+dmnsn_finish *
+dmnsn_new_diffuse_finish(double diffuse)
+{
+ dmnsn_finish *finish = dmnsn_new_finish();
+ if (finish) {
+ double *param = malloc(sizeof(double));
+ if (!param) {
+ dmnsn_delete_finish(finish);
+ return NULL;
+ }
+
+ *param = diffuse;
+
+ finish->ptr = param;
+ finish->finish_fn = &dmnsn_diffuse_finish_fn;
+ finish->free_fn = &free;
+ }
+ return finish;
+}
+
+/*
+ * Phong finish
+ */
+
+static dmnsn_color
dmnsn_phong_finish_fn(const dmnsn_finish *finish,
dmnsn_color light, dmnsn_color color,
dmnsn_vector ray, dmnsn_vector normal,
@@ -30,42 +174,30 @@ dmnsn_phong_finish_fn(const dmnsn_finish *finish,
{
double *params = finish->ptr;
- double diffuse = params[0];
- double specular = params[1];
- double exp = params[2];
-
- /* Diffuse component */
- double diffuse_factor = diffuse*dmnsn_vector_dot(ray, normal);
- dmnsn_color diffuse_color
- = dmnsn_color_mul(diffuse_factor, dmnsn_color_illuminate(light, color));
-
- /* Specular component */
+ double specular = params[0];
+ double exp = params[1];
dmnsn_vector proj = dmnsn_vector_mul(2*dmnsn_vector_dot(ray, normal), normal);
dmnsn_vector reflected = dmnsn_vector_sub(proj, ray);
- double specular_factor
- = specular*pow(dmnsn_vector_dot(reflected, viewer), exp);
- dmnsn_color specular_color = dmnsn_color_mul(specular_factor, light);
-
- return dmnsn_color_add(diffuse_color, specular_color);
+ double specular_factor = pow(dmnsn_vector_dot(reflected, viewer), exp);
+ return dmnsn_color_mul(specular*specular_factor, light);
}
/* A phong finish */
dmnsn_finish *
-dmnsn_new_phong_finish(double diffuse, double specular, double exp)
+dmnsn_new_phong_finish(double specular, double exp)
{
dmnsn_finish *finish = dmnsn_new_finish();
if (finish) {
- double *params = malloc(3*sizeof(double));
+ double *params = malloc(2*sizeof(double));
if (!params) {
dmnsn_delete_finish(finish);
return NULL;
}
- params[0] = diffuse;
- params[1] = specular;
- params[2] = exp;
+ params[0] = specular;
+ params[1] = exp;
finish->ptr = params;
finish->finish_fn = &dmnsn_phong_finish_fn;
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 71e60cd..594149c 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -359,8 +359,8 @@ dmnsn_raytrace_lighting(dmnsn_intersection *intersection, dmnsn_scene *scene,
/* The illuminated color */
dmnsn_color illum = dmnsn_black;
- if (finish)
- illum = dmnsn_color_mul(finish->ambient, color);
+ if (finish && finish->ambient_fn)
+ illum = (*finish->ambient_fn)(finish, color);
dmnsn_vector x0 = dmnsn_line_point(intersection->ray, intersection->t);
@@ -375,7 +375,9 @@ dmnsn_raytrace_lighting(dmnsn_intersection *intersection, dmnsn_scene *scene,
if (dmnsn_raytrace_light_ray(intersection, scene, kD_splay_tree, light,
&light_color))
{
- if (scene->quality >= DMNSN_RENDER_FINISH && finish) {
+ if (scene->quality >= DMNSN_RENDER_FINISH
+ && finish && finish->finish_fn)
+ {
dmnsn_vector ray = dmnsn_vector_normalize(
dmnsn_vector_sub(light->x0, x0)
);
diff --git a/libdimension/texture.c b/libdimension/texture.c
index a9d7de1..5fdd708 100644
--- a/libdimension/texture.c
+++ b/libdimension/texture.c
@@ -50,7 +50,9 @@ dmnsn_new_finish()
{
dmnsn_finish *finish = malloc(sizeof(dmnsn_finish));
if (finish) {
- finish->free_fn = NULL;
+ finish->finish_fn = NULL;
+ finish->ambient_fn = NULL;
+ finish->free_fn = NULL;
}
return finish;
}
diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c
index f632aa1..bc98cd5 100644
--- a/tests/libdimension/tests.c
+++ b/tests/libdimension/tests.c
@@ -29,18 +29,42 @@ dmnsn_new_default_scene()
}
/* Default finish */
-
- scene->default_texture->finish = dmnsn_new_phong_finish(1.0, 0.5, 50.0);
+ dmnsn_finish *ambient = dmnsn_new_ambient_finish(
+ dmnsn_color_mul(0.1, dmnsn_white)
+ );
+ dmnsn_finish *diffuse = dmnsn_new_diffuse_finish(0.6);
+ dmnsn_finish *phong = dmnsn_new_phong_finish(0.2, 40.0);
+ if (!ambient || !diffuse || !phong) {
+ dmnsn_delete_finish(diffuse);
+ dmnsn_delete_finish(ambient);
+ dmnsn_delete_finish(phong);
+ dmnsn_delete_scene(scene);
+ return NULL;
+ }
+ dmnsn_finish *comb1 = dmnsn_new_finish_combination(
+ ambient,
+ diffuse
+ );
+ if (!comb1) {
+ dmnsn_delete_finish(diffuse);
+ dmnsn_delete_finish(ambient);
+ dmnsn_delete_finish(phong);
+ dmnsn_delete_scene(scene);
+ return NULL;
+ }
+ scene->default_texture->finish = dmnsn_new_finish_combination(
+ phong,
+ comb1
+ );
if (!scene->default_texture->finish) {
+ dmnsn_delete_finish(comb1);
+ dmnsn_delete_finish(phong);
dmnsn_delete_scene(scene);
return NULL;
}
- scene->default_texture->finish->ambient = 0.1;
-
/* Background color */
- dmnsn_sRGB sRGB = { .R = 0.0, .G = 0.0, .B = 0.1 };
- scene->background = dmnsn_color_from_sRGB(sRGB);
+ scene->background = dmnsn_color_mul(0.1, dmnsn_blue);
scene->background.filter = 0.1;
/* Allocate a canvas */