summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-04-10 22:09:45 -0400
committerTavian Barnes <tavianator@gmail.com>2010-04-10 22:27:56 -0400
commit26a6f5d017be9ec0ec03cd20d082546a4e435746 (patch)
tree75dc9e989945e5b15909328d5a910646bf72abaa
parent0f356fe6d666b7f43b5b6f4565fe0b890228a75d (diff)
downloaddimension-26a6f5d017be9ec0ec03cd20d082546a4e435746.tar.xz
Improve CSG and light handling.
- Lights can be inside CSG objects - Lights can be modified by transformations - CSG objects can contain only one object
-rw-r--r--dimension/common.rules7
-rw-r--r--dimension/parse.c9
-rw-r--r--dimension/realize.c256
-rw-r--r--tests/dimension/Makefile.am10
-rw-r--r--tests/dimension/csg.pov65
-rwxr-xr-xtests/dimension/csg.sh85
-rwxr-xr-xtests/dimension/demo.sh3
7 files changed, 296 insertions, 139 deletions
diff --git a/dimension/common.rules b/dimension/common.rules
index e604b9f..c5f9eea 100644
--- a/dimension/common.rules
+++ b/dimension/common.rules
@@ -236,8 +236,8 @@ MERGE: "merge" "{"
}
;
-OBJECTS: OBJECT OBJECT {
- $$ = dmnsn_new_astnode2(DMNSN_AST_ARRAY, @$, $1, $2);
+OBJECTS: OBJECT {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_ARRAY, @$, $1);
}
| OBJECTS OBJECT {
$$ = $1;
@@ -246,9 +246,10 @@ OBJECTS: OBJECT OBJECT {
LIGHT_SOURCE: "light_source" "{"
VECTOR "," COLOR
+ OBJECT_MODIFIERS
"}"
{
- $$ = dmnsn_new_astnode2(DMNSN_AST_LIGHT_SOURCE, @$, $3, $5);
+ $$ = dmnsn_new_astnode3(DMNSN_AST_LIGHT_SOURCE, @$, $3, $5, $6);
}
;
diff --git a/dimension/parse.c b/dimension/parse.c
index 19ba24c..2f717f9 100644
--- a/dimension/parse.c
+++ b/dimension/parse.c
@@ -536,12 +536,7 @@ dmnsn_vector_promote(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) {
component = dmnsn_copy_astnode(component);
- component.type = DMNSN_AST_INTEGER;
-
- long *val = dmnsn_malloc(sizeof(long));
- *val = 0;
-
- component.ptr = val;
+ dmnsn_make_ast_integer(&component, 0);
dmnsn_array_push(promoted.children, &component);
}
} else {
@@ -1759,6 +1754,8 @@ dmnsn_print_astnode(FILE *file, dmnsn_astnode astnode)
case DMNSN_AST_FLOAT:
dvalue = *(double *)astnode.ptr;
+ /* Don't print -0 */
+ if (dvalue == 0.0) dvalue = 0.0;
fprintf(file, "(%s %g)", dmnsn_astnode_string(astnode.type), dvalue);
break;
diff --git a/dimension/realize.c b/dimension/realize.c
index 215d891..b5c6066 100644
--- a/dimension/realize.c
+++ b/dimension/realize.c
@@ -643,7 +643,76 @@ dmnsn_realize_object_modifiers(dmnsn_astnode astnode, dmnsn_object *object)
}
}
-static dmnsn_object *dmnsn_realize_object(dmnsn_astnode astnode);
+static void
+dmnsn_realize_light_source_modifiers(dmnsn_astnode astnode, dmnsn_light *light)
+{
+ dmnsn_assert(astnode.type == DMNSN_AST_OBJECT_MODIFIERS,
+ "Expected object modifiers.");
+
+ unsigned int i;
+ for (i = 0; i < dmnsn_array_size(astnode.children); ++i) {
+ dmnsn_astnode modifier;
+ dmnsn_array_get(astnode.children, i, &modifier);
+
+ switch (modifier.type) {
+ case DMNSN_AST_ROTATION:
+ light->x0 = dmnsn_matrix_vector_mul(
+ dmnsn_realize_rotation(modifier),
+ light->x0
+ );
+ break;
+ case DMNSN_AST_SCALE:
+ light->x0 = dmnsn_matrix_vector_mul(
+ dmnsn_realize_scale(modifier),
+ light->x0
+ );
+ break;
+ case DMNSN_AST_TRANSLATION:
+ light->x0 = dmnsn_matrix_vector_mul(
+ dmnsn_realize_translation(modifier),
+ light->x0
+ );
+ break;
+
+ case DMNSN_AST_TEXTURE:
+ case DMNSN_AST_PIGMENT:
+ case DMNSN_AST_FINISH:
+ case DMNSN_AST_INTERIOR:
+ dmnsn_diagnostic(modifier.filename, modifier.line, modifier.col,
+ "WARNING: ignoring %s applied to light source",
+ dmnsn_astnode_string(modifier.type));
+ break;
+
+ default:
+ dmnsn_assert(false, "Invalid object modifier.");
+ }
+ }
+}
+
+static dmnsn_light *
+dmnsn_realize_light_source(dmnsn_astnode astnode)
+{
+ dmnsn_assert(astnode.type == DMNSN_AST_LIGHT_SOURCE,
+ "Expected a light source.");
+
+ dmnsn_astnode point, color_node;
+ dmnsn_array_get(astnode.children, 0, &point);
+ dmnsn_array_get(astnode.children, 1, &color_node);
+
+ dmnsn_vector x0 = dmnsn_realize_vector(point);
+ dmnsn_color color = dmnsn_realize_color(color_node);
+
+ dmnsn_light *light = dmnsn_new_point_light(x0, color);
+
+ dmnsn_astnode modifiers;
+ dmnsn_array_get(astnode.children, 2, &modifiers);
+ dmnsn_realize_light_source_modifiers(modifiers, light);
+
+ return light;
+}
+
+static dmnsn_object *dmnsn_realize_object(dmnsn_astnode astnode,
+ dmnsn_array *lights);
static dmnsn_object *
dmnsn_realize_box(dmnsn_astnode astnode)
@@ -702,155 +771,103 @@ dmnsn_realize_sphere(dmnsn_astnode astnode)
return sphere;
}
+typedef dmnsn_object *dmnsn_csg_object_fn(dmnsn_object *a, dmnsn_object *b);
+
+/* Generalized CSG realizer */
static dmnsn_object *
-dmnsn_realize_union(dmnsn_astnode astnode)
+dmnsn_realize_csg(dmnsn_astnode astnode, dmnsn_array *lights,
+ dmnsn_csg_object_fn *csg_object_fn)
{
- dmnsn_assert(astnode.type == DMNSN_AST_UNION, "Expected a union.");
-
- dmnsn_astnode objects;
+ dmnsn_astnode objects, modifiers;
dmnsn_array_get(astnode.children, 0, &objects);
+ dmnsn_array_get(astnode.children, 1, &modifiers);
- dmnsn_astnode o1node, o2node;
- dmnsn_array_get(objects.children, 0, &o1node);
- dmnsn_array_get(objects.children, 1, &o2node);
-
- dmnsn_object *o1 = dmnsn_realize_object(o1node);
- dmnsn_object *o2 = dmnsn_realize_object(o2node);
+ unsigned int i;
+ dmnsn_object *csg = NULL;
+ for (i = 0; i < dmnsn_array_size(objects.children) && !csg; ++i) {
+ dmnsn_astnode onode;
+ dmnsn_array_get(objects.children, i, &onode);
- dmnsn_object *csg = dmnsn_new_csg_union(o1, o2);
+ if (onode.type == DMNSN_AST_LIGHT_SOURCE) {
+ dmnsn_light *light = dmnsn_realize_light_source(onode);
+ dmnsn_realize_light_source_modifiers(modifiers, light);
+ dmnsn_array_push(lights, &light);
+ } else {
+ csg = dmnsn_realize_object(onode, lights);
+ }
+ }
- unsigned int i;
- for (i = 2; i < dmnsn_array_size(objects.children); ++i) {
+ for (; i < dmnsn_array_size(objects.children); ++i) {
dmnsn_astnode onode;
dmnsn_array_get(objects.children, i, &onode);
- dmnsn_object *object = dmnsn_realize_object(onode);
- csg = dmnsn_new_csg_union(csg, object);
+ if (onode.type == DMNSN_AST_LIGHT_SOURCE) {
+ dmnsn_light *light = dmnsn_realize_light_source(onode);
+ dmnsn_realize_light_source_modifiers(modifiers, light);
+ dmnsn_array_push(lights, &light);
+ } else {
+ dmnsn_object *object = dmnsn_realize_object(onode, lights);
+ csg = (*csg_object_fn)(csg, object);
+ }
}
- dmnsn_astnode modifiers;
- dmnsn_array_get(astnode.children, 1, &modifiers);
dmnsn_realize_object_modifiers(modifiers, csg);
-
return csg;
}
static dmnsn_object *
-dmnsn_realize_intersection(dmnsn_astnode astnode)
+dmnsn_realize_union(dmnsn_astnode astnode, dmnsn_array *lights)
+{
+ dmnsn_assert(astnode.type == DMNSN_AST_UNION, "Expected a union.");
+ return dmnsn_realize_csg(astnode, lights, &dmnsn_new_csg_union);
+}
+
+static dmnsn_object *
+dmnsn_realize_intersection(dmnsn_astnode astnode, dmnsn_array *lights)
{
dmnsn_assert(astnode.type == DMNSN_AST_INTERSECTION,
"Expected an intersection.");
-
- dmnsn_astnode objects;
- dmnsn_array_get(astnode.children, 0, &objects);
-
- dmnsn_astnode o1node, o2node;
- dmnsn_array_get(objects.children, 0, &o1node);
- dmnsn_array_get(objects.children, 1, &o2node);
-
- dmnsn_object *o1 = dmnsn_realize_object(o1node);
- dmnsn_object *o2 = dmnsn_realize_object(o2node);
-
- dmnsn_object *csg = dmnsn_new_csg_intersection(o1, o2);
-
- unsigned int i;
- for (i = 2; i < dmnsn_array_size(objects.children); ++i) {
- dmnsn_astnode onode;
- dmnsn_array_get(objects.children, i, &onode);
-
- dmnsn_object *object = dmnsn_realize_object(onode);
- csg = dmnsn_new_csg_intersection(csg, object);
- }
-
- dmnsn_astnode modifiers;
- dmnsn_array_get(astnode.children, 1, &modifiers);
- dmnsn_realize_object_modifiers(modifiers, csg);
-
- return csg;
+ return dmnsn_realize_csg(astnode, lights, &dmnsn_new_csg_intersection);
}
static dmnsn_object *
-dmnsn_realize_difference(dmnsn_astnode astnode)
+dmnsn_realize_difference(dmnsn_astnode astnode, dmnsn_array *lights)
{
dmnsn_assert(astnode.type == DMNSN_AST_DIFFERENCE, "Expected a difference.");
-
- dmnsn_astnode objects;
- dmnsn_array_get(astnode.children, 0, &objects);
-
- dmnsn_astnode o1node, o2node;
- dmnsn_array_get(objects.children, 0, &o1node);
- dmnsn_array_get(objects.children, 1, &o2node);
-
- dmnsn_object *o1 = dmnsn_realize_object(o1node);
- dmnsn_object *o2 = dmnsn_realize_object(o2node);
-
- dmnsn_object *csg = dmnsn_new_csg_difference(o1, o2);
-
- unsigned int i;
- for (i = 2; i < dmnsn_array_size(objects.children); ++i) {
- dmnsn_astnode onode;
- dmnsn_array_get(objects.children, i, &onode);
-
- dmnsn_object *object = dmnsn_realize_object(onode);
- csg = dmnsn_new_csg_difference(csg, object);
- }
-
- dmnsn_astnode modifiers;
- dmnsn_array_get(astnode.children, 1, &modifiers);
- dmnsn_realize_object_modifiers(modifiers, csg);
-
- return csg;
+ return dmnsn_realize_csg(astnode, lights, &dmnsn_new_csg_difference);
}
static dmnsn_object *
-dmnsn_realize_merge(dmnsn_astnode astnode)
+dmnsn_realize_merge(dmnsn_astnode astnode, dmnsn_array *lights)
{
dmnsn_assert(astnode.type == DMNSN_AST_MERGE, "Expected a merge.");
-
- dmnsn_astnode objects;
- dmnsn_array_get(astnode.children, 0, &objects);
-
- dmnsn_astnode o1node, o2node;
- dmnsn_array_get(objects.children, 0, &o1node);
- dmnsn_array_get(objects.children, 1, &o2node);
-
- dmnsn_object *o1 = dmnsn_realize_object(o1node);
- dmnsn_object *o2 = dmnsn_realize_object(o2node);
-
- dmnsn_object *csg = dmnsn_new_csg_merge(o1, o2);
-
- unsigned int i;
- for (i = 2; i < dmnsn_array_size(objects.children); ++i) {
- dmnsn_astnode onode;
- dmnsn_array_get(objects.children, i, &onode);
-
- dmnsn_object *object = dmnsn_realize_object(onode);
- csg = dmnsn_new_csg_merge(csg, object);
- }
-
- dmnsn_astnode modifiers;
- dmnsn_array_get(astnode.children, 1, &modifiers);
- dmnsn_realize_object_modifiers(modifiers, csg);
-
- return csg;
+ return dmnsn_realize_csg(astnode, lights, &dmnsn_new_csg_merge);
}
+/* Realize an object, or maybe a light */
static dmnsn_object *
-dmnsn_realize_object(dmnsn_astnode astnode)
+dmnsn_realize_object(dmnsn_astnode astnode, dmnsn_array *lights)
{
switch (astnode.type) {
case DMNSN_AST_BOX:
return dmnsn_realize_box(astnode);
case DMNSN_AST_DIFFERENCE:
- return dmnsn_realize_difference(astnode);
+ return dmnsn_realize_difference(astnode, lights);
case DMNSN_AST_INTERSECTION:
- return dmnsn_realize_intersection(astnode);
+ return dmnsn_realize_intersection(astnode, lights);
case DMNSN_AST_MERGE:
- return dmnsn_realize_merge(astnode);
+ return dmnsn_realize_merge(astnode, lights);
case DMNSN_AST_SPHERE:
return dmnsn_realize_sphere(astnode);
case DMNSN_AST_UNION:
- return dmnsn_realize_union(astnode);
+ return dmnsn_realize_union(astnode, lights);
+
+ case DMNSN_AST_LIGHT_SOURCE:
+ {
+ dmnsn_light *light = dmnsn_realize_light_source(astnode);
+ dmnsn_array_push(lights, &light);
+ return NULL;
+ }
default:
dmnsn_assert(false, "Expected an object.");
@@ -858,24 +875,6 @@ dmnsn_realize_object(dmnsn_astnode astnode)
}
}
-static dmnsn_light *
-dmnsn_realize_light_source(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_LIGHT_SOURCE,
- "Expected a light source.");
-
- dmnsn_astnode point, color_node;
- dmnsn_array_get(astnode.children, 0, &point);
- dmnsn_array_get(astnode.children, 1, &color_node);
-
- dmnsn_vector x0 = dmnsn_realize_vector(point);
- dmnsn_color color = dmnsn_realize_color(color_node);
-
- dmnsn_light *light = dmnsn_new_point_light(x0, color);
-
- return light;
-}
-
static dmnsn_scene *
dmnsn_realize_astree(const dmnsn_astree *astree)
{
@@ -928,8 +927,9 @@ dmnsn_realize_astree(const dmnsn_astree *astree)
case DMNSN_AST_MERGE:
case DMNSN_AST_SPHERE:
case DMNSN_AST_UNION:
- object = dmnsn_realize_object(astnode);
- dmnsn_array_push(scene->objects, &object);
+ object = dmnsn_realize_object(astnode, scene->lights);
+ if (object)
+ dmnsn_array_push(scene->objects, &object);
break;
case DMNSN_AST_LIGHT_SOURCE:
diff --git a/tests/dimension/Makefile.am b/tests/dimension/Makefile.am
index bb4aa0f..44afead 100644
--- a/tests/dimension/Makefile.am
+++ b/tests/dimension/Makefile.am
@@ -19,7 +19,14 @@
INCLUDES = -I$(top_srcdir)/libdimension
-TESTS = punctuation.sh numeric.sh strings.sh labels.sh directives.sh arithexp.sh demo.sh
+TESTS = punctuation.sh \
+ numeric.sh \
+ strings.sh \
+ labels.sh \
+ directives.sh \
+ arithexp.sh \
+ csg.sh \
+ demo.sh
TESTS_ENVIRONMENT = top_builddir=$(top_builddir)
.sh:
@@ -33,6 +40,7 @@ EXTRA_DIST = $(TESTS) \
directives.inc \
directives.pov \
arithexp.pov \
+ csg.pov \
demo.pov
clean-local:
diff --git a/tests/dimension/csg.pov b/tests/dimension/csg.pov
new file mode 100644
index 0000000..046510f
--- /dev/null
+++ b/tests/dimension/csg.pov
@@ -0,0 +1,65 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of The Dimension Test Suite. *
+ * *
+ * The Dimension Test Suite is free software; you can redistribute it *
+ * and/or modify it under the terms of the GNU 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 Test Suite 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 *
+ * General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+// Test constructive solid geometry
+
+camera {
+ perspective
+ location -4*z
+ right 1.6*x
+ look_at 0
+}
+
+background {
+ color rgbf <0, 0.1, 0.2, 0.1>
+}
+
+/* One-object unions */
+
+union {
+ sphere {
+ -1.5*x, 1
+ pigment { color red 1 }
+ }
+}
+
+union {
+ light_source {
+ 20*y, color rgb 0.5
+ }
+}
+
+/* CSG with lights */
+difference {
+ light_source {
+ -15*x, color rgb 0.5
+ }
+ sphere {
+ 1.5*x - 20*y, 1
+ pigment { color green 1 }
+ }
+ light_source {
+ 15*x, color rgb 0.5
+ }
+ box {
+ <0.7, -20.8, -0.8>, <2.3, -19.2, 0.8>
+ pigment { color blue 1 }
+ }
+ translate 20*y
+}
diff --git a/tests/dimension/csg.sh b/tests/dimension/csg.sh
new file mode 100755
index 0000000..c27e448
--- /dev/null
+++ b/tests/dimension/csg.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+#########################################################################
+# Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> #
+# #
+# This file is part of The Dimension Test Suite. #
+# #
+# The Dimension Test Suite is free software; you can redistribute it #
+# and/or modify it under the terms of the GNU 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 Test Suite 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 #
+# General Public License for more details. #
+# #
+# You should have received a copy of the GNU General Public License #
+# along with this program. If not, see <http://www.gnu.org/licenses/>. #
+#########################################################################
+
+csg=$(${top_builddir}/dimension/dimension --parse ${srcdir}/csg.pov)
+csg_exp="$(echo -n \
+'((camera
+ perspective
+ (location (vector (integer 0) (integer 0) (integer -4)
+ (integer 0) (integer 0)))
+ (right (vector (float 1.6) (float 0) (float 0) (float 0) (float 0)))
+ (look_at (vector (integer 0) (integer 0) (integer 0)
+ (integer 0) (integer 0))))
+ (background
+ (vector (integer 0) (float 0.1) (float 0.2) (float 0.1) (integer 0)))
+ (union
+ (array
+ (sphere
+ (vector (float -1.5) (float 0) (float 0) (float 0) (float 0))
+ (integer 1)
+ (object-modifiers
+ (pigment
+ (vector (integer 1) (integer 0) (integer 0)
+ (integer 0) (integer 0))))))
+ object-modifiers)
+ (union
+ (array
+ (light_source
+ (vector (integer 0) (integer 20) (integer 0) (integer 0) (integer 0))
+ (vector (float 0.5) (float 0.5) (float 0.5) (integer 0) (integer 0))
+ object-modifiers))
+ object-modifiers)
+ (difference
+ (array
+ (light_source
+ (vector (integer -15) (integer 0) (integer 0) (integer 0) (integer 0))
+ (vector (float 0.5) (float 0.5) (float 0.5) (integer 0) (integer 0))
+ object-modifiers)
+ (sphere
+ (vector (float 1.5) (float -20) (float 0) (float 0) (float 0))
+ (integer 1)
+ (object-modifiers
+ (pigment
+ (vector (integer 0) (integer 1) (integer 0)
+ (integer 0) (integer 0)))))
+ (light_source
+ (vector (integer 15) (integer 0) (integer 0) (integer 0) (integer 0))
+ (vector (float 0.5) (float 0.5) (float 0.5) (integer 0) (integer 0))
+ object-modifiers)
+ (box
+ (vector (float 0.7) (float -20.8) (float -0.8) (integer 0) (integer 0))
+ (vector (float 2.3) (float -19.2) (float 0.8) (integer 0) (integer 0))
+ (object-modifiers
+ (pigment
+ (vector (integer 0) (integer 0) (integer 1)
+ (integer 0) (integer 0))))))
+ (object-modifiers
+ (translate (vector (integer 0) (integer 20) (integer 0)
+ (integer 0) (integer 0))))))' \
+| tr '\n' ' ' | sed -r 's/[[:space:]]+/ /g')"
+
+if [ "$csg" != "$csg_exp" ]; then
+ echo "csg.pov parsed as \"$csg\"" >&2
+ echo " -- expected \"$csg_exp\"" >&2
+ exit 1
+fi
+
+${top_builddir}/dimension/dimension -w768 -h480 -o csg.png ${srcdir}/csg.pov
diff --git a/tests/dimension/demo.sh b/tests/dimension/demo.sh
index 687d43c..7e9306a 100755
--- a/tests/dimension/demo.sh
+++ b/tests/dimension/demo.sh
@@ -34,7 +34,8 @@ demo_exp=$(echo -n \
(vector (integer 0) (float 0.1) (float 0.2) (float 0.1) (integer 0)))
(light_source
(vector (integer -15) (integer 20) (integer 10) (integer 0) (integer 0))
- (vector (integer 1) (integer 1) (integer 1) (integer 0) (integer 0)))
+ (vector (integer 1) (integer 1) (integer 1) (integer 0) (integer 0))
+ object-modifiers)
(difference
(array
(box