diff options
author | Tavian Barnes <tavianator@gmail.com> | 2010-04-10 22:09:45 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2010-04-10 22:27:56 -0400 |
commit | 26a6f5d017be9ec0ec03cd20d082546a4e435746 (patch) | |
tree | 75dc9e989945e5b15909328d5a910646bf72abaa /dimension | |
parent | 0f356fe6d666b7f43b5b6f4565fe0b890228a75d (diff) | |
download | dimension-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
Diffstat (limited to 'dimension')
-rw-r--r-- | dimension/common.rules | 7 | ||||
-rw-r--r-- | dimension/parse.c | 9 | ||||
-rw-r--r-- | dimension/realize.c | 256 |
3 files changed, 135 insertions, 137 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: |