From 5bde27bf4b3064a94131b71019469464023a6f63 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 4 Nov 2009 14:44:09 -0500 Subject: Handle spheres. --- dimension/parse.c | 51 +++++++++++++++++++++++++-- dimension/parse.h | 2 ++ dimension/realize.c | 85 +++++++++++++++++++++++++++++++++++++++------ tests/dimension/Makefile.am | 4 +-- tests/dimension/box.pov | 27 -------------- tests/dimension/box.sh | 32 ----------------- tests/dimension/demo.pov | 28 +++++++++++++++ tests/dimension/demo.sh | 32 +++++++++++++++++ 8 files changed, 187 insertions(+), 74 deletions(-) delete mode 100644 tests/dimension/box.pov delete mode 100755 tests/dimension/box.sh create mode 100644 tests/dimension/demo.pov create mode 100755 tests/dimension/demo.sh 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 +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/box.pov deleted file mode 100644 index 762e5df..0000000 --- a/tests/dimension/box.pov +++ /dev/null @@ -1,27 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009 Tavian Barnes * - * * - * This file is part of The Dimension Test Suite. * - * * - * The Dimension Test Suite is free software; you can redistribute it * - * and/or modify it under the terms of the GNU General Public License as * - * published by the Free Software Foundation; either version 3 of the * - * License, or (at your option) any later version. * - * * - * The Dimension Test Suite is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see . * - *************************************************************************/ - -// Render a box - -box { - <-0.125, -1, -1>, <0.125, 1, 1> -} -box { - <-1, -1, -0.125>, <1, 1, 0.125> -} diff --git a/tests/dimension/box.sh b/tests/dimension/box.sh deleted file mode 100755 index 7a9f754..0000000 --- a/tests/dimension/box.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -######################################################################### -# Copyright (C) 2009 Tavian Barnes # -# # -# This file is part of The Dimension Test Suite. # -# # -# The Dimension Test Suite is free software; you can redistribute it # -# and/or modify it under the terms of the GNU General Public License as # -# published by the Free Software Foundation; either version 3 of the # -# License, or (at your option) any later version. # -# # -# The Dimension Test Suite is distributed in the hope that it will be # -# useful, but WITHOUT ANY WARRANTY; without even the implied warranty # -# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # -# General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -######################################################################### - -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))))' - -if [ "$box" != "$box_exp" ]; then - echo "box.pov parsed as \"$box\"" >&2 - echo " -- expected \"$box_exp\"" >&2 - exit 1 -fi - -${top_builddir}/dimension/dimension -o box.png ${srcdir}/box.pov diff --git a/tests/dimension/demo.pov b/tests/dimension/demo.pov new file mode 100644 index 0000000..386fdd0 --- /dev/null +++ b/tests/dimension/demo.pov @@ -0,0 +1,28 @@ +/************************************************************************* + * Copyright (C) 2009 Tavian Barnes * + * * + * This file is part of The Dimension Test Suite. * + * * + * The Dimension Test Suite is free software; you can redistribute it * + * and/or modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 3 of the * + * License, or (at your option) any later version. * + * * + * The Dimension Test Suite is distributed in the hope that it will be * + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +// Render demo scene + +box { + <-1.0, -1.0, -1.0>, <1.0, 1.0, 1.0> +} + +sphere { + <0, 0, 0>, 1.25 +} diff --git a/tests/dimension/demo.sh b/tests/dimension/demo.sh new file mode 100755 index 0000000..7674fd4 --- /dev/null +++ b/tests/dimension/demo.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +######################################################################### +# Copyright (C) 2009 Tavian Barnes # +# # +# This file is part of The Dimension Test Suite. # +# # +# The Dimension Test Suite is free software; you can redistribute it # +# and/or modify it under the terms of the GNU General Public License as # +# published by the Free Software Foundation; either version 3 of the # +# License, or (at your option) any later version. # +# # +# The Dimension Test Suite is distributed in the hope that it will be # +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty # +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # +# General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +######################################################################### + +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 [ "$demo" != "$demo_exp" ]; then + echo "demo.pov parsed as \"$demo\"" >&2 + echo " -- expected \"$demo_exp\"" >&2 + exit 1 +fi + +${top_builddir}/dimension/dimension -o demo.png ${srcdir}/demo.pov -- cgit v1.2.3