From 7acd8ea6673b7a90ed4041408ccf1b024b8a007a Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Sun, 12 Jun 2011 02:37:51 -0600 Subject: Vast libdimension API and internals improvements. Couldn't really do these while I was trying to be POV-Ray compatible, 'cause they would've broken compatibility. --- libdimension/Makefile.am | 5 +- libdimension/ambient.c | 21 +++-- libdimension/bench/prtree.c | 12 +-- libdimension/camera.c | 4 +- libdimension/canvas.c | 4 +- libdimension/canvas_pigment.c | 2 - libdimension/color_map.c | 2 - libdimension/csg.c | 124 +++++++--------------------- libdimension/diffuse.c | 58 ------------- libdimension/dimension/finish.h | 158 ++++++++++++++++++++++++++---------- libdimension/dimension/finishes.h | 28 +++---- libdimension/dimension/interior.h | 8 ++ libdimension/dimension/object.h | 15 ++-- libdimension/dimension/pattern.h | 2 + libdimension/dimension/pigment.h | 12 +++ libdimension/dimension/refcount.h | 5 +- libdimension/dimension/scene.h | 44 ++-------- libdimension/dimension/sky_sphere.h | 5 +- libdimension/dimension/texture.h | 12 ++- libdimension/finish.c | 130 +++++++++++++++++++++++++---- libdimension/finish_combination.c | 150 ---------------------------------- libdimension/interior.c | 15 +++- libdimension/lambertian.c | 58 +++++++++++++ libdimension/light.c | 4 +- libdimension/object.c | 38 +++++---- libdimension/pattern.c | 13 +-- libdimension/phong.c | 24 +++--- libdimension/pigment.c | 15 +++- libdimension/pigment_map.c | 6 +- libdimension/prtree.c | 6 +- libdimension/raytrace.c | 114 +++++++++----------------- libdimension/reflection.c | 67 +++++++++++++++ libdimension/reflective.c | 67 --------------- libdimension/scene.c | 70 ++++++---------- libdimension/sky_sphere.c | 12 ++- libdimension/tests/prtree.c | 13 +-- libdimension/tests/render.c | 52 +++++++----- libdimension/texture.c | 38 +++++++-- 38 files changed, 685 insertions(+), 728 deletions(-) delete mode 100644 libdimension/diffuse.c delete mode 100644 libdimension/finish_combination.c create mode 100644 libdimension/lambertian.c create mode 100644 libdimension/reflection.c delete mode 100644 libdimension/reflective.c (limited to 'libdimension') diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am index 83e6f62..0f3dee5 100644 --- a/libdimension/Makefile.am +++ b/libdimension/Makefile.am @@ -74,15 +74,14 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \ cube.c \ csg.c \ dictionary.c \ - diffuse.c \ dimension-impl.h \ error.c \ finish.c \ - finish_combination.c \ geometry.c \ gradient.c \ inline.c \ interior.c \ + lambertian.c \ light.c \ malloc.c \ map.c \ @@ -103,7 +102,7 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \ prtree.c \ prtree.h \ raytrace.c \ - reflective.c \ + reflection.c \ scene.c \ sky_sphere.c \ solid_pigment.c \ diff --git a/libdimension/ambient.c b/libdimension/ambient.c index 180889b..5152f1d 100644 --- a/libdimension/ambient.c +++ b/libdimension/ambient.c @@ -29,26 +29,25 @@ /** Ambient finish callback. */ static dmnsn_color -dmnsn_ambient_finish_fn(const dmnsn_finish *finish, dmnsn_color pigment) +dmnsn_basic_ambient_fn(const dmnsn_ambient *ambient, dmnsn_color pigment) { - dmnsn_color *ambient = finish->ptr; - dmnsn_color ret = dmnsn_color_illuminate(*ambient, pigment); + dmnsn_color *light = ambient->ptr; + dmnsn_color ret = dmnsn_color_illuminate(*light, pigment); ret.trans = 0.0; ret.filter = 0.0; return ret; } -dmnsn_finish * -dmnsn_new_ambient_finish(dmnsn_color ambient) +dmnsn_ambient * +dmnsn_new_basic_ambient(dmnsn_color ambient) { - dmnsn_finish *finish = dmnsn_new_finish(); + dmnsn_ambient *basic = dmnsn_new_ambient(); dmnsn_color *param = dmnsn_malloc(sizeof(dmnsn_color)); *param = ambient; - finish->ptr = param; - finish->ambient_fn = dmnsn_ambient_finish_fn; - finish->free_fn = dmnsn_free; - - return finish; + basic->ambient_fn = dmnsn_basic_ambient_fn; + basic->free_fn = dmnsn_free; + basic->ptr = param; + return basic; } diff --git a/libdimension/bench/prtree.c b/libdimension/bench/prtree.c index b6f778a..05fc1ce 100644 --- a/libdimension/bench/prtree.c +++ b/libdimension/bench/prtree.c @@ -76,8 +76,12 @@ main(void) } dmnsn_array *objects = dmnsn_new_array(sizeof(dmnsn_object *)); + dmnsn_texture *texture = dmnsn_new_texture(); + texture->pigment = dmnsn_new_pigment(); for (size_t i = 0; i < nobjects; ++i) { dmnsn_object *object = dmnsn_new_fake_object(); + object->texture = texture; + DMNSN_INCREF(object->texture); dmnsn_initialize_object(object); dmnsn_array_push(objects, &object); } @@ -108,12 +112,10 @@ main(void) /* Cleanup */ dmnsn_delete_prtree(tree); - for (size_t i = 0; i < nobjects; ++i) { - dmnsn_object *object; - dmnsn_array_get(objects, i, &object); - dmnsn_delete_object(object); + DMNSN_ARRAY_FOREACH (dmnsn_object **, object, objects) { + dmnsn_delete_object(*object); } - + dmnsn_delete_texture(texture); dmnsn_delete_array(objects); return EXIT_SUCCESS; } diff --git a/libdimension/camera.c b/libdimension/camera.c index 935a129..5c8a2c6 100644 --- a/libdimension/camera.c +++ b/libdimension/camera.c @@ -33,7 +33,7 @@ dmnsn_new_camera(void) dmnsn_camera *camera = dmnsn_malloc(sizeof(dmnsn_camera)); camera->free_fn = NULL; camera->trans = dmnsn_identity_matrix(); - camera->refcount = 0; + camera->refcount = 1; return camera; } @@ -41,7 +41,7 @@ dmnsn_new_camera(void) void dmnsn_delete_camera(dmnsn_camera *camera) { - if (camera && DMNSN_DECREF(camera)) { + if (DMNSN_DECREF(camera)) { if (camera->free_fn) { camera->free_fn(camera->ptr); } diff --git a/libdimension/canvas.c b/libdimension/canvas.c index 6df5dd3..9eef4e7 100644 --- a/libdimension/canvas.c +++ b/libdimension/canvas.c @@ -36,7 +36,7 @@ dmnsn_new_canvas(size_t width, size_t height) canvas->height = height; canvas->optimizers = dmnsn_new_array(sizeof(dmnsn_canvas_optimizer)); canvas->pixels = dmnsn_malloc(sizeof(dmnsn_color)*width*height); - canvas->refcount = 0; + canvas->refcount = 1; return canvas; } @@ -45,7 +45,7 @@ dmnsn_new_canvas(size_t width, size_t height) void dmnsn_delete_canvas(dmnsn_canvas *canvas) { - if (canvas && DMNSN_DECREF(canvas)) { + if (DMNSN_DECREF(canvas)) { /* Free the optimizers */ DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) { if (i->free_fn) { diff --git a/libdimension/canvas_pigment.c b/libdimension/canvas_pigment.c index 002cea3..3ab9de4 100644 --- a/libdimension/canvas_pigment.c +++ b/libdimension/canvas_pigment.c @@ -29,8 +29,6 @@ static dmnsn_color dmnsn_canvas_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) { - v = dmnsn_transform_vector(pigment->trans_inv, v); - dmnsn_canvas *canvas = pigment->ptr; int x = (fmod(v.x, 1.0) + 1.0)*(canvas->width - 1) + 0.5; diff --git a/libdimension/color_map.c b/libdimension/color_map.c index e7a25a6..654fe97 100644 --- a/libdimension/color_map.c +++ b/libdimension/color_map.c @@ -75,8 +75,6 @@ static void dmnsn_color_map_initialize_fn(dmnsn_pigment *pigment) { dmnsn_color_map_payload *payload = pigment->ptr; - payload->pattern->trans = dmnsn_matrix_mul(pigment->trans, - payload->pattern->trans); dmnsn_initialize_pattern(payload->pattern); } diff --git a/libdimension/csg.c b/libdimension/csg.c index 0222b8b..1b2e36f 100644 --- a/libdimension/csg.c +++ b/libdimension/csg.c @@ -26,21 +26,6 @@ #include "dimension-impl.h" #include -/** Apply the properties of \p csg to its children. */ -static void -dmnsn_csg_cascade(const dmnsn_object *csg, dmnsn_object *object) -{ - if (!object->texture && csg->texture) { - object->texture = csg->texture; - } - - if (!object->interior && csg->interior) { - object->interior = csg->interior; - } - - object->trans = dmnsn_matrix_mul(csg->trans, object->trans); -} - /* * Unions */ @@ -67,10 +52,6 @@ dmnsn_csg_union_inside_fn(const dmnsn_object *csg, dmnsn_vector point) static void dmnsn_csg_union_initialize_fn(dmnsn_object *csg) { - DMNSN_ARRAY_FOREACH (dmnsn_object **, child, csg->children) { - dmnsn_csg_cascade(csg, *child); - dmnsn_initialize_object(*child); - } csg->trans = dmnsn_identity_matrix(); dmnsn_prtree *prtree = dmnsn_new_prtree(csg->children); @@ -92,10 +73,9 @@ dmnsn_new_csg_union(const dmnsn_array *objects) dmnsn_object *csg = dmnsn_new_object(); DMNSN_ARRAY_FOREACH (dmnsn_object **, object, objects) { - DMNSN_INCREF(*object); dmnsn_array_push(csg->children, object); } - + csg->split_children = true; csg->ptr = NULL; csg->intersection_fn = dmnsn_csg_union_intersection_fn; csg->inside_fn = dmnsn_csg_union_inside_fn; @@ -105,16 +85,6 @@ dmnsn_new_csg_union(const dmnsn_array *objects) return csg; } -/** Generic CSG destruction callback. */ -static void -dmnsn_csg_free_fn(void *ptr) -{ - dmnsn_object **params = ptr; - dmnsn_delete_object(params[1]); - dmnsn_delete_object(params[0]); - dmnsn_free(ptr); -} - /** * Generic CSG intersection callback. * @param[in] csg The CSG object. @@ -131,11 +101,12 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, dmnsn_intersection *intersection, bool inside1, bool inside2) { - const dmnsn_object **params = csg->ptr; + const dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); + const dmnsn_object *B = *(dmnsn_object **)dmnsn_array_last(csg->children); dmnsn_intersection i1, i2; - bool is_i1 = dmnsn_object_intersection(params[0], line, &i1); - bool is_i2 = dmnsn_object_intersection(params[1], line, &i2); + bool is_i1 = dmnsn_object_intersection(A, line, &i1); + bool is_i2 = dmnsn_object_intersection(B, line, &i2); double oldt = 0.0; while (is_i1) { @@ -144,11 +115,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, oldt = i1.t + dmnsn_epsilon; dmnsn_vector point = dmnsn_line_point(i1.ray, i1.t); - if (inside2 ^ dmnsn_object_inside(params[1], point)) { + if (inside2 ^ dmnsn_object_inside(B, point)) { dmnsn_line newline = line; newline.x0 = dmnsn_line_point(line, i1.t); newline = dmnsn_line_add_epsilon(newline); - is_i1 = dmnsn_object_intersection(params[0], newline, &i1); + is_i1 = dmnsn_object_intersection(A, newline, &i1); } else { break; } @@ -161,11 +132,11 @@ dmnsn_csg_intersection_fn(const dmnsn_object *csg, dmnsn_line line, oldt = i2.t + dmnsn_epsilon; dmnsn_vector point = dmnsn_line_point(i2.ray, i2.t); - if (inside1 ^ dmnsn_object_inside(params[0], point)) { + if (inside1 ^ dmnsn_object_inside(A, point)) { dmnsn_line newline = line; newline.x0 = dmnsn_line_point(line, i2.t); newline = dmnsn_line_add_epsilon(newline); - is_i2 = dmnsn_object_intersection(params[1], newline, &i2); + is_i2 = dmnsn_object_intersection(B, newline, &i2); } else { break; } @@ -205,24 +176,17 @@ dmnsn_csg_intersection_intersection_fn(const dmnsn_object *csg, static bool dmnsn_csg_intersection_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { - dmnsn_object **params = csg->ptr; - return dmnsn_object_inside(params[0], point) - && dmnsn_object_inside(params[1], point); + const dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); + const dmnsn_object *B = *(dmnsn_object **)dmnsn_array_last(csg->children); + return dmnsn_object_inside(A, point) && dmnsn_object_inside(B, point); } /** CSG intersection initialization callback. */ static void dmnsn_csg_intersection_initialize_fn(dmnsn_object *csg) { - dmnsn_object **params = csg->ptr; - dmnsn_object *A = params[0]; - dmnsn_object *B = params[1]; - - dmnsn_csg_cascade(csg, A); - dmnsn_csg_cascade(csg, B); - - dmnsn_initialize_object(A); - dmnsn_initialize_object(B); + dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); + dmnsn_object *B = *(dmnsn_object **)dmnsn_array_last(csg->children); csg->trans = dmnsn_identity_matrix(); csg->bounding_box.min @@ -236,17 +200,12 @@ dmnsn_new_csg_intersection(dmnsn_object *A, dmnsn_object *B) { dmnsn_object *csg = dmnsn_new_object(); - DMNSN_INCREF(A); - DMNSN_INCREF(B); - dmnsn_object **params = dmnsn_malloc(2*sizeof(dmnsn_object *)); - params[0] = A; - params[1] = B; + dmnsn_array_push(csg->children, &A); + dmnsn_array_push(csg->children, &B); - csg->ptr = params; csg->intersection_fn = dmnsn_csg_intersection_intersection_fn; csg->inside_fn = dmnsn_csg_intersection_inside_fn; csg->initialize_fn = dmnsn_csg_intersection_initialize_fn; - csg->free_fn = dmnsn_csg_free_fn; return csg; } @@ -268,24 +227,16 @@ dmnsn_csg_difference_intersection_fn(const dmnsn_object *csg, static bool dmnsn_csg_difference_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { - dmnsn_object **params = csg->ptr; - return dmnsn_object_inside(params[0], point) - && !dmnsn_object_inside(params[1], point); + const dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); + const dmnsn_object *B = *(dmnsn_object **)dmnsn_array_last(csg->children); + return dmnsn_object_inside(A, point) && !dmnsn_object_inside(B, point); } /** CSG difference initialization callback. */ static void dmnsn_csg_difference_initialize_fn(dmnsn_object *csg) { - dmnsn_object **params = csg->ptr; - dmnsn_object *A = params[0]; - dmnsn_object *B = params[1]; - - dmnsn_csg_cascade(csg, A); - dmnsn_csg_cascade(csg, B); - - dmnsn_initialize_object(A); - dmnsn_initialize_object(B); + dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); csg->trans = dmnsn_identity_matrix(); csg->bounding_box = A->bounding_box; @@ -296,17 +247,12 @@ dmnsn_new_csg_difference(dmnsn_object *A, dmnsn_object *B) { dmnsn_object *csg = dmnsn_new_object(); - DMNSN_INCREF(A); - DMNSN_INCREF(B); - dmnsn_object **params = dmnsn_malloc(2*sizeof(dmnsn_object *)); - params[0] = A; - params[1] = B; + dmnsn_array_push(csg->children, &A); + dmnsn_array_push(csg->children, &B); - csg->ptr = params; csg->intersection_fn = dmnsn_csg_difference_intersection_fn; csg->inside_fn = dmnsn_csg_difference_inside_fn; csg->initialize_fn = dmnsn_csg_difference_initialize_fn; - csg->free_fn = dmnsn_csg_free_fn; return csg; } @@ -328,24 +274,17 @@ dmnsn_csg_merge_intersection_fn(const dmnsn_object *csg, static bool dmnsn_csg_merge_inside_fn(const dmnsn_object *csg, dmnsn_vector point) { - dmnsn_object **params = csg->ptr; - return dmnsn_object_inside(params[0], point) - || dmnsn_object_inside(params[1], point); + const dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); + const dmnsn_object *B = *(dmnsn_object **)dmnsn_array_last(csg->children); + return dmnsn_object_inside(A, point) || dmnsn_object_inside(B, point); } /** CSG merge initialization callback. */ static void dmnsn_csg_merge_initialize_fn(dmnsn_object *csg) { - dmnsn_object **params = csg->ptr; - dmnsn_object *A = params[0]; - dmnsn_object *B = params[1]; - - dmnsn_csg_cascade(csg, A); - dmnsn_csg_cascade(csg, B); - - dmnsn_initialize_object(A); - dmnsn_initialize_object(B); + dmnsn_object *A = *(dmnsn_object **)dmnsn_array_first(csg->children); + dmnsn_object *B = *(dmnsn_object **)dmnsn_array_last(csg->children); csg->trans = dmnsn_identity_matrix(); csg->bounding_box.min @@ -359,17 +298,12 @@ dmnsn_new_csg_merge(dmnsn_object *A, dmnsn_object *B) { dmnsn_object *csg = dmnsn_new_object(); - DMNSN_INCREF(A); - DMNSN_INCREF(B); - dmnsn_object **params = dmnsn_malloc(2*sizeof(dmnsn_object *)); - params[0] = A; - params[1] = B; + dmnsn_array_push(csg->children, &A); + dmnsn_array_push(csg->children, &B); - csg->ptr = params; csg->intersection_fn = dmnsn_csg_merge_intersection_fn; csg->inside_fn = dmnsn_csg_merge_inside_fn; csg->initialize_fn = dmnsn_csg_merge_initialize_fn; - csg->free_fn = dmnsn_csg_free_fn; return csg; } diff --git a/libdimension/diffuse.c b/libdimension/diffuse.c deleted file mode 100644 index fae8e74..0000000 --- a/libdimension/diffuse.c +++ /dev/null @@ -1,58 +0,0 @@ -/************************************************************************* - * Copyright (C) 2010 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -/** - * @file - * Diffuse finish. - */ - -#include "dimension.h" -#include -#include - -/** Diffuse finish callback. */ -static dmnsn_color -dmnsn_diffuse_finish_fn(const dmnsn_finish *finish, - dmnsn_color light, dmnsn_color color, - dmnsn_vector ray, dmnsn_vector normal) -{ - double *diffuse = finish->ptr; - double diffuse_factor = fabs((*diffuse)*dmnsn_vector_dot(ray, normal)); - dmnsn_color ret - = dmnsn_color_mul(diffuse_factor, dmnsn_color_illuminate(light, color)); - ret.filter = 0.0; - ret.trans = 0.0; - return ret; -} - -dmnsn_finish * -dmnsn_new_diffuse_finish(double diffuse) -{ - dmnsn_finish *finish = dmnsn_new_finish(); - - double *param = dmnsn_malloc(sizeof(double)); - *param = diffuse; - - finish->ptr = param; - finish->diffuse_fn = dmnsn_diffuse_finish_fn; - finish->free_fn = dmnsn_free; - - return finish; -} diff --git a/libdimension/dimension/finish.h b/libdimension/dimension/finish.h index f2b1df7..a163496 100644 --- a/libdimension/dimension/finish.h +++ b/libdimension/dimension/finish.h @@ -23,76 +23,148 @@ * Object finishes. */ -/* Forward-declare dmnsn_finish */ -typedef struct dmnsn_finish dmnsn_finish; +/* Ambient component */ + +typedef struct dmnsn_ambient dmnsn_ambient; + +/** + * Ambient light callback. + * @param[in] ambient The ambient object itself. + * @param[in] pigment The pigment of the object. + * @return The ambient contribution to the object's color. + */ +typedef dmnsn_color dmnsn_ambient_fn(const dmnsn_ambient *ambient, + dmnsn_color pigment); + +struct dmnsn_ambient { + dmnsn_ambient_fn *ambient_fn; /**< Ambient callback. */ + dmnsn_free_fn *free_fn; /**< Destructor callback. */ + void *ptr; /**< Generic data pointer. */ + dmnsn_refcount refcount; /**< @internal Reference count. */ +}; + +/** Allocate a dummy ambient component. */ +dmnsn_ambient *dmnsn_new_ambient(void); +/** Delete an ambient component. */ +void dmnsn_delete_ambient(dmnsn_ambient *ambient); + +/* Diffuse component */ + +typedef struct dmnsn_diffuse dmnsn_diffuse; /** * Diffuse reflection callback. - * @param[in] finish The finish itself. - * @param[in] light The color of the light illuminating the object. - * @param[in] color The pigment of the object. - * @param[in] ray The direction of the light source. - * @param[in] normal The normal vector of the surface. + * @param[in] diffuse The diffuse object itself. + * @param[in] light The color of the light illuminating the object. + * @param[in] color The pigment of the object. + * @param[in] ray The direction of the light source. + * @param[in] normal The normal vector of the surface. * @return The diffuse reflection component of the object's color. */ -typedef dmnsn_color dmnsn_diffuse_fn(const dmnsn_finish *finish, +typedef dmnsn_color dmnsn_diffuse_fn(const dmnsn_diffuse *diffuse, dmnsn_color light, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal); + +/** Diffuse finish component. */ +struct dmnsn_diffuse { + dmnsn_diffuse_fn *diffuse_fn; /**< Diffuse callback. */ + dmnsn_free_fn *free_fn; /**< Destructor callback. */ + void *ptr; /**< Generic data pointer. */ + dmnsn_refcount refcount; /**< @internal Reference count. */ +}; + +/** Allocate a dummy diffuse component. */ +dmnsn_diffuse *dmnsn_new_diffuse(void); +/** Delete a diffuse component. */ +void dmnsn_delete_diffuse(dmnsn_diffuse *diffuse); + +/* Specular component */ + +typedef struct dmnsn_specular dmnsn_specular; + /** * Specular highlight callback. - * @param[in] finish The finish itself. - * @param[in] light The color of the light illuminating the object. - * @param[in] color The pigment of the object. - * @param[in] ray The direction of the light source. - * @param[in] normal The normal vector of the surface. - * @param[in] viewer The direction of the viewer. + * @param[in] specular The specular object itself. + * @param[in] light The color of the light illuminating the object. + * @param[in] color The pigment of the object. + * @param[in] ray The direction of the light source. + * @param[in] normal The normal vector of the surface. + * @param[in] viewer The direction of the viewer. * @return The specular reflection component of the object's color. */ -typedef dmnsn_color dmnsn_specular_fn(const dmnsn_finish *finish, +typedef dmnsn_color dmnsn_specular_fn(const dmnsn_specular *specular, dmnsn_color light, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal, dmnsn_vector viewer); -/** - * Ambient light callback. - * @param[in] finish The finish itself. - * @param[in] pigment The pigment of the object. - * @return The ambient contribution to the object's color. - */ -typedef dmnsn_color dmnsn_ambient_fn(const dmnsn_finish *finish, - dmnsn_color pigment); + +struct dmnsn_specular { + dmnsn_specular_fn *specular_fn; /**< Specular callback. */ + dmnsn_free_fn *free_fn; /**< Destructor callback. */ + void *ptr; /**< Generic data pointer. */ + dmnsn_refcount refcount; /**< @internal Reference count. */ +}; + +/** Allocate a dummy specular component. */ +dmnsn_specular *dmnsn_new_specular(void); +/** Delete a specular component. */ +void dmnsn_delete_specular(dmnsn_specular *specular); + +/* Reflection component */ + +typedef struct dmnsn_reflection dmnsn_reflection; + /** * Reflected light callback. - * @param[in] finish The finish itself. - * @param[in] reflect The color of the reflected ray. - * @param[in] color The pigment of the object. - * @param[in] ray The direction of the reflected ray. - * @param[in] normal The normal vector of the surface. + * @param[in] reflection The reflection object itself. + * @param[in] reflect The color of the reflected ray. + * @param[in] color The pigment of the object. + * @param[in] ray The direction of the reflected ray. + * @param[in] normal The normal vector of the surface. * @return The contribution of the reflected ray to the object's color. */ -typedef dmnsn_color dmnsn_reflection_fn(const dmnsn_finish *finish, +typedef dmnsn_color dmnsn_reflection_fn(const dmnsn_reflection *reflection, dmnsn_color reflect, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal); -/** A finish. */ -struct dmnsn_finish { - dmnsn_diffuse_fn *diffuse_fn; /**< The diffuse callback. */ - dmnsn_specular_fn *specular_fn; /**< The specular callback. */ - dmnsn_ambient_fn *ambient_fn; /**< The ambient callback. */ - dmnsn_reflection_fn *reflection_fn; /**< The reflection callback. */ - dmnsn_free_fn *free_fn; /**< The destruction callback. */ - - /** Generic pointer. */ - void *ptr; +/** The reflection component. */ +struct dmnsn_reflection { + dmnsn_reflection_fn *reflection_fn; /**< Reflection callback. */ + dmnsn_free_fn *free_fn; /**< Destructor callback. */ + void *ptr; /**< Generic data pointer. */ + dmnsn_refcount refcount; /**< @internal Reference count. */ }; +/** Allocate a dummy reflection component. */ +dmnsn_reflection *dmnsn_new_reflection(void); +/** Delete a reflection component. */ +void dmnsn_delete_reflection(dmnsn_reflection *reflection); + +/* Entire finishes */ + +/** A finish. */ +typedef struct dmnsn_finish { + dmnsn_ambient *ambient; /**< Ambient component. */ + dmnsn_diffuse *diffuse; /**< Diffuse component. */ + dmnsn_specular *specular; /**< Specular component. */ + dmnsn_reflection *reflection; /**< Reflection component. */ +} dmnsn_finish; + /** - * Allocate a new dummy finish. - * @return The allocated finish. + * Create a new blank finish. + * @return The new finish. */ -dmnsn_finish *dmnsn_new_finish(void); +dmnsn_finish dmnsn_new_finish(void); /** * Delete a finish. * @param[in,out] finish The finish to delete. */ -void dmnsn_delete_finish(dmnsn_finish *finish); +void dmnsn_delete_finish(dmnsn_finish finish); + +/** + * Fill missing finish properties from a default finish. + * @param[in] default_finish The default finish. + * @param[in,out] finish The finish to fill. + */ +void dmnsn_finish_cascade(const dmnsn_finish *default_finish, + dmnsn_finish *finish); diff --git a/libdimension/dimension/finishes.h b/libdimension/dimension/finishes.h index e3c308c..81b0ff6 100644 --- a/libdimension/dimension/finishes.h +++ b/libdimension/dimension/finishes.h @@ -23,42 +23,34 @@ * Pre-defined finishes. */ -/** - * Add two finishes together. - * @param[in,out] f1 The first finish. - * @param[in,out] f2 The second finish. - * @return A finish that adds the values of two finishes together. - */ -dmnsn_finish *dmnsn_new_finish_combination(dmnsn_finish *f1, dmnsn_finish *f2); - /** * Ambient finish. * @param[in] ambient The color of the ambient light. - * @return A finish with ambient light. + * @return An ambient finish component. */ -dmnsn_finish *dmnsn_new_ambient_finish(dmnsn_color ambient); +dmnsn_ambient *dmnsn_new_basic_ambient(dmnsn_color ambient); /** - * Diffuse finish. + * Regular diffuse finish. * @param[in] diffuse The diffuse reflection coefficient. - * @return A finish with diffuse reflection. + * @return A diffuse finish component. */ -dmnsn_finish *dmnsn_new_diffuse_finish(double diffuse); +dmnsn_diffuse *dmnsn_new_lambertian(double diffuse); /** * A phong specular highlight. * @param[in] specular The specular reflection coefficient. * @param[in] exp The exponent (roughly the highlight size). - * @return A finish with phong specular highlight. + * @return A phong specular finish component. */ -dmnsn_finish *dmnsn_new_phong_finish(double specular, double exp); +dmnsn_specular *dmnsn_new_phong(double specular, double exp); /** * Specular (mirror) reflection. * @param[in] min Reflection at paralell angles. * @param[in] max Reflection at perpendicular angles (often == \p min). * @param[in] falloff Degree of exponential falloff (usually 1). - * @return A finish with specular reflection. + * @return A reflective finish component. */ -dmnsn_finish *dmnsn_new_reflective_finish(dmnsn_color min, dmnsn_color max, - double falloff); +dmnsn_reflection *dmnsn_new_basic_reflection(dmnsn_color min, dmnsn_color max, + double falloff); diff --git a/libdimension/dimension/interior.h b/libdimension/dimension/interior.h index 22a9091..a52c225 100644 --- a/libdimension/dimension/interior.h +++ b/libdimension/dimension/interior.h @@ -47,3 +47,11 @@ dmnsn_interior *dmnsn_new_interior(void); * @param[in,out] interior The interior to delete. */ void dmnsn_delete_interior(dmnsn_interior *interior); + +/** + * Fill missing interior properties from a default interior. + * @param[in] default_interior The default interior. + * @param[in,out] interiorp A pointer to the interior to fill. + */ +void dmnsn_interior_cascade(dmnsn_interior *default_interior, + dmnsn_interior **interiorp); diff --git a/libdimension/dimension/object.h b/libdimension/dimension/object.h index 02daaba..24e1bcb 100644 --- a/libdimension/dimension/object.h +++ b/libdimension/dimension/object.h @@ -71,7 +71,7 @@ typedef bool dmnsn_object_inside_fn(const dmnsn_object *object, /** An object. */ struct dmnsn_object { - dmnsn_texture *texture; /**< Surface properties. */ + dmnsn_texture *texture; /**< Surface properties. */ dmnsn_interior *interior; /**< Interior properties. */ dmnsn_matrix trans; /**< Transformation matrix. */ @@ -79,20 +79,18 @@ struct dmnsn_object { dmnsn_bounding_box bounding_box; /**< Object bounding box. */ - /** Child objects. This array lists objects that can be split into - sub-objects for bounding purposes (for unions and meshes, for example). */ - dmnsn_array *children; + dmnsn_array *children; /**< Child objects. */ + bool split_children; /**< Whether the child objects can be split. */ dmnsn_object_initialize_fn *initialize_fn; /**< Initialization callback. */ dmnsn_object_intersection_fn *intersection_fn; /**< Intersection callback. */ dmnsn_object_inside_fn *inside_fn; /**< Inside callback. */ dmnsn_free_fn *free_fn; /**< Destruction callback. */ - /** Generic pointer for object info. */ - void *ptr; + void *ptr; /**< Generic pointer for object info. */ - /** @internal Reference count. */ - dmnsn_refcount refcount; + dmnsn_refcount refcount; /**< @internal Reference count. */ + bool initialized; /**< @internal Whether the object is initialized yet. */ }; /** @@ -113,7 +111,6 @@ void dmnsn_delete_object(dmnsn_object *object); */ void dmnsn_initialize_object(dmnsn_object *object); - /** * Transform a surface normal vector. * @param[in] trans The transformation matrix. diff --git a/libdimension/dimension/pattern.h b/libdimension/dimension/pattern.h index beeb9f7..de37286 100644 --- a/libdimension/dimension/pattern.h +++ b/libdimension/dimension/pattern.h @@ -44,6 +44,8 @@ struct dmnsn_pattern { dmnsn_matrix trans_inv; /**< The inverse of the transformation matrix. */ void *ptr; /**< Generic pointer. */ + + dmnsn_refcount refcount; /**< @internal Reference count. */ }; /** diff --git a/libdimension/dimension/pigment.h b/libdimension/dimension/pigment.h index 896c0bc..8b3ce4b 100644 --- a/libdimension/dimension/pigment.h +++ b/libdimension/dimension/pigment.h @@ -55,6 +55,9 @@ struct dmnsn_pigment { /** Generic pointer. */ void *ptr; + + dmnsn_refcount refcount; /** @internal Reference count. */ + bool initialized; /** @internal Whether the pigment is initialized. */ }; /** @@ -76,3 +79,12 @@ void dmnsn_delete_pigment(dmnsn_pigment *pigment); * @param[in,out] pigment The pigment to initialize. */ void dmnsn_initialize_pigment(dmnsn_pigment *pigment); + +/** + * Evaluate the color of a pigment at a point. + * @param[in] pigment The pigment to evaluate. + * @param[in] v The point to color. + * @return The color at \p v. + */ +dmnsn_color dmnsn_evaluate_pigment(const dmnsn_pigment *pigment, + dmnsn_vector v); diff --git a/libdimension/dimension/refcount.h b/libdimension/dimension/refcount.h index 4431cbc..be437a8 100644 --- a/libdimension/dimension/refcount.h +++ b/libdimension/dimension/refcount.h @@ -32,7 +32,7 @@ typedef unsigned int dmnsn_refcount; * Increment a reference count. * @param[in,out] object The reference-counted object to acquire. */ -#define DMNSN_INCREF(obj) ((void)++(obj)->refcount) +#define DMNSN_INCREF(obj) ((void)((obj) && ++(obj)->refcount)) /** * @internal @@ -40,4 +40,5 @@ typedef unsigned int dmnsn_refcount; * @param[in,out] object The reference-counted object to release. * @return Whether the object is now garbage. */ -#define DMNSN_DECREF(obj) ((obj)->refcount == 0 || --(obj)->refcount == 0) +#define DMNSN_DECREF(obj) \ + ((obj) && ((obj)->refcount == 0 || --(obj)->refcount == 0)) diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h index bb47ee9..969fa45 100644 --- a/libdimension/dimension/scene.h +++ b/libdimension/dimension/scene.h @@ -40,13 +40,10 @@ typedef unsigned int dmnsn_quality; /** An entire scene. */ typedef struct dmnsn_scene { /* World attributes */ - dmnsn_color background; /**< Background color. */ - dmnsn_color ambient; /**< Global ambient color. */ - dmnsn_sky_sphere *sky_sphere; /**< Sky sphere. */ - dmnsn_texture *default_texture; /**< Default object texture. */ - - /** Camera. */ - dmnsn_camera *camera; + dmnsn_color background; /**< Background color. */ + dmnsn_sky_sphere *sky_sphere; /**< Sky sphere. */ + dmnsn_texture *default_texture; /**< Default object texture. */ + dmnsn_interior *default_interior; /**< Default object interior. */ /** Canvas. */ dmnsn_canvas *canvas; @@ -57,6 +54,9 @@ typedef struct dmnsn_scene { /** Lights. */ dmnsn_array *lights; + /** Camera. */ + dmnsn_camera *camera; + /** Render quality. */ dmnsn_quality quality; @@ -72,6 +72,8 @@ typedef struct dmnsn_scene { /** Timers. */ dmnsn_timer *bounding_timer; dmnsn_timer *render_timer; + + bool initialized; /**< @internal Whether the scene is initialized. */ } dmnsn_scene; /** @@ -91,31 +93,3 @@ void dmnsn_delete_scene(dmnsn_scene *scene); * @param[in,out] scene The scene to initalize. */ void dmnsn_initialize_scene(dmnsn_scene *scene); - -/** - * Set the output canvas for a scene. - * @param[in,out] scene The scene for which to set the canvas. - * @param[in] canvas The canvas to set. - */ -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. - */ -void dmnsn_scene_set_camera(dmnsn_scene *scene, dmnsn_camera *camera); - -/** - * Add an object to a scene. - * @param[in,out] scene The scene to which to add the object. - * @param[in] object The object to add. - */ -void dmnsn_scene_add_object(dmnsn_scene *scene, dmnsn_object *object); diff --git a/libdimension/dimension/sky_sphere.h b/libdimension/dimension/sky_sphere.h index 43ad57e..2d2c834 100644 --- a/libdimension/dimension/sky_sphere.h +++ b/libdimension/dimension/sky_sphere.h @@ -27,7 +27,10 @@ typedef struct dmnsn_sky_sphere { /** An array of pigments in inside-to-outside order. */ dmnsn_array *pigments; - dmnsn_matrix trans; + + dmnsn_matrix trans; /**< Transformation matrix. */ + + dmnsn_refcount refcount; /**< @internal Reference count. */ } dmnsn_sky_sphere; /** diff --git a/libdimension/dimension/texture.h b/libdimension/dimension/texture.h index 7edcabc..0c944a9 100644 --- a/libdimension/dimension/texture.h +++ b/libdimension/dimension/texture.h @@ -26,13 +26,13 @@ /** A complete texture. */ typedef struct { dmnsn_pigment *pigment; /**< Pigment. */ - dmnsn_finish *finish; /**< Finish. */ + dmnsn_finish finish; /**< Finish. */ dmnsn_matrix trans; /**< Transformation matrix. */ dmnsn_matrix trans_inv; /**< The inverse of the transformation matrix. */ dmnsn_refcount refcount; /**< @internal Reference count. */ - bool should_init; /**< @internal Whether to initialize the texture. */ + bool initialized; /**< @internal Whether the texture is initialized yet. */ } dmnsn_texture; /** @@ -54,3 +54,11 @@ void dmnsn_delete_texture(dmnsn_texture *texture); * @param[in,out] texture The texture to initialize. */ void dmnsn_initialize_texture(dmnsn_texture *texture); + +/** + * Fill missing texture properties from a default texture. + * @param[in] default_texture The default texture. + * @param[in,out] texturep A pointer to the texture to fill. + */ +void dmnsn_texture_cascade(dmnsn_texture *default_texture, + dmnsn_texture **texture); diff --git a/libdimension/finish.c b/libdimension/finish.c index e647152..d356676 100644 --- a/libdimension/finish.c +++ b/libdimension/finish.c @@ -25,27 +25,127 @@ #include "dimension.h" -/* Allocate a dummy finish */ -dmnsn_finish * +dmnsn_ambient * +dmnsn_new_ambient(void) +{ + dmnsn_ambient *ambient = dmnsn_malloc(sizeof(dmnsn_ambient)); + ambient->free_fn = NULL; + ambient->ptr = NULL; + ambient->refcount = 1; + return ambient; +} + +void +dmnsn_delete_ambient(dmnsn_ambient *ambient) +{ + if (DMNSN_DECREF(ambient)) { + if (ambient->free_fn) { + ambient->free_fn(ambient->ptr); + } + dmnsn_free(ambient); + } +} + +dmnsn_diffuse * +dmnsn_new_diffuse(void) +{ + dmnsn_diffuse *diffuse = dmnsn_malloc(sizeof(dmnsn_diffuse)); + diffuse->free_fn = NULL; + diffuse->ptr = NULL; + diffuse->refcount = 1; + return diffuse; +} + +void +dmnsn_delete_diffuse(dmnsn_diffuse *diffuse) +{ + if (DMNSN_DECREF(diffuse)) { + if (diffuse->free_fn) { + diffuse->free_fn(diffuse->ptr); + } + dmnsn_free(diffuse); + } +} + +dmnsn_specular * +dmnsn_new_specular(void) +{ + dmnsn_specular *specular = dmnsn_malloc(sizeof(dmnsn_specular)); + specular->free_fn = NULL; + specular->ptr = NULL; + specular->refcount = 1; + return specular; +} + +void +dmnsn_delete_specular(dmnsn_specular *specular) +{ + if (DMNSN_DECREF(specular)) { + if (specular->free_fn) { + specular->free_fn(specular->ptr); + } + dmnsn_free(specular); + } +} + +dmnsn_reflection * +dmnsn_new_reflection(void) +{ + dmnsn_reflection *reflection = dmnsn_malloc(sizeof(dmnsn_reflection)); + reflection->free_fn = NULL; + reflection->ptr = NULL; + reflection->refcount = 1; + return reflection; +} + +void +dmnsn_delete_reflection(dmnsn_reflection *reflection) +{ + if (DMNSN_DECREF(reflection)) { + if (reflection->free_fn) { + reflection->free_fn(reflection->ptr); + } + dmnsn_free(reflection); + } +} + +dmnsn_finish dmnsn_new_finish(void) { - dmnsn_finish *finish = dmnsn_malloc(sizeof(dmnsn_finish)); - finish->diffuse_fn = NULL; - finish->specular_fn = NULL; - finish->ambient_fn = NULL; - finish->reflection_fn = NULL; - finish->free_fn = NULL; + dmnsn_finish finish; + finish.ambient = NULL; + finish.diffuse = NULL; + finish.specular = NULL; + finish.reflection = NULL; return finish; } -/* Free a finish */ void -dmnsn_delete_finish(dmnsn_finish *finish) +dmnsn_delete_finish(dmnsn_finish finish) { - if (finish) { - if (finish->free_fn) { - finish->free_fn(finish->ptr); - } - dmnsn_free(finish); + dmnsn_delete_reflection(finish.reflection); + dmnsn_delete_specular(finish.specular); + dmnsn_delete_diffuse(finish.diffuse); + dmnsn_delete_ambient(finish.ambient); +} + +void +dmnsn_finish_cascade(const dmnsn_finish *default_finish, dmnsn_finish *finish) +{ + if (!finish->ambient) { + finish->ambient = default_finish->ambient; + DMNSN_INCREF(finish->ambient); + } + if (!finish->diffuse) { + finish->diffuse = default_finish->diffuse; + DMNSN_INCREF(finish->diffuse); + } + if (!finish->specular) { + finish->specular = default_finish->specular; + DMNSN_INCREF(finish->specular); + } + if (!finish->reflection) { + finish->reflection = default_finish->reflection; + DMNSN_INCREF(finish->reflection); } } diff --git a/libdimension/finish_combination.c b/libdimension/finish_combination.c deleted file mode 100644 index acdc719..0000000 --- a/libdimension/finish_combination.c +++ /dev/null @@ -1,150 +0,0 @@ -/************************************************************************* - * Copyright (C) 2010 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -/** - * @file - * Finish combinations. - */ - -#include "dimension.h" -#include -#include - -/** Diffuse combination callback. */ -static dmnsn_color -dmnsn_finish_combination_diffuse_fn(const dmnsn_finish *finish, - dmnsn_color light, dmnsn_color color, - dmnsn_vector ray, dmnsn_vector normal) -{ - dmnsn_finish **params = finish->ptr; - if (params[0]->diffuse_fn && params[1]->diffuse_fn) { - return dmnsn_color_add( - params[0]->diffuse_fn(params[0], light, color, ray, normal), - params[1]->diffuse_fn(params[1], light, color, ray, normal) - ); - } else if (params[0]->diffuse_fn) { - return params[0]->diffuse_fn(params[0], light, color, ray, normal); - } else if (params[1]->diffuse_fn) { - return params[1]->diffuse_fn(params[1], light, color, ray, normal); - } else { - return dmnsn_black; - } -} - -/** Specular combination callback. */ -static dmnsn_color -dmnsn_finish_combination_specular_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]->specular_fn && params[1]->specular_fn) { - return dmnsn_color_add( - params[0]->specular_fn(params[0], light, color, ray, normal, viewer), - params[1]->specular_fn(params[1], light, color, ray, normal, viewer) - ); - } else if (params[0]->specular_fn) { - return params[0]->specular_fn(params[0], light, color, ray, - normal, viewer); - } else if (params[1]->specular_fn) { - return params[1]->specular_fn(params[1], light, color, ray, - normal, viewer); - } else { - return dmnsn_black; - } -} - -/** Ambient combination callback. */ -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; - } -} - -/** Reflection combination callback. */ -static dmnsn_color -dmnsn_finish_combination_reflection_fn(const dmnsn_finish *finish, - dmnsn_color reflect, dmnsn_color color, - dmnsn_vector ray, dmnsn_vector normal) -{ - dmnsn_finish **params = finish->ptr; - if (params[0]->reflection_fn && params[1]->reflection_fn) { - return dmnsn_color_add( - params[0]->reflection_fn(params[0], reflect, color, ray, normal), - params[1]->reflection_fn(params[1], reflect, color, ray, normal) - ); - } else if (params[0]->reflection_fn) { - return params[0]->reflection_fn(params[0], reflect, color, ray, normal); - } else if (params[1]->reflection_fn) { - return params[1]->reflection_fn(params[1], reflect, color, ray, normal); - } else { - return dmnsn_black; - } -} - -/** Finish combination destructor callback. */ -static void -dmnsn_finish_combination_free_fn(void *ptr) -{ - dmnsn_finish **params = ptr; - dmnsn_delete_finish(params[0]); - dmnsn_delete_finish(params[1]); - dmnsn_free(ptr); -} - -dmnsn_finish * -dmnsn_new_finish_combination(dmnsn_finish *f1, dmnsn_finish *f2) -{ - dmnsn_finish *finish = dmnsn_new_finish(); - - dmnsn_finish **params = dmnsn_malloc(2*sizeof(dmnsn_finish *)); - params[0] = f1; - params[1] = f2; - - finish->ptr = params; - - if (f1->diffuse_fn || f2->diffuse_fn) - finish->diffuse_fn = dmnsn_finish_combination_diffuse_fn; - - if (f1->specular_fn || f2->specular_fn) - finish->specular_fn = dmnsn_finish_combination_specular_fn; - - if (f1->ambient_fn || f2->ambient_fn) - finish->ambient_fn = dmnsn_finish_combination_ambient_fn; - - if (f1->reflection_fn || f2->reflection_fn) - finish->reflection_fn = dmnsn_finish_combination_reflection_fn; - - finish->free_fn = dmnsn_finish_combination_free_fn; - - return finish; -} diff --git a/libdimension/interior.c b/libdimension/interior.c index 0594e06..47ba19f 100644 --- a/libdimension/interior.c +++ b/libdimension/interior.c @@ -33,7 +33,7 @@ dmnsn_new_interior(void) dmnsn_interior *interior = dmnsn_malloc(sizeof(dmnsn_interior)); interior->ior = 1.0; interior->free_fn = NULL; - interior->refcount = 0; + interior->refcount = 1; return interior; } @@ -41,10 +41,21 @@ dmnsn_new_interior(void) void dmnsn_delete_interior(dmnsn_interior *interior) { - if (interior && DMNSN_DECREF(interior)) { + if (DMNSN_DECREF(interior)) { if (interior->free_fn) { interior->free_fn(interior->ptr); } dmnsn_free(interior); } } + +/* Cascade a interior */ +void +dmnsn_interior_cascade(dmnsn_interior *default_interior, + dmnsn_interior **interiorp) +{ + if (!*interiorp) { + *interiorp = default_interior; + DMNSN_INCREF(*interiorp); + } +} diff --git a/libdimension/lambertian.c b/libdimension/lambertian.c new file mode 100644 index 0000000..089ce56 --- /dev/null +++ b/libdimension/lambertian.c @@ -0,0 +1,58 @@ +/************************************************************************* + * Copyright (C) 2010 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Diffuse finish. + */ + +#include "dimension.h" +#include +#include + +/** Diffuse finish callback. */ +static dmnsn_color +dmnsn_lambertian_diffuse_fn(const dmnsn_diffuse *diffuse, + dmnsn_color light, dmnsn_color color, + dmnsn_vector ray, dmnsn_vector normal) +{ + double *coeff = diffuse->ptr; + double diffuse_factor = fabs((*coeff)*dmnsn_vector_dot(ray, normal)); + dmnsn_color ret + = dmnsn_color_mul(diffuse_factor, dmnsn_color_illuminate(light, color)); + ret.filter = 0.0; + ret.trans = 0.0; + return ret; +} + +dmnsn_diffuse * +dmnsn_new_lambertian(double diffuse) +{ + dmnsn_diffuse *lambertian = dmnsn_new_diffuse(); + + double *param = dmnsn_malloc(sizeof(double)); + *param = diffuse; + + lambertian->diffuse_fn = dmnsn_lambertian_diffuse_fn; + lambertian->free_fn = dmnsn_free; + lambertian->ptr = param; + + return lambertian; +} diff --git a/libdimension/light.c b/libdimension/light.c index 1103727..2ff8820 100644 --- a/libdimension/light.c +++ b/libdimension/light.c @@ -36,7 +36,7 @@ dmnsn_new_light(void) light->shadow_fn = NULL; light->free_fn = NULL; light->ptr = NULL; - light->refcount = 0; + light->refcount = 1; return light; } @@ -44,7 +44,7 @@ dmnsn_new_light(void) void dmnsn_delete_light(dmnsn_light *light) { - if (light && DMNSN_DECREF(light)) { + if (DMNSN_DECREF(light)) { if (light->free_fn) { light->free_fn(light->ptr); } diff --git a/libdimension/object.c b/libdimension/object.c index fecfdbe..bb7773d 100644 --- a/libdimension/object.c +++ b/libdimension/object.c @@ -35,11 +35,13 @@ dmnsn_new_object(void) object->interior = NULL; object->trans = dmnsn_identity_matrix(); object->children = dmnsn_new_array(sizeof(dmnsn_object *)); + object->split_children = false; object->intersection_fn = NULL; object->inside_fn = NULL; object->initialize_fn = NULL; object->free_fn = NULL; - object->refcount = 0; + object->refcount = 1; + object->initialized = false; return object; } @@ -47,7 +49,7 @@ dmnsn_new_object(void) void dmnsn_delete_object(dmnsn_object *object) { - if (object && DMNSN_DECREF(object)) { + if (DMNSN_DECREF(object)) { DMNSN_ARRAY_FOREACH (dmnsn_object **, child, object->children) { dmnsn_delete_object(*child); } @@ -65,31 +67,31 @@ dmnsn_delete_object(dmnsn_object *object) void dmnsn_initialize_object(dmnsn_object *object) { - /* Don't double-init textures */ - bool should_init = false; - dmnsn_matrix old_trans = object->trans; - if (object->texture) { - DMNSN_INCREF(object->texture); - should_init = object->texture->should_init; - object->texture->should_init = false; + dmnsn_assert(!object->initialized, "Object double-initialized."); + object->initialized = true; + + /* Initialize the texture */ + if (!object->texture->initialized) { + object->texture->trans = dmnsn_matrix_mul(object->trans, + object->texture->trans); + dmnsn_initialize_texture(object->texture); } - if (object->interior) { - DMNSN_INCREF(object->interior); + /* Initialize the object's children */ + DMNSN_ARRAY_FOREACH (dmnsn_object **, child, object->children) { + (*child)->trans = dmnsn_matrix_mul(object->trans, (*child)->trans); + dmnsn_texture_cascade(object->texture, &(*child)->texture); + dmnsn_interior_cascade(object->interior, &(*child)->interior); + dmnsn_initialize_object(*child); } + /* Initialization callback */ if (object->initialize_fn) { object->initialize_fn(object); } + /* Precalculate object values */ object->bounding_box = dmnsn_transform_bounding_box(object->trans, object->bounding_box); object->trans_inv = dmnsn_matrix_inverse(object->trans); - - if (should_init) { - /* Transform the texture with the object */ - object->texture->trans - = dmnsn_matrix_mul(old_trans, object->texture->trans); - dmnsn_initialize_texture(object->texture); - } } diff --git a/libdimension/pattern.c b/libdimension/pattern.c index b266527..368755a 100644 --- a/libdimension/pattern.c +++ b/libdimension/pattern.c @@ -30,8 +30,9 @@ dmnsn_pattern * dmnsn_new_pattern(void) { dmnsn_pattern *pattern = dmnsn_malloc(sizeof(dmnsn_pattern)); - pattern->trans = dmnsn_identity_matrix(); - pattern->free_fn = NULL; + pattern->trans = dmnsn_identity_matrix(); + pattern->free_fn = NULL; + pattern->refcount = 1; return pattern; } @@ -39,10 +40,12 @@ dmnsn_new_pattern(void) void dmnsn_delete_pattern(dmnsn_pattern *pattern) { - if (pattern->free_fn) { - pattern->free_fn(pattern->ptr); + if (DMNSN_DECREF(pattern)) { + if (pattern->free_fn) { + pattern->free_fn(pattern->ptr); + } + dmnsn_free(pattern); } - dmnsn_free(pattern); } /* Precompute the transformation matrix inverse */ diff --git a/libdimension/phong.c b/libdimension/phong.c index 3fc154f..90bf505 100644 --- a/libdimension/phong.c +++ b/libdimension/phong.c @@ -28,15 +28,15 @@ /** Phong specular highlight callback. */ static dmnsn_color -dmnsn_phong_specular_fn(const dmnsn_finish *finish, +dmnsn_phong_specular_fn(const dmnsn_specular *specular, dmnsn_color light, dmnsn_color color, dmnsn_vector ray, dmnsn_vector normal, dmnsn_vector viewer) { - double *params = finish->ptr; + double *params = specular->ptr; - double specular = params[0]; - double exp = params[1]; + double coeff = 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); @@ -47,22 +47,22 @@ dmnsn_phong_specular_fn(const dmnsn_finish *finish, } specular_factor = pow(specular_factor, exp); - return dmnsn_color_mul(specular*specular_factor, light); + return dmnsn_color_mul(coeff*specular_factor, light); } /* A phong finish */ -dmnsn_finish * -dmnsn_new_phong_finish(double specular, double exp) +dmnsn_specular * +dmnsn_new_phong(double specular, double exp) { - dmnsn_finish *finish = dmnsn_new_finish(); + dmnsn_specular *phong = dmnsn_new_specular(); double *params = dmnsn_malloc(2*sizeof(double)); params[0] = specular; params[1] = exp; - finish->ptr = params; - finish->specular_fn = dmnsn_phong_specular_fn; - finish->free_fn = dmnsn_free; + phong->specular_fn = dmnsn_phong_specular_fn; + phong->free_fn = dmnsn_free; + phong->ptr = params; - return finish; + return phong; } diff --git a/libdimension/pigment.c b/libdimension/pigment.c index a1b4fb7..5522d71 100644 --- a/libdimension/pigment.c +++ b/libdimension/pigment.c @@ -35,6 +35,8 @@ dmnsn_new_pigment(void) pigment->free_fn = NULL; pigment->trans = dmnsn_identity_matrix(); pigment->quick_color = dmnsn_black; + pigment->refcount = 1; + pigment->initialized = false; return pigment; } @@ -42,7 +44,7 @@ dmnsn_new_pigment(void) void dmnsn_delete_pigment(dmnsn_pigment *pigment) { - if (pigment) { + if (DMNSN_DECREF(pigment)) { if (pigment->free_fn) { pigment->free_fn(pigment->ptr); } @@ -54,9 +56,20 @@ dmnsn_delete_pigment(dmnsn_pigment *pigment) void dmnsn_initialize_pigment(dmnsn_pigment *pigment) { + dmnsn_assert(!pigment->initialized, "Pigment double-initialized."); + pigment->initialized = true; + if (pigment->initialize_fn) { pigment->initialize_fn(pigment); } pigment->trans_inv = dmnsn_matrix_inverse(pigment->trans); } + +/* Evaluate a pigment */ +dmnsn_color +dmnsn_evaluate_pigment(const dmnsn_pigment *pigment, dmnsn_vector v) +{ + dmnsn_vector v_trans = dmnsn_transform_vector(pigment->trans_inv, v); + return pigment->pigment_fn(pigment, v_trans); +} diff --git a/libdimension/pigment_map.c b/libdimension/pigment_map.c index e97553f..cf49649 100644 --- a/libdimension/pigment_map.c +++ b/libdimension/pigment_map.c @@ -75,8 +75,8 @@ dmnsn_pigment_map_pigment_fn(const dmnsn_pigment *pigment, dmnsn_vector v) dmnsn_pigment *pigment1, *pigment2; dmnsn_evaluate_map(payload->map, dmnsn_pattern_value(payload->pattern, v), &n, &pigment1, &pigment2); - dmnsn_color color1 = pigment1->pigment_fn(pigment1, v); - dmnsn_color color2 = pigment2->pigment_fn(pigment2, v); + dmnsn_color color1 = dmnsn_evaluate_pigment(pigment1, v); + dmnsn_color color2 = dmnsn_evaluate_pigment(pigment2, v); if (payload->flags == DMNSN_PIGMENT_MAP_SRGB) { color1 = dmnsn_color_to_sRGB(color1); @@ -95,8 +95,6 @@ static void dmnsn_pigment_map_initialize_fn(dmnsn_pigment *pigment) { dmnsn_pigment_map_payload *payload = pigment->ptr; - payload->pattern->trans = dmnsn_matrix_mul(pigment->trans, - payload->pattern->trans); dmnsn_initialize_pattern(payload->pattern); dmnsn_map_apply(payload->map, dmnsn_initialize_mapped_pigment); } diff --git a/libdimension/prtree.c b/libdimension/prtree.c index 2d8acc4..06cecf9 100644 --- a/libdimension/prtree.c +++ b/libdimension/prtree.c @@ -349,12 +349,12 @@ dmnsn_make_prtree(const dmnsn_array *objects) static void dmnsn_split_add_object(dmnsn_array *objects, const dmnsn_object *object) { - if (dmnsn_array_size(object->children) == 0) { - dmnsn_array_push(objects, &object); - } else { + if (object->split_children) { DMNSN_ARRAY_FOREACH (const dmnsn_object **, child, object->children) { dmnsn_split_add_object(objects, *child); } + } else { + dmnsn_array_push(objects, &object); } } diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c index e2fd61e..5d62738 100644 --- a/libdimension/raytrace.c +++ b/libdimension/raytrace.c @@ -113,9 +113,9 @@ typedef struct dmnsn_raytrace_state { unsigned int reclevel; dmnsn_vector r; - dmnsn_vector light; dmnsn_vector viewer; dmnsn_vector reflected; + dmnsn_vector light; dmnsn_color pigment; dmnsn_color diffuse; @@ -171,45 +171,6 @@ dmnsn_raytrace_scene_concurrent(void *ptr, unsigned int thread, return 0; } -/** Get the intersection texture. */ -#define ITEXTURE(state) (state->intersection->texture) -/** Get the default texture. */ -#define DTEXTURE(state) (state->scene->default_texture) - -/** Can a texture element be accessed? */ -#define CAN_ACCESS(texture, telem) \ - ((texture) && (texture)->telem) -/** Can a texture element callback be called? */ -#define CAN_CALL(texture, telem, fn) \ - (CAN_ACCESS(texture, telem) && (texture)->telem->fn) - -/** Determine whether a callback may be called. */ -#define TEXTURE_HAS_CALLBACK(state, telem, fn) \ - (CAN_CALL(ITEXTURE(state), telem, fn) \ - || CAN_CALL(DTEXTURE(state), telem, fn)) - -/** Call the appropriate overloaded texture callback. */ -#define TEXTURE_CALLBACK(state, telem, fn, def, ...) \ - (CAN_CALL(ITEXTURE(state), telem, fn) \ - ? ITEXTURE(state)->telem->fn(ITEXTURE(state)->telem, __VA_ARGS__) \ - : (CAN_CALL(DTEXTURE(state), telem, fn) \ - ? DTEXTURE(state)->telem->fn(DTEXTURE(state)->telem, __VA_ARGS__) \ - : def)); - -/** Get a property from a texture element. */ -#define TEXTURE_PROPERTY(state, telem, prop, def) \ - (CAN_ACCESS(ITEXTURE(state), telem) \ - ? ITEXTURE(state)->telem->prop \ - : (CAN_ACCESS(DTEXTURE(state), telem) \ - ? DTEXTURE(state)->telem->prop \ - : def)) - -/** Get the current index of refraction. */ -#define IOR(state) \ - ((state)->intersection->interior \ - ? (state)->intersection->interior->ior \ - : 1.0) - /** Calculate the background color. */ static dmnsn_color dmnsn_raytrace_background(dmnsn_raytrace_state *state, dmnsn_line ray) @@ -230,12 +191,13 @@ dmnsn_raytrace_background(dmnsn_raytrace_state *state, dmnsn_line ray) static void dmnsn_raytrace_pigment(dmnsn_raytrace_state *state) { + dmnsn_pigment *pigment = state->intersection->texture->pigment; if (state->scene->quality & DMNSN_RENDER_PIGMENT) { - state->pigment = TEXTURE_CALLBACK(state, pigment, pigment_fn, dmnsn_black, - state->r); + state->pigment = dmnsn_evaluate_pigment(pigment, state->r); } else { - state->pigment = TEXTURE_PROPERTY(state, pigment, quick_color, dmnsn_black); + state->pigment = pigment->quick_color; } + state->diffuse = state->pigment; } @@ -297,15 +259,12 @@ static void dmnsn_raytrace_lighting(dmnsn_raytrace_state *state) { /* The ambient color */ - state->diffuse = TEXTURE_CALLBACK(state, finish, ambient_fn, dmnsn_black, - state->pigment); - state->diffuse = dmnsn_color_illuminate(state->scene->ambient, - state->diffuse); + state->diffuse = dmnsn_black; - if (!TEXTURE_HAS_CALLBACK(state, finish, diffuse_fn) - && !TEXTURE_HAS_CALLBACK(state, finish, specular_fn)) - { - return; + const dmnsn_finish *finish = &state->intersection->texture->finish; + if (finish->ambient) { + state->diffuse + = finish->ambient->ambient_fn(finish->ambient, state->pigment); } /* Iterate over each light */ @@ -314,16 +273,22 @@ dmnsn_raytrace_lighting(dmnsn_raytrace_state *state) if (!dmnsn_color_is_black(light_color)) { if (state->scene->quality & DMNSN_RENDER_FINISH) { /* Get this light's color contribution to the object */ - dmnsn_color diffuse = TEXTURE_CALLBACK( - state, finish, diffuse_fn, dmnsn_black, - light_color, state->pigment, state->light, - state->intersection->normal - ); - dmnsn_color specular = TEXTURE_CALLBACK( - state, finish, specular_fn, dmnsn_black, - light_color, state->pigment, state->light, - state->intersection->normal, state->viewer - ); + dmnsn_color diffuse = dmnsn_black; + if (finish->diffuse) { + diffuse = finish->diffuse->diffuse_fn( + finish->diffuse, light_color, state->pigment, state->light, + state->intersection->normal + ); + } + + dmnsn_color specular = dmnsn_black; + if (finish->specular) { + specular = finish->specular->specular_fn( + finish->specular, 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); } else { @@ -341,20 +306,21 @@ dmnsn_raytrace_reflection(const dmnsn_raytrace_state *state) { dmnsn_color reflected = dmnsn_black; - if (TEXTURE_HAS_CALLBACK(state, finish, reflection_fn)) { + const dmnsn_finish *finish = &state->intersection->texture->finish; + if (finish->reflection) { dmnsn_line refl_ray = dmnsn_new_line(state->r, state->reflected); refl_ray = dmnsn_line_add_epsilon(refl_ray); dmnsn_raytrace_state recursive_state = *state; - recursive_state.adc_value = TEXTURE_CALLBACK( - state, finish, reflection_fn, dmnsn_black, - state->adc_value, state->pigment, state->reflected, + recursive_state.adc_value = finish->reflection->reflection_fn( + finish->reflection, state->adc_value, state->pigment, state->reflected, state->intersection->normal ); + dmnsn_color rec = dmnsn_raytrace_shoot(&recursive_state, refl_ray); - reflected = TEXTURE_CALLBACK( - state, finish, reflection_fn, dmnsn_black, - rec, state->pigment, state->reflected, state->intersection->normal + reflected = finish->reflection->reflection_fn( + finish->reflection, rec, state->pigment, state->reflected, + state->intersection->normal ); reflected.trans = 0.0; reflected.filter = 0.0; @@ -378,7 +344,7 @@ dmnsn_raytrace_translucency(dmnsn_raytrace_state *state) if (dmnsn_vector_dot(r, n) < 0.0) { /* We are entering an object */ - recursive_state.ior = IOR(state); + recursive_state.ior = state->intersection->interior->ior; recursive_state.parent = state; } else { /* We are leaving an object */ @@ -438,15 +404,15 @@ dmnsn_raytrace_shoot(dmnsn_raytrace_state *state, dmnsn_line ray) bool reset = state->reclevel == state->scene->reclimit - 1; if (dmnsn_prtree_intersection(state->prtree, ray, &intersection, reset)) { state->intersection = &intersection; - state->r = dmnsn_line_point(state->intersection->ray, - state->intersection->t); + + state->r = dmnsn_line_point(intersection.ray, intersection.t); state->viewer = dmnsn_vector_normalized( - dmnsn_vector_negate(state->intersection->ray.n) + dmnsn_vector_negate(intersection.ray.n) ); state->reflected = dmnsn_vector_sub( dmnsn_vector_mul( - 2*dmnsn_vector_dot(state->viewer, state->intersection->normal), - state->intersection->normal), + 2*dmnsn_vector_dot(state->viewer, intersection.normal), + intersection.normal), state->viewer ); diff --git a/libdimension/reflection.c b/libdimension/reflection.c new file mode 100644 index 0000000..2417304 --- /dev/null +++ b/libdimension/reflection.c @@ -0,0 +1,67 @@ +/************************************************************************* + * Copyright (C) 2010 Tavian Barnes * + * * + * This file is part of The Dimension Library. * + * * + * The Dimension Library is free software; you can redistribute it and/ * + * or modify it under the terms of the GNU Lesser General Public License * + * as published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Library is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this program. If not, see * + * . * + *************************************************************************/ + +/** + * @file + * Reflective finish. + */ + +#include "dimension.h" +#include +#include + +/** Reflective finish payload. */ +typedef struct dmnsn_reflection_params { + dmnsn_color min, max; + double falloff; +} dmnsn_reflection_params; + +/** Reflective finish callback. */ +static dmnsn_color +dmnsn_basic_reflection_fn(const dmnsn_reflection *reflection, + dmnsn_color reflect, dmnsn_color color, + dmnsn_vector ray, dmnsn_vector normal) +{ + dmnsn_reflection_params *params = reflection->ptr; + double coeff = pow(fabs(dmnsn_vector_dot(ray, normal)), params->falloff); + + return dmnsn_color_illuminate( + dmnsn_color_gradient(params->min, params->max, coeff), + reflect + ); +} + +dmnsn_reflection * +dmnsn_new_basic_reflection(dmnsn_color min, dmnsn_color max, double falloff) +{ + dmnsn_reflection *reflection = dmnsn_new_reflection(); + + dmnsn_reflection_params *params + = dmnsn_malloc(sizeof(dmnsn_reflection_params)); + params->min = min; + params->max = max; + params->falloff = falloff; + + reflection->reflection_fn = dmnsn_basic_reflection_fn; + reflection->free_fn = dmnsn_free; + reflection->ptr = params; + + return reflection; +} diff --git a/libdimension/reflective.c b/libdimension/reflective.c deleted file mode 100644 index 32bec58..0000000 --- a/libdimension/reflective.c +++ /dev/null @@ -1,67 +0,0 @@ -/************************************************************************* - * Copyright (C) 2010 Tavian Barnes * - * * - * This file is part of The Dimension Library. * - * * - * The Dimension Library is free software; you can redistribute it and/ * - * or modify it under the terms of the GNU Lesser General Public License * - * as published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Library is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this program. If not, see * - * . * - *************************************************************************/ - -/** - * @file - * Reflective finish. - */ - -#include "dimension.h" -#include -#include - -/** Reflective finish payload. */ -typedef struct dmnsn_reflection_params { - dmnsn_color min, max; - double falloff; -} dmnsn_reflection_params; - -/** Reflective finish callback. */ -static dmnsn_color -dmnsn_reflective_finish_fn(const dmnsn_finish *finish, - dmnsn_color reflect, dmnsn_color color, - dmnsn_vector ray, dmnsn_vector normal) -{ - dmnsn_reflection_params *params = finish->ptr; - double reflection = pow(fabs(dmnsn_vector_dot(ray, normal)), params->falloff); - - return dmnsn_color_illuminate( - dmnsn_color_gradient(params->min, params->max, reflection), - reflect - ); -} - -dmnsn_finish * -dmnsn_new_reflective_finish(dmnsn_color min, dmnsn_color max, double falloff) -{ - dmnsn_finish *finish = dmnsn_new_finish(); - - dmnsn_reflection_params *params - = dmnsn_malloc(sizeof(dmnsn_reflection_params)); - params->min = min; - params->max = max; - params->falloff = falloff; - - finish->ptr = params; - finish->reflection_fn = dmnsn_reflective_finish_fn; - finish->free_fn = dmnsn_free; - - return finish; -} diff --git a/libdimension/scene.c b/libdimension/scene.c index 8462203..ef597ee 100644 --- a/libdimension/scene.c +++ b/libdimension/scene.c @@ -32,20 +32,21 @@ dmnsn_new_scene(void) { dmnsn_scene *scene = dmnsn_malloc(sizeof(dmnsn_scene)); - scene->background = dmnsn_black; - scene->ambient = dmnsn_white; - scene->sky_sphere = NULL; - scene->default_texture = dmnsn_new_texture(); - scene->camera = NULL; - scene->canvas = NULL; - scene->objects = dmnsn_new_array(sizeof(dmnsn_object *)); - scene->lights = dmnsn_new_array(sizeof(dmnsn_light *)); - scene->quality = DMNSN_RENDER_FULL; - scene->reclimit = 5; - scene->adc_bailout = 1.0/255.0; - scene->nthreads = dmnsn_ncpus(); - scene->bounding_timer = NULL; - scene->render_timer = NULL; + scene->background = dmnsn_black; + scene->sky_sphere = NULL; + scene->default_texture = dmnsn_new_texture(); + scene->default_interior = dmnsn_new_interior(); + scene->canvas = NULL; + scene->objects = dmnsn_new_array(sizeof(dmnsn_object *)); + scene->lights = dmnsn_new_array(sizeof(dmnsn_light *)); + scene->camera = NULL; + scene->quality = DMNSN_RENDER_FULL; + scene->reclimit = 5; + scene->adc_bailout = 1.0/255.0; + scene->nthreads = dmnsn_ncpus(); + scene->bounding_timer = NULL; + scene->render_timer = NULL; + scene->initialized = false; return scene; } @@ -69,6 +70,7 @@ dmnsn_delete_scene(dmnsn_scene *scene) dmnsn_delete_array(scene->objects); dmnsn_delete_canvas(scene->canvas); dmnsn_delete_camera(scene->camera); + dmnsn_delete_interior(scene->default_interior); dmnsn_delete_texture(scene->default_texture); dmnsn_delete_sky_sphere(scene->sky_sphere); dmnsn_free(scene); @@ -78,38 +80,18 @@ dmnsn_delete_scene(dmnsn_scene *scene) void dmnsn_initialize_scene(dmnsn_scene *scene) { + dmnsn_assert(!scene->initialized, "Texture double-initialized."); + scene->initialized = true; + + dmnsn_initialize_texture(scene->default_texture); + if (scene->sky_sphere) { dmnsn_initialize_sky_sphere(scene->sky_sphere); } -} - -void -dmnsn_scene_set_canvas(dmnsn_scene *scene, dmnsn_canvas *canvas) -{ - DMNSN_INCREF(canvas); - dmnsn_delete_canvas(scene->canvas); - scene->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); - dmnsn_delete_camera(scene->camera); - scene->camera = camera; -} - -void -dmnsn_scene_add_object(dmnsn_scene *scene, dmnsn_object *object) -{ - DMNSN_INCREF(object); - dmnsn_initialize_object(object); - dmnsn_array_push(scene->objects, &object); + DMNSN_ARRAY_FOREACH (dmnsn_object **, object, scene->objects) { + dmnsn_texture_cascade(scene->default_texture, &(*object)->texture); + dmnsn_interior_cascade(scene->default_interior, &(*object)->interior); + dmnsn_initialize_object(*object); + } } diff --git a/libdimension/sky_sphere.c b/libdimension/sky_sphere.c index 0ea5fa3..2279881 100644 --- a/libdimension/sky_sphere.c +++ b/libdimension/sky_sphere.c @@ -30,14 +30,15 @@ dmnsn_new_sky_sphere(void) { dmnsn_sky_sphere *sky_sphere = dmnsn_malloc(sizeof(dmnsn_sky_sphere)); sky_sphere->pigments = dmnsn_new_array(sizeof(dmnsn_pigment *)); - sky_sphere->trans = dmnsn_identity_matrix(); + sky_sphere->trans = dmnsn_identity_matrix(); + sky_sphere->refcount = 1; return sky_sphere; } void dmnsn_delete_sky_sphere(dmnsn_sky_sphere *sky_sphere) { - if (sky_sphere) { + if (DMNSN_DECREF(sky_sphere)) { DMNSN_ARRAY_FOREACH (dmnsn_pigment **, pigment, sky_sphere->pigments) { dmnsn_delete_pigment(*pigment); } @@ -61,11 +62,8 @@ dmnsn_sky_sphere_color(const dmnsn_sky_sphere *sky_sphere, dmnsn_vector d) dmnsn_color color = dmnsn_clear; DMNSN_ARRAY_FOREACH (const dmnsn_pigment **, pigment, sky_sphere->pigments) { - dmnsn_pigment_fn *pigment_fn = (*pigment)->pigment_fn; - if (pigment_fn) { - dmnsn_color sky = pigment_fn(*pigment, d); - color = dmnsn_apply_filter(color, sky); - } + dmnsn_color sky = dmnsn_evaluate_pigment(*pigment, d); + color = dmnsn_apply_filter(color, sky); } return color; diff --git a/libdimension/tests/prtree.c b/libdimension/tests/prtree.c index 86aaa4e..5fb2f10 100644 --- a/libdimension/tests/prtree.c +++ b/libdimension/tests/prtree.c @@ -62,17 +62,17 @@ main(void) dmnsn_die_on_warnings(true); const size_t nobjects = 128; - dmnsn_scene *scene = dmnsn_new_scene(); + dmnsn_array *objects = dmnsn_new_array(sizeof(dmnsn_object *)); for (size_t i = 0; i < nobjects; ++i) { dmnsn_object *object = dmnsn_new_object(); dmnsn_randomize_bounding_box(object); object->intersection_fn = dmnsn_fake_intersection_fn; - dmnsn_initialize_object(object); - dmnsn_scene_add_object(scene, object); + object->trans_inv = dmnsn_identity_matrix(); + dmnsn_array_push(objects, &object); } - dmnsn_prtree *prtree = dmnsn_new_prtree(scene->objects); + dmnsn_prtree *prtree = dmnsn_new_prtree(objects); dmnsn_intersection intersection; dmnsn_line ray = dmnsn_new_line( @@ -93,6 +93,9 @@ main(void) } dmnsn_delete_prtree(prtree); - dmnsn_delete_scene(scene); + DMNSN_ARRAY_FOREACH (dmnsn_object **, object, objects) { + dmnsn_delete_object(*object); + } + dmnsn_delete_array(objects); return EXIT_SUCCESS; } diff --git a/libdimension/tests/render.c b/libdimension/tests/render.c index 85742d0..13a4b2c 100644 --- a/libdimension/tests/render.c +++ b/libdimension/tests/render.c @@ -23,7 +23,7 @@ #include /* - * Test scene -- code version of tests/dimension/demo.pov + * Test scene */ static dmnsn_scene * dmnsn_new_test_scene(void) @@ -31,16 +31,20 @@ dmnsn_new_test_scene(void) /* Allocate a new scene */ dmnsn_scene *scene = dmnsn_new_scene(); - /* Default finish */ - scene->default_texture->finish = dmnsn_new_finish_combination( - dmnsn_new_ambient_finish( - dmnsn_color_mul(0.01, dmnsn_white) - ), - dmnsn_new_diffuse_finish(0.3) + /* Default texture */ + scene->default_texture->pigment = dmnsn_new_solid_pigment(dmnsn_black); + dmnsn_finish *default_finish = &scene->default_texture->finish; + default_finish->ambient = dmnsn_new_basic_ambient( + dmnsn_color_from_sRGB(dmnsn_color_mul(0.1, dmnsn_white)) + ); + default_finish->diffuse = dmnsn_new_lambertian( + dmnsn_color_intensity( + dmnsn_color_from_sRGB(dmnsn_color_mul(0.6, dmnsn_white)) + ) ); /* Allocate a canvas */ - dmnsn_scene_set_canvas(scene, dmnsn_new_canvas(768, 480)); + scene->canvas = dmnsn_new_canvas(768, 480); /* Set up the transformation matrix for the perspective camera */ dmnsn_matrix trans = dmnsn_scale_matrix( @@ -62,9 +66,8 @@ dmnsn_new_test_scene(void) ); /* Create a perspective camera */ - dmnsn_camera *camera = dmnsn_new_perspective_camera(); - camera->trans = trans; - dmnsn_scene_set_camera(scene, camera); + scene->camera = dmnsn_new_perspective_camera(); + scene->camera->trans = trans; /* Background color */ scene->background = dmnsn_clear; @@ -88,7 +91,7 @@ dmnsn_new_test_scene(void) dmnsn_new_vector(-15.0, 20.0, 10.0), dmnsn_white ); - dmnsn_scene_add_light(scene, light); + dmnsn_array_push(scene->lights, &light); /* Now make our objects */ @@ -96,15 +99,18 @@ dmnsn_new_test_scene(void) cube->trans = dmnsn_rotation_matrix( dmnsn_new_vector(dmnsn_radians(45.0), 0.0, 0.0) ); - cube->texture = dmnsn_new_texture(); dmnsn_color cube_color = dmnsn_blue; cube_color.trans = 0.75; cube_color.filter = 1.0/3.0; + cube->texture = dmnsn_new_texture(); cube->texture->pigment = dmnsn_new_solid_pigment(cube_color); - dmnsn_color reflect = dmnsn_color_mul(0.5, dmnsn_white); - cube->texture->finish = dmnsn_new_reflective_finish(reflect, reflect, 1.0); + dmnsn_color reflect = dmnsn_color_from_sRGB( + dmnsn_color_mul(0.5, dmnsn_white) + ); + cube->texture->finish.reflection + = dmnsn_new_basic_reflection(reflect, reflect, 1.0); cube->interior = dmnsn_new_interior(); cube->interior->ior = 1.1; @@ -112,11 +118,11 @@ dmnsn_new_test_scene(void) dmnsn_object *sphere = dmnsn_new_sphere(); sphere->texture = dmnsn_new_texture(); sphere->texture->pigment = dmnsn_new_solid_pigment(dmnsn_green); - sphere->texture->finish = dmnsn_new_phong_finish(0.2, 40.0); + sphere->texture->finish.specular = dmnsn_new_phong(0.2, 40.0); sphere->trans = dmnsn_scale_matrix(dmnsn_new_vector(1.25, 1.25, 1.25)); dmnsn_object *csg = dmnsn_new_csg_difference(cube, sphere); - dmnsn_scene_add_object(scene, csg); + dmnsn_array_push(scene->objects, &csg); dmnsn_array *arrow_array = dmnsn_new_array(sizeof(dmnsn_object *)); @@ -149,12 +155,13 @@ dmnsn_new_test_scene(void) arrow->texture->pigment = dmnsn_new_color_map_pigment(gradient, gradient_color_map, DMNSN_PIGMENT_MAP_SRGB); + arrow->texture->trans = dmnsn_matrix_mul( dmnsn_translation_matrix(dmnsn_new_vector(0.0, -1.25, 0.0)), dmnsn_scale_matrix(dmnsn_new_vector(1.0, 2.75, 1.0)) ); - dmnsn_scene_add_object(scene, arrow); + dmnsn_array_push(scene->objects, &arrow); dmnsn_delete_array(arrow_array); dmnsn_array *torus_array = dmnsn_new_array(sizeof(dmnsn_object *)); @@ -176,13 +183,13 @@ dmnsn_new_test_scene(void) ); torii->texture = dmnsn_new_texture(); torii->texture->pigment = dmnsn_new_solid_pigment(dmnsn_blue); - torii->texture->finish = dmnsn_new_ambient_finish(dmnsn_white); - dmnsn_scene_add_object(scene, torii); + torii->texture->finish.ambient + = dmnsn_new_basic_ambient(dmnsn_white); + dmnsn_array_push(scene->objects, &torii); dmnsn_delete_array(torus_array); dmnsn_object *plane = dmnsn_new_plane(dmnsn_new_vector(0.0, 1.0, 0.0)); plane->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, -2.0, 0.0)); - plane->texture = dmnsn_new_texture(); dmnsn_pattern *checker1 = dmnsn_new_checker_pattern(); dmnsn_pattern *checker2 = dmnsn_new_checker_pattern(); dmnsn_map *checker_color_map = dmnsn_new_color_map(); @@ -197,13 +204,14 @@ dmnsn_new_test_scene(void) dmnsn_map *checker_pigment_map = dmnsn_new_pigment_map(); dmnsn_add_map_entry(checker_pigment_map, 0.0, &pigment1); dmnsn_add_map_entry(checker_pigment_map, 1.0, &pigment2); + plane->texture = dmnsn_new_texture(); plane->texture->pigment = dmnsn_new_pigment_map_pigment(checker2, checker_pigment_map, DMNSN_PIGMENT_MAP_REGULAR); plane->texture->pigment->quick_color = dmnsn_color_from_sRGB( dmnsn_new_color(1.0, 0.5, 0.75) ); - dmnsn_scene_add_object(scene, plane); + dmnsn_array_push(scene->objects, &plane); return scene; } diff --git a/libdimension/texture.c b/libdimension/texture.c index c65c913..6f52abe 100644 --- a/libdimension/texture.c +++ b/libdimension/texture.c @@ -31,10 +31,10 @@ dmnsn_new_texture(void) { dmnsn_texture *texture = dmnsn_malloc(sizeof(dmnsn_texture)); texture->pigment = NULL; - texture->finish = NULL; + texture->finish = dmnsn_new_finish(); texture->trans = dmnsn_identity_matrix(); - texture->refcount = 0; - texture->should_init = true; + texture->refcount = 1; + texture->initialized = false; return texture; } @@ -42,7 +42,7 @@ dmnsn_new_texture(void) void dmnsn_delete_texture(dmnsn_texture *texture) { - if (texture && DMNSN_DECREF(texture)) { + if (DMNSN_DECREF(texture)) { dmnsn_delete_finish(texture->finish); dmnsn_delete_pigment(texture->pigment); dmnsn_free(texture); @@ -53,10 +53,34 @@ dmnsn_delete_texture(dmnsn_texture *texture) void dmnsn_initialize_texture(dmnsn_texture *texture) { + dmnsn_assert(!texture->initialized, "Texture double-initialized."); + texture->initialized = true; + texture->trans_inv = dmnsn_matrix_inverse(texture->trans); - if (texture->pigment) { - texture->pigment->trans - = dmnsn_matrix_mul(texture->trans, texture->pigment->trans); + + if (!texture->pigment->initialized) { + texture->pigment->trans = dmnsn_matrix_mul(texture->trans, + texture->pigment->trans); dmnsn_initialize_pigment(texture->pigment); } } + +/* Cascade a texture */ +void +dmnsn_texture_cascade(dmnsn_texture *default_texture, + dmnsn_texture **texturep) +{ + if (!*texturep) { + *texturep = default_texture; + DMNSN_INCREF(*texturep); + } + + dmnsn_texture *texture = *texturep; + + if (!texture->pigment) { + texture->pigment = default_texture->pigment; + DMNSN_INCREF(texture->pigment); + } + + dmnsn_finish_cascade(&default_texture->finish, &texture->finish); +} -- cgit v1.2.3