summaryrefslogtreecommitdiffstats
path: root/dimension
diff options
context:
space:
mode:
Diffstat (limited to 'dimension')
-rw-r--r--dimension/parse.c51
-rw-r--r--dimension/parse.h2
-rw-r--r--dimension/realize.c85
3 files changed, 125 insertions, 13 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, &center);
+ 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;
}
}