summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-03-23 01:53:28 -0400
committerTavian Barnes <tavianator@gmail.com>2010-03-23 01:53:28 -0400
commit1d441aea4446484342f93fbf315f7f70de8adaf7 (patch)
tree98dd1c7521155b0390976d847e841db2227a6704
parent7fc84f364bcb2e37363d3e22300180ba92288811 (diff)
downloaddimension-1d441aea4446484342f93fbf315f7f70de8adaf7.tar.xz
Implement most vector functions.
-rw-r--r--dimension/common.rules15
-rw-r--r--dimension/common.terminals8
-rw-r--r--dimension/grammar.epilogue72
-rw-r--r--dimension/lexer.l4
-rw-r--r--dimension/parse.c189
-rw-r--r--dimension/parse.h4
-rw-r--r--tests/dimension/arithexp.pov33
7 files changed, 285 insertions, 40 deletions
diff --git a/dimension/common.rules b/dimension/common.rules
index 81719c5..e22995f 100644
--- a/dimension/common.rules
+++ b/dimension/common.rules
@@ -495,12 +495,27 @@ ARITH_EXPR: FLOAT_LITERAL
| "val" "(" STRING ")" {
$$ = dmnsn_new_astnode1(DMNSN_AST_VAL, @$, $3);
}
+ | "vaxis_rotate" "(" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ")" {
+ dmnsn_astnode axis
+ = dmnsn_new_astnode1(DMNSN_AST_VNORMALIZE, @$, $5);
+ axis = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $7, axis);
+ $$ = dmnsn_new_astnode2(DMNSN_AST_VAXIS_ROTATE, @$, $3, axis);
+ }
+ | "vcross" "(" ARITH_EXPR "," ARITH_EXPR ")" {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_VCROSS, @$, $3, $5);
+ }
| "vdot" "(" ARITH_EXPR "," ARITH_EXPR ")" {
$$ = dmnsn_new_astnode2(DMNSN_AST_VDOT, @$, $3, $5);
}
| "vlength" "(" ARITH_EXPR ")" {
$$ = dmnsn_new_astnode1(DMNSN_AST_VLENGTH, @$, $3);
}
+ | "vnormalize" "(" ARITH_EXPR ")" {
+ $$ = dmnsn_new_astnode1(DMNSN_AST_VNORMALIZE, @$, $3);
+ }
+ | "vrotate" "(" ARITH_EXPR "," ARITH_EXPR ")" {
+ $$ = dmnsn_new_astnode2(DMNSN_AST_VROTATE, @$, $3, $5);
+ }
| "pi" { $$ = dmnsn_new_astnode(DMNSN_AST_PI, @$); }
| "true" { $$ = dmnsn_new_astnode(DMNSN_AST_TRUE, @$); }
| "on" { $$ = dmnsn_new_astnode(DMNSN_AST_TRUE, @$); }
diff --git a/dimension/common.terminals b/dimension/common.terminals
index 490df65..089fe29 100644
--- a/dimension/common.terminals
+++ b/dimension/common.terminals
@@ -471,13 +471,13 @@
%token DMNSN_T_V_STEPS
%token DMNSN_T_VAL "val"
%token DMNSN_T_VARIANCE
-%token DMNSN_T_VAXIS_ROTATE
-%token DMNSN_T_VCROSS
+%token DMNSN_T_VAXIS_ROTATE "vaxis_rotate"
+%token DMNSN_T_VCROSS "vcross"
%token DMNSN_T_VDOT "vdot"
%token DMNSN_T_VERTEX_VECTORS
%token DMNSN_T_VLENGTH "vlength"
-%token DMNSN_T_VNORMALIZE
-%token DMNSN_T_VROTATE
+%token DMNSN_T_VNORMALIZE "vnormalize"
+%token DMNSN_T_VROTATE "vrotate"
%token DMNSN_T_VSTR
%token DMNSN_T_VTURBULENCE
%token DMNSN_T_WARP
diff --git a/dimension/grammar.epilogue b/dimension/grammar.epilogue
index 6b93dc3..6393044 100644
--- a/dimension/grammar.epilogue
+++ b/dimension/grammar.epilogue
@@ -180,40 +180,44 @@ dmnsn_astnode_string(dmnsn_astnode_type astnode_type)
dmnsn_astnode_map(DMNSN_AST_NOT, "!" );
dmnsn_astnode_map(DMNSN_AST_TERNARY, "?:");
- dmnsn_astnode_map(DMNSN_AST_ABS, "abs" );
- dmnsn_astnode_map(DMNSN_AST_ACOS, "acos" );
- dmnsn_astnode_map(DMNSN_AST_ACOSH, "acosh" );
- dmnsn_astnode_map(DMNSN_AST_ASC, "asc" );
- dmnsn_astnode_map(DMNSN_AST_ASIN, "asin" );
- dmnsn_astnode_map(DMNSN_AST_ASINH, "asinh" );
- dmnsn_astnode_map(DMNSN_AST_ATAN, "atan" );
- dmnsn_astnode_map(DMNSN_AST_ATAN2, "atan2" );
- dmnsn_astnode_map(DMNSN_AST_ATANH, "atanh" );
- dmnsn_astnode_map(DMNSN_AST_CEIL, "ceil" );
- dmnsn_astnode_map(DMNSN_AST_COS, "cos" );
- dmnsn_astnode_map(DMNSN_AST_COSH, "cosh" );
- dmnsn_astnode_map(DMNSN_AST_DEGREES, "degrees");
- dmnsn_astnode_map(DMNSN_AST_INT_DIV, "div" );
- dmnsn_astnode_map(DMNSN_AST_EXP, "exp" );
- dmnsn_astnode_map(DMNSN_AST_FLOOR, "floor" );
- dmnsn_astnode_map(DMNSN_AST_INT, "int" );
- dmnsn_astnode_map(DMNSN_AST_LN, "ln" );
- dmnsn_astnode_map(DMNSN_AST_LOG, "log" );
- dmnsn_astnode_map(DMNSN_AST_MAX, "max" );
- dmnsn_astnode_map(DMNSN_AST_MIN, "min" );
- dmnsn_astnode_map(DMNSN_AST_MOD, "mod" );
- dmnsn_astnode_map(DMNSN_AST_POW, "pow" );
- dmnsn_astnode_map(DMNSN_AST_RADIANS, "radians");
- dmnsn_astnode_map(DMNSN_AST_SIN, "sin" );
- dmnsn_astnode_map(DMNSN_AST_SINH, "sinh" );
- dmnsn_astnode_map(DMNSN_AST_SQRT, "sqrt" );
- dmnsn_astnode_map(DMNSN_AST_STRCMP, "strcmp" );
- dmnsn_astnode_map(DMNSN_AST_STRLEN, "strlen" );
- dmnsn_astnode_map(DMNSN_AST_TAN, "tan" );
- dmnsn_astnode_map(DMNSN_AST_TANH, "tanh" );
- dmnsn_astnode_map(DMNSN_AST_VAL, "val" );
- dmnsn_astnode_map(DMNSN_AST_VDOT, "vdot" );
- dmnsn_astnode_map(DMNSN_AST_VLENGTH, "vlength");
+ dmnsn_astnode_map(DMNSN_AST_ABS, "abs" );
+ dmnsn_astnode_map(DMNSN_AST_ACOS, "acos" );
+ dmnsn_astnode_map(DMNSN_AST_ACOSH, "acosh" );
+ dmnsn_astnode_map(DMNSN_AST_ASC, "asc" );
+ dmnsn_astnode_map(DMNSN_AST_ASIN, "asin" );
+ dmnsn_astnode_map(DMNSN_AST_ASINH, "asinh" );
+ dmnsn_astnode_map(DMNSN_AST_ATAN, "atan" );
+ dmnsn_astnode_map(DMNSN_AST_ATAN2, "atan2" );
+ dmnsn_astnode_map(DMNSN_AST_ATANH, "atanh" );
+ dmnsn_astnode_map(DMNSN_AST_CEIL, "ceil" );
+ dmnsn_astnode_map(DMNSN_AST_COS, "cos" );
+ dmnsn_astnode_map(DMNSN_AST_COSH, "cosh" );
+ dmnsn_astnode_map(DMNSN_AST_DEGREES, "degrees" );
+ dmnsn_astnode_map(DMNSN_AST_INT_DIV, "div" );
+ dmnsn_astnode_map(DMNSN_AST_EXP, "exp" );
+ dmnsn_astnode_map(DMNSN_AST_FLOOR, "floor" );
+ dmnsn_astnode_map(DMNSN_AST_INT, "int" );
+ dmnsn_astnode_map(DMNSN_AST_LN, "ln" );
+ dmnsn_astnode_map(DMNSN_AST_LOG, "log" );
+ dmnsn_astnode_map(DMNSN_AST_MAX, "max" );
+ dmnsn_astnode_map(DMNSN_AST_MIN, "min" );
+ dmnsn_astnode_map(DMNSN_AST_MOD, "mod" );
+ dmnsn_astnode_map(DMNSN_AST_POW, "pow" );
+ dmnsn_astnode_map(DMNSN_AST_RADIANS, "radians" );
+ dmnsn_astnode_map(DMNSN_AST_SIN, "sin" );
+ dmnsn_astnode_map(DMNSN_AST_SINH, "sinh" );
+ dmnsn_astnode_map(DMNSN_AST_SQRT, "sqrt" );
+ dmnsn_astnode_map(DMNSN_AST_STRCMP, "strcmp" );
+ dmnsn_astnode_map(DMNSN_AST_STRLEN, "strlen" );
+ dmnsn_astnode_map(DMNSN_AST_TAN, "tan" );
+ dmnsn_astnode_map(DMNSN_AST_TANH, "tanh" );
+ dmnsn_astnode_map(DMNSN_AST_VAL, "val" );
+ dmnsn_astnode_map(DMNSN_AST_VAXIS_ROTATE, "vaxis_rotate");
+ dmnsn_astnode_map(DMNSN_AST_VCROSS, "vcross" );
+ dmnsn_astnode_map(DMNSN_AST_VDOT, "vdot" );
+ dmnsn_astnode_map(DMNSN_AST_VLENGTH, "vlength" );
+ dmnsn_astnode_map(DMNSN_AST_VNORMALIZE, "vnormalize" );
+ dmnsn_astnode_map(DMNSN_AST_VROTATE, "vrotate" );
dmnsn_astnode_map(DMNSN_AST_PI, "pi" );
dmnsn_astnode_map(DMNSN_AST_TRUE, "true" );
diff --git a/dimension/lexer.l b/dimension/lexer.l
index ab9bcdd..3a05ca9 100644
--- a/dimension/lexer.l
+++ b/dimension/lexer.l
@@ -254,8 +254,12 @@ unsigned long wchar;
"up" RETURN_TOKEN(DMNSN_T_UP);
"v" RETURN_TOKEN(DMNSN_T_V);
"val" RETURN_TOKEN(DMNSN_T_VAL);
+"vaxis_rotate" RETURN_TOKEN(DMNSN_T_VAXIS_ROTATE);
+"vcross" RETURN_TOKEN(DMNSN_T_VCROSS);
"vdot" RETURN_TOKEN(DMNSN_T_VDOT);
"vlength" RETURN_TOKEN(DMNSN_T_VLENGTH);
+"vrotate" RETURN_TOKEN(DMNSN_T_VROTATE);
+"vnormalize" RETURN_TOKEN(DMNSN_T_VNORMALIZE);
"x" RETURN_TOKEN(DMNSN_T_X);
"y" RETURN_TOKEN(DMNSN_T_Y);
"yes" RETURN_TOKEN(DMNSN_T_YES);
diff --git a/dimension/parse.c b/dimension/parse.c
index 52479ad..4008fcf 100644
--- a/dimension/parse.c
+++ b/dimension/parse.c
@@ -521,6 +521,17 @@ dmnsn_copy_astnode(dmnsn_astnode astnode)
return copy;
}
+static dmnsn_astnode
+dmnsn_new_astnode2(dmnsn_astnode_type type, dmnsn_astnode loc,
+ dmnsn_astnode n1, dmnsn_astnode n2)
+{
+ dmnsn_astnode astnode = dmnsn_copy_astnode(loc);
+ astnode.type = type;
+ dmnsn_array_push(astnode.children, &n1);
+ dmnsn_array_push(astnode.children, &n2);
+ return astnode;
+}
+
/* 5-element vectors */
#define DMNSN_VECTOR_NELEM 5
@@ -676,7 +687,24 @@ dmnsn_eval_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
rewrite.type = DMNSN_AST_SQRT;
dmnsn_array_push(rewrite.children, &dot);
- ret = dmnsn_eval_unary(rewrite, symtable);
+ ret = dmnsn_eval(rewrite, symtable);
+ dmnsn_delete_astnode(rewrite);
+ break;
+ }
+ case DMNSN_AST_VNORMALIZE:
+ {
+ dmnsn_astnode norm = dmnsn_copy_astnode(astnode);
+ norm.type = DMNSN_AST_VLENGTH;
+ ++*rhs.refcount;
+ dmnsn_array_push(norm.children, &rhs);
+
+ dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode);
+ rewrite.type = DMNSN_AST_DIV;
+ ++*rhs.refcount;
+ dmnsn_array_push(rewrite.children, &rhs);
+ dmnsn_array_push(rewrite.children, &norm);
+
+ ret = dmnsn_eval(rewrite, symtable);
dmnsn_delete_astnode(rewrite);
break;
}
@@ -787,8 +815,14 @@ dmnsn_eval_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
dmnsn_make_ast_float(&ret, tanh(n));
break;
case DMNSN_AST_VLENGTH:
- dmnsn_make_ast_float(&ret, sqrt(3*n*n));
+ dmnsn_make_ast_float(&ret, sqrt(3.0*n*n));
break;
+ case DMNSN_AST_VNORMALIZE:
+ {
+ double elem = 1.0/sqrt(DMNSN_VECTOR_NELEM);
+ dmnsn_make_ast_vector(&ret, elem, elem, elem, elem, elem);
+ break;
+ }
default:
dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col,
@@ -888,6 +922,12 @@ dmnsn_eval_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
case DMNSN_AST_VLENGTH:
dmnsn_make_ast_float(&ret, sqrt(3.0*n*n));
break;
+ case DMNSN_AST_VNORMALIZE:
+ {
+ double elem = 1.0/sqrt(DMNSN_VECTOR_NELEM);
+ dmnsn_make_ast_vector(&ret, elem, elem, elem, elem, elem);
+ break;
+ }
default:
dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col,
@@ -973,6 +1013,14 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
dmnsn_delete_astnode(oldlhs);
dmnsn_delete_astnode(oldrhs);
+ if (lhs.type == DMNSN_AST_NONE || rhs.type == DMNSN_AST_NONE) {
+ ret = dmnsn_copy_astnode(astnode);
+ ret.type = DMNSN_AST_NONE;
+ dmnsn_delete_astnode(lhs);
+ dmnsn_delete_astnode(rhs);
+ return ret;
+ }
+
switch (astnode.type) {
case DMNSN_AST_EQUAL:
{
@@ -1121,6 +1169,78 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
ret.type = DMNSN_AST_NONE;
break;
+ case DMNSN_AST_VAXIS_ROTATE:
+ {
+ dmnsn_astnode rx, ry, rz;
+ dmnsn_array_get(lhs.children, 0, &rx);
+ dmnsn_array_get(lhs.children, 1, &ry);
+ dmnsn_array_get(lhs.children, 2, &rz);
+ dmnsn_astnode ax, ay, az;
+ dmnsn_array_get(rhs.children, 0, &ax);
+ dmnsn_array_get(rhs.children, 1, &ay);
+ dmnsn_array_get(rhs.children, 2, &az);
+
+ dmnsn_vector r = dmnsn_new_vector(
+ rx.type == DMNSN_AST_INTEGER ? *(long *)rx.ptr : *(double *)rx.ptr,
+ ry.type == DMNSN_AST_INTEGER ? *(long *)ry.ptr : *(double *)ry.ptr,
+ rz.type == DMNSN_AST_INTEGER ? *(long *)rz.ptr : *(double *)rz.ptr
+ );
+ dmnsn_vector axis = dmnsn_new_vector(
+ ax.type == DMNSN_AST_INTEGER ? *(long *)ax.ptr : *(double *)ax.ptr,
+ ay.type == DMNSN_AST_INTEGER ? *(long *)ay.ptr : *(double *)ay.ptr,
+ az.type == DMNSN_AST_INTEGER ? *(long *)az.ptr : *(double *)az.ptr
+ );
+
+ axis = dmnsn_vector_mul(atan(1.0)/45.0, axis);
+ r = dmnsn_matrix_vector_mul(dmnsn_rotation_matrix(axis), r);
+
+ ret = dmnsn_copy_astnode(astnode);
+ dmnsn_make_ast_vector(&ret, r.x, r.y, r.z, 0.0, 0.0);
+ break;
+ }
+ case DMNSN_AST_VCROSS:
+ {
+ dmnsn_astnode ux, uy, uz;
+ dmnsn_array_get(lhs.children, 0, &ux);
+ dmnsn_array_get(lhs.children, 1, &uy);
+ dmnsn_array_get(lhs.children, 2, &uz);
+ *ux.refcount += 2;
+ *uy.refcount += 2;
+ *uz.refcount += 2;
+ dmnsn_astnode vx, vy, vz;
+ dmnsn_array_get(rhs.children, 0, &vx);
+ dmnsn_array_get(rhs.children, 1, &vy);
+ dmnsn_array_get(rhs.children, 2, &vz);
+ *vx.refcount += 2;
+ *vy.refcount += 2;
+ *vz.refcount += 2;
+
+ dmnsn_astnode uvx = dmnsn_new_astnode2(
+ DMNSN_AST_SUB, astnode,
+ dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uy, vz),
+ dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uz, vy)
+ );
+ dmnsn_astnode uvy = dmnsn_new_astnode2(
+ DMNSN_AST_SUB, astnode,
+ dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uz, vx),
+ dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, ux, vz)
+ );
+ dmnsn_astnode uvz = dmnsn_new_astnode2(
+ DMNSN_AST_SUB, astnode,
+ dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, ux, vy),
+ dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uy, vx)
+ );
+
+ dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode);
+ rewrite.type = DMNSN_AST_VECTOR;
+ dmnsn_array_push(rewrite.children, &uvx);
+ dmnsn_array_push(rewrite.children, &uvy);
+ dmnsn_array_push(rewrite.children, &uvz);
+
+ ret = dmnsn_eval(rewrite, symtable);
+ dmnsn_delete_astnode(rewrite);
+ break;
+ }
case DMNSN_AST_VDOT:
{
dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode);
@@ -1155,6 +1275,47 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
dmnsn_delete_astnode(rewrite);
break;
}
+ case DMNSN_AST_VROTATE:
+ {
+ dmnsn_astnode rx, ry, rz;
+ dmnsn_array_get(lhs.children, 0, &rx);
+ dmnsn_array_get(lhs.children, 1, &ry);
+ dmnsn_array_get(lhs.children, 2, &rz);
+ dmnsn_astnode ax, ay, az;
+ dmnsn_array_get(rhs.children, 0, &ax);
+ dmnsn_array_get(rhs.children, 1, &ay);
+ dmnsn_array_get(rhs.children, 2, &az);
+
+ dmnsn_vector r = dmnsn_new_vector(
+ rx.type == DMNSN_AST_INTEGER ? *(long *)rx.ptr : *(double *)rx.ptr,
+ ry.type == DMNSN_AST_INTEGER ? *(long *)ry.ptr : *(double *)ry.ptr,
+ rz.type == DMNSN_AST_INTEGER ? *(long *)rz.ptr : *(double *)rz.ptr
+ );
+ dmnsn_vector axis = dmnsn_new_vector(
+ ax.type == DMNSN_AST_INTEGER ? *(long *)ax.ptr : *(double *)ax.ptr,
+ ay.type == DMNSN_AST_INTEGER ? *(long *)ay.ptr : *(double *)ay.ptr,
+ az.type == DMNSN_AST_INTEGER ? *(long *)az.ptr : *(double *)az.ptr
+ );
+
+ axis = dmnsn_vector_mul(atan(1.0)/45.0, axis);
+
+ r = dmnsn_matrix_vector_mul(
+ dmnsn_rotation_matrix(dmnsn_new_vector(axis.x, 0.0, 0.0)),
+ r
+ );
+ r = dmnsn_matrix_vector_mul(
+ dmnsn_rotation_matrix(dmnsn_new_vector(0.0, axis.y, 0.0)),
+ r
+ );
+ r = dmnsn_matrix_vector_mul(
+ dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 0.0, axis.z)),
+ r
+ );
+
+ ret = dmnsn_copy_astnode(astnode);
+ dmnsn_make_ast_vector(&ret, r.x, r.y, r.z, 0.0, 0.0);
+ break;
+ }
default:
{
@@ -1260,9 +1421,19 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
case DMNSN_AST_POW:
dmnsn_make_ast_float(&ret, pow(l, r));
break;
+ case DMNSN_AST_VCROSS:
+ dmnsn_make_ast_integer(&ret, 0);
+ break;
case DMNSN_AST_VDOT:
dmnsn_make_ast_integer(&ret, 3*l*r);
break;
+ case DMNSN_AST_VROTATE:
+ ret.type = DMNSN_AST_VECTOR;
+ *lhs.refcount += 3;
+ dmnsn_array_push(ret.children, &lhs);
+ dmnsn_array_push(ret.children, &lhs);
+ dmnsn_array_push(ret.children, &lhs);
+ break;
default:
dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col,
@@ -1393,9 +1564,19 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
case DMNSN_AST_POW:
dmnsn_make_ast_float(&ret, pow(l, r));
break;
+ case DMNSN_AST_VCROSS:
+ dmnsn_make_ast_integer(&ret, 0);
+ break;
case DMNSN_AST_VDOT:
dmnsn_make_ast_float(&ret, 3.0*l*r);
break;
+ case DMNSN_AST_VROTATE:
+ ret.type = DMNSN_AST_VECTOR;
+ *lhs.refcount += 3;
+ dmnsn_array_push(ret.children, &lhs);
+ dmnsn_array_push(ret.children, &lhs);
+ dmnsn_array_push(ret.children, &lhs);
+ break;
default:
dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col,
@@ -1518,6 +1699,7 @@ dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
case DMNSN_AST_TANH:
case DMNSN_AST_VAL:
case DMNSN_AST_VLENGTH:
+ case DMNSN_AST_VNORMALIZE:
return dmnsn_eval_unary(astnode, symtable);
case DMNSN_AST_ADD:
@@ -1539,7 +1721,10 @@ dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable)
case DMNSN_AST_MOD:
case DMNSN_AST_POW:
case DMNSN_AST_STRCMP:
+ case DMNSN_AST_VAXIS_ROTATE:
+ case DMNSN_AST_VCROSS:
case DMNSN_AST_VDOT:
+ case DMNSN_AST_VROTATE:
return dmnsn_eval_binary(astnode, symtable);
case DMNSN_AST_TERNARY:
diff --git a/dimension/parse.h b/dimension/parse.h
index ef5bb17..35a82db 100644
--- a/dimension/parse.h
+++ b/dimension/parse.h
@@ -133,8 +133,12 @@ typedef enum {
DMNSN_AST_TAN,
DMNSN_AST_TANH,
DMNSN_AST_VAL,
+ DMNSN_AST_VAXIS_ROTATE,
+ DMNSN_AST_VCROSS,
DMNSN_AST_VDOT,
DMNSN_AST_VLENGTH,
+ DMNSN_AST_VNORMALIZE,
+ DMNSN_AST_VROTATE,
DMNSN_AST_PI,
DMNSN_AST_TRUE,
diff --git a/tests/dimension/arithexp.pov b/tests/dimension/arithexp.pov
index 863c254..3f4e29b 100644
--- a/tests/dimension/arithexp.pov
+++ b/tests/dimension/arithexp.pov
@@ -154,6 +154,22 @@ sphere {
#error "val"
#end
+#if (vaxis_rotate(<1, 0, 0>, <1, 0, 1>, 180) != <0, 0, 1>)
+ #error "vaxis_rotate"
+#end
+
+#if (vaxis_rotate(1, 1, 180) != <1, 1, 1>)
+ #error "vaxis_rotate"
+#end
+
+#if (vcross(<1, 2, 3>, <3, 2, 1>) != <-4, 8, -4>)
+ #error "vcross"
+#end
+
+#if (vcross(1, 2) != 0)
+ #error "vcross"
+#end
+
#if (vdot(<1, 2, 3>, 2) != 12)
#error "vdot"
#end
@@ -170,6 +186,23 @@ sphere {
#error "vlength"
#end
+#if (vnormalize(<1, 1, 1>)
+ != <0.5773502691896258, 0.5773502691896258, 0.5773502691896258>)
+ #error "vnormalize"
+#end
+
+#if (vnormalize(1) != 0.4472135954999579) // Vector promoted comparison
+ #error "vnormalize"
+#end
+
+#if (vrotate(<1, 0, 0>, <0, -90, 0>) != <0, 0, 1>)
+ #error "vrotate"
+#end
+
+#if (vrotate(1, 2) != <1, 1, 1>)
+ #error "vrotate"
+#end
+
/* Float built-in IDs */
#if (pi != 3.141592653589793)