summaryrefslogtreecommitdiffstats
path: root/libdimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2011-06-12 02:37:51 -0600
committerTavian Barnes <tavianator@gmail.com>2011-06-13 00:16:06 -0600
commit7acd8ea6673b7a90ed4041408ccf1b024b8a007a (patch)
treed52199dd7c58e0217bfd1a74e7601d739ad333f5 /libdimension
parent066261810c2fca192677c5c1c01c91d6ecec65a0 (diff)
downloaddimension-7acd8ea6673b7a90ed4041408ccf1b024b8a007a.tar.xz
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.
Diffstat (limited to 'libdimension')
-rw-r--r--libdimension/Makefile.am5
-rw-r--r--libdimension/ambient.c21
-rw-r--r--libdimension/bench/prtree.c12
-rw-r--r--libdimension/camera.c4
-rw-r--r--libdimension/canvas.c4
-rw-r--r--libdimension/canvas_pigment.c2
-rw-r--r--libdimension/color_map.c2
-rw-r--r--libdimension/csg.c124
-rw-r--r--libdimension/dimension/finish.h158
-rw-r--r--libdimension/dimension/finishes.h28
-rw-r--r--libdimension/dimension/interior.h8
-rw-r--r--libdimension/dimension/object.h15
-rw-r--r--libdimension/dimension/pattern.h2
-rw-r--r--libdimension/dimension/pigment.h12
-rw-r--r--libdimension/dimension/refcount.h5
-rw-r--r--libdimension/dimension/scene.h44
-rw-r--r--libdimension/dimension/sky_sphere.h5
-rw-r--r--libdimension/dimension/texture.h12
-rw-r--r--libdimension/finish.c130
-rw-r--r--libdimension/finish_combination.c150
-rw-r--r--libdimension/interior.c15
-rw-r--r--libdimension/lambertian.c (renamed from libdimension/diffuse.c)24
-rw-r--r--libdimension/light.c4
-rw-r--r--libdimension/object.c38
-rw-r--r--libdimension/pattern.c13
-rw-r--r--libdimension/phong.c24
-rw-r--r--libdimension/pigment.c15
-rw-r--r--libdimension/pigment_map.c6
-rw-r--r--libdimension/prtree.c6
-rw-r--r--libdimension/raytrace.c114
-rw-r--r--libdimension/reflection.c (renamed from libdimension/reflective.c)26
-rw-r--r--libdimension/scene.c70
-rw-r--r--libdimension/sky_sphere.c12
-rw-r--r--libdimension/tests/prtree.c13
-rw-r--r--libdimension/tests/render.c52
-rw-r--r--libdimension/texture.c38
36 files changed, 585 insertions, 628 deletions
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 <stdlib.h>
-/** 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/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
@@ -24,41 +24,33 @@
*/
/**
- * 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 <tavianator@tavianator.com> *
- * *
- * 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 *
- * <http://www.gnu.org/licenses/>. *
- *************************************************************************/
-
-/**
- * @file
- * Finish combinations.
- */
-
-#include "dimension.h"
-#include <math.h>
-#include <stdlib.h>
-
-/** 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/diffuse.c b/libdimension/lambertian.c
index fae8e74..089ce56 100644
--- a/libdimension/diffuse.c
+++ b/libdimension/lambertian.c
@@ -29,12 +29,12 @@
/** 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)
+dmnsn_lambertian_diffuse_fn(const dmnsn_diffuse *diffuse,
+ 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));
+ 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;
@@ -42,17 +42,17 @@ dmnsn_diffuse_finish_fn(const dmnsn_finish *finish,
return ret;
}
-dmnsn_finish *
-dmnsn_new_diffuse_finish(double diffuse)
+dmnsn_diffuse *
+dmnsn_new_lambertian(double diffuse)
{
- dmnsn_finish *finish = dmnsn_new_finish();
+ dmnsn_diffuse *lambertian = dmnsn_new_diffuse();
double *param = dmnsn_malloc(sizeof(double));
*param = diffuse;
- finish->ptr = param;
- finish->diffuse_fn = dmnsn_diffuse_finish_fn;
- finish->free_fn = dmnsn_free;
+ lambertian->diffuse_fn = dmnsn_lambertian_diffuse_fn;
+ lambertian->free_fn = dmnsn_free;
+ lambertian->ptr = param;
- return finish;
+ 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/reflective.c b/libdimension/reflection.c
index 32bec58..2417304 100644
--- a/libdimension/reflective.c
+++ b/libdimension/reflection.c
@@ -35,23 +35,23 @@ typedef struct 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_basic_reflection_fn(const dmnsn_reflection *reflection,
+ 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);
+ 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, reflection),
+ dmnsn_color_gradient(params->min, params->max, coeff),
reflect
);
}
-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)
{
- dmnsn_finish *finish = dmnsn_new_finish();
+ dmnsn_reflection *reflection = dmnsn_new_reflection();
dmnsn_reflection_params *params
= dmnsn_malloc(sizeof(dmnsn_reflection_params));
@@ -59,9 +59,9 @@ dmnsn_new_reflective_finish(dmnsn_color min, dmnsn_color max, double falloff)
params->max = max;
params->falloff = falloff;
- finish->ptr = params;
- finish->reflection_fn = dmnsn_reflective_finish_fn;
- finish->free_fn = dmnsn_free;
+ reflection->reflection_fn = dmnsn_basic_reflection_fn;
+ reflection->free_fn = dmnsn_free;
+ reflection->ptr = params;
- return finish;
+ return reflection;
}
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 <stdio.h>
/*
- * 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);
+}