diff options
Diffstat (limited to 'dimension')
-rw-r--r-- | dimension/parse.c | 51 | ||||
-rw-r--r-- | dimension/parse.h | 2 | ||||
-rw-r--r-- | dimension/realize.c | 85 |
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, ¢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; } } |