diff options
Diffstat (limited to 'dimension')
-rw-r--r-- | dimension/main.c | 9 | ||||
-rw-r--r-- | dimension/parse.c | 231 | ||||
-rw-r--r-- | dimension/parse.h | 20 | ||||
-rw-r--r-- | dimension/realize.c | 50 | ||||
-rw-r--r-- | dimension/realize.h | 3 | ||||
-rw-r--r-- | dimension/tokenize.c | 2 |
6 files changed, 305 insertions, 10 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 */ |