From c8667ce6ae94929e9bc06c9af51b6589bc528946 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 17 Jun 2010 09:16:20 -0600 Subject: Fully implement POV-Ray transformations. --- dimension/common.nonterminals | 2 + dimension/common.rules | 108 +++++++++++++++++++++++++++++++++++- dimension/common.terminals | 6 +- dimension/directives.rules | 7 ++- dimension/grammar.epilogue | 9 ++- dimension/lexer.l | 3 + dimension/parse.h | 3 + dimension/realize.c | 124 ++++++++++++++++++++++++++++-------------- 8 files changed, 211 insertions(+), 51 deletions(-) (limited to 'dimension') diff --git a/dimension/common.nonterminals b/dimension/common.nonterminals index 1d39424..5f915c5 100644 --- a/dimension/common.nonterminals +++ b/dimension/common.nonterminals @@ -25,6 +25,8 @@ /* Transformations */ %type TRANSFORMATION +%type TRANSFORMATION_ITEMS +%type TRANSFORMATION_ITEM /* The camera */ %type CAMERA diff --git a/dimension/common.rules b/dimension/common.rules index d897eb3..77830a6 100644 --- a/dimension/common.rules +++ b/dimension/common.rules @@ -43,14 +43,116 @@ STRING: "string" { /* Transformations */ TRANSFORMATION: "rotate" VECTOR { - $$ = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2); + dmnsn_astnode rotation + = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2); + $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, rotation); } | "scale" VECTOR { - $$ = dmnsn_new_astnode1(DMNSN_AST_SCALE, @$, $2); + dmnsn_astnode scale + = dmnsn_new_astnode1(DMNSN_AST_SCALE, @$, $2); + $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, scale); } | "translate" VECTOR { - $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSLATION, @$, $2); + dmnsn_astnode translation + = dmnsn_new_astnode1(DMNSN_AST_TRANSLATION, @$, $2); + $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, + translation); } + | "matrix" "<" FLOAT "," FLOAT "," FLOAT "," + FLOAT "," FLOAT "," FLOAT "," + FLOAT "," FLOAT "," FLOAT "," + FLOAT "," FLOAT "," FLOAT ">" + { + dmnsn_astnode matrix = dmnsn_new_astnode(DMNSN_AST_MATRIX, @$); + + dmnsn_array_push(matrix.children, &$3); + dmnsn_array_push(matrix.children, &$5); + dmnsn_array_push(matrix.children, &$7); + + dmnsn_array_push(matrix.children, &$9); + dmnsn_array_push(matrix.children, &$11); + dmnsn_array_push(matrix.children, &$13); + + dmnsn_array_push(matrix.children, &$15); + dmnsn_array_push(matrix.children, &$17); + dmnsn_array_push(matrix.children, &$19); + + dmnsn_array_push(matrix.children, &$21); + dmnsn_array_push(matrix.children, &$23); + dmnsn_array_push(matrix.children, &$25); + + $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, matrix); + } + | "transform" IDENTIFIER { + dmnsn_astnode *trans = dmnsn_find_symbol(symtable, $2.ptr); + if (!trans) { + dmnsn_diagnostic(@2, "unbound identifier '%s'", + (const char *)$2.ptr); + dmnsn_delete_astnode($2); + YYERROR; + } + if (trans->type != DMNSN_AST_TRANSFORMATION) { + dmnsn_diagnostic( + @2, "identifier '%s' is a %s; expected a %s", + (const char *)$2.ptr, + dmnsn_astnode_string(trans->type), + dmnsn_astnode_string(DMNSN_AST_TRANSFORMATION) + ); + dmnsn_delete_astnode($2); + YYERROR; + } + + $$ = dmnsn_new_astnode(DMNSN_AST_TRANSFORMATION, @$); + dmnsn_copy_children($$, *trans); + dmnsn_delete_astnode($2); + } + | "transform" "{" + TRANSFORMATION_ITEMS + "}" + { + $$ = $3; + } +; + +TRANSFORMATION_ITEMS: TRANSFORMATION_ITEM { + $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, $1); + } + | TRANSFORMATION_ITEMS TRANSFORMATION_ITEM { + $$ = $1; + dmnsn_array_push($$.children, &$2); + } +; + +TRANSFORMATION_ITEM: IDENTIFIER { + dmnsn_astnode *trans = dmnsn_find_symbol(symtable, $1.ptr); + if (!trans) { + dmnsn_diagnostic(@1, "unbound identifier '%s'", + (const char *)$1.ptr); + dmnsn_delete_astnode($1); + YYERROR; + } + if (trans->type != DMNSN_AST_TRANSFORMATION) { + dmnsn_diagnostic( + @1, "identifier '%s' is a %s; expected a %s", + (const char *)$1.ptr, + dmnsn_astnode_string(trans->type), + dmnsn_astnode_string(DMNSN_AST_TRANSFORMATION) + ); + dmnsn_delete_astnode($1); + YYERROR; + } + + dmnsn_array_get(trans->children, 0, &$$); + ++*$$.refcount; + } + | TRANSFORMATION { + dmnsn_array_get($1.children, 0, &$$); + ++*$$.refcount; + dmnsn_delete_astnode($1); + } + | "inverse" { + $$ = dmnsn_new_astnode(DMNSN_AST_INVERSE, @$); + } ; /* Cameras */ diff --git a/dimension/common.terminals b/dimension/common.terminals index fd62320..7ccc8cb 100644 --- a/dimension/common.terminals +++ b/dimension/common.terminals @@ -240,7 +240,7 @@ %token DMNSN_T_INTERPOLATE %token DMNSN_T_INTERSECTION "intersection" %token DMNSN_T_INTERVALS -%token DMNSN_T_INVERSE +%token DMNSN_T_INVERSE "inverse" %token DMNSN_T_IOR "ior" %token DMNSN_T_IRID %token DMNSN_T_IRID_WAVELENGTH @@ -270,7 +270,7 @@ %token DMNSN_T_MARBLE %token DMNSN_T_MATERIAL %token DMNSN_T_MATERIAL_MAP -%token DMNSN_T_MATRIX +%token DMNSN_T_MATRIX "matrix" %token DMNSN_T_MAX "max" %token DMNSN_T_MAX_EXTENT %token DMNSN_T_MAX_GRADIENT @@ -445,7 +445,7 @@ %token DMNSN_T_TOROIDAL %token DMNSN_T_TORUS %token DMNSN_T_TRACE -%token DMNSN_T_TRANSFORM +%token DMNSN_T_TRANSFORM "transform" %token DMNSN_T_TRANSLATE "translate" %token DMNSN_T_TRANSMIT "transmit" %token DMNSN_T_TRIANGLE diff --git a/dimension/directives.rules b/dimension/directives.rules index 84358f6..a3c53d2 100644 --- a/dimension/directives.rules +++ b/dimension/directives.rules @@ -115,7 +115,12 @@ RVALUE: ARITH_EXPR ";" %dprec 2 { | FINISH | INTERIOR | CAMERA - | TRANSFORMATION + | "transform" "{" + TRANSFORMATION_ITEMS + "}" + { + $$ = $3; + } ; DECL_PARAMS: /* empty */ { diff --git a/dimension/grammar.epilogue b/dimension/grammar.epilogue index 7b004e3..073f412 100644 --- a/dimension/grammar.epilogue +++ b/dimension/grammar.epilogue @@ -163,9 +163,12 @@ dmnsn_astnode_string(dmnsn_astnode_type astnode_type) dmnsn_astnode_map(DMNSN_AST_INTERIOR, "interior"); dmnsn_astnode_map(DMNSN_AST_IOR, "ior"); - dmnsn_astnode_map(DMNSN_AST_ROTATION, "rotate"); - dmnsn_astnode_map(DMNSN_AST_SCALE, "scale"); - dmnsn_astnode_map(DMNSN_AST_TRANSLATION, "translate"); + dmnsn_astnode_map(DMNSN_AST_TRANSFORMATION, "transformation"); + dmnsn_astnode_map(DMNSN_AST_ROTATION, "rotation"); + dmnsn_astnode_map(DMNSN_AST_SCALE, "scale"); + dmnsn_astnode_map(DMNSN_AST_TRANSLATION, "translation"); + dmnsn_astnode_map(DMNSN_AST_MATRIX, "matrix"); + dmnsn_astnode_map(DMNSN_AST_INVERSE, "inverse"); dmnsn_astnode_map(DMNSN_AST_FLOAT, "float"); dmnsn_astnode_map(DMNSN_AST_INTEGER, "integer"); diff --git a/dimension/lexer.l b/dimension/lexer.l index 85c3fda..ea98c07 100644 --- a/dimension/lexer.l +++ b/dimension/lexer.l @@ -207,12 +207,14 @@ unsigned long wchar; "int" RETURN_TOKEN(DMNSN_T_INT); "interior" RETURN_TOKEN(DMNSN_T_INTERIOR); "intersection" RETURN_TOKEN(DMNSN_T_INTERSECTION); +"inverse" RETURN_TOKEN(DMNSN_T_INVERSE); "ior" RETURN_TOKEN(DMNSN_T_IOR); "ln" RETURN_TOKEN(DMNSN_T_LN); "location" RETURN_TOKEN(DMNSN_T_LOCATION); "log" RETURN_TOKEN(DMNSN_T_LOG); "look_at" RETURN_TOKEN(DMNSN_T_LOOK_AT); "light_source" RETURN_TOKEN(DMNSN_T_LIGHT_SOURCE); +"matrix" RETURN_TOKEN(DMNSN_T_MATRIX); "max" RETURN_TOKEN(DMNSN_T_MAX); "max_trace_level" RETURN_TOKEN(DMNSN_T_MAX_TRACE_LEVEL); "merge" RETURN_TOKEN(DMNSN_T_MERGE); @@ -251,6 +253,7 @@ unsigned long wchar; "tan" RETURN_TOKEN(DMNSN_T_TAN); "tanh" RETURN_TOKEN(DMNSN_T_TANH); "texture" RETURN_TOKEN(DMNSN_T_TEXTURE); +"transform" RETURN_TOKEN(DMNSN_T_TRANSFORM); "translate" RETURN_TOKEN(DMNSN_T_TRANSLATE); "transmit" RETURN_TOKEN(DMNSN_T_TRANSMIT); "true" RETURN_TOKEN(DMNSN_T_TRUE); diff --git a/dimension/parse.h b/dimension/parse.h index b4bd8fe..fd78665 100644 --- a/dimension/parse.h +++ b/dimension/parse.h @@ -77,9 +77,12 @@ typedef enum { DMNSN_AST_INTERIOR, DMNSN_AST_IOR, + DMNSN_AST_TRANSFORMATION, DMNSN_AST_ROTATION, DMNSN_AST_SCALE, DMNSN_AST_TRANSLATION, + DMNSN_AST_MATRIX, + DMNSN_AST_INVERSE, DMNSN_AST_FLOAT, DMNSN_AST_INTEGER, diff --git a/dimension/realize.c b/dimension/realize.c index e558c5b..a9b9c71 100644 --- a/dimension/realize.c +++ b/dimension/realize.c @@ -112,6 +112,31 @@ dmnsn_realize_color(dmnsn_astnode astnode) return color; } +static dmnsn_matrix +dmnsn_realize_translation(dmnsn_astnode astnode) +{ + dmnsn_assert(astnode.type == DMNSN_AST_TRANSLATION, + "Expected a translation."); + + dmnsn_astnode trans_node; + dmnsn_array_get(astnode.children, 0, &trans_node); + dmnsn_vector trans = dmnsn_realize_vector(trans_node); + + return dmnsn_translation_matrix(trans); +} + +static dmnsn_matrix +dmnsn_realize_scale(dmnsn_astnode astnode) +{ + dmnsn_assert(astnode.type == DMNSN_AST_SCALE, "Expected a scale."); + + dmnsn_astnode scale_node; + dmnsn_array_get(astnode.children, 0, &scale_node); + dmnsn_vector scale = dmnsn_realize_vector(scale_node); + + return dmnsn_scale_matrix(scale); +} + static dmnsn_matrix dmnsn_realize_rotation(dmnsn_astnode astnode) { @@ -143,45 +168,72 @@ dmnsn_realize_rotation(dmnsn_astnode astnode) } static dmnsn_matrix -dmnsn_realize_scale(dmnsn_astnode astnode) +dmnsn_realize_matrix(dmnsn_astnode astnode) { - dmnsn_assert(astnode.type == DMNSN_AST_SCALE, "Expected a scale."); + dmnsn_assert(astnode.type == DMNSN_AST_MATRIX, "Expected a matrix."); - dmnsn_astnode scale_node; - dmnsn_array_get(astnode.children, 0, &scale_node); - dmnsn_vector scale = dmnsn_realize_vector(scale_node); + dmnsn_astnode *children = dmnsn_array_first(astnode.children); + dmnsn_matrix trans; - return dmnsn_scale_matrix(scale); -} + trans.n[0][0] = dmnsn_realize_float(children[0]); + trans.n[0][1] = dmnsn_realize_float(children[1]); + trans.n[0][2] = dmnsn_realize_float(children[2]); + trans.n[0][3] = dmnsn_realize_float(children[9]); -static dmnsn_matrix -dmnsn_realize_translation(dmnsn_astnode astnode) -{ - dmnsn_assert(astnode.type == DMNSN_AST_TRANSLATION, - "Expected a translation."); + trans.n[1][0] = dmnsn_realize_float(children[3]); + trans.n[1][1] = dmnsn_realize_float(children[4]); + trans.n[1][2] = dmnsn_realize_float(children[5]); + trans.n[1][3] = dmnsn_realize_float(children[10]); - dmnsn_astnode trans_node; - dmnsn_array_get(astnode.children, 0, &trans_node); - dmnsn_vector trans = dmnsn_realize_vector(trans_node); + trans.n[2][0] = dmnsn_realize_float(children[6]); + trans.n[2][1] = dmnsn_realize_float(children[7]); + trans.n[2][2] = dmnsn_realize_float(children[8]); + trans.n[2][3] = dmnsn_realize_float(children[11]); - return dmnsn_translation_matrix(trans); + trans.n[3][0] = 0.0; + trans.n[3][1] = 0.0; + trans.n[3][2] = 0.0; + trans.n[3][3] = 1.0; + + return trans; } static dmnsn_matrix dmnsn_realize_transformation(dmnsn_astnode astnode) { - switch (astnode.type) { - case DMNSN_AST_ROTATION: - return dmnsn_realize_rotation(astnode); - case DMNSN_AST_SCALE: - return dmnsn_realize_scale(astnode); - case DMNSN_AST_TRANSLATION: - return dmnsn_realize_translation(astnode); + dmnsn_assert(astnode.type == DMNSN_AST_TRANSFORMATION, + "Expected a transformation."); - default: - dmnsn_assert(false, "Expected a transformation."); - return dmnsn_identity_matrix(); /* Shut up compiler */ + dmnsn_matrix trans = dmnsn_identity_matrix(); + + DMNSN_ARRAY_FOREACH (dmnsn_astnode *, child, astnode.children) { + switch (child->type) { + case DMNSN_AST_TRANSLATION: + trans = dmnsn_matrix_mul(trans, dmnsn_realize_translation(*child)); + break; + case DMNSN_AST_SCALE: + trans = dmnsn_matrix_mul(trans, dmnsn_realize_scale(*child)); + break; + case DMNSN_AST_ROTATION: + trans = dmnsn_matrix_mul(trans, dmnsn_realize_rotation(*child)); + break; + case DMNSN_AST_MATRIX: + trans = dmnsn_matrix_mul(trans, dmnsn_realize_matrix(*child)); + break; + case DMNSN_AST_INVERSE: + trans = dmnsn_matrix_inverse(trans); + break; + case DMNSN_AST_TRANSFORMATION: + trans = dmnsn_matrix_mul(trans, dmnsn_realize_transformation(*child)); + break; + + default: + dmnsn_assert(false, "Invalid transformation type."); + break; + } } + + return trans; } static void @@ -320,9 +372,7 @@ dmnsn_realize_camera(dmnsn_astnode astnode) } /* Transformations */ - case DMNSN_AST_ROTATION: - case DMNSN_AST_SCALE: - case DMNSN_AST_TRANSLATION: + case DMNSN_AST_TRANSFORMATION: trans = dmnsn_matrix_mul(dmnsn_realize_transformation(*item), trans); break; @@ -408,9 +458,7 @@ dmnsn_realize_pigment_modifiers(dmnsn_astnode astnode, dmnsn_pigment *pigment) DMNSN_ARRAY_FOREACH(dmnsn_astnode *, modifier, astnode.children) { switch (modifier->type) { - case DMNSN_AST_ROTATION: - case DMNSN_AST_SCALE: - case DMNSN_AST_TRANSLATION: + case DMNSN_AST_TRANSFORMATION: pigment->trans = dmnsn_matrix_mul( dmnsn_realize_transformation(*modifier), pigment->trans @@ -621,9 +669,7 @@ dmnsn_realize_texture(dmnsn_astnode astnode) texture->finish = dmnsn_realize_finish(*item); break; - case DMNSN_AST_ROTATION: - case DMNSN_AST_SCALE: - case DMNSN_AST_TRANSLATION: + case DMNSN_AST_TRANSFORMATION: texture->trans = dmnsn_matrix_mul( dmnsn_realize_transformation(*item), texture->trans @@ -673,9 +719,7 @@ dmnsn_realize_object_modifiers(dmnsn_astnode astnode, dmnsn_object *object) DMNSN_ARRAY_FOREACH (dmnsn_astnode *, modifier, astnode.children) { switch (modifier->type) { - case DMNSN_AST_ROTATION: - case DMNSN_AST_SCALE: - case DMNSN_AST_TRANSLATION: + case DMNSN_AST_TRANSFORMATION: object->trans = dmnsn_matrix_mul( dmnsn_realize_transformation(*modifier), object->trans @@ -728,9 +772,7 @@ dmnsn_realize_light_source_modifiers(dmnsn_astnode astnode, dmnsn_light *light) DMNSN_ARRAY_FOREACH (dmnsn_astnode *, modifier, astnode.children) { switch (modifier->type) { - case DMNSN_AST_ROTATION: - case DMNSN_AST_SCALE: - case DMNSN_AST_TRANSLATION: + case DMNSN_AST_TRANSFORMATION: light->x0 = dmnsn_transform_vector( dmnsn_realize_transformation(*modifier), light->x0 -- cgit v1.2.3