diff options
author | Tavian Barnes <tavianator@gmail.com> | 2009-12-23 02:04:32 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2009-12-23 02:04:32 -0500 |
commit | a9ce26a1cd786690b4b8f4b54fc7077b3d3569e5 (patch) | |
tree | 1d6e3676224699d828180a15edbca8a3ed39d75a | |
parent | ff44d1b89812c1c7ef86c848937f17a59c64a66e (diff) | |
download | dimension-a9ce26a1cd786690b4b8f4b54fc7077b3d3569e5.tar.xz |
Separate finishes into single-purpose finishes.
-rw-r--r-- | dimension/realize.c | 18 | ||||
-rw-r--r-- | libdimension/dimension/finishes.h | 11 | ||||
-rw-r--r-- | libdimension/dimension/texture.h | 6 | ||||
-rw-r--r-- | libdimension/finishes.c | 174 | ||||
-rw-r--r-- | libdimension/raytrace.c | 8 | ||||
-rw-r--r-- | libdimension/texture.c | 4 | ||||
-rw-r--r-- | tests/libdimension/tests.c | 36 |
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 */ |