From 9af188db64514fd5dd6db0a0bf82920b9b661758 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 25 Nov 2009 01:42:37 -0500 Subject: Implement object modifiers and rotation. --- dimension/grammar.y | 46 ++++++++++++++++++++-- dimension/lexer.l | 1 + dimension/parse.h | 2 + dimension/realize.c | 96 +++++++++++++++++++++++++++++---------------- tests/dimension/arithexp.sh | 2 +- tests/dimension/demo.pov | 1 + tests/dimension/demo.sh | 4 +- 7 files changed, 112 insertions(+), 40 deletions(-) diff --git a/dimension/grammar.y b/dimension/grammar.y index 6bf6569..91d3852 100644 --- a/dimension/grammar.y +++ b/dimension/grammar.y @@ -188,6 +188,8 @@ yyerror(YYLTYPE *locp, dmnsn_array *astree, dmnsn_token_iterator *iterator, %error-verbose %token-table +%expect 2 + %parse-param {dmnsn_array *astree} %parse-param {dmnsn_token_iterator *iterator} %lex-param {dmnsn_token_iterator *iterator} @@ -550,7 +552,7 @@ yyerror(YYLTYPE *locp, dmnsn_array *astree, dmnsn_token_iterator *iterator, %token DMNSN_T_RGBT %token DMNSN_T_RIGHT %token DMNSN_T_RIPPLES -%token DMNSN_T_ROTATE +%token DMNSN_T_ROTATE "rotate" %token DMNSN_T_ROUGHNESS %token DMNSN_T_SAMPLES %token DMNSN_T_SAVE_FILE @@ -699,12 +701,19 @@ yyerror(YYLTYPE *locp, dmnsn_array *astree, dmnsn_token_iterator *iterator, /* Top-level items */ %type SCENE_ITEM +/* Transformations */ +%type TRANSFORMATION + /* Objects */ %type OBJECT %type FINITE_SOLID_OBJECT %type BOX %type SPHERE +/* Object modifiers */ +%type OBJECT_MODIFIERS +%type OBJECT_MODIFIER + /* Floats */ %type FLOAT %type FLOAT_EXPR @@ -719,6 +728,8 @@ yyerror(YYLTYPE *locp, dmnsn_array *astree, dmnsn_token_iterator *iterator, %% +/* Start symbol */ + SCENE: /* empty */ { } | SCENE SCENE_ITEM { dmnsn_array_push(astree, &$2); @@ -728,6 +739,14 @@ SCENE: /* empty */ { } SCENE_ITEM: OBJECT ; +/* Transformations */ + +TRANSFORMATION: "rotate" VECTOR { + $$ = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2); + } + +/* Objects */ + OBJECT: FINITE_SOLID_OBJECT ; @@ -737,20 +756,37 @@ FINITE_SOLID_OBJECT: BOX BOX: "box" "{" VECTOR "," VECTOR + OBJECT_MODIFIERS "}" { - $$ = dmnsn_new_astnode2(DMNSN_AST_BOX, @$, $3, $5); + $$ = dmnsn_new_astnode3(DMNSN_AST_BOX, @$, $3, $5, $6); } ; SPHERE: "sphere" "{" VECTOR "," FLOAT + OBJECT_MODIFIERS "}" { - $$ = dmnsn_new_astnode2(DMNSN_AST_SPHERE, @$, $3, $5); + $$ = dmnsn_new_astnode3(DMNSN_AST_SPHERE, @$, $3, $5, $6); } ; +/* Object modifiers */ + +OBJECT_MODIFIERS: /* empty */ { + $$ = dmnsn_new_astnode(DMNSN_AST_OBJECT_MODIFIERS, + @$); + } + | OBJECT_MODIFIERS OBJECT_MODIFIER { + $$ = $1; + dmnsn_array_push($$.children, &$2); + } + +OBJECT_MODIFIER: TRANSFORMATION + +/* Floats */ + FLOAT: FLOAT_EXPR { $$ = dmnsn_eval_scalar($1); dmnsn_delete_astnode($1); @@ -856,6 +892,8 @@ FLOAT_LITERAL: "integer" { } ; +/* Vectors */ + VECTOR: VECTOR_EXPR { $$ = dmnsn_eval_vector($1); dmnsn_delete_astnode($1); @@ -1334,6 +1372,8 @@ dmnsn_astnode_string(dmnsn_astnode_type astnode_type) dmnsn_astnode_map(DMNSN_AST_BOX, "box"); dmnsn_astnode_map(DMNSN_AST_VECTOR, "vector"); dmnsn_astnode_map(DMNSN_AST_SPHERE, "sphere"); + dmnsn_astnode_map(DMNSN_AST_OBJECT_MODIFIERS, "object-modifiers"); + dmnsn_astnode_map(DMNSN_AST_ROTATION, "rotate"); default: fprintf(stderr, "Warning: unrecognised astnode type %d.\n", diff --git a/dimension/lexer.l b/dimension/lexer.l index 50e9a8b..618bb7b 100644 --- a/dimension/lexer.l +++ b/dimension/lexer.l @@ -160,6 +160,7 @@ unsigned long wchar; "grey" PUSH_TOKEN(DMNSN_T_GRAY); "green" PUSH_TOKEN(DMNSN_T_GREEN); "red" PUSH_TOKEN(DMNSN_T_RED); +"rotate" PUSH_TOKEN(DMNSN_T_ROTATE); "sphere" PUSH_TOKEN(DMNSN_T_SPHERE); "t" PUSH_TOKEN(DMNSN_T_T); "transmit" PUSH_TOKEN(DMNSN_T_TRANSMIT); diff --git a/dimension/parse.h b/dimension/parse.h index 5801cdf..ea9ec87 100644 --- a/dimension/parse.h +++ b/dimension/parse.h @@ -33,6 +33,8 @@ typedef enum { DMNSN_AST_VECTOR, DMNSN_AST_BOX, DMNSN_AST_SPHERE, + DMNSN_AST_ROTATION, + DMNSN_AST_OBJECT_MODIFIERS, } dmnsn_astnode_type; typedef struct dmnsn_astnode dmnsn_astnode; diff --git a/dimension/realize.c b/dimension/realize.c index 264c4a7..2c5bd81 100644 --- a/dimension/realize.c +++ b/dimension/realize.c @@ -25,41 +25,14 @@ static double dmnsn_realize_float(dmnsn_astnode astnode) { - dmnsn_astnode lhs, rhs; - switch (astnode.type) { case DMNSN_AST_FLOAT: return *(double *)astnode.ptr; - case DMNSN_AST_INTEGER: return *(long *)astnode.ptr; - case DMNSN_AST_NEGATE: - dmnsn_array_get(astnode.children, 0, &rhs); - return -dmnsn_realize_float(rhs); - - case DMNSN_AST_ADD: - dmnsn_array_get(astnode.children, 0, &lhs); - dmnsn_array_get(astnode.children, 1, &rhs); - return dmnsn_realize_float(lhs) + dmnsn_realize_float(rhs); - - case DMNSN_AST_SUB: - dmnsn_array_get(astnode.children, 0, &lhs); - dmnsn_array_get(astnode.children, 1, &rhs); - return dmnsn_realize_float(lhs) - dmnsn_realize_float(rhs); - - case DMNSN_AST_MUL: - dmnsn_array_get(astnode.children, 0, &lhs); - dmnsn_array_get(astnode.children, 1, &rhs); - return dmnsn_realize_float(lhs) * dmnsn_realize_float(rhs); - - case DMNSN_AST_DIV: - dmnsn_array_get(astnode.children, 0, &lhs); - dmnsn_array_get(astnode.children, 1, &rhs); - return dmnsn_realize_float(lhs) / dmnsn_realize_float(rhs); - default: - dmnsn_error(DMNSN_SEVERITY_HIGH, "Invalid arithmetic expression."); + dmnsn_error(DMNSN_SEVERITY_HIGH, "Invalid float."); return 0; /* Silence compiler warning */ } } @@ -83,7 +56,58 @@ dmnsn_realize_vector(dmnsn_astnode astnode) return dmnsn_new_vector(x, y, z); } -dmnsn_object * +static dmnsn_object * +dmnsn_realize_rotation(dmnsn_astnode astnode, dmnsn_object *object) +{ + const double deg2rad = atan(1.0)/45.0; + + dmnsn_astnode angle_node; + dmnsn_array_get(astnode.children, 0, &angle_node); + + dmnsn_vector angle = dmnsn_vector_mul( + deg2rad, + dmnsn_realize_vector(angle_node) + ); + + /* Rotations in POV-Ray are done about the X-axis first, then Y, then Z */ + object->trans = dmnsn_matrix_mul( + dmnsn_rotation_matrix(dmnsn_new_vector(angle.x, 0.0, 0.0)), + object->trans + ); + object->trans = dmnsn_matrix_mul( + dmnsn_rotation_matrix(dmnsn_new_vector(0.0, angle.y, 0.0)), + object->trans + ); + object->trans = dmnsn_matrix_mul( + dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 0.0, angle.z)), + object->trans + ); + + return object; +} + +static dmnsn_object * +dmnsn_realize_object_modifiers(dmnsn_astnode astnode, dmnsn_object *object) +{ + 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: + object = dmnsn_realize_rotation(modifier, object); + break; + + default: + dmnsn_error(DMNSN_SEVERITY_HIGH, "Invalid object modifier."); + } + } + + return object; +} + +static dmnsn_object * dmnsn_realize_box(dmnsn_astnode astnode) { if (astnode.type != DMNSN_AST_BOX) { @@ -114,10 +138,14 @@ dmnsn_realize_box(dmnsn_astnode astnode) box->trans ); + dmnsn_astnode modifiers; + dmnsn_array_get(astnode.children, 2, &modifiers); + box = dmnsn_realize_object_modifiers(modifiers, box); + return box; } -dmnsn_object * +static dmnsn_object * dmnsn_realize_sphere(dmnsn_astnode astnode) { if (astnode.type != DMNSN_AST_SPHERE) { @@ -151,6 +179,10 @@ dmnsn_realize_sphere(dmnsn_astnode astnode) sphere->trans = dmnsn_scale_matrix(dmnsn_new_vector(r, r, r)); sphere->trans = dmnsn_matrix_mul(dmnsn_translation_matrix(x0), sphere->trans); + dmnsn_astnode modifiers; + dmnsn_array_get(astnode.children, 2, &modifiers); + sphere = dmnsn_realize_object_modifiers(modifiers, sphere); + return sphere; } @@ -188,10 +220,6 @@ dmnsn_realize(const dmnsn_array *astree) dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 1.0, 0.0)), trans ); - trans = dmnsn_matrix_mul( - dmnsn_rotation_matrix(dmnsn_new_vector(-0.75, 0.0, 0.0)), - trans - ); /* Create a perspective camera */ scene->camera = dmnsn_new_perspective_camera(); diff --git a/tests/dimension/arithexp.sh b/tests/dimension/arithexp.sh index 12e3432..dc63576 100755 --- a/tests/dimension/arithexp.sh +++ b/tests/dimension/arithexp.sh @@ -21,7 +21,7 @@ arithexp=$(${top_builddir}/dimension/dimension --tokenize --parse ${srcdir}/arithexp.pov) arithexp_exp='(sphere { < < (float "2.0") - (float "1.0") , (float "3.0") , (float "4.0") > . x , \( (float "1.0") + (integer "2") \) * (integer "2") - (integer "5") , (float "1.0") + (integer "2") * (integer "2") - (integer "4") > - - < (integer "0") , (integer "0") , (integer "1") > , (float "2.25") - (integer "1") * (integer "2") }) -((sphere (vector (float 0) (float 0) (float 0) (integer 0) (integer 0)) (float 0.25)))' +((sphere (vector (float 0) (float 0) (float 0) (integer 0) (integer 0)) (float 0.25) object-modifiers))' if [ "$arithexp" != "$arithexp_exp" ]; then echo "arithexp.pov parsed as \"$arithexp\"" >&2 diff --git a/tests/dimension/demo.pov b/tests/dimension/demo.pov index 85607b8..453ebfc 100644 --- a/tests/dimension/demo.pov +++ b/tests/dimension/demo.pov @@ -21,6 +21,7 @@ box { <-1, -1, -1>, <1, 1, 1> + rotate <45, 0, 0> } sphere { diff --git a/tests/dimension/demo.sh b/tests/dimension/demo.sh index 3ee9635..da3548a 100755 --- a/tests/dimension/demo.sh +++ b/tests/dimension/demo.sh @@ -20,8 +20,8 @@ ######################################################################### demo=$(${top_builddir}/dimension/dimension --tokenize --parse ${srcdir}/demo.pov) -demo_exp='(box { < - (integer "1") , - (integer "1") , - (integer "1") > , < (integer "1") , (integer "1") , (integer "1") > } sphere { < (integer "0") , (integer "0") , (integer "0") > , (float "1.25") }) -((box (vector (integer -1) (integer -1) (integer -1) (integer 0) (integer 0)) (vector (integer 1) (integer 1) (integer 1) (integer 0) (integer 0))) (sphere (vector (integer 0) (integer 0) (integer 0) (integer 0) (integer 0)) (float 1.25)))' +demo_exp='(box { < - (integer "1") , - (integer "1") , - (integer "1") > , < (integer "1") , (integer "1") , (integer "1") > rotate < (integer "45") , (integer "0") , (integer "0") > } sphere { < (integer "0") , (integer "0") , (integer "0") > , (float "1.25") }) +((box (vector (integer -1) (integer -1) (integer -1) (integer 0) (integer 0)) (vector (integer 1) (integer 1) (integer 1) (integer 0) (integer 0)) (object-modifiers (rotate (vector (integer 45) (integer 0) (integer 0) (integer 0) (integer 0))))) (sphere (vector (integer 0) (integer 0) (integer 0) (integer 0) (integer 0)) (float 1.25) object-modifiers))' if [ "$demo" != "$demo_exp" ]; then echo "demo.pov parsed as \"$demo\"" >&2 -- cgit v1.2.3