From 1d441aea4446484342f93fbf315f7f70de8adaf7 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 23 Mar 2010 01:53:28 -0400 Subject: Implement most vector functions. --- dimension/common.rules | 15 ++++ dimension/common.terminals | 8 +- dimension/grammar.epilogue | 72 +++++++++-------- dimension/lexer.l | 4 + dimension/parse.c | 189 ++++++++++++++++++++++++++++++++++++++++++- dimension/parse.h | 4 + tests/dimension/arithexp.pov | 33 ++++++++ 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) -- cgit v1.2.3