summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-10-30 01:13:34 -0400
committerTavian Barnes <tavianator@gmail.com>2009-10-30 01:13:34 -0400
commitd615d6795ee81e59795081b7fb2524978b6aa9cb (patch)
tree5ba19b6c55df2332ff71a795f11f590caf59c16d
parentf5f8d18d86e15e0bd14f955768edb616e1357a66 (diff)
downloaddimension-d615d6795ee81e59795081b7fb2524978b6aa9cb.tar.xz
(Sort of) parse boxes.
-rw-r--r--dimension/main.c9
-rw-r--r--dimension/parse.c231
-rw-r--r--dimension/parse.h20
-rw-r--r--dimension/realize.c50
-rw-r--r--dimension/realize.h3
-rw-r--r--dimension/tokenize.c2
-rw-r--r--tests/dimension/Makefile.am24
-rw-r--r--tests/dimension/box.pov24
-rwxr-xr-xtests/dimension/box.sh22
-rwxr-xr-xtests/dimension/numeric.sh2
10 files changed, 360 insertions, 27 deletions
diff --git a/dimension/main.c b/dimension/main.c
index 990ee14..5d921e7 100644
--- a/dimension/main.c
+++ b/dimension/main.c
@@ -145,11 +145,14 @@ main(int argc, char **argv) {
* Now we render the scene
*/
+ if (dmnsn_png_optimize_canvas(scene->canvas) != 0) {
+ fprintf(stderr, "WARNING: Couldn't optimize canvas for PNG\n");
+ }
+
if (dmnsn_raytrace_scene(scene) != 0) {
- dmnsn_delete_scene(scene);
+ dmnsn_delete_realized_scene(scene);
dmnsn_error(DMNSN_SEVERITY_HIGH, "Error rendering scene.");
}
- dmnsn_delete_scene(scene);
/* Open the output file */
output_file = fopen(output, "wb");
@@ -163,6 +166,6 @@ main(int argc, char **argv) {
}
fclose(output_file);
- /* Clean up and exit! */
+ dmnsn_delete_realized_scene(scene);
return EXIT_SUCCESS;
}
diff --git a/dimension/parse.c b/dimension/parse.c
index 2c1b67c..c868d95 100644
--- a/dimension/parse.c
+++ b/dimension/parse.c
@@ -20,17 +20,244 @@
#include "parse.h"
#include "tokenize.h"
#include "utility.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <locale.h>
+
+static int
+dmnsn_parse_expect(dmnsn_token_type type, const dmnsn_array *tokens,
+ unsigned int *ip)
+{
+ dmnsn_token token;
+
+ if (*ip < dmnsn_array_size(tokens)) {
+ dmnsn_array_get(tokens, *ip, &token);
+ if (token.type != type) {
+ dmnsn_diagnostic(token.filename, token.line, token.col,
+ "Expected '%s', found '%s'",
+ dmnsn_token_name(type),
+ dmnsn_token_name(token.type));
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Expected '%s', found end of file\n",
+ dmnsn_token_name(type));
+ return 1;
+ }
+
+ ++*ip;
+ return 0;
+}
+
+static int
+dmnsn_parse_float(const dmnsn_array *tokens, unsigned int *ip,
+ dmnsn_array *astree)
+{
+ unsigned int i = *ip;
+
+ if (i >= dmnsn_array_size(tokens)) {
+ fprintf(stderr, "Expected '%s' or '%s', found end of file\n",
+ dmnsn_token_name(DMNSN_T_INTEGER),
+ dmnsn_token_name(DMNSN_T_FLOAT));
+ return 1;
+ }
+
+ int negative = 0;
+ dmnsn_token token;
+ dmnsn_array_get(tokens, i, &token);
+
+ if (token.type == DMNSN_T_MINUS) {
+ negative = 1;
+
+ ++i;
+ if (i >= dmnsn_array_size(tokens)) {
+ fprintf(stderr, "Expected '%s' or '%s', found end of file\n",
+ dmnsn_token_name(DMNSN_T_INTEGER),
+ dmnsn_token_name(DMNSN_T_FLOAT));
+ return 1;
+ }
+ dmnsn_array_get(tokens, i, &token);
+ }
+
+ double *value = malloc(sizeof(double));
+ if (!value)
+ dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate room for float.");
+
+ if (token.type == DMNSN_T_INTEGER || token.type == DMNSN_T_FLOAT) {
+ *value = strtod(token.value, NULL);
+ ++i;
+ } else {
+ fprintf(stderr, "Expected '%s' or '%s', found '%s'\n",
+ dmnsn_token_name(DMNSN_T_INTEGER),
+ dmnsn_token_name(DMNSN_T_FLOAT),
+ dmnsn_token_name(token.type));
+ return 1;
+ }
+
+ if (negative)
+ *value *= -1.0;
+
+ dmnsn_astnode astnode;
+ astnode.type = DMNSN_AST_FLOAT;
+ astnode.children = NULL;
+ astnode.ptr = value;
+
+ dmnsn_array_push(astree, &astnode);
+ *ip = i;
+ return 0;
+}
+
+static int
+dmnsn_parse_vector(const dmnsn_array *tokens, unsigned int *ip,
+ dmnsn_array *astree)
+{
+ unsigned int i = *ip;
+
+ if (dmnsn_parse_expect(DMNSN_T_LESS, tokens, &i) != 0)
+ return 1;
+
+ dmnsn_astnode astnode;
+ astnode.type = DMNSN_AST_VECTOR;
+ astnode.children = dmnsn_new_array(sizeof(dmnsn_astnode));
+ astnode.ptr = NULL;
+
+ /* First element */
+ if (dmnsn_parse_float(tokens, &i, astnode.children) != 0)
+ goto bailout;
+
+ if (dmnsn_parse_expect(DMNSN_T_COMMA, tokens, &i) != 0)
+ goto bailout;
+
+ /* Second element */
+ if (dmnsn_parse_float(tokens, &i, astnode.children) != 0)
+ goto bailout;
+
+ if (dmnsn_parse_expect(DMNSN_T_COMMA, tokens, &i) != 0)
+ goto bailout;
+
+ /* Third element */
+ if (dmnsn_parse_float(tokens, &i, astnode.children) != 0)
+ goto bailout;
+
+ if (dmnsn_parse_expect(DMNSN_T_GREATER, tokens, &i) != 0)
+ goto bailout;
+
+ dmnsn_array_push(astree, &astnode);
+ *ip = i;
+ return 0;
+
+ bailout:
+ dmnsn_delete_astree(astnode.children);
+ return 1;
+}
+
+static int
+dmnsn_parse_box(const dmnsn_array *tokens, unsigned int *ip,
+ dmnsn_array *astree)
+{
+ unsigned int i = *ip;
+
+ if (dmnsn_parse_expect(DMNSN_T_BOX, tokens, &i) != 0)
+ return 1;
+ if (dmnsn_parse_expect(DMNSN_T_LBRACE, tokens, &i) != 0)
+ return 1;
+
+ dmnsn_astnode astnode;
+ astnode.type = DMNSN_AST_BOX;
+ astnode.children = dmnsn_new_array(sizeof(dmnsn_astnode));
+ astnode.ptr = NULL;
+
+ /* First corner */
+ if (dmnsn_parse_vector(tokens, &i, astnode.children) != 0)
+ goto bailout;
+
+ if (dmnsn_parse_expect(DMNSN_T_COMMA, tokens, &i) != 0)
+ goto bailout;
+
+ /* Second corner */
+ if (dmnsn_parse_vector(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(dmnsn_array *tokens)
+dmnsn_parse(const dmnsn_array *tokens)
{
+ unsigned int i;
+ dmnsn_array *astree = dmnsn_new_array(sizeof(dmnsn_astnode));
+ dmnsn_token token;
+
+ /* Save the current locale */
+ char *lc_ctype = strdup(setlocale(LC_CTYPE, NULL));
+ char *lc_numeric = strdup(setlocale(LC_NUMERIC, NULL));
+
+ /* Set the locale to `C' to make strtoul(), etc. consistent */
+ setlocale(LC_CTYPE, "C");
+ setlocale(LC_NUMERIC, "C");
+
+ for (i = 0; i < dmnsn_array_size(tokens); ++i) {
+ dmnsn_array_get(tokens, i, &token);
+
+ if (token.type == DMNSN_T_BOX) {
+ if (dmnsn_parse_box(tokens, &i, astree) != 0) {
+ dmnsn_diagnostic(token.filename, token.line, token.col,
+ "Invalid box",
+ dmnsn_token_name(DMNSN_T_BOX),
+ dmnsn_token_name(token.type));
+ goto bailout;
+ }
+ } else {
+ dmnsn_diagnostic(token.filename, token.line, token.col,
+ "Expected '%s', found '%s'",
+ dmnsn_token_name(DMNSN_T_BOX),
+ dmnsn_token_name(token.type));
+ goto bailout;
+ }
+ }
+
+ /* Restore the original locale */
+ setlocale(LC_CTYPE, lc_ctype);
+ setlocale(LC_NUMERIC, lc_numeric);
+ free(lc_ctype);
+ free(lc_numeric);
+
+ return astree;
+
+ bailout:
+ /* Restore the original locale */
+ setlocale(LC_CTYPE, lc_ctype);
+ setlocale(LC_NUMERIC, lc_numeric);
+ free(lc_ctype);
+ free(lc_numeric);
+
+ dmnsn_delete_astree(astree);
return NULL;
}
void
dmnsn_delete_astree(dmnsn_array *astree)
{
- dmnsn_delete_array(astree);
+ unsigned int i;
+ dmnsn_astnode node;
+
+ if (astree) {
+ for (i = 0; i < dmnsn_array_size(astree); ++i) {
+ dmnsn_array_get(astree, i, &node);
+ dmnsn_delete_astree(node.children);
+ free(node.ptr);
+ }
+ dmnsn_delete_array(astree);
+ }
}
void
diff --git a/dimension/parse.h b/dimension/parse.h
index d51144a..aa6ee58 100644
--- a/dimension/parse.h
+++ b/dimension/parse.h
@@ -19,8 +19,26 @@
#include "../libdimension/dimension.h"
+typedef enum {
+ DMNSN_AST_FLOAT,
+ DMNSN_AST_VECTOR,
+ DMNSN_AST_BOX,
+} dmnsn_astnode_type;
+
+typedef struct dmnsn_astnode dmnsn_astnode;
+
+struct dmnsn_astnode {
+ dmnsn_astnode_type type;
+
+ /* Child nodes */
+ dmnsn_array *children;
+
+ /* Generic data pointer */
+ void *ptr;
+};
+
/* The workhorse */
-dmnsn_array *dmnsn_parse(dmnsn_array *tokens);
+dmnsn_array *dmnsn_parse(const dmnsn_array *tokens);
/* Free an abstract syntax tree */
void dmnsn_delete_astree(dmnsn_array *astree);
diff --git a/dimension/realize.c b/dimension/realize.c
index 7f5e385..67536e6 100644
--- a/dimension/realize.c
+++ b/dimension/realize.c
@@ -22,7 +22,53 @@
#include "utility.h"
dmnsn_scene *
-dmnsn_realize(dmnsn_array *astree)
+dmnsn_realize(const dmnsn_array *astree)
{
- return dmnsn_new_scene();
+ dmnsn_scene *scene = dmnsn_new_scene();
+ if (!scene) {
+ return NULL;
+ }
+
+ /* Background color */
+ dmnsn_sRGB background_sRGB = { .R = 0.0, .G = 0.05, .B = 0.1 };
+ scene->background = dmnsn_color_from_sRGB(background_sRGB);
+
+ /* Allocate a canvas */
+ scene->canvas = dmnsn_new_canvas(768, 480);
+ if (!scene->canvas) {
+ dmnsn_delete_realized_scene(scene);
+ return NULL;
+ }
+
+ /* Set up the transformation matrix for the perspective camera */
+ dmnsn_matrix trans = dmnsn_scale_matrix(
+ dmnsn_vector_construct(
+ ((double)scene->canvas->x)/scene->canvas->y, 1.0, 1.0
+ )
+ );
+ trans = dmnsn_matrix_mul(
+ dmnsn_translation_matrix(dmnsn_vector_construct(0.0, 0.0, -4.0)),
+ trans
+ );
+ trans = dmnsn_matrix_mul(
+ dmnsn_rotation_matrix(dmnsn_vector_construct(0.0, 1.0, 0.0)),
+ trans
+ );
+
+ /* Create a perspective camera */
+ scene->camera = dmnsn_new_perspective_camera();
+ if (!scene->camera) {
+ dmnsn_delete_realized_scene(scene);
+ return NULL;
+ }
+
+ return scene;
+}
+
+void
+dmnsn_delete_realized_scene(dmnsn_scene *scene)
+{
+ dmnsn_delete_camera(scene->camera);
+ dmnsn_delete_canvas(scene->canvas);
+ dmnsn_delete_scene(scene);
}
diff --git a/dimension/realize.h b/dimension/realize.h
index fa2b6eb..73ea109 100644
--- a/dimension/realize.h
+++ b/dimension/realize.h
@@ -19,4 +19,5 @@
#include "../libdimension/dimension.h"
-dmnsn_scene *dmnsn_realize(dmnsn_array *astree);
+dmnsn_scene *dmnsn_realize(const dmnsn_array *astree);
+void dmnsn_delete_realized_scene(dmnsn_scene *scene);
diff --git a/dimension/tokenize.c b/dimension/tokenize.c
index 1a74d44..acd48f5 100644
--- a/dimension/tokenize.c
+++ b/dimension/tokenize.c
@@ -1124,7 +1124,7 @@ dmnsn_token_name(dmnsn_token_type token_type)
dmnsn_token_map(DMNSN_T_NOT_EQUAL, "!=");
/* Numeric values */
- dmnsn_token_map(DMNSN_T_INTEGER, "int");
+ dmnsn_token_map(DMNSN_T_INTEGER, "integer");
dmnsn_token_map(DMNSN_T_FLOAT, "float");
/* Keywords */
diff --git a/tests/dimension/Makefile.am b/tests/dimension/Makefile.am
index 8bf7550..36d0989 100644
--- a/tests/dimension/Makefile.am
+++ b/tests/dimension/Makefile.am
@@ -19,27 +19,19 @@
INCLUDES = -I$(top_srcdir)/libdimension
-TESTS = punctuation.sh numeric.sh strings.sh labels.sh directives.sh
+TESTS = punctuation.sh numeric.sh strings.sh labels.sh directives.sh box.sh
TESTS_ENVIRONMENT = top_builddir=$(top_builddir)
-punctuation.sh:
- cp $(srcdir)/punctuation.sh .
-
-numeric.sh:
- cp $(srcdir)/numeric.sh .
-
-strings.sh:
- cp $(srcdir)/strings.sh .
-
-labels.sh:
- cp $(srcdir)/labels.sh .
-
-directives.sh:
- cp $(srcdir)/directives.sh .
+%.sh:
+ cp $(srcdir)/$@ .
EXTRA_DIST = $(TESTS) \
punctuation.pov \
numeric.pov \
strings.pov \
labels.pov \
- directives.pov
+ directives.pov \
+ box.pov
+
+clean-local:
+ rm *.png
diff --git a/tests/dimension/box.pov b/tests/dimension/box.pov
new file mode 100644
index 0000000..47b1cde
--- /dev/null
+++ b/tests/dimension/box.pov
@@ -0,0 +1,24 @@
+/*************************************************************************
+ * Copyright (C) 2009 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * 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 <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+// Render a box
+
+box {
+ <-1, -1, -1>, <1, 1, 1>
+}
diff --git a/tests/dimension/box.sh b/tests/dimension/box.sh
new file mode 100755
index 0000000..244b6fa
--- /dev/null
+++ b/tests/dimension/box.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+#########################################################################
+# Copyright (C) 2009 Tavian Barnes <tavianator@gmail.com> #
+# #
+# 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 <http://www.gnu.org/licenses/>. #
+#########################################################################
+
+${top_builddir}/dimension/dimension -o box.png ${srcdir}/box.pov
diff --git a/tests/dimension/numeric.sh b/tests/dimension/numeric.sh
index b64c218..d4b4d89 100755
--- a/tests/dimension/numeric.sh
+++ b/tests/dimension/numeric.sh
@@ -20,7 +20,7 @@
#########################################################################
numeric=$(${top_builddir}/dimension/dimension --tokenize ${srcdir}/numeric.pov)
-numeric_exp='((int "1") (int "123456789") (int "01234567") (int "0x123456789") - (int "0x01") (float ".1") (float "0.1") (float "1.0") (float "0.123456789") - (float "0.123456789") < (int "1") , (float "2.2") , - (float "3.03") >)'
+numeric_exp='((integer "1") (integer "123456789") (integer "01234567") (integer "0x123456789") - (integer "0x01") (float ".1") (float "0.1") (float "1.0") (float "0.123456789") - (float "0.123456789") < (integer "1") , (float "2.2") , - (float "3.03") >)'
if [ "$numeric" != "$numeric_exp" ]; then
echo "numeric.pov tokenized as \"$numeric\"" >&2