summaryrefslogtreecommitdiffstats
path: root/dimension/realize.c
diff options
context:
space:
mode:
Diffstat (limited to 'dimension/realize.c')
-rw-r--r--dimension/realize.c1450
1 files changed, 0 insertions, 1450 deletions
diff --git a/dimension/realize.c b/dimension/realize.c
deleted file mode 100644
index c9a507d..0000000
--- a/dimension/realize.c
+++ /dev/null
@@ -1,1450 +0,0 @@
-/*************************************************************************
- * Copyright (C) 2009-2011 Tavian Barnes <tavianator@tavianator.com> *
- * *
- * This file is part of Dimension. *
- * *
- * Dimension 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. *
- * *
- * Dimension 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/>. *
- *************************************************************************/
-
-#include "realize.h"
-#include "parse.h"
-#include "utility.h"
-#include <math.h>
-#include <fenv.h>
-#include <stdio.h>
-#include <stdbool.h>
-
-static long
-dmnsn_realize_integer(dmnsn_astnode astnode)
-{
- switch (astnode.type) {
- case DMNSN_AST_INTEGER:
- return *(long *)astnode.ptr;
- case DMNSN_AST_FLOAT:
- {
- feclearexcept(FE_ALL_EXCEPT);
- long ret = lrint(*(double *)astnode.ptr);
- if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW))
- dmnsn_error("Float out of range of integer.");
- return ret;
- }
-
- default:
- dmnsn_assert(false, "Invalid integer.");
- return 0; /* Silence compiler warning */
- }
-}
-
-static double
-dmnsn_realize_float(dmnsn_astnode astnode)
-{
- switch (astnode.type) {
- case DMNSN_AST_FLOAT:
- return *(double *)astnode.ptr;
- case DMNSN_AST_INTEGER:
- return *(long *)astnode.ptr;
-
- default:
- dmnsn_assert(false, "Invalid float.");
- return 0; /* Silence compiler warning */
- }
-}
-
-/* dmnsn_realize_string is an API function, so call this dmnsn_realize_str */
-static const char*
-dmnsn_realize_str(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_STRING, "Expected a string.");
- return astnode.ptr;
-}
-
-static dmnsn_vector
-dmnsn_realize_vector(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_VECTOR, "Expected a vector.");
-
- dmnsn_astnode xnode, ynode, znode;
- dmnsn_array_get(astnode.children, 0, &xnode);
- dmnsn_array_get(astnode.children, 1, &ynode);
- dmnsn_array_get(astnode.children, 2, &znode);
-
- double x = dmnsn_realize_float(xnode),
- y = dmnsn_realize_float(ynode),
- z = dmnsn_realize_float(znode);
-
- return dmnsn_new_vector(x, y, z);
-}
-
-static dmnsn_color
-dmnsn_realize_color(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_VECTOR, "Expected a vector.");
-
- dmnsn_astnode rnode, gnode, bnode, fnode, tnode;
- dmnsn_array_get(astnode.children, 0, &rnode);
- dmnsn_array_get(astnode.children, 1, &gnode);
- dmnsn_array_get(astnode.children, 2, &bnode);
- dmnsn_array_get(astnode.children, 3, &fnode);
- dmnsn_array_get(astnode.children, 4, &tnode);
-
- return dmnsn_new_color5(dmnsn_realize_float(rnode),
- dmnsn_realize_float(gnode),
- dmnsn_realize_float(bnode),
- dmnsn_realize_float(fnode),
- dmnsn_realize_float(tnode));
-}
-
-static dmnsn_matrix
-dmnsn_realize_translation(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_TRANSLATION,
- "Expected a translation.");
-
- dmnsn_astnode trans_node;
- dmnsn_array_get(astnode.children, 0, &trans_node);
- dmnsn_vector trans = dmnsn_realize_vector(trans_node);
-
- return dmnsn_translation_matrix(trans);
-}
-
-static dmnsn_matrix
-dmnsn_realize_scale(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_SCALE, "Expected a scale.");
-
- dmnsn_astnode scale_node;
- dmnsn_array_get(astnode.children, 0, &scale_node);
- dmnsn_vector scale = dmnsn_realize_vector(scale_node);
-
- return dmnsn_scale_matrix(scale);
-}
-
-static dmnsn_matrix
-dmnsn_realize_rotation(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_ROTATION, "Expected a rotation.");
-
- dmnsn_astnode angle_node;
- dmnsn_array_get(astnode.children, 0, &angle_node);
-
- dmnsn_vector angle = dmnsn_vector_mul(
- dmnsn_radians(1.0),
- dmnsn_realize_vector(angle_node)
- );
-
- dmnsn_matrix trans = dmnsn_rotation_matrix(
- dmnsn_new_vector(angle.x, 0.0, 0.0)
- );
- trans = dmnsn_matrix_mul(
- dmnsn_rotation_matrix(dmnsn_new_vector(0.0, angle.y, 0.0)),
- trans
- );
- trans = dmnsn_matrix_mul(
- dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 0.0, angle.z)),
- trans
- );
-
- return trans;
-}
-
-static dmnsn_matrix
-dmnsn_realize_matrix(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_MATRIX, "Expected a matrix.");
-
- dmnsn_astnode *children = dmnsn_array_first(astnode.children);
- dmnsn_matrix trans;
-
- trans.n[0][0] = dmnsn_realize_float(children[0]);
- trans.n[0][1] = dmnsn_realize_float(children[1]);
- trans.n[0][2] = dmnsn_realize_float(children[2]);
- trans.n[0][3] = dmnsn_realize_float(children[9]);
-
- trans.n[1][0] = dmnsn_realize_float(children[3]);
- trans.n[1][1] = dmnsn_realize_float(children[4]);
- trans.n[1][2] = dmnsn_realize_float(children[5]);
- trans.n[1][3] = dmnsn_realize_float(children[10]);
-
- trans.n[2][0] = dmnsn_realize_float(children[6]);
- trans.n[2][1] = dmnsn_realize_float(children[7]);
- trans.n[2][2] = dmnsn_realize_float(children[8]);
- trans.n[2][3] = dmnsn_realize_float(children[11]);
-
- return trans;
-}
-
-static dmnsn_matrix
-dmnsn_realize_transformation(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_TRANSFORMATION,
- "Expected a transformation.");
-
- dmnsn_matrix trans = dmnsn_identity_matrix();
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, child, astnode.children) {
- switch (child->type) {
- case DMNSN_AST_TRANSLATION:
- trans = dmnsn_matrix_mul(trans, dmnsn_realize_translation(*child));
- break;
- case DMNSN_AST_SCALE:
- trans = dmnsn_matrix_mul(trans, dmnsn_realize_scale(*child));
- break;
- case DMNSN_AST_ROTATION:
- trans = dmnsn_matrix_mul(trans, dmnsn_realize_rotation(*child));
- break;
- case DMNSN_AST_MATRIX:
- trans = dmnsn_matrix_mul(trans, dmnsn_realize_matrix(*child));
- break;
- case DMNSN_AST_INVERSE:
- trans = dmnsn_matrix_inverse(trans);
- break;
- case DMNSN_AST_TRANSFORMATION:
- trans = dmnsn_matrix_mul(trans, dmnsn_realize_transformation(*child));
- break;
-
- default:
- dmnsn_assert(false, "Invalid transformation type.");
- break;
- }
- }
-
- return trans;
-}
-
-static void
-dmnsn_realize_global_settings(dmnsn_astnode astnode, dmnsn_scene *scene)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_GLOBAL_SETTINGS,
- "Expected global settings.");
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, astnode.children) {
- dmnsn_astnode child;
-
- switch (item->type) {
- case DMNSN_AST_ADC_BAILOUT:
- dmnsn_array_get(item->children, 0, &child);
- scene->adc_bailout = dmnsn_realize_float(child);
- break;
-
- case DMNSN_AST_AMBIENT:
- dmnsn_array_get(item->children, 0, &child);
- scene->ambient = dmnsn_realize_color(child);
- scene->ambient.filter = 0.0;
- scene->ambient.trans = 0.0;
- break;
-
- case DMNSN_AST_MAX_TRACE_LEVEL:
- dmnsn_array_get(item->children, 0, &child);
- scene->reclimit = dmnsn_realize_integer(child);
- break;
-
- case DMNSN_AST_ASSUMED_GAMMA:
- case DMNSN_AST_CHARSET:
- case DMNSN_AST_MAX_INTERSECTIONS:
- /* Ignored settings */
- break;
-
- default:
- dmnsn_assert(false, "Invalid global settings item.");
- }
- }
-}
-
-static dmnsn_pigment *dmnsn_realize_pigment(dmnsn_astnode astnode);
-
-static dmnsn_sky_sphere *
-dmnsn_realize_sky_sphere(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_SKY_SPHERE, "Expected a sky sphere.");
-
- dmnsn_sky_sphere *sky_sphere = dmnsn_new_sky_sphere();
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, astnode.children) {
- switch (item->type) {
- case DMNSN_AST_PIGMENT:
- {
- dmnsn_pigment *pigment = dmnsn_realize_pigment(*item);
- dmnsn_array_push(sky_sphere->pigments, &pigment);
- break;
- }
-
- case DMNSN_AST_TRANSFORMATION:
- sky_sphere->trans = dmnsn_matrix_mul(
- dmnsn_realize_transformation(*item),
- sky_sphere->trans
- );
- break;
-
- default:
- dmnsn_assert(false, "Invalid sky sphere item.");
- }
- }
-
- return sky_sphere;
-}
-
-static dmnsn_camera *
-dmnsn_realize_camera(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_CAMERA, "Expected a camera.");
-
- dmnsn_astnode_type camera_type = DMNSN_AST_PERSPECTIVE;
- dmnsn_vector location = dmnsn_new_vector(0.0, 0.0, 0.0);
- dmnsn_vector direction = dmnsn_new_vector(0.0, 0.0, 1.0);
- dmnsn_vector right = dmnsn_new_vector(4.0/3.0, 0.0, 0.0);
- dmnsn_vector up = dmnsn_new_vector(0.0, 1.0, 0.0);
- dmnsn_vector sky = dmnsn_new_vector(0.0, 1.0, 0.0);
- dmnsn_matrix trans = dmnsn_identity_matrix();
-
- dmnsn_camera *camera = NULL;
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, astnode.children) {
- dmnsn_astnode child;
-
- switch (item->type) {
- /* Camera types */
- case DMNSN_AST_PERSPECTIVE:
- camera_type = item->type;
- break;
-
- /* Camera vectors */
- case DMNSN_AST_LOCATION:
- dmnsn_array_get(item->children, 0, &child);
- location = dmnsn_realize_vector(child);
- break;
- case DMNSN_AST_RIGHT:
- dmnsn_array_get(item->children, 0, &child);
- right = dmnsn_realize_vector(child);
- break;
- case DMNSN_AST_UP:
- dmnsn_array_get(item->children, 0, &child);
- right = dmnsn_realize_vector(child);
- break;
- case DMNSN_AST_SKY:
- dmnsn_array_get(item->children, 0, &child);
- sky = dmnsn_realize_vector(child);
- break;
- case DMNSN_AST_DIRECTION:
- dmnsn_array_get(item->children, 0, &child);
- direction = dmnsn_realize_vector(child);
- break;
-
- /* Camera modifiers */
-
- case DMNSN_AST_LOOK_AT:
- {
- dmnsn_array_get(item->children, 0, &child);
- dmnsn_vector look_at = dmnsn_realize_vector(child);
-
- /* Line the camera up with the sky */
-
- dmnsn_matrix sky1 = dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(up, sky, direction),
- dmnsn_vector_normalize(direction)
- )
- );
- up = dmnsn_transform_vector(sky1, up);
- right = dmnsn_transform_vector(sky1, right);
-
- dmnsn_matrix sky2 = dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(up, sky, right),
- dmnsn_vector_normalize(right)
- )
- );
- up = dmnsn_transform_vector(sky2, up);
- direction = dmnsn_transform_vector(sky2, direction);
-
- /* Line up the camera with the look_at */
-
- look_at = dmnsn_vector_sub(look_at, location);
- dmnsn_matrix look_at1 = dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(direction, look_at, up),
- dmnsn_vector_normalize(up)
- )
- );
- right = dmnsn_transform_vector(look_at1, right);
- direction = dmnsn_transform_vector(look_at1, direction);
-
- dmnsn_matrix look_at2 = dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(direction, look_at, right),
- dmnsn_vector_normalize(right)
- )
- );
- up = dmnsn_transform_vector(look_at2, up);
- direction = dmnsn_transform_vector(look_at2, direction);
-
- break;
- }
-
- case DMNSN_AST_ANGLE:
- {
- dmnsn_array_get(item->children, 0, &child);
- double angle = dmnsn_radians(dmnsn_realize_float(child));
- direction = dmnsn_vector_mul(
- 0.5*dmnsn_vector_norm(right)/tan(angle/2.0),
- dmnsn_vector_normalize(direction)
- );
- break;
- }
-
- /* Transformations */
- case DMNSN_AST_TRANSFORMATION:
- trans = dmnsn_matrix_mul(dmnsn_realize_transformation(*item), trans);
- break;
-
- default:
- dmnsn_assert(false, "Invalid camera item.");
- break;
- }
- }
-
- switch (camera_type) {
- case DMNSN_AST_PERSPECTIVE:
- {
- /* These multiplications are in right-to-left order so that user
- transformations happen after camera alignment */
-
- trans = dmnsn_matrix_mul(trans, dmnsn_translation_matrix(location));
-
- /* Align y with `up' */
-
- dmnsn_matrix align = dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(dmnsn_y, up, dmnsn_z),
- dmnsn_z
- )
- );
-
- dmnsn_vector x = dmnsn_transform_vector(align, dmnsn_x);
- dmnsn_vector y = dmnsn_transform_vector(align, dmnsn_y);
-
- align = dmnsn_matrix_mul(
- dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(y, up, x),
- x
- )
- ),
- align
- );
-
- /* Align x with `right' */
-
- align = dmnsn_matrix_mul(
- dmnsn_rotation_matrix(
- dmnsn_vector_mul(
- dmnsn_vector_axis_angle(x, right, up),
- dmnsn_vector_normalize(up)
- )
- ),
- align
- );
-
- trans = dmnsn_matrix_mul(trans, align);
-
- /* Scale the camera with `up', `right', and `direction' */
- trans = dmnsn_matrix_mul(
- trans,
- dmnsn_scale_matrix(
- dmnsn_new_vector(
- dmnsn_vector_norm(right),
- dmnsn_vector_norm(up),
- dmnsn_vector_norm(direction)
- )
- )
- );
-
- camera = dmnsn_new_perspective_camera();
- break;
- }
-
- default:
- dmnsn_assert(false, "Unsupported camera type.");
- }
-
- camera->trans = trans;
- return camera;
-}
-
-static dmnsn_pattern *
-dmnsn_realize_pattern(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_PATTERN, "Expected a pattern.");
-
- dmnsn_astnode type;
- dmnsn_array_get(astnode.children, 0, &type);
-
- dmnsn_pattern *pattern = NULL;
-
- switch (type.type) {
- case DMNSN_AST_CHECKER:
- pattern = dmnsn_new_checker_pattern();
- break;
- case DMNSN_AST_GRADIENT:
- {
- dmnsn_astnode orientation;
- dmnsn_array_get(type.children, 0, &orientation);
- dmnsn_vector v = dmnsn_realize_vector(orientation);
- pattern = dmnsn_new_gradient_pattern(v);
- break;
- }
-
- default:
- dmnsn_assert(false, "Unexpected pattern type.");
- }
-
- return pattern;
-}
-
-static dmnsn_map *
-dmnsn_realize_color_list(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_COLOR_LIST, "Expected a color list.");
-
- dmnsn_map *color_map = dmnsn_new_color_map();
-
- double n = 0.0, i = 1.0/(dmnsn_array_size(astnode.children) - 1);
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, entry, astnode.children) {
- dmnsn_color color = dmnsn_realize_color(*entry);
- dmnsn_add_map_entry(color_map, n, &color);
- n += i;
- }
-
- return color_map;
-}
-
-static dmnsn_map *
-dmnsn_realize_color_map(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_COLOR_MAP, "Expected a color_map.");
-
- dmnsn_map *color_map = dmnsn_new_color_map();
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, entry, astnode.children) {
- dmnsn_assert(entry->type == DMNSN_AST_COLOR_MAP_ENTRY,
- "Expected a color_map entry.");
-
- dmnsn_astnode n_node, color_node;
- dmnsn_array_get(entry->children, 0, &n_node);
- dmnsn_array_get(entry->children, 1, &color_node);
-
- double n = dmnsn_realize_float(n_node);
- dmnsn_color color = dmnsn_realize_color(color_node);
-
- dmnsn_add_map_entry(color_map, n, &color);
- }
-
- return color_map;
-}
-
-static dmnsn_map *
-dmnsn_realize_pigment_list(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_PIGMENT_LIST,
- "Expected a pigment list.");
-
- dmnsn_map *pigment_map = dmnsn_new_pigment_map();
-
- double n = 0.0, i = 1.0/(dmnsn_array_size(astnode.children) - 1);
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, entry, astnode.children) {
- dmnsn_pigment *pigment = dmnsn_realize_pigment(*entry);
- dmnsn_add_map_entry(pigment_map, n, &pigment);
- n += i;
- }
-
- return pigment_map;
-}
-
-static dmnsn_map *
-dmnsn_realize_pigment_map(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_PIGMENT_MAP,
- "Expected a pigment_map.");
-
- dmnsn_map *pigment_map = dmnsn_new_pigment_map();
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, entry, astnode.children) {
- dmnsn_assert(entry->type == DMNSN_AST_PIGMENT_MAP_ENTRY,
- "Expected a pigment_map entry.");
-
- dmnsn_astnode n_node, pigment_node;
- dmnsn_array_get(entry->children, 0, &n_node);
- dmnsn_array_get(entry->children, 1, &pigment_node);
-
- double n = dmnsn_realize_float(n_node);
- dmnsn_pigment *pigment = dmnsn_realize_pigment(pigment_node);
-
- dmnsn_add_map_entry(pigment_map, n, &pigment);
- }
-
- return pigment_map;
-}
-
-static dmnsn_pigment *
-dmnsn_realize_pattern_pigment(dmnsn_astnode type, dmnsn_astnode modifiers)
-{
- dmnsn_assert(modifiers.type == DMNSN_AST_PIGMENT_MODIFIERS,
- "Expected pigment modifiers");
-
- dmnsn_pattern *pattern = dmnsn_realize_pattern(type);
- dmnsn_map *color_map = NULL, *pigment_map = NULL;
-
- /* Set up the map */
- DMNSN_ARRAY_FOREACH_REVERSE (dmnsn_astnode *, modifier, modifiers.children) {
- switch (modifier->type) {
- case DMNSN_AST_COLOR_LIST:
- color_map = dmnsn_realize_color_list(*modifier);
- break;
- case DMNSN_AST_COLOR_MAP:
- color_map = dmnsn_realize_color_map(*modifier);
- break;
-
- case DMNSN_AST_PIGMENT_LIST:
- pigment_map = dmnsn_realize_pigment_list(*modifier);
- break;
- case DMNSN_AST_PIGMENT_MAP:
- pigment_map = dmnsn_realize_pigment_map(*modifier);
- break;
-
- default:
- break;
- }
-
- if (color_map || pigment_map)
- break;
- }
-
- /* Now add the default values */
-
- dmnsn_astnode pattern_type;
- dmnsn_array_get(type.children, 0, &pattern_type);
-
- switch (pattern_type.type) {
- case DMNSN_AST_CHECKER:
- /* Default checker pattern is blue and green */
- if (!color_map && !pigment_map) {
- color_map = dmnsn_new_color_map();
- if (dmnsn_map_size(color_map) < 1)
- dmnsn_add_map_entry(color_map, 0.0, &dmnsn_blue);
- if (dmnsn_map_size(color_map) < 2)
- dmnsn_add_map_entry(color_map, 1.0, &dmnsn_green);
- }
- break;
-
- default:
- /* Default map is grayscale */
- if (!color_map && !pigment_map) {
- color_map = dmnsn_new_color_map();
- dmnsn_add_map_entry(color_map, 0.0, &dmnsn_black);
- dmnsn_add_map_entry(color_map, 1.0, &dmnsn_white);
- }
- break;
- }
-
- dmnsn_pigment *pigment = NULL;
- if (color_map) {
- pigment = dmnsn_new_color_map_pigment(pattern, color_map);
- } else if (pigment_map) {
- pigment = dmnsn_new_pigment_map_pigment(pattern, pigment_map);
- } else {
- dmnsn_assert(false, "No appropriate map constructed.");
- }
- return pigment;
-}
-
-static void
-dmnsn_realize_pigment_modifiers(dmnsn_astnode astnode, dmnsn_pigment *pigment)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_PIGMENT_MODIFIERS,
- "Expected pigment modifiers.");
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, modifier, astnode.children) {
- switch (modifier->type) {
- case DMNSN_AST_TRANSFORMATION:
- pigment->trans = dmnsn_matrix_mul(
- dmnsn_realize_transformation(*modifier),
- pigment->trans
- );
- break;
-
- case DMNSN_AST_QUICK_COLOR:
- {
- dmnsn_astnode quick_color;
- dmnsn_array_get(modifier->children, 0, &quick_color);
- pigment->quick_color = dmnsn_realize_color(quick_color);
- break;
- }
-
- case DMNSN_AST_COLOR_LIST:
- case DMNSN_AST_COLOR_MAP:
- case DMNSN_AST_PIGMENT_LIST:
- case DMNSN_AST_PIGMENT_MAP:
- /* Already handled by dmnsn_realize_pattern_pigment() */
- break;
-
- default:
- dmnsn_assert(false, "Invalid pigment modifier.");
- }
- }
-}
-
-static dmnsn_pigment *
-dmnsn_realize_pigment(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_PIGMENT, "Expected a pigment.");
-
- dmnsn_pigment *pigment = NULL;
-
- dmnsn_astnode type_node, modifiers;
- dmnsn_array_get(astnode.children, 0, &type_node);
- dmnsn_array_get(astnode.children, 1, &modifiers);
-
- switch (type_node.type) {
- case DMNSN_AST_NONE:
- break;
-
- case DMNSN_AST_VECTOR:
- {
- dmnsn_color color = dmnsn_realize_color(type_node);
- pigment = dmnsn_new_solid_pigment(color);
- break;
- }
-
- case DMNSN_AST_PATTERN:
- {
- pigment = dmnsn_realize_pattern_pigment(type_node, modifiers);
- break;
- }
-
- case DMNSN_AST_IMAGE_MAP:
- {
- dmnsn_astnode filetype, strnode;
- dmnsn_array_get(type_node.children, 0, &filetype);
- dmnsn_array_get(type_node.children, 1, &strnode);
-
- const char *path = dmnsn_realize_str(strnode);
- FILE *file = fopen(path, "rb");
- if (!file) {
- dmnsn_error("Couldn't open image file.");
- }
-
- dmnsn_canvas *canvas;
- switch (filetype.type) {
- case DMNSN_AST_PNG:
- canvas = dmnsn_png_read_canvas(file);
- if (!canvas) {
- dmnsn_error("Invalid PNG file.");
- }
- pigment = dmnsn_new_canvas_pigment(canvas);
- break;
-
- default:
- dmnsn_assert(false, "Invalid image_map type.");
- break;
- }
- break;
- }
-
- default:
- dmnsn_assert(false, "Invalid pigment type.");
- }
-
- dmnsn_realize_pigment_modifiers(modifiers, pigment);
-
- return pigment;
-}
-
-static dmnsn_finish *
-dmnsn_realize_reflection(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_REFLECTION, "Expected a reflection.");
-
- dmnsn_astnode min_node, max_node;
- dmnsn_array_get(astnode.children, 0, &min_node);
- dmnsn_array_get(astnode.children, 1, &max_node);
-
- dmnsn_color min = dmnsn_realize_color(min_node);
- dmnsn_color max = dmnsn_realize_color(max_node);
-
- double falloff = 1.0;
-
- dmnsn_astnode items;
- dmnsn_array_get(astnode.children, 2, &items);
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, items.children) {
- dmnsn_astnode child;
-
- switch (item->type) {
- case DMNSN_AST_FALLOFF:
- dmnsn_array_get(item->children, 0, &child);
- falloff = dmnsn_realize_float(child);
- break;
-
- default:
- dmnsn_assert(false, "Invalid reflection item.");
- }
- }
-
- dmnsn_finish *reflection = dmnsn_new_reflective_finish(min, max, falloff);
-
- return reflection;
-}
-
-static dmnsn_finish *
-dmnsn_realize_finish(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_FINISH, "Expected a finish.");
-
- dmnsn_finish *finish = dmnsn_new_finish();
-
- dmnsn_color ambient = dmnsn_black;
- bool ambient_set = false;
-
- double diffuse = 0.0;
- bool diffuse_set = false;
-
- double phong = 0.0;
- double phong_size = 40.0;
-
- dmnsn_finish *reflection = NULL;
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, astnode.children) {
- dmnsn_astnode child;
-
- switch (item->type) {
- case DMNSN_AST_AMBIENT:
- dmnsn_array_get(item->children, 0, &child);
- ambient = dmnsn_realize_color(child);
- ambient_set = true;
- break;
-
- case DMNSN_AST_DIFFUSE:
- dmnsn_array_get(item->children, 0, &child);
- diffuse = dmnsn_realize_float(child);
- diffuse_set = true;
- break;
-
- case DMNSN_AST_PHONG:
- dmnsn_array_get(item->children, 0, &child);
- phong = dmnsn_realize_float(child);
- break;
- case DMNSN_AST_PHONG_SIZE:
- dmnsn_array_get(item->children, 0, &child);
- phong_size = dmnsn_realize_float(child);
- break;
-
- case DMNSN_AST_REFLECTION:
- dmnsn_delete_finish(reflection);
- reflection = dmnsn_realize_reflection(*item);
- break;
-
- default:
- dmnsn_assert(false, "Invalid finish item.");
- }
- }
-
- if (ambient_set) {
- finish = dmnsn_new_finish_combination(
- dmnsn_new_ambient_finish(ambient),
- finish
- );
- }
-
- if (diffuse_set) {
- finish = dmnsn_new_finish_combination(
- dmnsn_new_diffuse_finish(diffuse),
- finish
- );
- }
-
- if (phong) {
- finish = dmnsn_new_finish_combination(
- dmnsn_new_phong_finish(phong, phong_size),
- finish
- );
- }
-
- if (reflection) {
- finish = dmnsn_new_finish_combination(reflection, finish);
- }
-
- return finish;
-}
-
-static dmnsn_texture *
-dmnsn_realize_texture(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_TEXTURE, "Expected a texture.");
-
- dmnsn_texture *texture = dmnsn_new_texture();
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, astnode.children) {
- switch (item->type) {
- case DMNSN_AST_PIGMENT:
- dmnsn_delete_pigment(texture->pigment);
- texture->pigment = dmnsn_realize_pigment(*item);
- break;
-
- case DMNSN_AST_FINISH:
- dmnsn_delete_finish(texture->finish);
- texture->finish = dmnsn_realize_finish(*item);
- break;
-
- case DMNSN_AST_TRANSFORMATION:
- texture->trans = dmnsn_matrix_mul(
- dmnsn_realize_transformation(*item),
- texture->trans
- );
- break;
-
- default:
- dmnsn_assert(false, "Invalid texture item.");
- }
- }
-
- return texture;
-}
-
-static dmnsn_interior *
-dmnsn_realize_interior(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_INTERIOR, "Expected a texture.");
-
- dmnsn_interior *interior = dmnsn_new_interior();
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, item, astnode.children) {
- dmnsn_astnode child;
-
- switch (item->type) {
- case DMNSN_AST_IOR:
- dmnsn_array_get(item->children, 0, &child);
- interior->ior = dmnsn_realize_float(child);
- break;
-
- default:
- dmnsn_assert(false, "Invalid interior item.");
- }
- }
-
- return interior;
-}
-
-static void
-dmnsn_realize_object_modifiers(dmnsn_astnode astnode, dmnsn_object *object)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_OBJECT_MODIFIERS,
- "Expected object modifiers.");
-
- /* Save the pre-existing transformations */
- dmnsn_matrix existing_trans = dmnsn_matrix_inverse(object->trans);
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, modifier, astnode.children) {
- switch (modifier->type) {
- case DMNSN_AST_TRANSFORMATION:
- object->trans = dmnsn_matrix_mul(
- dmnsn_realize_transformation(*modifier),
- object->trans
- );
- break;
-
- case DMNSN_AST_TEXTURE:
- dmnsn_delete_texture(object->texture);
- object->texture = dmnsn_realize_texture(*modifier);
- break;
- case DMNSN_AST_PIGMENT:
- if (!object->texture)
- object->texture = dmnsn_new_texture();
- dmnsn_delete_pigment(object->texture->pigment);
- object->texture->pigment = dmnsn_realize_pigment(*modifier);
- break;
- case DMNSN_AST_FINISH:
- if (!object->texture)
- object->texture = dmnsn_new_texture();
- dmnsn_delete_finish(object->texture->finish);
- object->texture->finish = dmnsn_realize_finish(*modifier);
- break;
-
- case DMNSN_AST_INTERIOR:
- dmnsn_delete_interior(object->interior);
- object->interior = dmnsn_realize_interior(*modifier);
- break;
-
- case DMNSN_AST_STURM:
- /* Ignored */
- break;
-
- default:
- dmnsn_assert(false, "Invalid object modifier.");
- }
- }
-
- if (object->texture) {
- /* Right-multiply to counteract any pre-existing transformations -- this
- means, for example, that the transformation that makes a sphere have
- radius 2 doesn't scale the texture by a factor of 2 */
- object->texture->trans = dmnsn_matrix_mul(
- object->texture->trans,
- existing_trans
- );
- }
-}
-
-static void
-dmnsn_realize_light_source_modifiers(dmnsn_astnode astnode, dmnsn_light *light)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_OBJECT_MODIFIERS,
- "Expected object modifiers.");
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, modifier, astnode.children) {
- switch (modifier->type) {
- case DMNSN_AST_TRANSFORMATION:
- light->x0 = dmnsn_transform_vector(
- dmnsn_realize_transformation(*modifier),
- light->x0
- );
- break;
-
- case DMNSN_AST_TEXTURE:
- case DMNSN_AST_PIGMENT:
- case DMNSN_AST_FINISH:
- case DMNSN_AST_INTERIOR:
- /* Ignore other object modifiers */
- break;
-
- default:
- dmnsn_assert(false, "Invalid object modifier.");
- }
- }
-}
-
-static dmnsn_light *
-dmnsn_realize_light_source(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_LIGHT_SOURCE,
- "Expected a light source.");
-
- dmnsn_astnode point, color_node;
- dmnsn_array_get(astnode.children, 0, &point);
- dmnsn_array_get(astnode.children, 1, &color_node);
-
- dmnsn_vector x0 = dmnsn_realize_vector(point);
- dmnsn_color color = dmnsn_realize_color(color_node);
-
- dmnsn_light *light = dmnsn_new_point_light(x0, color);
-
- dmnsn_astnode modifiers;
- dmnsn_array_get(astnode.children, 2, &modifiers);
- dmnsn_realize_light_source_modifiers(modifiers, light);
-
- return light;
-}
-
-static dmnsn_object *dmnsn_realize_object(dmnsn_astnode astnode,
- dmnsn_array *lights);
-
-static dmnsn_object *
-dmnsn_realize_box(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_BOX, "Expected a box.");
-
- dmnsn_astnode corner1, corner2;
- dmnsn_array_get(astnode.children, 0, &corner1);
- dmnsn_array_get(astnode.children, 1, &corner2);
-
- dmnsn_vector x1 = dmnsn_realize_vector(corner1),
- x2 = dmnsn_realize_vector(corner2);
-
- dmnsn_object *box = dmnsn_new_cube();
-
- box->trans = dmnsn_scale_matrix(
- dmnsn_new_vector(fabs(x2.x - x1.x)/2.0,
- fabs(x2.y - x1.y)/2.0,
- fabs(x2.z - x1.z)/2.0)
- );
- box->trans = dmnsn_matrix_mul(
- dmnsn_translation_matrix(dmnsn_new_vector((x2.x + x1.x)/2.0,
- (x2.y + x1.y)/2.0,
- (x2.z + x1.z)/2.0)),
- box->trans
- );
-
- return box;
-}
-
-static dmnsn_object *
-dmnsn_realize_cone(dmnsn_astnode astnode)
-{
- dmnsn_astnode pnode1, rnode1, pnode2, rnode2, open;
-
- if (astnode.type == DMNSN_AST_CONE) {
- dmnsn_array_get(astnode.children, 0, &pnode1);
- dmnsn_array_get(astnode.children, 1, &rnode1);
- dmnsn_array_get(astnode.children, 2, &pnode2);
- dmnsn_array_get(astnode.children, 3, &rnode2);
- dmnsn_array_get(astnode.children, 4, &open);
- } else if (astnode.type == DMNSN_AST_CYLINDER) {
- dmnsn_array_get(astnode.children, 0, &pnode1);
- dmnsn_array_get(astnode.children, 1, &pnode2);
- dmnsn_array_get(astnode.children, 2, &rnode1);
- dmnsn_array_get(astnode.children, 2, &rnode2);
- dmnsn_array_get(astnode.children, 3, &open);
- } else {
- dmnsn_assert(false, "Expected a cone or cylinder.");
- }
-
- dmnsn_vector p1 = dmnsn_realize_vector(pnode1);
- dmnsn_vector p2 = dmnsn_realize_vector(pnode2);
- double r1 = dmnsn_realize_float(rnode1);
- double r2 = dmnsn_realize_float(rnode2);
-
- dmnsn_vector dir = dmnsn_vector_sub(p2, p1);
- double l = dmnsn_vector_norm(dir);
-
- double theta1 = dmnsn_vector_axis_angle(dmnsn_y, dir, dmnsn_x);
- double theta2 = dmnsn_vector_axis_angle(dmnsn_y, dir, dmnsn_z);
-
- dmnsn_object *cone = dmnsn_new_cone(r1, r2, dmnsn_realize_integer(open));
- /* Transformations: lift the cone to start at the origin, scale, rotate,
- and translate properly */
- cone->trans = dmnsn_translation_matrix(dmnsn_new_vector(0.0, 1.0, 0.0));
- cone->trans = dmnsn_matrix_mul(
- dmnsn_scale_matrix(dmnsn_new_vector(1.0, l/2.0, 1.0)),
- cone->trans
- );
- cone->trans = dmnsn_matrix_mul(
- dmnsn_rotation_matrix(dmnsn_new_vector(theta1, 0.0, 0.0)),
- cone->trans
- );
- cone->trans = dmnsn_matrix_mul(
- dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 0.0, theta2)),
- cone->trans
- );
- cone->trans = dmnsn_matrix_mul(
- dmnsn_translation_matrix(p1),
- cone->trans
- );
- return cone;
-}
-
-static dmnsn_object *
-dmnsn_realize_sphere(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_SPHERE, "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();
- sphere->trans = dmnsn_scale_matrix(dmnsn_new_vector(r, r, r));
- sphere->trans = dmnsn_matrix_mul(dmnsn_translation_matrix(x0), sphere->trans);
- return sphere;
-}
-
-static dmnsn_object *
-dmnsn_realize_torus(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_TORUS, "Expected a torus.");
-
- dmnsn_astnode major, minor;
- dmnsn_array_get(astnode.children, 0, &major);
- dmnsn_array_get(astnode.children, 1, &minor);
-
- double R = dmnsn_realize_float(major);
- double r = dmnsn_realize_float(minor);
-
- dmnsn_object *torus = dmnsn_new_torus(R, r);
- return torus;
-}
-
-static dmnsn_object *
-dmnsn_realize_plane(dmnsn_astnode astnode)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_PLANE, "Expected a plane.");
-
- dmnsn_astnode normal, distance;
- dmnsn_array_get(astnode.children, 0, &normal);
- dmnsn_array_get(astnode.children, 1, &distance);
-
- dmnsn_vector n = dmnsn_vector_normalize(dmnsn_realize_vector(normal));
- double d = dmnsn_realize_float(distance);
-
- dmnsn_object *plane = dmnsn_new_plane(n);
- plane->trans = dmnsn_translation_matrix(dmnsn_vector_mul(d, n));
- return plane;
-}
-
-/* Bulk-load a union */
-static dmnsn_object *
-dmnsn_realize_union(dmnsn_astnode astnode, dmnsn_astnode modifiers,
- dmnsn_array *lights)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_UNION, "Expected a union.");
-
- dmnsn_array *children = dmnsn_new_array(sizeof(dmnsn_object *));
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, onode, astnode.children) {
- if (onode->type == DMNSN_AST_LIGHT_SOURCE) {
- dmnsn_light *light = dmnsn_realize_light_source(*onode);
- dmnsn_realize_light_source_modifiers(modifiers, light);
- dmnsn_array_push(lights, &light);
- } else {
- dmnsn_object *object = dmnsn_realize_object(*onode, lights);
- if (object)
- dmnsn_array_push(children, &object);
- }
- }
-
- dmnsn_object *csg = NULL;
- if (dmnsn_array_size(children) > 0)
- csg = dmnsn_new_csg_union(children);
- dmnsn_delete_array(children);
- return csg;
-}
-
-typedef dmnsn_object *dmnsn_csg_object_fn(dmnsn_object *a, dmnsn_object *b);
-
-/* Generalized CSG realizer */
-static dmnsn_object *
-dmnsn_realize_csg(dmnsn_astnode astnode, dmnsn_astnode modifiers,
- dmnsn_array *lights, dmnsn_csg_object_fn *csg_object_fn)
-{
- dmnsn_object *csg = NULL;
- dmnsn_astnode *onode;
- for (onode = dmnsn_array_first(astnode.children);
- onode <= (dmnsn_astnode *)dmnsn_array_last(astnode.children);
- ++onode)
- {
- if (onode->type == DMNSN_AST_LIGHT_SOURCE) {
- dmnsn_light *light = dmnsn_realize_light_source(*onode);
- dmnsn_realize_light_source_modifiers(modifiers, light);
- dmnsn_array_push(lights, &light);
- } else {
- csg = dmnsn_realize_object(*onode, lights);
- break;
- }
- }
-
- for (++onode;
- onode <= (dmnsn_astnode *)dmnsn_array_last(astnode.children);
- ++onode)
- {
- if (onode->type == DMNSN_AST_LIGHT_SOURCE) {
- dmnsn_light *light = dmnsn_realize_light_source(*onode);
- dmnsn_realize_light_source_modifiers(modifiers, light);
- dmnsn_array_push(lights, &light);
- } else {
- dmnsn_object *object = dmnsn_realize_object(*onode, lights);
- csg = csg_object_fn(csg, object);
- }
- }
-
- return csg;
-}
-
-static dmnsn_object *
-dmnsn_realize_intersection(dmnsn_astnode astnode, dmnsn_astnode modifiers,
- dmnsn_array *lights)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_INTERSECTION,
- "Expected an intersection.");
- return dmnsn_realize_csg(astnode, modifiers, lights,
- dmnsn_new_csg_intersection);
-}
-
-static dmnsn_object *
-dmnsn_realize_difference(dmnsn_astnode astnode, dmnsn_astnode modifiers,
- dmnsn_array *lights)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_DIFFERENCE, "Expected a difference.");
- return dmnsn_realize_csg(astnode, modifiers, lights,
- dmnsn_new_csg_difference);
-}
-
-static dmnsn_object *
-dmnsn_realize_merge(dmnsn_astnode astnode, dmnsn_astnode modifiers,
- dmnsn_array *lights)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_MERGE, "Expected a merge.");
- return dmnsn_realize_csg(astnode, modifiers, lights, dmnsn_new_csg_merge);
-}
-
-/* Realize an object, or maybe a light */
-static dmnsn_object *
-dmnsn_realize_object(dmnsn_astnode astnode, dmnsn_array *lights)
-{
- dmnsn_assert(astnode.type == DMNSN_AST_OBJECT
- || astnode.type == DMNSN_AST_LIGHT_SOURCE,
- "Expected an object.");
-
- dmnsn_astnode onode, modifiers;
- dmnsn_array_get(astnode.children, 0, &onode);
- dmnsn_array_get(astnode.children, 1, &modifiers);
-
- dmnsn_object *object = NULL;
-
- switch (onode.type) {
- case DMNSN_AST_BOX:
- object = dmnsn_realize_box(onode);
- break;
- case DMNSN_AST_CONE:
- case DMNSN_AST_CYLINDER:
- object = dmnsn_realize_cone(onode);
- break;
- case DMNSN_AST_DIFFERENCE:
- object = dmnsn_realize_difference(onode, modifiers, lights);
- break;
- case DMNSN_AST_INTERSECTION:
- object = dmnsn_realize_intersection(onode, modifiers, lights);
- break;
- case DMNSN_AST_MERGE:
- object = dmnsn_realize_merge(onode, modifiers, lights);
- break;
- case DMNSN_AST_PLANE:
- object = dmnsn_realize_plane(onode);
- break;
- case DMNSN_AST_SPHERE:
- object = dmnsn_realize_sphere(onode);
- break;
- case DMNSN_AST_TORUS:
- object = dmnsn_realize_torus(onode);
- break;
- case DMNSN_AST_UNION:
- object = dmnsn_realize_union(onode, modifiers, lights);
- break;
-
- case DMNSN_AST_LIGHT_SOURCE:
- {
- dmnsn_light *light = dmnsn_realize_light_source(astnode);
- dmnsn_array_push(lights, &light);
- return NULL;
- }
-
- default:
- dmnsn_assert(false, "Expected an object type.");
- }
-
- if (object) {
- dmnsn_realize_object_modifiers(modifiers, object);
- }
- return object;
-}
-
-static dmnsn_scene *
-dmnsn_realize_astree(const dmnsn_astree *astree)
-{
- dmnsn_scene *scene = dmnsn_new_scene();
-
- /* Default finish */
- scene->default_texture->finish = dmnsn_new_finish_combination(
- dmnsn_new_ambient_finish(
- dmnsn_color_mul(0.1, dmnsn_white)
- ),
- dmnsn_new_diffuse_finish(0.6)
- );
-
- /* Background color */
- scene->background = dmnsn_black;
-
- /* Create the default perspective camera */
- scene->camera = dmnsn_new_perspective_camera();
-
- /*
- * Now parse the abstract syntax tree
- */
-
- DMNSN_ARRAY_FOREACH (dmnsn_astnode *, astnode, astree) {
- dmnsn_astnode child;
- dmnsn_light *light;
- dmnsn_object *object;
-
- switch (astnode->type) {
- case DMNSN_AST_GLOBAL_SETTINGS:
- dmnsn_realize_global_settings(*astnode, scene);
- break;
-
- case DMNSN_AST_BACKGROUND:
- dmnsn_array_get(astnode->children, 0, &child);
- scene->background = dmnsn_realize_color(child);
- break;
- case DMNSN_AST_SKY_SPHERE:
- dmnsn_delete_sky_sphere(scene->sky_sphere);
- scene->sky_sphere = dmnsn_realize_sky_sphere(*astnode);
- break;
-
- case DMNSN_AST_CAMERA:
- dmnsn_delete_camera(scene->camera);
- scene->camera = dmnsn_realize_camera(*astnode);
- break;
-
- case DMNSN_AST_OBJECT:
- object = dmnsn_realize_object(*astnode, scene->lights);
- if (object)
- dmnsn_array_push(scene->objects, &object);
- break;
-
- case DMNSN_AST_LIGHT_SOURCE:
- light = dmnsn_realize_light_source(*astnode);
- dmnsn_array_push(scene->lights, &light);
- break;
-
- default:
- dmnsn_assert(false, "Unrecognised syntax element.");
- }
- }
-
- return scene;
-}
-
-dmnsn_scene *
-dmnsn_realize(FILE *file, dmnsn_symbol_table *symtable)
-{
- if (!symtable) {
- symtable = dmnsn_new_symbol_table();
- }
-
- dmnsn_astree *astree = dmnsn_parse(file, symtable);
- if (!astree) {
- return NULL;
- }
-
- dmnsn_scene *scene = dmnsn_realize_astree(astree);
-
- dmnsn_delete_astree(astree);
- return scene;
-}
-
-dmnsn_scene *
-dmnsn_realize_string(const char *str, dmnsn_symbol_table *symtable)
-{
- if (!symtable) {
- symtable = dmnsn_new_symbol_table();
- }
-
- dmnsn_astree *astree = dmnsn_parse_string(str, symtable);
- if (!astree) {
- return NULL;
- }
-
- dmnsn_scene *scene = dmnsn_realize_astree(astree);
-
- dmnsn_delete_astree(astree);
- return scene;
-}