diff options
-rw-r--r-- | dimension/parse.c | 51 | ||||
-rw-r--r-- | dimension/parse.h | 2 | ||||
-rw-r--r-- | dimension/realize.c | 85 | ||||
-rw-r--r-- | tests/dimension/Makefile.am | 4 | ||||
-rw-r--r-- | tests/dimension/demo.pov (renamed from tests/dimension/box.pov) | 9 | ||||
-rwxr-xr-x | tests/dimension/demo.sh (renamed from tests/dimension/box.sh) | 14 |
6 files changed, 139 insertions, 26 deletions
diff --git a/dimension/parse.c b/dimension/parse.c index 42a48bd..51203c5 100644 --- a/dimension/parse.c +++ b/dimension/parse.c @@ -190,6 +190,45 @@ dmnsn_parse_box(const dmnsn_array *tokens, unsigned int *ip, return 1; } +static int +dmnsn_parse_sphere(const dmnsn_array *tokens, unsigned int *ip, + dmnsn_array *astree) +{ + unsigned int i = *ip; + + if (dmnsn_parse_expect(DMNSN_T_SPHERE, tokens, &i) != 0) + return 1; + if (dmnsn_parse_expect(DMNSN_T_LBRACE, tokens, &i) != 0) + return 1; + + dmnsn_astnode astnode; + astnode.type = DMNSN_AST_SPHERE; + astnode.children = dmnsn_new_array(sizeof(dmnsn_astnode)); + astnode.ptr = NULL; + + /* Center */ + if (dmnsn_parse_vector(tokens, &i, astnode.children) != 0) + goto bailout; + + if (dmnsn_parse_expect(DMNSN_T_COMMA, tokens, &i) != 0) + goto bailout; + + /* Radius */ + if (dmnsn_parse_float(tokens, &i, astnode.children) != 0) + goto bailout; + + if (dmnsn_parse_expect(DMNSN_T_RBRACE, tokens, &i) != 0) + goto bailout; + + dmnsn_array_push(astree, &astnode); + *ip = i; + return 0; + + bailout: + dmnsn_delete_astree(astnode.children); + return 1; +} + dmnsn_array * dmnsn_parse(const dmnsn_array *tokens) { @@ -212,10 +251,15 @@ dmnsn_parse(const dmnsn_array *tokens) switch (token.type) { case DMNSN_T_BOX: if (dmnsn_parse_box(tokens, &i, astree) != 0) { + dmnsn_diagnostic(token.filename, token.line, token.col, "Invalid box"); + goto bailout; + } + break; + + case DMNSN_T_SPHERE: + if (dmnsn_parse_sphere(tokens, &i, astree) != 0) { dmnsn_diagnostic(token.filename, token.line, token.col, - "Invalid box", - dmnsn_token_string(DMNSN_T_BOX), - dmnsn_token_string(token.type)); + "Invalid sphere"); goto bailout; } break; @@ -336,6 +380,7 @@ 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_FLOAT, "float"); + dmnsn_astnode_map(DMNSN_AST_SPHERE, "sphere"); default: fprintf(stderr, "Warning: unrecognised astnode type %d.\n", diff --git a/dimension/parse.h b/dimension/parse.h index 0b818bf..02bda6e 100644 --- a/dimension/parse.h +++ b/dimension/parse.h @@ -21,8 +21,10 @@ typedef enum { DMNSN_AST_FLOAT, + DMNSN_AST_INTEGER, DMNSN_AST_VECTOR, DMNSN_AST_BOX, + DMNSN_AST_SPHERE, } dmnsn_astnode_type; typedef struct dmnsn_astnode dmnsn_astnode; diff --git a/dimension/realize.c b/dimension/realize.c index 38a74e6..8bbf0cc 100644 --- a/dimension/realize.c +++ b/dimension/realize.c @@ -22,6 +22,21 @@ #include "utility.h" #include <math.h> +static double +dmnsn_realize_float(dmnsn_astnode astnode) +{ + if (astnode.type == DMNSN_AST_FLOAT) { + double *x = astnode.ptr; + return *x; + } else if (astnode.type == DMNSN_AST_INTEGER) { + long *x = astnode.ptr; + return *x; + } else { + dmnsn_error(DMNSN_SEVERITY_HIGH, "Expected a float or an integer."); + return 0; /* Silence compiler warning */ + } +} + static dmnsn_vector dmnsn_realize_vector(dmnsn_astnode astnode) { @@ -34,15 +49,11 @@ dmnsn_realize_vector(dmnsn_astnode astnode) dmnsn_array_get(astnode.children, 1, &ynode); dmnsn_array_get(astnode.children, 2, &znode); - if (xnode.type != DMNSN_AST_FLOAT - || ynode.type != DMNSN_AST_FLOAT - || znode.type != DMNSN_AST_FLOAT) - { - dmnsn_error(DMNSN_SEVERITY_HIGH, "Expected a float."); - } + double x = dmnsn_realize_float(xnode), + y = dmnsn_realize_float(ynode), + z = dmnsn_realize_float(znode); - double *x = xnode.ptr, *y = ynode.ptr, *z = znode.ptr; - return dmnsn_vector_construct(*x, *y, *z); + return dmnsn_vector_construct(x, y, z); } dmnsn_object * @@ -60,6 +71,10 @@ dmnsn_realize_box(dmnsn_astnode astnode) x2 = dmnsn_realize_vector(corner2); dmnsn_object *box = dmnsn_new_cube(); + if (!box) { + dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate box."); + } + box->trans = dmnsn_scale_matrix( dmnsn_vector_construct(fabs(x2.x - x1.x)/2.0, fabs(x2.y - x1.y)/2.0, @@ -76,6 +91,44 @@ dmnsn_realize_box(dmnsn_astnode astnode) return box; } +dmnsn_object * +dmnsn_realize_sphere(dmnsn_astnode astnode) +{ + if (astnode.type != DMNSN_AST_SPHERE) { + dmnsn_error(DMNSN_SEVERITY_HIGH, "Expected a sphere."); + } + + dmnsn_astnode center, radius; + dmnsn_array_get(astnode.children, 0, ¢er); + dmnsn_array_get(astnode.children, 1, &radius); + + dmnsn_vector x0 = dmnsn_realize_vector(center); + double r = dmnsn_realize_float(radius); + + dmnsn_object *sphere = dmnsn_new_sphere(); + if (!sphere) { + dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate sphere."); + } + + sphere->texture = dmnsn_new_texture(); + if (!sphere->texture) { + dmnsn_delete_object(sphere); + dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate sphere texture."); + } + + sphere->texture->pigment = dmnsn_new_solid_pigment(dmnsn_white); + if (!sphere->texture->pigment) { + dmnsn_delete_object(sphere); + dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate sphere pigment."); + } + + sphere->trans = dmnsn_scale_matrix(dmnsn_vector_construct(r, r, r)); + sphere->trans = dmnsn_matrix_mul(dmnsn_translation_matrix(x0), sphere->trans); + sphere->trans = dmnsn_matrix_inverse(sphere->trans); + + return sphere; +} + dmnsn_scene * dmnsn_realize(const dmnsn_array *astree) { @@ -107,7 +160,11 @@ dmnsn_realize(const dmnsn_array *astree) trans ); trans = dmnsn_matrix_mul( - dmnsn_rotation_matrix(dmnsn_vector_construct(0.8, 0.7, 0.0)), + dmnsn_rotation_matrix(dmnsn_vector_construct(0.0, 1.0, 0.0)), + trans + ); + trans = dmnsn_matrix_mul( + dmnsn_rotation_matrix(dmnsn_vector_construct(-0.75, 0.0, 0.0)), trans ); @@ -136,8 +193,16 @@ dmnsn_realize(const dmnsn_array *astree) dmnsn_array_push(scene->objects, &object); break; + case DMNSN_AST_SPHERE: + object = dmnsn_realize_sphere(astnode); + dmnsn_array_push(scene->objects, &object); + break; + default: - dmnsn_error(DMNSN_SEVERITY_HIGH, "We only handle boxes right now."); + fprintf(stderr, "Unrecognised syntax element '%s'.\n", + dmnsn_astnode_string(astnode.type)); + dmnsn_delete_realized_scene(scene); + return NULL; } } diff --git a/tests/dimension/Makefile.am b/tests/dimension/Makefile.am index 36d0989..214c88a 100644 --- a/tests/dimension/Makefile.am +++ b/tests/dimension/Makefile.am @@ -19,7 +19,7 @@ INCLUDES = -I$(top_srcdir)/libdimension -TESTS = punctuation.sh numeric.sh strings.sh labels.sh directives.sh box.sh +TESTS = punctuation.sh numeric.sh strings.sh labels.sh directives.sh demo.sh TESTS_ENVIRONMENT = top_builddir=$(top_builddir) %.sh: @@ -31,7 +31,7 @@ EXTRA_DIST = $(TESTS) \ strings.pov \ labels.pov \ directives.pov \ - box.pov + demo.pov clean-local: rm *.png diff --git a/tests/dimension/box.pov b/tests/dimension/demo.pov index 762e5df..386fdd0 100644 --- a/tests/dimension/box.pov +++ b/tests/dimension/demo.pov @@ -17,11 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * *************************************************************************/ -// Render a box +// Render demo scene box { - <-0.125, -1, -1>, <0.125, 1, 1> + <-1.0, -1.0, -1.0>, <1.0, 1.0, 1.0> } -box { - <-1, -1, -0.125>, <1, 1, 0.125> + +sphere { + <0, 0, 0>, 1.25 } diff --git a/tests/dimension/box.sh b/tests/dimension/demo.sh index 7a9f754..7674fd4 100755 --- a/tests/dimension/box.sh +++ b/tests/dimension/demo.sh @@ -19,14 +19,14 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # ######################################################################### -box=$(${top_builddir}/dimension/dimension --tokenize --parse ${srcdir}/box.pov) -box_exp='(box { < - (float "0.125") , - (integer "1") , - (integer "1") > , < (float "0.125") , (integer "1") , (integer "1") > } box { < - (integer "1") , - (integer "1") , - (float "0.125") > , < (integer "1") , (integer "1") , (float "0.125") > }) -((box (vector (float -0.125) (float -1) (float -1)) (vector (float 0.125) (float 1) (float 1))) (box (vector (float -1) (float -1) (float -0.125)) (vector (float 1) (float 1) (float 0.125))))' +demo=$(${top_builddir}/dimension/dimension --tokenize --parse ${srcdir}/demo.pov) +demo_exp='(box { < - (float "1.0") , - (float "1.0") , - (float "1.0") > , < (float "1.0") , (float "1.0") , (float "1.0") > } sphere { < (integer "0") , (integer "0") , (integer "0") > , (float "1.25") }) +((box (vector (float -1) (float -1) (float -1)) (vector (float 1) (float 1) (float 1))) (sphere (vector (float 0) (float 0) (float 0)) (float 1.25)))' -if [ "$box" != "$box_exp" ]; then - echo "box.pov parsed as \"$box\"" >&2 - echo " -- expected \"$box_exp\"" >&2 +if [ "$demo" != "$demo_exp" ]; then + echo "demo.pov parsed as \"$demo\"" >&2 + echo " -- expected \"$demo_exp\"" >&2 exit 1 fi -${top_builddir}/dimension/dimension -o box.png ${srcdir}/box.pov +${top_builddir}/dimension/dimension -o demo.png ${srcdir}/demo.pov |