summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dimension/grammar.y46
-rw-r--r--dimension/lexer.l1
-rw-r--r--dimension/parse.h2
-rw-r--r--dimension/realize.c96
-rwxr-xr-xtests/dimension/arithexp.sh2
-rw-r--r--tests/dimension/demo.pov1
-rwxr-xr-xtests/dimension/demo.sh4
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 <astnode> SCENE_ITEM
+/* Transformations */
+%type <astnode> TRANSFORMATION
+
/* Objects */
%type <astnode> OBJECT
%type <astnode> FINITE_SOLID_OBJECT
%type <astnode> BOX
%type <astnode> SPHERE
+/* Object modifiers */
+%type <astnode> OBJECT_MODIFIERS
+%type <astnode> OBJECT_MODIFIER
+
/* Floats */
%type <astnode> FLOAT
%type <astnode> 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