solstice

Compute collected power and efficiencies of a solar plant
git clone git://git.meso-star.com/solstice.git
Log | Files | Refs | README | LICENSE

commit 054fb381cc6c2698ddb7964213f28f0fc6d78cb0
parent 9286d2298cbf03a0a798510ad0fc85c1514e9290
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  2 Dec 2016 09:07:33 +0100

Rename the parser API

Prefix the parser API functions by "solparser_" and its constants par
"SOLPARSER_".

Diffstat:
Mcmake/CMakeLists.txt | 2+-
Mcmake/parser/CMakeLists.txt | 62+++++++++++++++++++++++++++++++-------------------------------
Asrc/parser/solparser.c | 3402+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser.h | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_entity.h | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_geometry.h | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_material.h | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_pivot.h | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_shape.h | 260+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/solparser_sun.h | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/parser/solstice_entity.h | 202-------------------------------------------------------------------------------
Dsrc/parser/solstice_geometry.h | 90-------------------------------------------------------------------------------
Dsrc/parser/solstice_material.h | 56--------------------------------------------------------
Dsrc/parser/solstice_parser.c | 3402-------------------------------------------------------------------------------
Dsrc/parser/solstice_parser.h | 289------------------------------------------------------------------------------
Dsrc/parser/solstice_pivot.h | 84-------------------------------------------------------------------------------
Dsrc/parser/solstice_shape.h | 260-------------------------------------------------------------------------------
Dsrc/parser/solstice_sun.h | 88-------------------------------------------------------------------------------
Asrc/parser/test_solparser.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/test_solparser2.c | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/test_solparser3.c | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/parser/test_solparser4.c | 208+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/parser/test_solstice_parser.c | 80-------------------------------------------------------------------------------
Dsrc/parser/test_solstice_parser2.c | 215-------------------------------------------------------------------------------
Dsrc/parser/test_solstice_parser3.c | 246-------------------------------------------------------------------------------
Dsrc/parser/test_solstice_parser4.c | 208-------------------------------------------------------------------------------
Msrc/solstice.c | 12++++++------
27 files changed, 5256 insertions(+), 5258 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -70,7 +70,7 @@ if(CMAKE_COMPILER_IS_GNUCC) endif() add_executable(solstice ${SOLSTICE_SOURCE_DIR}/solstice.c) -target_link_libraries(solstice LibYAML RSys ${MATH_LIB} solstice-parser SolAnim SolSolver) +target_link_libraries(solstice LibYAML RSys ${MATH_LIB} solparser SolAnim SolSolver) set_target_properties(solstice PROPERTIES VERSION ${VERSION} SOVERSION ${VERSION_MAJOR}) diff --git a/cmake/parser/CMakeLists.txt b/cmake/parser/CMakeLists.txt @@ -16,7 +16,7 @@ cmake_minimum_required(VERSION 2.8) project(solstice-parser C CXX) -set(PARSER_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../../src/parser) +set(SOLPARSER_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../../src/parser) ################################################################################ # Define include directories @@ -24,31 +24,31 @@ set(PARSER_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../../src/parser) include_directories( ${LibYAML_INCLUDE_DIR} ${RSys_INCLUDE_DIR} - ${PARSER_SOURCE_DIR}/../) + ${SOLPARSER_SOURCE_DIR}/../) ################################################################################ # Configure and define targets ################################################################################ -set(PARSER_FILES_SRC - solstice_parser.c) -set(PARSER_FILES_INC - solstice_entity.h - solstice_material.h - solstice_parser.h - solstice_pivot.h - solstice_shape.h - solstice_sun.h) +set(SOLPARSER_FILES_SRC + solparser.c) +set(SOLPARSER_FILES_INC + solparser.h + solparser_entity.h + solparser_material.h + solparser_pivot.h + solparser_shape.h + solparser_sun.h) # Prepend each file in the `SOLSTICE_FILES_<SRC|INC>' list by `SOLSTICE_SOURCE_DIR' -rcmake_prepend_path(PARSER_FILES_SRC ${PARSER_SOURCE_DIR}) -rcmake_prepend_path(PARSER_FILES_INC ${PARSER_SOURCE_DIR}) -rcmake_prepend_path(PARSER_FILES_DOC ${PROJECT_SOURCE_DIR}/../) +rcmake_prepend_path(SOLPARSER_FILES_SRC ${SOLPARSER_SOURCE_DIR}) +rcmake_prepend_path(SOLPARSER_FILES_INC ${SOLPARSER_SOURCE_DIR}) +rcmake_prepend_path(SOLPARSER_FILES_DOC ${PROJECT_SOURCE_DIR}/../) if(CMAKE_COMPILER_IS_GNUCC) set(MATH_LIB m) endif() -add_library(solstice-parser STATIC ${PARSER_FILES_SRC} ${PARSER_FILES_INC}) +add_library(solparser STATIC ${SOLPARSER_FILES_SRC} ${SOLPARSER_FILES_INC}) ################################################################################ # Tests @@ -56,9 +56,9 @@ add_library(solstice-parser STATIC ${PARSER_FILES_SRC} ${PARSER_FILES_INC}) if(NOT NO_TEST) function(build_test _name) add_executable(${_name} - ${PARSER_SOURCE_DIR}/${_name}.c - ${PARSER_SOURCE_DIR}/../test_solstice_utils.h) - target_link_libraries(${_name} LibYAML ${MATH_LIB} RSys solstice-parser) + ${SOLPARSER_SOURCE_DIR}/${_name}.c + ${SOLPARSER_SOURCE_DIR}/../test_solstice_utils.h) + target_link_libraries(${_name} LibYAML ${MATH_LIB} RSys solparser) endfunction() function(new_test _name) @@ -66,15 +66,15 @@ if(NOT NO_TEST) add_test(${_name} ${_name}) endfunction() - build_test(test_solstice_parser) - add_test(test_solstice_parser_ok_0 test_solstice_parser - ${PARSER_SOURCE_DIR}/yaml/test_ok_0.yaml) - add_test(test_solstice_parser_ok_1 test_solstice_parser - ${PARSER_SOURCE_DIR}/yaml/test_ok_1.yaml) - add_test(test_solstice_parser_ok_2 test_solstice_parser - ${PARSER_SOURCE_DIR}/yaml/test_ok_2.yaml) - add_test(test_solstice_parser_ok_2 test_solstice_parser - ${PARSER_SOURCE_DIR}/yaml/test_ok_3.yaml) + build_test(test_solparser) + add_test(test_solparser_ok_0 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_0.yaml) + add_test(test_solparser_ok_1 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_1.yaml) + add_test(test_solparser_ok_2 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_2.yaml) + add_test(test_solparser_ok_2 test_solparser + ${SOLPARSER_SOURCE_DIR}/yaml/test_ok_3.yaml) # TODO rewrite them wrt the update of the input specification # add_test(test_solstice_parser_ko_0 test_solstice_parser -e # ${SOLSTICE_SOURCE_DIR}/yaml/test_ko_0.yaml) @@ -83,11 +83,11 @@ if(NOT NO_TEST) # add_test(test_solstice_parser_ko_2 test_solstice_parser -e # ${SOLSTICE_SOURCE_DIR}/yaml/test_ko_2.yaml) - new_test(test_solstice_parser2) - new_test(test_solstice_parser3) - new_test(test_solstice_parser4) + new_test(test_solparser2) + new_test(test_solparser3) + new_test(test_solparser4) - rcmake_copy_runtime_libraries(test_solstice_parser) + rcmake_copy_runtime_libraries(test_solparser) endif() diff --git a/src/parser/solparser.c b/src/parser/solparser.c @@ -0,0 +1,3402 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#define _POSIX_C_SOURCE 200112L /* nextafter support */ + +#include "solparser.h" +#include "solparser_entity.h" +#include "solparser_material.h" +#include "solparser_pivot.h" +#include "solparser_shape.h" +#include "solparser_sun.h" + +#include <rsys/cstr.h> +#include <rsys/double3.h> +#include <rsys/dynamic_array.h> +#include <rsys/hash_table.h> +#include <rsys/ref_count.h> +#include <rsys/str.h> + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <yaml.h> + +/* Declare the array of matte materials */ +#define DARRAY_NAME matte +#define DARRAY_DATA struct solparser_material_matte +#include <rsys/dynamic_array.h> + +/* Declare the array of mirror materials */ +#define DARRAY_NAME mirror +#define DARRAY_DATA struct solparser_material_mirror +#include <rsys/dynamic_array.h> + +/* Declare the array of materials */ +#define DARRAY_NAME material +#define DARRAY_DATA struct solparser_material +#include <rsys/dynamic_array.h> + +/* Declare the array of the double sided materials */ +#define DARRAY_NAME material2 +#define DARRAY_DATA struct solparser_material_double_sided +#include <rsys/dynamic_array.h> + +/* Declare the array of the shapes */ +#define DARRAY_NAME shape +#define DARRAY_DATA struct solparser_shape +#include <rsys/dynamic_array.h> + +/* Declare the array of cuboid */ +#define DARRAY_NAME cuboid +#define DARRAY_DATA struct solparser_shape_cuboid +#include <rsys/dynamic_array.h> + +/* Declare the array of cylinder */ +#define DARRAY_NAME cylinder +#define DARRAY_DATA struct solparser_shape_cylinder +#include <rsys/dynamic_array.h> + +/* Declare the array of imported geometries */ +#define DARRAY_NAME impgeom +#define DARRAY_DATA struct solparser_shape_imported_geometry +#define DARRAY_FUNCTOR_INIT solparser_shape_imported_geometry_init +#define DARRAY_FUNCTOR_RELEASE solparser_shape_imported_geometry_release +#define DARRAY_FUNCTOR_COPY solparser_shape_imported_geometry_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ + solparser_shape_imported_geometry_copy_and_release +#include <rsys/dynamic_array.h> + +/* Declare the array of paraboloids */ +#define DARRAY_NAME paraboloid +#define DARRAY_DATA struct solparser_shape_paraboloid +#define DARRAY_FUNCTOR_INIT solparser_shape_paraboloid_init +#define DARRAY_FUNCTOR_RELEASE solparser_shape_paraboloid_release +#define DARRAY_FUNCTOR_COPY solparser_shape_paraboloid_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ + solparser_shape_paraboloid_copy_and_release +#include <rsys/dynamic_array.h> + +/* Declare the array of planes */ +#define DARRAY_NAME plane +#define DARRAY_DATA struct solparser_shape_plane +#define DARRAY_FUNCTOR_INIT solparser_shape_plane_init +#define DARRAY_FUNCTOR_RELEASE solparser_shape_plane_release +#define DARRAY_FUNCTOR_COPY solparser_shape_plane_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_shape_plane_copy_and_release +#include <rsys/dynamic_array.h> + +/* Declare the array of spheres */ +#define DARRAY_NAME sphere +#define DARRAY_DATA struct solparser_shape_sphere +#include <rsys/dynamic_array.h> + +/* Declare the array of objects */ +#define DARRAY_NAME object +#define DARRAY_DATA struct solparser_object +#include <rsys/dynamic_array.h> + +/* Declare the array of geometries */ +#define DARRAY_NAME geometry +#define DARRAY_DATA struct solparser_geometry +#define DARRAY_FUNCTOR_INIT solparser_geometry_init +#define DARRAY_FUNCTOR_RELEASE solparser_geometry_release +#define DARRAY_FUNCTOR_COPY solparser_geometry_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_geometry_copy_and_release +#include <rsys/dynamic_array.h> + +/* Declare the array of entities */ +#define DARRAY_NAME entity +#define DARRAY_DATA struct solparser_entity +#define DARRAY_FUNCTOR_INIT solparser_entity_init +#define DARRAY_FUNCTOR_RELEASE solparser_entity_release +#define DARRAY_FUNCTOR_COPY solparser_entity_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_entity_copy_and_release +#include <rsys/dynamic_array.h> + +/* Declare the array of anchors */ +#define DARRAY_NAME anchor +#define DARRAY_DATA struct solparser_anchor +#define DARRAY_FUNCTOR_INIT solparser_anchor_init +#define DARRAY_FUNCTOR_RELEASE solparser_anchor_release +#define DARRAY_FUNCTOR_COPY solparser_anchor_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_anchor_copy_and_release +#include <rsys/dynamic_array.h> + +/* Declare the array of pivots */ +#define DARRAY_NAME pivot +#define DARRAY_DATA struct solparser_pivot +#include <rsys/dynamic_array.h> + +/* Declare the hash table that maps the address of a YAML node to the id of its + * in memory representation. */ +#define HTABLE_NAME yaml2sols +#define HTABLE_KEY yaml_node_t* +#define HTABLE_DATA size_t +#include <rsys/hash_table.h> + +struct solparser { + yaml_parser_t parser; + struct str stream_name; + int parser_is_init; + + /* Materia data */ + struct htable_yaml2sols yaml2mtls; /* Cache of materials */ + struct darray_material mtls; + struct darray_material2 mtls2; /* Double sided materials */ + struct darray_matte mattes; + struct darray_mirror mirrors; + + /* Shape data */ + struct darray_shape shapes; /* Generic loaded shapes */ + struct darray_cuboid cuboids; + struct darray_cylinder cylinders; + struct darray_impgeom objs; + struct darray_paraboloid parabols; + struct darray_paraboloid parabolic_cylinders; + struct darray_plane planes; + struct darray_sphere spheres; + struct darray_impgeom stls; + + /* Geometries & objects */ + struct htable_yaml2sols yaml2geoms; /* Cache of geometries */ + struct darray_object objects; + struct darray_geometry geometries; + + /* Sun. Note that only one sun is supported */ + const yaml_node_t* sun_key; /* yaml_node_t ptr used to spawn the sun */ + struct solparser_sun sun; /* The loaded sun */ + + /* Entity */ + struct htable_yaml2sols yaml2entities; /* Cache of entities */ + struct htable_str2sols str2entities; + struct darray_entity entities; + + /* Miscellaneous */ + struct darray_anchor anchors; + struct darray_pivot pivots; + + ref_T ref; + struct mem_allocator* allocator; +}; + +static res_T +parse_entity + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* entity, + struct htable_str2sols* htable, + struct solparser_entity_id* solent); + +static res_T +parse_geometry + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* geometry, + struct solparser_geometry_id* solgeom); + +static res_T +parse_pivot + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* pivot, + struct solparser_pivot_id* out_isolpivot); + +static res_T +parse_sun + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* sun, + struct solparser_sun** solsun); + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE void +log_err + (const struct solparser* parser, + const yaml_node_t* node, + const char* fmt, + ...) +{ + va_list vargs_list; + ASSERT(parser && node && fmt); + + fprintf(stderr, "%s:%lu:%lu: ", + str_cget(&parser->stream_name), + (unsigned long)node->start_mark.line+1, + (unsigned long)node->start_mark.column+1); + va_start(vargs_list, fmt); + vfprintf(stderr, fmt, vargs_list); + va_end(vargs_list); +} + +/* Clean up loaded data */ +static INLINE void +parser_clear(struct solparser* parser) +{ + ASSERT(parser); + + /* Materials */ + htable_yaml2sols_clear(&parser->yaml2mtls); + darray_material_clear(&parser->mtls); + darray_material2_clear(&parser->mtls2); + darray_matte_clear(&parser->mattes); + darray_mirror_clear(&parser->mirrors); + + /* Shapes */ + darray_shape_clear(&parser->shapes); + darray_cuboid_clear(&parser->cuboids); + darray_cylinder_clear(&parser->cylinders); + darray_impgeom_clear(&parser->objs); + darray_paraboloid_clear(&parser->parabols); + darray_paraboloid_clear(&parser->parabolic_cylinders); + darray_plane_clear(&parser->planes); + darray_sphere_clear(&parser->spheres); + darray_impgeom_clear(&parser->stls); + + /* Geometries */ + htable_yaml2sols_clear(&parser->yaml2geoms); + darray_object_clear(&parser->objects); + darray_geometry_clear(&parser->geometries); + + /* Sun */ + solparser_sun_clear(&parser->sun); + parser->sun_key = 0; + + /* Entities */ + htable_yaml2sols_clear(&parser->yaml2entities); + htable_str2sols_clear(&parser->str2entities); + darray_entity_clear(&parser->entities); + + /* Miscellaneous */ + darray_anchor_clear(&parser->anchors); + darray_pivot_clear(&parser->pivots); +} + +static void +parser_release(ref_T* ref) +{ + struct solparser* parser; + ASSERT(ref); + + parser = CONTAINER_OF(ref, struct solparser, ref); + if(parser->parser_is_init) yaml_parser_delete(&parser->parser); + str_release(&parser->stream_name); + + /* Materials */ + htable_yaml2sols_release(&parser->yaml2mtls); + darray_material_release(&parser->mtls); + darray_material2_release(&parser->mtls2); + darray_matte_release(&parser->mattes); + darray_mirror_release(&parser->mirrors); + + /* Shapes */ + darray_shape_release(&parser->shapes); + darray_cuboid_release(&parser->cuboids); + darray_cylinder_release(&parser->cylinders); + darray_impgeom_release(&parser->objs); + darray_paraboloid_release(&parser->parabols); + darray_paraboloid_release(&parser->parabolic_cylinders); + darray_plane_release(&parser->planes); + darray_sphere_release(&parser->spheres); + darray_impgeom_release(&parser->stls); + + /* Geometries */ + htable_yaml2sols_release(&parser->yaml2geoms); + darray_object_release(&parser->objects); + darray_geometry_release(&parser->geometries); + + /* Sun */ + solparser_sun_release(&parser->sun); + + /* Entities */ + htable_yaml2sols_release(&parser->yaml2entities); + htable_str2sols_release(&parser->str2entities); + darray_entity_release(&parser->entities); + + /* Miscellaneous */ + darray_anchor_release(&parser->anchors); + darray_pivot_release(&parser->pivots); + + MEM_RM(parser->allocator, parser); +} + +/******************************************************************************* + * Miscellaneous parsing functions + ******************************************************************************/ +static res_T +parse_real + (struct solparser* parser, + const yaml_node_t* real, + const double lower_bound, + const double upper_bound, + double* dst) +{ + res_T res = RES_OK; + ASSERT(real && dst && lower_bound < upper_bound); + + if(real->type != YAML_SCALAR_NODE + || !strlen((char*)real->data.scalar.value)) { + log_err(parser, real, "expect a floating point number.\n"); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_double((char*)real->data.scalar.value, dst); + if(res != RES_OK) { + log_err(parser, real, "invalid floating point number `%s'.\n", + real->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + + if(*dst < lower_bound || *dst > upper_bound) { + log_err(parser, real, "%g is not in [%g, %g].\n", + *dst, lower_bound, upper_bound); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_real3 + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* real3, + const double lower_bound, + const double upper_bound, + double dst[3]) +{ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && real3 && dst); + + if(real3->type != YAML_SEQUENCE_NODE) { + log_err(parser, real3, "expect a sequence of 3 reals.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = real3->data.sequence.items.top - real3->data.sequence.items.start; + if(n != 3) { + log_err(parser, real3, "expect 3 reals while `%li' %s submitted.\n", + n, n > 1 ? "are" : "is"); + res = RES_BAD_ARG; + goto error; + } + + FOR_EACH(i, 0, n) { + yaml_node_t* real; + real = yaml_document_get_node(doc, real3->data.sequence.items.start[i]); + res = parse_real(parser, real, lower_bound, upper_bound, dst + i); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_integer + (struct solparser* parser, + yaml_node_t* integer, + const long lower_bound, + const long upper_bound, + long* dst) +{ + res_T res = RES_OK; + ASSERT(integer && dst && lower_bound < upper_bound); + + if(integer->type != YAML_SCALAR_NODE + || !strlen((char*)integer->data.scalar.value)) { + log_err(parser, integer, "expect an integer.\n"); + res = RES_BAD_ARG; + goto error; + } + + res = cstr_to_long((char*)integer->data.scalar.value, dst); + if(res != RES_OK) { + log_err(parser, integer, "invalid integer `%s'.\n", + integer->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + + if(*dst < lower_bound || *dst > upper_bound) { + log_err(parser, integer, "%li is not in [%li, %li].\n", + *dst, lower_bound, upper_bound); + res = RES_BAD_ARG; + goto error; + } +exit: + return res; +error: + goto exit; +} + +static res_T +parse_string + (struct solparser* parser, + yaml_node_t* string, + struct str* str) +{ + res_T res = RES_OK; + ASSERT(string && str); + + if(string->type != YAML_SCALAR_NODE + || !strlen((char*)string->data.scalar.value)) { + log_err(parser, string, "expect a character string.\n"); + res = RES_BAD_ARG; + goto error; + } + res = str_set(str, (char*)string->data.scalar.value); + if(res != RES_OK) { + log_err(parser, string, "could not register the string `%s'.\n", + string->data.scalar.value); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_transform + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* transform, + double translation[3], + double rotation[3]) +{ + enum { ROTATION, TRANSLATION }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && translation && rotation && transform); + + d3_splat(translation, 0); + d3_splat(rotation, 0); + + if(transform->type != YAML_MAPPING_NODE) { + log_err(parser, transform, "expect a mapping of transform parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = transform->data.mapping.pairs.top - transform->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, transform->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, transform->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect transform parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, "the transform `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "translation")) { + SETUP_MASK(TRANSLATION, "translation"); + res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, translation); + } else if(!strcmp((char*)key->data.scalar.value, "rotation")) { + SETUP_MASK(ROTATION, "rotation"); + res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, rotation); + } else { + log_err(parser, key, "unknown transform parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } +exit: + return res; +error: + goto exit; +} + +static res_T +parse_spectrum_data + (struct solparser* parser, + yaml_document_t* doc, + const double lower_bound, + const double upper_bound, + const yaml_node_t* sdata, + struct solparser_spectrum_data* spectrum_data) +{ + enum { DATA, WAVELENGTH }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && sdata && lower_bound < upper_bound && spectrum_data); + + if(sdata->type != YAML_MAPPING_NODE) { + log_err(parser, sdata, "expect the definition of a spectrum data.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = sdata->data.mapping.pairs.top - sdata->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, sdata->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, sdata->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a spectrum data parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the `"Name"' of the spectrum data is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "data")) { + SETUP_MASK(DATA, "data"); + res = parse_real(parser, val, lower_bound, upper_bound, &spectrum_data->data); + } else if(!strcmp((char*)key->data.scalar.value, "wavelength")) { + SETUP_MASK(WAVELENGTH, "wavelength"); + res = parse_real(parser, val, 0, DBL_MAX, &spectrum_data->wavelength); + } else { + log_err(parser, key, "unknown spectrum data parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, sdata,"the "Name" of the spectrum data is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(DATA, "data"); + CHECK_PARAM(WAVELENGTH, "wavelength"); + #undef CHECK_PARAM + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_spectrum + (struct solparser* parser, + yaml_document_t* doc, + const double lower_bound, + const double upper_bound, + const yaml_node_t* spectrum, + struct darray_spectrum_data* data) +{ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && spectrum && lower_bound < upper_bound && data); + + if(spectrum->type != YAML_SEQUENCE_NODE) { + log_err(parser, spectrum, "expect a list of spectrum data.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = spectrum->data.sequence.items.top - spectrum->data.sequence.items.start; + res = darray_spectrum_data_resize(data, (size_t)n); + if(res != RES_OK) { + log_err(parser, spectrum, "could not allocate the list of spectrum data.\n"); + goto error; + } + + FOR_EACH(i, 0, n) { + yaml_node_t* sdata; + struct solparser_spectrum_data* spectrum_data; + + sdata = yaml_document_get_node(doc, spectrum->data.sequence.items.start[i]); + spectrum_data = darray_spectrum_data_data_get(data) + i; + res = parse_spectrum_data + (parser, doc, lower_bound, upper_bound, sdata, spectrum_data); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + darray_spectrum_data_clear(data); + goto exit; +} + +/******************************************************************************* + * Material + ******************************************************************************/ +static res_T +parse_material_matte + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* matte, + struct solparser_material_matte_id* out_imtl) +{ + enum { REFLECTIVITY }; + struct solparser_material_matte* mtl = NULL; + size_t imtl = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && matte && out_imtl); + + if(matte->type != YAML_MAPPING_NODE) { + log_err(parser, matte, "expect a mapping of matte material parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the matte material */ + imtl = darray_matte_size_get(&parser->mattes); + res = darray_matte_resize(&parser->mattes, imtl + 1); + if(res != RES_OK) { + log_err(parser, matte, "could not allocate the matte material.\n"); + goto error; + } + mtl = darray_matte_data_get(&parser->mattes) + imtl; + + n = matte->data.mapping.pairs.top - matte->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, matte->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, matte->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a matte material parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { + if(mask & BIT(REFLECTIVITY)) { + log_err(parser, key, "the matte reflectivity is already defined.\n"); + res = RES_BAD_ARG; + goto error; + } + mask |= BIT(REFLECTIVITY); + res = parse_real(parser, val, 0, 1, &mtl->reflectivity); + } else { + log_err(parser, key, "unknown matte parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + } + + if(!(mask & BIT(REFLECTIVITY))) { + log_err(parser, matte, "the matte reflectivity is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + out_imtl->i = imtl; + return res; +error: + if(mtl) { + darray_matte_pop_back(&parser->mattes); + imtl = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_material_mirror + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* mirror, + struct solparser_material_mirror_id* out_imtl) +{ + enum { REFLECTIVITY, ROUGHNESS }; + struct solparser_material_mirror* mtl = NULL; + size_t imtl = SIZE_MAX; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && mirror && out_imtl); + + if(mirror->type != YAML_MAPPING_NODE) { + log_err(parser, mirror, + "expect a mapping of mirror material attributes .\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the mirror material */ + imtl = darray_mirror_size_get(&parser->mirrors); + res = darray_mirror_resize(&parser->mirrors, imtl + 1); + if(res != RES_OK) { + log_err(parser, mirror, "could not allocate the mirror material.\n"); + goto error; + } + mtl = darray_mirror_data_get(&parser->mirrors) + imtl; + + n = mirror->data.mapping.pairs.top - mirror->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, mirror->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, mirror->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a mirror material parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the "Name" of the mirror material is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { + SETUP_MASK(REFLECTIVITY, "reflectivity"); + res = parse_real(parser, val, 0, 1, &mtl->reflectivity); + } else if(!strcmp((char*)key->data.scalar.value, "roughness")) { + SETUP_MASK(ROUGHNESS, "roughness"); + res = parse_real(parser, val, 0, 1, &mtl->roughness); + } else { + log_err(parser, key, "unknown mirror attribute `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, mirror, "the mirror "Name" is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(REFLECTIVITY, "reflectivity"); + CHECK_PARAM(ROUGHNESS, "roughness"); + #undef CHECK_PARAM + +exit: + out_imtl->i = imtl; + return res; +error: + if(mtl) { + darray_mirror_pop_back(&parser->mirrors); + imtl = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_material_descriptor + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* desc, + struct solparser_material_id* out_imtl) +{ + enum { DESCRIPTOR }; + struct solparser_material* mtl = NULL; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + size_t* pimtl; + size_t imtl = SIZE_MAX; + res_T res = RES_OK; + ASSERT(doc && desc && out_imtl); + + /* Check whether or not the YAML descriptor alias an already created Solstice + * material */ + pimtl = htable_yaml2sols_find(&parser->yaml2mtls, &desc); + if(pimtl) { + imtl = *pimtl; + goto exit; + } + + /* Allocate the solstice material */ + imtl = darray_material_size_get(&parser->mtls); + res = darray_material_resize(&parser->mtls, imtl + 1); + if(res != RES_OK) { + log_err(parser, desc, "could not allocate the material descriptor.\n"); + goto error; + } + mtl = darray_material_data_get(&parser->mtls) + imtl; + + if(desc->type != YAML_MAPPING_NODE) { + log_err(parser, desc, "expect a material descriptor.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = desc->data.mapping.pairs.top - desc->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a material name.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, "the material "Name" is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "matte")) { + SETUP_MASK(DESCRIPTOR, "descriptor"); + mtl->type = SOLPARSER_MATERIAL_MATTE; + res = parse_material_matte(parser, doc, val, &mtl->data.matte); + } else if(!strcmp((char*)key->data.scalar.value, "mirror")) { + SETUP_MASK(DESCRIPTOR, "descriptor"); + mtl->type = SOLPARSER_MATERIAL_MIRROR; + res = parse_material_mirror(parser, doc, val, &mtl->data.mirror); + } else { + log_err(parser, key, "unknown material descriptor `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + if(!(mask & BIT(DESCRIPTOR))) { + log_err(parser, desc, "the material descriptor is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Cache the material */ + res = htable_yaml2sols_set(&parser->yaml2mtls, &desc, &imtl); + if(res != RES_OK) { + log_err(parser, desc, "could not register the material.\n"); + goto error; + } + +exit: + out_imtl->i = imtl; + return res; +error: + if(mtl) { + darray_material_pop_back(&parser->mtls); + imtl = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_material + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* mtl, + struct solparser_material_double_sided_id* out_imtl2) +{ + enum { FRONT, BACK }; + struct solparser_material_double_sided* mtl2 = NULL; + size_t imtl2 = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && mtl && out_imtl2); + + if(mtl->type != YAML_MAPPING_NODE) { + log_err(parser, mtl, "expect a material definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the double sided material */ + imtl2 = darray_material2_size_get(&parser->mtls2); + res = darray_material2_resize(&parser->mtls2, imtl2 + 1); + if(res != RES_OK) { + log_err(parser, mtl, "could not allocate the material.\n"); + goto error; + } + mtl2 = darray_material2_data_get(&parser->mtls2) + imtl2; + + n = mtl->data.mapping.pairs.top - mtl->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, mtl->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, mtl->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, + "expect a material descriptor or a double sided material.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the "Name" material descriptor is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "front")) { + SETUP_MASK(FRONT, "front"); + res = parse_material_descriptor(parser, doc, val, &mtl2->front); + } else if(!strcmp((char*)key->data.scalar.value, "back")) { + SETUP_MASK(BACK, "back"); + res = parse_material_descriptor(parser, doc, val, &mtl2->back); + } else { + SETUP_MASK(FRONT, "front"); + SETUP_MASK(BACK, "back"); + res = parse_material_descriptor(parser, doc, mtl, &mtl2->front); + mtl2->back = mtl2->front; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, mtl, "the "Name" material descriptor is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(FRONT, "front"); + CHECK_PARAM(BACK, "back"); + #undef CHECK_PARAM + +exit: + out_imtl2->i = imtl2; + return res; +error: + if(mtl2) { + darray_material2_pop_back(&parser->mtls2); + imtl2 = SIZE_MAX; + } + goto exit; +} + +/******************************************************************************* + * Clipping polygon + ******************************************************************************/ +static res_T +parse_clip_op + (struct solparser* parser, + const yaml_node_t* op, + enum solparser_clip_op* clip_op) +{ + res_T res = RES_OK; + ASSERT(op && clip_op); + + if(op->type != YAML_SCALAR_NODE) { + log_err(parser, op, "expect a clipping operation.\n"); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp((char*)op->data.scalar.value, "AND")) { + *clip_op = SOLPARSER_CLIP_OP_AND; + } else if(!strcmp((char*)op->data.scalar.value, "SUB")) { + *clip_op = SOLPARSER_CLIP_OP_SUB; + } else { + log_err(parser, op, "unknown clipping operation `%s'.\n", + op->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_vertices + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* vertices, + struct darray_double* coords) +{ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && vertices && coords); + + if(vertices->type != YAML_SEQUENCE_NODE) { + log_err(parser, vertices, "expect a list of vertices.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = vertices->data.sequence.items.top - vertices->data.sequence.items.start; + if(n < 3) { + log_err(parser, vertices, "expect at least 3 vertices.\n"); + res = RES_BAD_ARG; + goto error; + } + + res = darray_double_resize(coords, (size_t)n*3/*#coords per vertex*/); + if(res != RES_OK) { + log_err(parser, vertices, "could not allocate the array of vertices.\n"); + goto error; + } + + FOR_EACH(i, 0, n) { + yaml_node_t* vertex; + double* real3 = darray_double_data_get(coords) + i*3/*#coords per vertex*/; + + vertex = yaml_document_get_node(doc, vertices->data.sequence.items.start[i]); + res = parse_real3(parser, doc, vertex, -DBL_MAX, DBL_MAX, real3); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + darray_double_clear(coords); + goto exit; +} + +static res_T +parse_polyclip + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* polyclip, + struct solparser_polyclip* clip) +{ + enum { OPERATION, VERTICES }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && polyclip && clip); + + if(polyclip->type != YAML_MAPPING_NODE) { + log_err(parser, polyclip, + "expect a mapping of clipping polygon parameters.\n"); + res = RES_OK; + goto error; + } + + n = polyclip->data.mapping.pairs.top - polyclip->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, polyclip->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, polyclip->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a clipping polygon parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the clipping polygon parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "operation")) { + SETUP_MASK(OPERATION, "operation"); + res = parse_clip_op(parser, val, &clip->op); + } else if(!strcmp((char*)key->data.scalar.value, "vertices")) { + SETUP_MASK(VERTICES, "vertices"); + res = parse_vertices(parser, doc, val, &clip->vertices); + } else { + log_err(parser, key, "unknown clipping polygon parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, polyclip, \ + "the clipping polygon parameter `"Name"' is missing"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(OPERATION, "operation"); + CHECK_PARAM(VERTICES, "vertices"); + #undef CHECK_PARAM + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_clip + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* clip, + struct darray_polyclip* polyclips) +{ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && clip && polyclips); + + if(clip->type != YAML_SEQUENCE_NODE) { + log_err(parser, clip, "expect a list of clipping polygons.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = clip->data.sequence.items.top - clip->data.sequence.items.start; + + /* Allocate the clipping polygons */ + res = darray_polyclip_resize(polyclips, (size_t)n); + if(res != RES_OK) { + log_err(parser, clip, "could not allocate the list of clipping polygons.\n"); + goto error; + } + + FOR_EACH(i, 0, n) { + yaml_node_t* node; + struct solparser_polyclip* polyclip = darray_polyclip_data_get(polyclips) + i; + + node = yaml_document_get_node(doc, clip->data.sequence.items.start[i]); + res = parse_polyclip(parser, doc, node, polyclip); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Shapes + ******************************************************************************/ +static res_T +parse_cuboid + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* cuboid, + struct solparser_shape_cuboid_id* out_ishape) +{ + enum { SIZE }; + struct solparser_shape_cuboid* shape = NULL; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && cuboid && out_ishape); + + if(cuboid->type != YAML_MAPPING_NODE) { + log_err(parser, cuboid, "expect a mapping of cuboid parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a cuboid */ + ishape = darray_cuboid_size_get(&parser->cuboids); + res = darray_cuboid_resize(&parser->cuboids, ishape + 1); + if(res != RES_OK) { + log_err(parser, cuboid, "could not allocate the cuboid shape.\n"); + goto exit; + } + shape = darray_cuboid_data_get(&parser->cuboids) + ishape; + + n = cuboid->data.mapping.pairs.top - cuboid->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, cuboid->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, cuboid->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect cuboid parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + if(!strcmp((char*)key->data.scalar.value, "size")) { + if(mask & BIT(SIZE)) { + log_err(parser, key, "the cuboid size is already defined.\n"); + res = RES_BAD_ARG; + goto error; + } + mask |= BIT(SIZE); + res = parse_real3(parser, doc, val, 0, DBL_MAX, shape->size); + } else { + log_err(parser, key, "unknown cuboid parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + } + + if(!(mask & BIT(SIZE))) { + log_err(parser, cuboid, "the size of the cuboid is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_cuboid_pop_back(&parser->cuboids); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_cylinder + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* cylinder, + struct solparser_shape_cylinder_id* out_ishape) +{ + enum { HEIGHT, RADIUS, SLICES }; + struct solparser_shape_cylinder* shape = NULL; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && cylinder && out_ishape); + + if(cylinder->type != YAML_MAPPING_NODE) { + log_err(parser, cylinder, "expect a mapping of cylinder parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a cylinder */ + ishape = darray_cylinder_size_get(&parser->cylinders); + res = darray_cylinder_resize(&parser->cylinders, ishape + 1); + if(res != RES_OK) { + log_err(parser, cylinder, "could not alocate the cylinder shape.\n"); + goto exit; + } + shape = darray_cylinder_data_get(&parser->cylinders) + ishape; + + n = cylinder->data.mapping.pairs.top - cylinder->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, cylinder->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, cylinder->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect cylinder parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the cylinder parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "height")) { + SETUP_MASK(HEIGHT, "height"); + res = parse_real(parser, val, 0, DBL_MAX, &shape->height); + } else if(!strcmp((char*)key->data.scalar.value, "radius")) { + SETUP_MASK(RADIUS, "radius"); + res = parse_real(parser, val, 0, DBL_MAX, &shape->radius); + } else if(!strcmp((char*)key->data.scalar.value, "slices")) { + SETUP_MASK(SLICES, "slices"); + res = parse_integer(parser, val, 4, 4096, &shape->nslices); + } else { + log_err(parser, key, "unknown cylinder parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, cylinder, \ + "the cylinder parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(HEIGHT, "height"); + CHECK_PARAM(RADIUS, "radius"); + #undef CHECK_PARAM + +exit: + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_cylinder_pop_back(&parser->cylinders); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_imported_geometry + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* geom, + const enum solparser_shape_type type, + struct solparser_shape_imported_geometry_id* out_ishape) +{ + enum { PATH }; + struct solparser_shape_imported_geometry* shape = NULL; + size_t ishape = SIZE_MAX; + const char* name; + struct darray_impgeom* impgeoms; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && geom && out_ishape); + + switch(type) { + case SOLPARSER_SHAPE_OBJ: name = "obj"; impgeoms = &parser->objs; break; + case SOLPARSER_SHAPE_STL: name = "stl"; impgeoms = &parser->stls; break; + default: FATAL("Unreachable code.\n"); break; + } + + if(geom->type != YAML_MAPPING_NODE) { + log_err(parser, geom, "expect a mapping of %s parameters.\n", name); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate an imported geometry */ + ishape = darray_impgeom_size_get(impgeoms); + res = darray_impgeom_resize(impgeoms, ishape + 1); + if(res != RES_OK) { + log_err(parser, geom, "could not allocate the %s shape.\n", name); + goto error; + } + shape = darray_impgeom_data_get(impgeoms) + ishape; + + n = geom->data.mapping.pairs.top - geom->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, geom->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, geom->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect %s parameters.\n", name); + res = RES_BAD_ARG; + goto error; + } + if(!strcmp((char*)key->data.scalar.value, "path")) { + if(mask & BIT(PATH)) { + log_err(parser, key, "the %s path is already defined.\n", name); + res = RES_BAD_ARG; + goto error; + } + mask |= BIT(PATH); + res = parse_string(parser, val, &shape->filename); + } else { + log_err(parser, key, "unknown %s parameter `%s'.\n", + name, key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + } + + if(!(mask & BIT(PATH))) { + log_err(parser, geom, "the path of the %s geometry is missing.\n", name); + res = RES_BAD_ARG; + goto error; + } + +exit: + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_impgeom_pop_back(impgeoms); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_paraboloid + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* paraboloid, + const enum solparser_shape_type type, + struct solparser_shape_paraboloid_id* out_ishape) +{ + enum { CLIP, FOCAL }; + struct solparser_shape_paraboloid* shape = NULL; + struct darray_paraboloid* paraboloids; + const char* name; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && paraboloid && out_ishape); + + switch(type) { + case SOLPARSER_SHAPE_PARABOL: + name = "parabol"; + paraboloids = &parser->parabols; + break; + case SOLPARSER_SHAPE_PARABOLIC_CYLINDER: + name = "parabolic cylinder"; + paraboloids = &parser->parabolic_cylinders; + break; + default: FATAL("Unreachable code.\n"); break; + } + + if(paraboloid->type != YAML_MAPPING_NODE) { + log_err(parser, paraboloid, "expect a mapping of %s parameters.\n", name); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a paraboloid shape */ + ishape = darray_paraboloid_size_get(paraboloids); + res = darray_paraboloid_resize(paraboloids, ishape + 1); + if(res != RES_OK) { + log_err(parser, paraboloid, "could not allocate the %s shape.\n", name); + goto error; + } + shape = darray_paraboloid_data_get(paraboloids) + ishape; + + n = paraboloid->data.mapping.pairs.top - paraboloid->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, paraboloid->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, paraboloid->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect %s parameters.\n", name); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the %s parameter `"Name"' is already defined.\n", name); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "clip")) { + SETUP_MASK(CLIP, "clip"); + res = parse_clip(parser, doc, val, &shape->polyclips); + } else if(!strcmp((char*)key->data.scalar.value, "focal")) { + SETUP_MASK(FOCAL, "focal"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->focal); + } else { + log_err(parser, key, "unknown %s parameter `%s'.\n", + name, key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, paraboloid, \ + "the %s parameter `"Name"' is missing.\n", name); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(CLIP, "clip"); + CHECK_PARAM(FOCAL, "focal"); + #undef CHECK_PARAM + +exit: + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_paraboloid_pop_back(paraboloids); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_plane + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* plane, + struct solparser_shape_plane_id* out_ishape) +{ + enum { CLIP }; + struct solparser_shape_plane* shape = NULL; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && plane && out_ishape); + + if(plane->type != YAML_MAPPING_NODE) { + log_err(parser, plane, "expect a mapping of plane parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a plane shape */ + ishape = darray_plane_size_get(&parser->planes); + res = darray_plane_resize(&parser->planes, ishape + 1); + if(res != RES_OK) { + log_err(parser, plane, "could not allocate the plane shape.\n"); + goto error; + } + shape = darray_plane_data_get(&parser->planes) + ishape; + + n = plane->data.mapping.pairs.top - plane->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, plane->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, plane->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect plane parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + if(!strcmp((char*)key->data.scalar.value, "clip")) { + if(mask & BIT(CLIP)) { + log_err(parser, key, "the plane clipping is already defined.\n"); + res = RES_BAD_ARG; + goto error; + } + mask |= BIT(CLIP); + res = parse_clip(parser, doc, val, &shape->polyclips); + } else { + log_err(parser, key, "unknown plane parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + } + if(!(mask & BIT(CLIP))) { + log_err(parser, plane, "the plane parameter `clip' is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_plane_pop_back(&parser->planes); + ishape = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_sphere + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* sphere, + struct solparser_shape_sphere_id* out_ishape) +{ + enum { RADIUS, SLICES }; + struct solparser_shape_sphere* shape = NULL; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && sphere && out_ishape); + + if(sphere->type != YAML_MAPPING_NODE) { + log_err(parser, sphere, "expect a mapping of sphere parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate a shpere shape */ + ishape = darray_sphere_size_get(&parser->spheres); + res = darray_sphere_resize(&parser->spheres, ishape + 1); + if(res != RES_OK) { + log_err(parser, sphere, "could not allocate the sphere shape.\n"); + goto error; + } + shape = darray_sphere_data_get(&parser->spheres) + ishape; + + n = sphere->data.mapping.pairs.top - sphere->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, sphere->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, sphere->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect sphere parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the sphere parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "radius")) { + SETUP_MASK(RADIUS, "radius"); + res = parse_real(parser, val, 0, DBL_MAX, &shape->radius); + } else if(!strcmp((char*)key->data.scalar.value, "slices")) { + SETUP_MASK(SLICES, "slices"); + res = parse_integer(parser, val, 4, 4096, &shape->nslices); + } else { + log_err(parser, key, "unknown sphere parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + if(!(mask & BIT(RADIUS))) { + log_err(parser, sphere, "the sphere radius is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + out_ishape->i = ishape; + return res; +error: + if(shape) { + darray_sphere_pop_back(&parser->spheres); + ishape = SIZE_MAX; + } + goto exit; +} + +/******************************************************************************* + * Geometry + ******************************************************************************/ +static res_T +parse_object + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* object, + struct solparser_object_id* out_iobj) +{ + enum { MATERIAL, SHAPE, TRANSFORM }; + struct solparser_object* obj = NULL; + struct solparser_shape* shape = NULL; + size_t iobj = SIZE_MAX; + size_t ishape = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && object && out_iobj); + + if(object->type != YAML_MAPPING_NODE) { + log_err(parser, object, "expect an object definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate an object */ + iobj = darray_object_size_get(&parser->objects); + res = darray_object_resize(&parser->objects, iobj + 1); + if(res != RES_OK) { + log_err(parser, object, "could not allocate the object.\n"); + goto error; + } + obj = darray_object_data_get(&parser->objects) + iobj; + + /* Allocate a shape */ + ishape = darray_shape_size_get(&parser->shapes); + res = darray_shape_resize(&parser->shapes, ishape + 1); + if(res != RES_OK) { + log_err(parser, object, "could not allocate the object shape.\n"); + goto error; + } + shape = darray_shape_data_get(&parser->shapes) + ishape; + obj->shape.i = ishape; + + /* Setup default object transformation */ + d3_splat(obj->translation, 0); + d3_splat(obj->rotation, 0); + + n = object->data.mapping.pairs.top - object->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, object->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, object->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect an object parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the object "Name" is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "material")) { + SETUP_MASK(MATERIAL, "material"); + res = parse_material(parser, doc, val, &obj->mtl2); + } else if(!strcmp((char*)key->data.scalar.value, "cuboid")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_CUBOID; + res = parse_cuboid(parser, doc, val, &shape->data.cuboid); + } else if(!strcmp((char*)key->data.scalar.value, "cylinder")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_CYLINDER; + res = parse_cylinder(parser, doc, val, &shape->data.cylinder); + } else if(!strcmp((char*)key->data.scalar.value, "obj")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_OBJ; + res = parse_imported_geometry + (parser, doc, val, shape->type, &shape->data.obj); + } else if(!strcmp((char*)key->data.scalar.value, "parabol")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_PARABOL; + res = parse_paraboloid + (parser, doc, val, shape->type, &shape->data.parabol); + } else if(!strcmp((char*)key->data.scalar.value, "parabolic-cylinder")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_PARABOLIC_CYLINDER; + res = parse_paraboloid + (parser, doc, val, shape->type, &shape->data.parabolic_cylinder); + } else if(!strcmp((char*)key->data.scalar.value, "plane")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_PLANE; + res = parse_plane(parser, doc, val, &shape->data.plane); + } else if(!strcmp((char*)key->data.scalar.value, "sphere")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_SPHERE; + res = parse_sphere(parser, doc, val, &shape->data.sphere); + } else if(!strcmp((char*)key->data.scalar.value, "stl")) { + SETUP_MASK(SHAPE, "shape"); + shape->type = SOLPARSER_SHAPE_STL; + res = parse_imported_geometry + (parser, doc, val, shape->type, &shape->data.stl); + } else if(!strcmp((char*)key->data.scalar.value, "transform")) { + SETUP_MASK(TRANSFORM, "transform"); + res = parse_transform(parser, doc, val, obj->translation, obj->rotation); + } else { + log_err(parser, key, "unknown object parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, object, "the object "Name" is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(MATERIAL, "material"); + CHECK_PARAM(SHAPE, "shape"); + #undef CHECK_PARAM + +exit: + out_iobj->i = iobj; + return res; +error: + if(obj) { + if(shape) darray_shape_pop_back(&parser->shapes); + darray_object_pop_back(&parser->objects); + obj = NULL; + } + goto exit; +} + +static res_T +parse_geometry + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* geometry, + struct solparser_geometry_id* out_isolgeom) +{ + struct solparser_geometry* solgeom = NULL; + size_t* pisolgeom; + size_t isolgeom = SIZE_MAX; + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && geometry && out_isolgeom); + + if(geometry->type != YAML_SEQUENCE_NODE) { + log_err(parser, geometry, "expect a list of objects.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Check whether or not the YAML descriptor alias an already created Solstice + * geometry */ + pisolgeom = htable_yaml2sols_find(&parser->yaml2geoms, &geometry); + if(pisolgeom) { + isolgeom = *pisolgeom; + goto exit; + } + + /* Allocate the geometry */ + isolgeom = darray_geometry_size_get(&parser->geometries); + res = darray_geometry_resize(&parser->geometries, isolgeom + 1); + if(res != RES_OK) { + log_err(parser, geometry, "could not allocate the geometry.\n"); + goto error; + } + solgeom = darray_geometry_data_get(&parser->geometries) + isolgeom; + + n = geometry->data.sequence.items.top - geometry->data.sequence.items.start; + res = darray_object_id_resize(&solgeom->objects, (size_t)n); + if(res != RES_OK) { + log_err(parser, geometry, "could not allocate the objects list.\n"); + goto error; + } + + FOR_EACH(i, 0, n) { + struct solparser_object_id* obj_id; + yaml_node_t* obj; + + obj_id = darray_object_id_data_get(&solgeom->objects) + i; + obj = yaml_document_get_node(doc, geometry->data.sequence.items.start[i]); + res = parse_object(parser, doc, obj, obj_id); + if(res != RES_OK) goto error; + } + + /* Cache the geometry */ + res = htable_yaml2sols_set(&parser->yaml2geoms, &geometry, &isolgeom); + if(res != RES_OK) { + log_err(parser, geometry, "could not register the geometry.\n"); + goto error; + } + +exit: + out_isolgeom->i = isolgeom; + return res; +error: + if(solgeom) { + darray_geometry_pop_back(&parser->geometries); + isolgeom = SIZE_MAX; + } + goto exit; +} + + +/******************************************************************************* + * Entity + ******************************************************************************/ +static res_T +entity_register_name + (struct solparser* parser, + const yaml_node_t* entity, + struct htable_str2sols* htable, + const size_t isolent) +{ + struct solparser_entity* solent; + size_t* pisolent; + res_T res = RES_OK; + ASSERT(parser && htable); + ASSERT(isolent < darray_entity_size_get(&parser->entities)); + + solent = darray_entity_data_get(&parser->entities) + isolent; + + pisolent = htable_str2sols_find(htable, &solent->name); + if(pisolent) { + log_err(parser, entity, + "an entity with the name `%s' is already defined in the current context.\n", + str_cget(&solent->name)); + return RES_BAD_ARG; + } + + res = htable_str2sols_set(htable, &solent->name, &isolent); + if(res != RES_OK) { + log_err(parser, entity, "could not register the entity.\n"); + return res; + } + return RES_OK; +} + +static res_T +anchor_register_name + (struct solparser* parser, + const yaml_node_t* anchor, + struct htable_str2sols* htable, + const size_t isolanchor) +{ + struct solparser_anchor* solanchor; + size_t* pisolanchor; + res_T res = RES_OK; + ASSERT(parser && htable); + ASSERT(isolanchor < darray_anchor_size_get(&parser->anchors)); + + solanchor = darray_anchor_data_get(&parser->anchors) + isolanchor; + + pisolanchor = htable_str2sols_find(htable, &solanchor->name); + if(pisolanchor) { + log_err(parser, anchor, + "an anchor with the name `%s' is already defined in the cunrrent context.\n", + str_cget(&solanchor->name)); + return RES_BAD_ARG; + } + + res = htable_str2sols_set(htable, &solanchor->name, &isolanchor); + if(res != RES_OK) { + log_err(parser, anchor, "could not register the anchor.\n"); + return res; + } + return RES_OK; +} + +static res_T +parse_identifier_string + (struct solparser* parser, + yaml_node_t* name, + struct str* str) +{ + res_T res = RES_OK; + ASSERT(parser && name && str); + + res = parse_string(parser, name, str); + if(res != RES_OK) goto error; + + if(strchr(str_cget(str), '.')) { + log_err(parser, name, "invalid character `.' in the name `%s'.\n", + str_cget(str)); + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_anchor + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* anchor, + struct htable_str2sols* htable, + struct solparser_anchor_id* out_isolanchor) +{ + enum { NAME, POSITION }; + struct solparser_anchor* solanchor = NULL; + size_t isolanchor = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(parser && anchor && out_isolanchor); + + if(anchor->type != YAML_MAPPING_NODE) { + log_err(parser, anchor, "expect an anchor definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the anchor */ + isolanchor = darray_anchor_size_get(&parser->anchors); + res = darray_anchor_resize(&parser->anchors, isolanchor + 1); + if(res != RES_OK) { + log_err(parser, anchor, "could not allocate the anchor.\n"); + goto error; + } + solanchor = darray_anchor_data_get(&parser->anchors) + isolanchor; + + n = anchor->data.mapping.pairs.top - anchor->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, anchor->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, anchor->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect an anchor attribute.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, "the anchor "Name" is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "name")) { + SETUP_MASK(NAME, "name"); + res = parse_identifier_string(parser, val, &solanchor->name); + } else if(!strcmp((char*)key->data.scalar.value, "position")) { + SETUP_MASK(POSITION, "position"); + res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solanchor->position); + } else { + log_err(parser, key, "unknown anchor parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, anchor, "the anchor "Name" is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(NAME, "name"); + CHECK_PARAM(POSITION, "position"); + #undef CHECK_PARAM + + res = anchor_register_name(parser, anchor, htable, isolanchor); + if(res != RES_OK) goto error; + +exit: + out_isolanchor->i = isolanchor; + return res; +error: + if(solanchor) { + darray_anchor_pop_back(&parser->anchors); + isolanchor = SIZE_MAX; + } + goto exit; +} + +static res_T +parse_anchors + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* anchors, + struct htable_str2sols* htable, + struct darray_anchor_id* solanchors) +{ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(parser && anchors); + + if(anchors->type != YAML_SEQUENCE_NODE) { + log_err(parser, anchors, "expect a list of anchors.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = anchors->data.sequence.items.top - anchors->data.sequence.items.start; + res = darray_anchor_id_resize(solanchors, (size_t)n); + if(res != RES_OK) { + log_err(parser, anchors, "could not allocate the anchors list.\n"); + goto error; + } + + FOR_EACH(i, 0, n) { + struct solparser_anchor_id* anchor_id; + yaml_node_t* anchor; + + anchor_id = darray_anchor_id_data_get(solanchors)+i; + anchor = yaml_document_get_node(doc, anchors->data.sequence.items.start[i]); + res = parse_anchor(parser, doc, anchor, htable, anchor_id); + if(res != RES_OK) goto error; + } +exit: + return res; +error: + goto exit; +} + +static res_T +parse_children + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* children, + struct htable_str2sols* htable, + struct darray_child_id* entities) +{ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(parser && children && htable && entities); + + if(children->type != YAML_SEQUENCE_NODE) { + log_err(parser, children, "expect a list of entities.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = children->data.sequence.items.top - children->data.sequence.items.start; + res = darray_child_id_resize(entities, (size_t)n); + if(res != RES_OK) { + log_err(parser, children, "could not allocate the children list.\n"); + goto error; + } + + FOR_EACH(i, 0, n) { + struct solparser_entity_id* entity_id = darray_child_id_data_get(entities) + i; + yaml_node_t* child; + + child = yaml_document_get_node(doc, children->data.sequence.items.start[i]); + res = parse_entity(parser, doc, child, htable, entity_id); + if(res != RES_OK) goto error; + } + +exit: + return res; +error: + darray_child_id_clear(entities); + goto exit; +} + +res_T +parse_entity + (struct solparser* parser, + yaml_document_t* doc, + yaml_node_t* entity, + struct htable_str2sols* htable, + struct solparser_entity_id* out_isolent) +{ + enum { ANCHORS, CHILDREN, DATA, NAME, TRANSFORM }; + struct solparser_entity solent; + struct solparser_entity* psolent; + const size_t *pisolent; + size_t isolent = SIZE_MAX; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && entity && htable && out_isolent); + + solparser_entity_init(parser->allocator, &solent); + + pisolent = htable_yaml2sols_find(&parser->yaml2entities, &entity); + if(pisolent) { + isolent = *pisolent; + res = entity_register_name(parser, entity, htable, *pisolent); + if(res != RES_OK) goto error; + goto exit; + } + + if(entity->type != YAML_MAPPING_NODE) { + log_err(parser, entity, "expect an entity definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the entity but *DO NOT* retrieve a pointer onto it since the + * allocation of its children may update its memory location. Use the "on + * stack" entity `solent' instead. */ + isolent = darray_entity_size_get(&parser->entities); + res = darray_entity_resize(&parser->entities, isolent + 1); + if(res != RES_OK) { + log_err(parser, entity, "could not allocate the entity.\n"); + goto error; + } + + n = entity->data.mapping.pairs.top - entity->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, entity->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, entity->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect an entity attribute.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the entity "Name" is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "anchors")) { + SETUP_MASK(ANCHORS, "anchors"); + res = parse_anchors + (parser, doc, val, &solent.str2anchors, &solent.anchors); + } else if(!strcmp((char*)key->data.scalar.value, "children")) { + SETUP_MASK(CHILDREN, "children"); + res = parse_children + (parser, doc, val, &solent.str2children, &solent.children); + } else if(!strcmp((char*)key->data.scalar.value, "geometry")) { + SETUP_MASK(DATA, "data"); + solent.type = SOLPARSER_ENTITY_GEOMETRY; + res = parse_geometry(parser, doc, val, &solent.data.geometry); + } else if(!strcmp((char*)key->data.scalar.value, "name")) { + SETUP_MASK(NAME, "name"); + res = parse_identifier_string(parser, val, &solent.name); + } else if(!strcmp((char*)key->data.scalar.value, "pivot")) { + SETUP_MASK(DATA, "data"); + solent.type = SOLPARSER_ENTITY_PIVOT; + res = parse_pivot(parser, doc, val, &solent.data.pivot); + } else if(!strcmp((char*)key->data.scalar.value, "transform")) { + SETUP_MASK(TRANSFORM, "transform"); + res = parse_transform + (parser, doc, val, solent.translation, solent.rotation); + } else { + log_err(parser, key, "unknown entity parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + if(!(mask & BIT(DATA))) { + solent.type = SOLPARSER_ENTITY_EMPTY; + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, entity, "the entity "Name" is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(NAME, "name"); + #undef CHECK_PARAM + + psolent = darray_entity_data_get(&parser->entities) + isolent; + res = solparser_entity_copy_and_clear(psolent, &solent); + if(res != RES_OK) { + log_err(parser, entity, + "could not copy the loaded entity into the parser data structures.\n"); + goto error; + } + res = entity_register_name(parser, entity, htable, isolent); + if(res != RES_OK) goto error; + + res = htable_yaml2sols_set(&parser->yaml2entities, &entity, &isolent); + if(res != RES_OK) { + log_err(parser, entity, "could not register the entity.\n"); + goto error; + } + +exit: + solparser_entity_release(&solent); + out_isolent->i = isolent; + return res; +error: + if(isolent != SIZE_MAX) { + htable_str2sols_erase(htable, &solent.name); + darray_entity_pop_back(&parser->entities); + isolent = SIZE_MAX; + } + goto exit; +} + +/******************************************************************************* + * Pivot + ******************************************************************************/ +static res_T +parse_anchor_alias + (struct solparser* parser, + const yaml_node_t* alias, + struct solparser_anchor_id* out_ianchor) +{ + const struct solparser_anchor* anchor = NULL; + intptr_t ianchor = INTPTR_MAX; + res_T res = RES_OK; + ASSERT(parser && alias && out_ianchor); + + if(alias->type != YAML_SCALAR_NODE) { + log_err(parser, alias, "expect an anchor idententifier.\n"); + res = RES_BAD_ARG; + goto error; + } + + anchor = solparser_find_anchor(parser, (char*)alias->data.scalar.value); + if(!anchor) { + log_err(parser, alias, "undefined anchor `%s'.\n", + alias->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + + ianchor = anchor - darray_anchor_cdata_get(&parser->anchors); + ASSERT(ianchor >= 0); + ASSERT((size_t)ianchor < darray_anchor_size_get(&parser->anchors)); + +exit: + out_ianchor->i = (size_t)ianchor; + return res; +error: + ianchor = INTPTR_MAX; + goto exit; +} + +static res_T +parse_target + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* target, + struct solparser_pivot* pivot) +{ + enum { POLICY }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && target && pivot); + + if(target->type != YAML_MAPPING_NODE) { + log_err(parser, target, "expect a target definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = target->data.mapping.pairs.top - target->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, target->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, target->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a target parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, "the target "Name" is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "anchor")) { + SETUP_MASK(POLICY, "policy"); + pivot->target_type = SOLPARSER_TARGET_ANCHOR; + res = parse_anchor_alias(parser, val, &pivot->target.anchor); + } else if(!strcmp((char*)key->data.scalar.value, "direction")) { + SETUP_MASK(POLICY, "policy"); + pivot->target_type = SOLPARSER_TARGET_DIRECTION; + res = parse_real3 + (parser, doc, val, -DBL_MAX, DBL_MAX, pivot->target.direction); + } else if(!strcmp((char*)key->data.scalar.value, "position")) { + SETUP_MASK(POLICY, "policy"); + pivot->target_type = SOLPARSER_TARGET_POSITION; + res = parse_real3 + (parser, doc, val, -DBL_MAX, DBL_MAX, pivot->target.position); + } else if(!strcmp((char*)key->data.scalar.value, "sun")) { + /* There is only one sun per YAML file. It is thus sufficient to define + * the target_type to SOLPARSER_TARGET_SUN to indentify which data is + * targeted, i.e. it is not necessary to store the identifier of the sun + * to target */ + struct solparser_sun* sun; + SETUP_MASK(POLICY, "policy"); + pivot->target_type = SOLPARSER_TARGET_SUN; + res = parse_sun(parser, doc, val, &sun); + } else { + log_err(parser, key, "unknown target parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + goto error; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + if(!(mask & BIT(POLICY))) { + log_err(parser, target, "the target policy is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_pivot + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* pivot, + struct solparser_pivot_id* out_isolpivot) +{ + enum { NORMAL, POINT, TARGET, TRANSFORM }; + struct solparser_pivot* solpivot = NULL; + size_t isolpivot = SIZE_MAX; + int mask = 0; /* Register the parsed attributes */ + intptr_t i, n; + res_T res = RES_OK; + ASSERT(doc && pivot && out_isolpivot); + + if(pivot->type != YAML_MAPPING_NODE) { + log_err(parser, pivot, "expect a pivot definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + /* Allocate the solstice pivot */ + isolpivot = darray_pivot_size_get(&parser->pivots); + res = darray_pivot_resize(&parser->pivots, isolpivot + 1); + if(res != RES_OK) { + log_err(parser, pivot, "could not allocate the pivot.\n"); + res = RES_BAD_ARG; + goto error; + } + solpivot = darray_pivot_data_get(&parser->pivots) + isolpivot; + + n = pivot->data.mapping.pairs.top - pivot->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, pivot->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, pivot->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect pivot parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, \ + "the pivot parameter `"Name"' is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "point")) { + SETUP_MASK(POINT, "point"); + res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solpivot->point); + } else if(!strcmp((char*)key->data.scalar.value, "normal")) { + SETUP_MASK(NORMAL, "normal"); + res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solpivot->normal); + } else if(!strcmp((char*)key->data.scalar.value, "target")) { + SETUP_MASK(TARGET, "target"); + res = parse_target(parser, doc, val, solpivot); + } else if(!strcmp((char*)key->data.scalar.value, "transform")) { + SETUP_MASK(TRANSFORM, "transform"); + res = parse_transform + (parser, doc, val, solpivot->translation, solpivot->rotation); + } else { + log_err(parser, key, "unknown pivot parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, pivot, "the pivot parameter `"Name"' is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(POINT, "point"); + CHECK_PARAM(NORMAL, "normal"); + CHECK_PARAM(TARGET, "target"); + #undef CHECK_PARAM + +exit: + out_isolpivot->i = isolpivot; + return res; +error: + if(solpivot) { + darray_pivot_pop_back(&parser->pivots); + isolpivot = SIZE_MAX; + } + goto exit; +} + +/******************************************************************************* + * Sun + ******************************************************************************/ +static res_T +parse_buie + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* buie, + struct solparser_sun_buie* sun) +{ + enum { CSR }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && buie && sun); + + if(buie->type != YAML_MAPPING_NODE) { + log_err(parser, buie, + "expect a buie definition of the sun radial angular distribution.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = buie->data.mapping.pairs.top - buie->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, buie->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, buie->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a buie parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp((char*)key->data.scalar.value, "csr")) { + if(mask & BIT(CSR)) { + log_err(parser, key, "the buie `csr' is already defined.\n"); + res = RES_BAD_ARG; + goto error; + } + mask |= BIT(CSR); + res = parse_real(parser, val, nextafter(0, 1), nextafter(1, 0), &sun->csr); + } else { + log_err(parser, key, "unknown buie parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + } + + if(!(mask & BIT(CSR))) { + log_err(parser, buie, "the buie csr parameter is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_pillbox + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* pillbox, + struct solparser_sun_pillbox* sun) +{ + enum { APERTURE }; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && pillbox && sun); + + if(pillbox->type != YAML_MAPPING_NODE) { + log_err(parser, pillbox, + "expect a pillbox definition of the sun radial angular distribution.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = pillbox->data.mapping.pairs.top - pillbox->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, pillbox->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, pillbox->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect a pillbox parameter.\n"); + res = RES_BAD_ARG; + goto error; + } + if(!strcmp((char*)key->data.scalar.value, "aperture")) { + if(mask & BIT(APERTURE)) { + log_err(parser, key, "the pillbox `aperture' is already defined.\n"); + res = RES_BAD_ARG; + goto error; + } + mask |= BIT(APERTURE); + res = parse_real(parser, val, nextafter(0, 1), PI/2.0, &sun->aperture); + } else { + log_err(parser, pillbox, "unknown pillbox parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + } + + if(!(mask & BIT(APERTURE))) { + log_err(parser, pillbox, "the pillbox aperture parameter is missing.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + return res; +error: + goto exit; +} + +res_T +parse_sun + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* sun, + struct solparser_sun** out_solsun) +{ + enum { DNI, RADIAL_ANGULAR_DISTRIB, SPECTRUM }; + struct solparser_sun* solsun = NULL; + intptr_t i, n; + int mask = 0; /* Register the parsed attributes */ + res_T res = RES_OK; + ASSERT(doc && sun && out_solsun); + + if(sun == parser->sun_key) { + solsun = &parser->sun; + goto exit; + } else if(parser->sun_key != 0) { + log_err(parser, sun, + "a sun is already defined. Previous definition is here %lu:%lu.\n", + (unsigned long)parser->sun_key->start_mark.line+1, + (unsigned long)parser->sun_key->start_mark.column+1); + res = RES_BAD_ARG; + goto error; + } else { + solsun = &parser->sun; + parser->sun_key = sun; + solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL; + } + + if(sun->type != YAML_MAPPING_NODE) { + log_err(parser, sun, "expect a sun definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = sun->data.mapping.pairs.top - sun->data.mapping.pairs.start; + FOR_EACH(i, 0, n) { + yaml_node_t* key; + yaml_node_t* val; + + key = yaml_document_get_node(doc, sun->data.mapping.pairs.start[i].key); + val = yaml_document_get_node(doc, sun->data.mapping.pairs.start[i].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expect sun parameters.\n"); + res = RES_BAD_ARG; + goto error; + } + #define SETUP_MASK(Flag, Name) { \ + if(mask & BIT(Flag)) { \ + log_err(parser, key, "the sun "Name" is already defined.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } \ + mask |= BIT(Flag); \ + } (void)0 + if(!strcmp((char*)key->data.scalar.value, "dni")) { + SETUP_MASK(DNI, "dni"); + res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &solsun->dni); + } else if(!strcmp((char*)key->data.scalar.value, "buie")) { + SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution"); + solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_BUIE; + res = parse_buie(parser, doc, val, &solsun->radang_distrib.buie); + } else if(!strcmp((char*)key->data.scalar.value, "pillbox")) { + SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution"); + solsun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_PILLBOX; + res = parse_pillbox(parser, doc, val, &solsun->radang_distrib.pillbox); + } else if(!strcmp((char*)key->data.scalar.value, "spectrum")) { + SETUP_MASK(SPECTRUM, "spectrum"); + res = parse_spectrum(parser, doc, 0, DBL_MAX, val, &solsun->spectrum); + } else { + log_err(parser, key, "unknown sun parameter `%s'.\n", + key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + #undef SETUP_MASK + } + + #define CHECK_PARAM(Flag, Name) \ + if(!(mask & BIT(Flag))) { \ + log_err(parser, sun, "the sun "Name" is missing.\n"); \ + res = RES_BAD_ARG; \ + goto error; \ + } (void)0 + CHECK_PARAM(DNI, "dni"); + CHECK_PARAM(SPECTRUM, "spectrum"); + #undef CHECK_PARAM + +exit: + *out_solsun = solsun; + return res; +error: + if(solsun) { + solparser_sun_clear(solsun); + solsun = NULL; + parser->sun_key = 0; + } + goto exit; +} + +/******************************************************************************* + * Item + ******************************************************************************/ +static res_T +parse_item + (struct solparser* parser, + yaml_document_t* doc, + const yaml_node_t* item) +{ + yaml_node_t* key; + yaml_node_t* val; + struct solparser_material_double_sided_id mtl2; /* TODO */ + struct solparser_entity_id entity; /* TODO */ + struct solparser_geometry_id geometry; /* TODO */ + struct solparser_sun* sun; /* TODO */ + intptr_t n; + res_T res = RES_OK; + ASSERT(doc && item); + + if(item->type != YAML_MAPPING_NODE) { + log_err(parser, item, "expect an item definition.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = item->data.mapping.pairs.top - item->data.mapping.pairs.start; + if(n != 1) { + log_err(parser, item, + "expect only one \"key:value\" pair while %li are provided.\n", n); + res = RES_BAD_ARG; + goto error; + } + + key = yaml_document_get_node(doc, item->data.mapping.pairs.start[0].key); + val = yaml_document_get_node(doc, item->data.mapping.pairs.start[0].value); + if(key->type != YAML_SCALAR_NODE) { + log_err(parser, key, "expecting an item name.\n"); + res = RES_BAD_ARG; + goto error; + } + + if(!strcmp((char*)key->data.scalar.value, "material")) { + res = parse_material(parser, doc, val, &mtl2); + } else if(!strcmp((char*)key->data.scalar.value, "entity")) { + res = parse_entity(parser, doc, val, &parser->str2entities, &entity); + } else if(!strcmp((char*)key->data.scalar.value, "template")) { + /* The parsing of the template data is deferred to its explicit used in the + * definition of an entity. If the parsing of the template becomes a + * bottleneck, parse the data only once here and cache them for reuse. */ + } else if(!strcmp((char*)key->data.scalar.value, "geometry")) { + res = parse_geometry(parser, doc, val, &geometry); + } else if(!strcmp((char*)key->data.scalar.value, "sun")) { + res = parse_sun(parser, doc, val, &sun); + } else { + log_err(parser, key, "unknown item `%s'.\n", key->data.scalar.value); + res = RES_BAD_ARG; + } + if(res != RES_OK) goto error; + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +solparser_create + (struct mem_allocator* allocator, struct solparser** out_parser) +{ + struct solparser* parser = NULL; + struct mem_allocator* mem_allocator; + res_T res = RES_OK; + ASSERT(out_parser); + + mem_allocator = allocator ? allocator : &mem_default_allocator; + parser = MEM_CALLOC(mem_allocator, 1, sizeof(struct solparser)); + if(!parser) { + fprintf(stderr, "Could not allocat the Solstice parser.\n"); + res = RES_MEM_ERR; + goto error; + } + parser->allocator = mem_allocator; + ref_init(&parser->ref); + str_init(mem_allocator, &parser->stream_name); + + /* Materials */ + htable_yaml2sols_init(mem_allocator, &parser->yaml2mtls); + darray_material_init(mem_allocator, &parser->mtls); + darray_material2_init(mem_allocator, &parser->mtls2); + darray_matte_init(mem_allocator, &parser->mattes); + darray_mirror_init(mem_allocator, &parser->mirrors); + + /* Shapes */ + darray_shape_init(mem_allocator, &parser->shapes); + darray_cuboid_init(mem_allocator, &parser->cuboids); + darray_cylinder_init(mem_allocator, &parser->cylinders); + darray_impgeom_init(mem_allocator, &parser->objs); + darray_paraboloid_init(mem_allocator, &parser->parabols); + darray_paraboloid_init(mem_allocator, &parser->parabolic_cylinders); + darray_plane_init(mem_allocator, &parser->planes); + darray_sphere_init(mem_allocator, &parser->spheres); + darray_impgeom_init(mem_allocator, &parser->stls); + + /* Geometries */ + htable_yaml2sols_init(mem_allocator, &parser->yaml2geoms); + darray_object_init(mem_allocator, &parser->objects); + darray_geometry_init(mem_allocator, &parser->geometries); + + /* Sun */ + solparser_sun_init(mem_allocator, &parser->sun); + + /* Entities */ + htable_yaml2sols_init(mem_allocator, &parser->yaml2entities); + htable_str2sols_init(mem_allocator, &parser->str2entities); + darray_entity_init(mem_allocator, &parser->entities); + + /* Anchors */ + darray_anchor_init(mem_allocator, &parser->anchors); + darray_pivot_init(mem_allocator, &parser->pivots); + +exit: + *out_parser = parser; + return res; +error: + if(parser) { + solparser_ref_put(parser); + parser = NULL; + } + goto exit; +} + +void +solparser_ref_get(struct solparser* parser) +{ + ASSERT(parser); + ref_get(&parser->ref); +} + +void +solparser_ref_put(struct solparser* parser) +{ + ASSERT(parser); + ref_put(&parser->ref, parser_release); +} + +res_T +solparser_setup + (struct solparser* parser, + const char* stream_name, + FILE* stream) +{ + res_T res = RES_OK; + ASSERT(parser && stream ); + + if(parser->parser_is_init) { + yaml_parser_delete(&parser->parser); + parser->parser_is_init = 0; + } + res = str_set(&parser->stream_name, stream_name ? stream_name : "<stream>"); + if(res != RES_OK) { + fprintf(stderr, "Could not register the filename.\n"); + goto error; + } + if(!yaml_parser_initialize(&parser->parser)) { + fprintf(stderr, "Could not initialise the YAML parser.\n"); + res = RES_UNKNOWN_ERR; + goto error; + } + parser->parser_is_init = 1; + yaml_parser_set_input_file(&parser->parser, stream); + +exit: + return res; +error: + str_clear(&parser->stream_name); + if(parser->parser_is_init) { + yaml_parser_delete(&parser->parser); + parser->parser_is_init = 0; + } + goto exit; +} + +res_T +solparser_load(struct solparser* parser) +{ + yaml_document_t doc; + yaml_node_t* root; + const char* filename; + intptr_t i, n; + int doc_is_init = 0; + res_T res = RES_OK; + ASSERT(parser); + + filename = str_cget(&parser->stream_name); + + parser_clear(parser); /* Clean up previously loaded data */ + + if(!parser->parser_is_init) { + res = RES_BAD_OP; + goto error; + } + + if(!yaml_parser_load(&parser->parser, &doc)) { + fprintf(stderr, "%s:%lu:%lu: %s.\n", + filename, + (unsigned long)parser->parser.problem_mark.line+1, + (unsigned long)parser->parser.problem_mark.column+1, + parser->parser.problem); + yaml_parser_delete(&parser->parser); + parser->parser_is_init = 0; + res = RES_BAD_OP; + goto error; + } + doc_is_init = 1; + + root = yaml_document_get_root_node(&doc); + if(!root) { + yaml_parser_delete(&parser->parser); + parser->parser_is_init = 0; + res = RES_BAD_OP; + goto error; + } + + if(root->type != YAML_SEQUENCE_NODE) { + log_err(parser, root, "expect a list of items.\n"); + res = RES_BAD_ARG; + goto error; + } + + n = root->data.sequence.items.top - root->data.sequence.items.start; + FOR_EACH(i, 0, n) { + yaml_node_t* item; + + item = yaml_document_get_node(&doc, root->data.sequence.items.start[i]); + res = parse_item(parser, &doc, item); + if(res != RES_OK) goto error; + } + + if(!parser->sun_key) { + log_err(parser, root, "%s: no sun definition in the document.\n"); + res = RES_BAD_ARG; + goto error; + } + +exit: + if(doc_is_init) yaml_document_delete(&doc); + return res; +error: + parser_clear(parser); + goto exit; +} + +const struct solparser_anchor* +solparser_find_anchor + (struct solparser* parser, const char* name) +{ + struct str str; + struct str str_tk; + struct htable_str2sols* htable = NULL; + struct solparser_entity* entity = NULL; + struct solparser_anchor* anchor = NULL; + char* cstr; + char* tk; + char* tk_anchor; + res_T res = RES_OK; + ASSERT(parser && name); + + str_init(parser->allocator, &str); + str_init(parser->allocator, &str_tk); + + res = str_set(&str, name); + if(res != RES_OK) { + fprintf(stderr, "%s: could not copy the input string.\n", FUNC_NAME); + goto error; + } + res = str_reserve(&str_tk, str_len(&str)); + if(res != RES_OK) { + fprintf(stderr, "%s: could not allocate the temporary token string.\n", + FUNC_NAME); + goto error; + } + + cstr = str_get(&str); + tk_anchor = strrchr(cstr, '.'); + if(!tk_anchor) goto exit; + *tk_anchor='\0'; + ++tk_anchor; + + tk = strtok(cstr, "."); + htable = &parser->str2entities; + while(tk) { + size_t* pientity; + str_set(&str_tk, tk); + pientity = htable_str2sols_find(htable, &str_tk); + if(!pientity) { + tk = NULL; + entity = NULL; + } else { + tk = strtok(NULL, "."); + entity = darray_entity_data_get(&parser->entities) + *pientity; + htable = &entity->str2children; + } + } + + if(entity) { + size_t* pianchor; + str_set(&str_tk, tk_anchor); + pianchor = htable_str2sols_find(&entity->str2anchors, &str_tk); + if(pianchor) { + anchor = darray_anchor_data_get(&parser->anchors) + *pianchor; + } + } + +exit: + str_release(&str); + str_release(&str_tk); + return anchor; +error: + anchor = NULL; + goto exit; +} + +const struct solparser_entity* +solparser_find_entity + (struct solparser* parser, const char* name) +{ + struct htable_str2sols* htable = NULL; + struct solparser_entity* entity = NULL; + struct str str; + struct str str_tk; + char* cstr; + char* tk; + res_T res = RES_OK; + ASSERT(parser && name); + + str_init(parser->allocator, &str); + str_init(parser->allocator, &str_tk); + + res = str_set(&str, name); + if(res != RES_OK) { + fprintf(stderr, "%s: could not copy the input string.\n", FUNC_NAME); + goto error; + } + res = str_reserve(&str_tk, str_len(&str)); + if(res != RES_OK) { + fprintf(stderr, "%s: could not allocate the temporary token sting.\n", + FUNC_NAME); + goto error; + } + + cstr = str_get(&str); + tk = strtok(cstr, "."); + htable = &parser->str2entities; + while(tk) { + size_t* pientity; + str_set(&str_tk, tk); + pientity = htable_str2sols_find(htable, &str_tk); + if(!pientity) { + tk = NULL; + entity = NULL; + } else { + tk = strtok(NULL, "."); + entity = darray_entity_data_get(&parser->entities) + *pientity; + htable = &entity->str2children; + } + } + +exit: + str_release(&str); + str_release(&str_tk); + return entity; +error: + entity = NULL; + goto exit; +} + +const struct solparser_anchor* +solparser_get_anchor + (const struct solparser* parser, + const struct solparser_anchor_id anchor) +{ + ASSERT(parser && anchor.i < darray_anchor_size_get(&parser->anchors)); + return darray_anchor_cdata_get(&parser->anchors) + anchor.i; +} + +const struct solparser_entity* +solparser_get_entity + (const struct solparser* parser, + const struct solparser_entity_id entity) +{ + ASSERT(parser && entity.i < darray_entity_size_get(&parser->entities)); + return darray_entity_cdata_get(&parser->entities) + entity.i; +} + +const struct solparser_geometry* +solparser_get_geometry + (const struct solparser* parser, + const struct solparser_geometry_id geom) +{ + ASSERT(parser && geom.i < darray_geometry_size_get(&parser->geometries)); + return darray_geometry_cdata_get(&parser->geometries) + geom.i; +} + +const struct solparser_material* +solparser_get_material + (const struct solparser* parser, + const struct solparser_material_id mtl) +{ + ASSERT(parser && mtl.i < darray_material_size_get(&parser->mtls)); + return darray_material_cdata_get(&parser->mtls) + mtl.i; +} + +const struct solparser_material_double_sided* +solparser_get_material_double_sided + (const struct solparser* parser, + const struct solparser_material_double_sided_id mtl2) +{ + ASSERT(parser && mtl2.i < darray_material2_size_get(&parser->mtls2)); + return darray_material2_cdata_get(&parser->mtls2) + mtl2.i; +} + +const struct solparser_material_matte* +solparser_get_material_matte + (const struct solparser* parser, + const struct solparser_material_matte_id matte) +{ + ASSERT(parser && matte.i < darray_matte_size_get(&parser->mattes)); + return darray_matte_cdata_get(&parser->mattes) + matte.i; +} + +const struct solparser_material_mirror* +solparser_get_material_mirror + (const struct solparser* parser, + const struct solparser_material_mirror_id mirror) +{ + ASSERT(parser && mirror.i < darray_mirror_size_get(&parser->mirrors)); + return darray_mirror_cdata_get(&parser->mirrors) + mirror.i; +} + +const struct solparser_object* +solparser_get_object + (const struct solparser* parser, + const struct solparser_object_id obj) +{ + ASSERT(parser && obj.i < darray_object_size_get(&parser->objects)); + return darray_object_cdata_get(&parser->objects) + obj.i; +} + +const struct solparser_pivot* +solparser_get_pivot + (const struct solparser* parser, + const struct solparser_pivot_id pivot) +{ + ASSERT(parser && pivot.i < darray_pivot_size_get(&parser->pivots)); + return darray_pivot_cdata_get(&parser->pivots) + pivot.i; +} + +const struct solparser_shape* +solparser_get_shape + (const struct solparser* parser, + const struct solparser_shape_id shape) +{ + ASSERT(parser && shape.i < darray_shape_size_get(&parser->shapes)); + return darray_shape_cdata_get(&parser->shapes) + shape.i; +} + +const struct solparser_shape_cuboid* +solparser_get_shape_cuboid + (const struct solparser* parser, + const struct solparser_shape_cuboid_id cuboid) +{ + ASSERT(parser && cuboid.i < darray_cuboid_size_get(&parser->cuboids)); + return darray_cuboid_cdata_get(&parser->cuboids) + cuboid.i; +} + +const struct solparser_shape_cylinder* +solparser_get_shape_cylinder + (const struct solparser* parser, + const struct solparser_shape_cylinder_id cylinder) +{ + ASSERT(parser && cylinder.i < darray_cylinder_size_get(&parser->cylinders)); + return darray_cylinder_cdata_get(&parser->cylinders) + cylinder.i; +} + +const struct solparser_shape_imported_geometry* +solparser_get_shape_obj + (const struct solparser* parser, + const struct solparser_shape_imported_geometry_id impgeom) +{ + ASSERT(parser && impgeom.i < darray_impgeom_size_get(&parser->objs)); + return darray_impgeom_cdata_get(&parser->objs) + impgeom.i; +} + +const struct solparser_shape_paraboloid* +solparser_get_shape_parabol + (const struct solparser* parser, + const struct solparser_shape_paraboloid_id paraboloid) +{ + ASSERT(parser && paraboloid.i < darray_paraboloid_size_get(&parser->parabols)); + return darray_paraboloid_cdata_get(&parser->parabols) + paraboloid.i; +} + +const struct solparser_shape_paraboloid* +solparser_get_shape_parabolic_cylinder + (const struct solparser* parser, + const struct solparser_shape_paraboloid_id paraboloid) +{ + ASSERT(parser); + ASSERT(paraboloid.i<darray_paraboloid_size_get(&parser->parabolic_cylinders)); + return darray_paraboloid_cdata_get(&parser->parabolic_cylinders)+paraboloid.i; +} + +const struct solparser_shape_plane* +solparser_get_shape_plane + (const struct solparser* parser, + const struct solparser_shape_plane_id plane) +{ + ASSERT(parser && plane.i < darray_plane_size_get(&parser->planes)); + return darray_plane_cdata_get(&parser->planes) + plane.i; +} + +const struct solparser_shape_sphere* +solparser_get_shape_sphere + (const struct solparser* parser, + const struct solparser_shape_sphere_id sphere) +{ + ASSERT(parser && sphere.i < darray_sphere_size_get(&parser->spheres)); + return darray_sphere_cdata_get(&parser->spheres) + sphere.i; +} + +const struct solparser_shape_imported_geometry* +solparser_get_shape_stl + (const struct solparser* parser, + const struct solparser_shape_imported_geometry_id impgeom) +{ + ASSERT(parser && impgeom.i < darray_impgeom_size_get(&parser->stls)); + return darray_impgeom_cdata_get(&parser->stls) + impgeom.i; +} + +const struct solparser_sun* +solparser_get_sun(const struct solparser* parser) +{ + ASSERT(parser && parser->sun_key); + return &parser->sun; +} + +void +solparser_entity_iterator_begin + (struct solparser* parser, + struct solparser_entity_iterator* it) +{ + ASSERT(parser && it); + htable_str2sols_begin(&parser->str2entities, &it->it__); +} + +void +solparser_entity_iterator_end + (struct solparser* parser, + struct solparser_entity_iterator* it) +{ + ASSERT(parser && it); + htable_str2sols_end(&parser->str2entities, &it->it__); +} + +void +solparser_material_iterator_begin + (struct solparser* parser, struct solparser_material_iterator* it) +{ + ASSERT(parser && it); + it->mtls__ = darray_material_cdata_get(&parser->mtls); + it->imtl__ = 0; +} + +void +solparser_material_iterator_end + (struct solparser* parser, struct solparser_material_iterator* it) +{ + ASSERT(parser && it); + it->mtls__ = darray_material_cdata_get(&parser->mtls); + it->imtl__ = darray_material_size_get(&parser->mtls); +} + +void +solparser_geometry_iterator_begin + (struct solparser* parser, struct solparser_geometry_iterator* it) +{ + ASSERT(parser && it); + it->geoms__ = darray_geometry_cdata_get(&parser->geometries); + it->igeom__ = 0; +} + +void +solparser_geometry_iterator_end + (struct solparser* parser, struct solparser_geometry_iterator* it) +{ + ASSERT(parser && it); + it->geoms__ = darray_geometry_cdata_get(&parser->geometries); + it->igeom__ = darray_geometry_size_get(&parser->geometries); +} + diff --git a/src/parser/solparser.h b/src/parser/solparser.h @@ -0,0 +1,287 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_H +#define SOLPARSER_H + +#include "solparser_entity.h" +#include <rsys/rsys.h> + +struct mem_allocator; +struct solparser; + +struct solparser_entity_iterator { + struct htable_str2sols_iterator it__; /* Internal data */ +}; + +struct solparser_material_iterator { + /* Internal data */ + const struct solparser_material* mtls__; + size_t imtl__; +}; + +struct solparser_geometry_iterator { + /* Internal data */ + const struct solparser_geometry* geoms__; + size_t igeom__; +}; + +/******************************************************************************* + * Solstice parser API. + ******************************************************************************/ +extern LOCAL_SYM res_T +solparser_create + (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ + struct solparser** parser); + +extern LOCAL_SYM void +solparser_ref_get + (struct solparser* parser); + +extern LOCAL_SYM void +solparser_ref_put + (struct solparser* parser); + +extern LOCAL_SYM res_T +solparser_setup + (struct solparser* parser, + const char* stream_name, /* May be NULL */ + FILE* stream); + +/* Return RES_BAD_OP if there is no more YAML document to parse */ +extern LOCAL_SYM res_T +solparser_load + (struct solparser* parser); + +/* Return NULL if no entity is found */ +extern LOCAL_SYM const struct solparser_anchor* +solparser_find_anchor + (struct solparser* parser, + const char* anchor_name); + +/* Return NULL if no entity is found */ +extern LOCAL_SYM const struct solparser_entity* +solparser_find_entity + (struct solparser* parser, + const char* entity_name); + +extern LOCAL_SYM const struct solparser_anchor* +solparser_get_anchor + (const struct solparser* parser, + const struct solparser_anchor_id anchor); + +extern LOCAL_SYM const struct solparser_entity* +solparser_get_entity + (const struct solparser* parser, + const struct solparser_entity_id entity); + +extern LOCAL_SYM const struct solparser_geometry* +solparser_get_geometry + (const struct solparser* parser, + const struct solparser_geometry_id geom); + +extern LOCAL_SYM const struct solparser_material* +solparser_get_material + (const struct solparser* parser, + const struct solparser_material_id mtl); + +extern LOCAL_SYM const struct solparser_material_double_sided* +solparser_get_material_double_sided + (const struct solparser* parser, + const struct solparser_material_double_sided_id mtl2); + +extern LOCAL_SYM const struct solparser_material_matte* +solparser_get_material_matte + (const struct solparser* parser, + const struct solparser_material_matte_id matte); + +extern LOCAL_SYM const struct solparser_material_mirror* +solparser_get_material_mirror + (const struct solparser* parser, + const struct solparser_material_mirror_id mirror); + +extern LOCAL_SYM const struct solparser_object* +solparser_get_object + (const struct solparser* parser, + const struct solparser_object_id obj); + +extern LOCAL_SYM const struct solparser_pivot* +solparser_get_pivot + (const struct solparser* parser, + const struct solparser_pivot_id pivot); + +extern LOCAL_SYM const struct solparser_shape* +solparser_get_shape + (const struct solparser* parser, + const struct solparser_shape_id shape); + +extern LOCAL_SYM const struct solparser_shape_cuboid* +solparser_get_shape_cuboid + (const struct solparser* parser, + const struct solparser_shape_cuboid_id cuboid); + +extern LOCAL_SYM const struct solparser_shape_cylinder* +solparser_get_shape_cylinder + (const struct solparser* parser, + const struct solparser_shape_cylinder_id cylinder); + +extern LOCAL_SYM const struct solparser_shape_imported_geometry* +solparser_get_shape_obj + (const struct solparser* parser, + const struct solparser_shape_imported_geometry_id impgeom); + +extern LOCAL_SYM const struct solparser_shape_paraboloid* +solparser_get_shape_parabol + (const struct solparser* parser, + const struct solparser_shape_paraboloid_id paraboloid); + +extern LOCAL_SYM const struct solparser_shape_paraboloid* +solparser_get_shape_parabolic_cylinder + (const struct solparser* parser, + const struct solparser_shape_paraboloid_id paraboloid); + +extern LOCAL_SYM const struct solparser_shape_plane* +solparser_get_shape_plane + (const struct solparser* parser, + const struct solparser_shape_plane_id plane); + +extern LOCAL_SYM const struct solparser_shape_sphere* +solparser_get_shape_sphere + (const struct solparser* parser, + const struct solparser_shape_sphere_id sphere); + +extern LOCAL_SYM const struct solparser_shape_imported_geometry* +solparser_get_shape_stl + (const struct solparser* parser, + const struct solparser_shape_imported_geometry_id impgeom); + +extern LOCAL_SYM const struct solparser_sun* +solparser_get_sun + (const struct solparser* parser); + +/******************************************************************************* + * Entity interator + ******************************************************************************/ +extern LOCAL_SYM void +solparser_entity_iterator_begin + (struct solparser* parser, + struct solparser_entity_iterator* it); + +extern LOCAL_SYM void +solparser_entity_iterator_end + (struct solparser* parser, + struct solparser_entity_iterator* it); + +static FINLINE void +solparser_entity_iterator_next(struct solparser_entity_iterator* it) +{ + ASSERT(it); + htable_str2sols_iterator_next(&it->it__); +} + +static FINLINE int +solparser_entity_iterator_eq + (const struct solparser_entity_iterator* a, + const struct solparser_entity_iterator* b) +{ + ASSERT(a && b); + return htable_str2sols_iterator_eq(&a->it__, &b->it__); +} + +static FINLINE struct solparser_entity_id +solparser_entity_iterator_get(struct solparser_entity_iterator* it) +{ + struct solparser_entity_id id; + ASSERT(it); + id.i = *htable_str2sols_iterator_data_get(&it->it__); + return id; +} + +/******************************************************************************* + * Material iterator + ******************************************************************************/ +extern LOCAL_SYM void +solparser_material_iterator_begin + (struct solparser* parser, + struct solparser_material_iterator* it); + +extern LOCAL_SYM void +solparser_material_iterator_end + (struct solparser* parser, + struct solparser_material_iterator* it); + +static FINLINE void +solparser_material_iterator_next(struct solparser_material_iterator* it) +{ + ASSERT(it); + ++it->imtl__; +} + +static FINLINE int +solparser_material_iterator_eq + (const struct solparser_material_iterator* a, + const struct solparser_material_iterator* b) +{ + ASSERT(a && b); + return a->mtls__ == b->mtls__ && a->imtl__ == b->imtl__; +} + +static FINLINE struct solparser_material_id +solparser_material_iterator_get(struct solparser_material_iterator* it) +{ + struct solparser_material_id id; + ASSERT(it); + id.i = it->imtl__; + return id; +} + +/******************************************************************************* + * Geometry iterator + ******************************************************************************/ +extern LOCAL_SYM void +solparser_geometry_iterator_begin + (struct solparser* parser, struct solparser_geometry_iterator* it); + +extern LOCAL_SYM void +solparser_geometry_iterator_end + (struct solparser* parser, struct solparser_geometry_iterator* it); + +static FINLINE void +solparser_geometry_iterator_next(struct solparser_geometry_iterator* it) +{ + ASSERT(it); + ++it->igeom__; +} + +static FINLINE int +solparser_geometry_iterator_eq + (const struct solparser_geometry_iterator* a, + const struct solparser_geometry_iterator* b) +{ + ASSERT(a && b); + return a->geoms__ == b->geoms__ && a->igeom__ == b->igeom__; +} + +static FINLINE struct solparser_geometry_id +solparser_geometry_iterator_get(struct solparser_geometry_iterator* it) +{ + struct solparser_geometry_id id; + ASSERT(it); + id.i = it->igeom__; + return id; +} + +#endif /* SOLPARSER_H */ + diff --git a/src/parser/solparser_entity.h b/src/parser/solparser_entity.h @@ -0,0 +1,202 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_ENTITY_H +#define SOLPARSER_ENTITY_H + +#include "solparser_geometry.h" +#include "solparser_pivot.h" +#include "solparser_shape.h" + +#include <rsys/double3.h> +#include <rsys/dynamic_array.h> +#include <rsys/hash_table.h> +#include <rsys/list.h> +#include <rsys/str.h> + +enum solparser_entity_type { + SOLPARSER_ENTITY_EMPTY, + SOLPARSER_ENTITY_GEOMETRY, + SOLPARSER_ENTITY_PIVOT +}; + +struct solparser_entity_id { size_t i; }; + +#define DARRAY_NAME child_id +#define DARRAY_DATA struct solparser_entity_id +#include <rsys/dynamic_array.h> + +#define DARRAY_NAME anchor_id +#define DARRAY_DATA struct solparser_anchor_id +#include <rsys/dynamic_array.h> + +/* Declare the hash table that map an entity name to the index of its in memory + * solstice representation. */ +#define HTABLE_NAME str2sols +#define HTABLE_KEY struct str +#define HTABLE_KEY_FUNCTOR_INIT str_init +#define HTABLE_KEY_FUNCTOR_RELEASE str_release +#define HTABLE_KEY_FUNCTOR_COPY str_copy +#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release +#define HTABLE_KEY_FUNCTOR_EQ str_eq +#define HTABLE_KEY_FUNCTOR_HASH str_hash +#define HTABLE_DATA size_t +#include <rsys/hash_table.h> + +struct solparser_entity { + double rotation[3]; + double translation[3]; + + struct str name; + + enum solparser_entity_type type; + union { + struct solparser_geometry_id geometry; + struct solparser_pivot_id pivot; + } data; + + /* Internal data. Should not be acceded directly. */ + struct htable_str2sols str2anchors; + struct htable_str2sols str2children; + struct darray_anchor_id anchors; /* List of anchors */ + struct darray_child_id children; /* List of children nodes */ +}; + +static INLINE void +solparser_entity_init + (struct mem_allocator* allocator, struct solparser_entity* entity) +{ + ASSERT(entity); + d3_splat(entity->rotation, 0); + d3_splat(entity->translation, 0); + entity->type = SOLPARSER_ENTITY_GEOMETRY; + entity->data.geometry.i = SIZE_MAX; + str_init(allocator, &entity->name); + htable_str2sols_init(allocator, &entity->str2anchors); + htable_str2sols_init(allocator, &entity->str2children); + darray_anchor_id_init(allocator, &entity->anchors); + darray_child_id_init(allocator, &entity->children); +} + +static INLINE void +solparser_entity_release(struct solparser_entity* entity) +{ + ASSERT(entity); + str_release(&entity->name); + htable_str2sols_release(&entity->str2anchors); + htable_str2sols_release(&entity->str2children); + darray_anchor_id_release(&entity->anchors); + darray_child_id_release(&entity->children); +} + +static INLINE res_T +solparser_entity_copy + (struct solparser_entity* dst, const struct solparser_entity* src) +{ + res_T res = RES_OK; + ASSERT(dst && src); + d3_set(dst->translation, src->translation); + d3_set(dst->rotation, src->rotation); + dst->type = src->type; + dst->data = src->data; + res = str_copy(&dst->name, &src->name); + if(res != RES_OK) return res; + res = htable_str2sols_copy(&dst->str2anchors, &src->str2anchors); + if(res != RES_OK) return res; + res = htable_str2sols_copy(&dst->str2children, &src->str2children); + if(res != RES_OK) return res; + res = darray_anchor_id_copy(&dst->anchors, &src->anchors); + if(res != RES_OK) return res; + res = darray_child_id_copy(&dst->children, &src->children); + if(res != RES_OK) return res; + return RES_OK; +} + +static INLINE res_T +solparser_entity_copy_and_release + (struct solparser_entity* dst, struct solparser_entity* src) +{ + res_T res = RES_OK; + ASSERT(dst && src); + d3_set(dst->translation, src->translation); + d3_set(dst->rotation, src->rotation); + dst->type = src->type; + dst->data = src->data; + res = str_copy_and_release(&dst->name, &src->name); + if(res != RES_OK) return res; + res = htable_str2sols_copy_and_release(&dst->str2anchors, &src->str2anchors); + if(res != RES_OK) return res; + res = htable_str2sols_copy_and_release(&dst->str2children, &src->str2children); + if(res != RES_OK) return res; + res = darray_anchor_id_copy_and_release(&dst->anchors, &src->anchors); + if(res != RES_OK) return res; + res = darray_child_id_copy_and_release(&dst->children, &src->children); + if(res != RES_OK) return res; + return RES_OK; +} + +static INLINE res_T +solparser_entity_copy_and_clear + (struct solparser_entity* dst, struct solparser_entity* src) +{ + res_T res = RES_OK; + ASSERT(dst && src); + d3_set(dst->translation, src->translation); + d3_set(dst->rotation, src->rotation); + dst->type = src->type; + dst->data = src->data; + res = str_copy_and_clear(&dst->name, &src->name); + if(res != RES_OK) return res; + res = htable_str2sols_copy_and_clear(&dst->str2anchors, &src->str2anchors); + if(res != RES_OK) return res; + res = htable_str2sols_copy_and_clear(&dst->str2children, &src->str2children); + if(res != RES_OK) return res; + res = darray_anchor_id_copy_and_clear(&dst->anchors, &src->anchors); + if(res != RES_OK) return res; + res = darray_child_id_copy_and_clear(&dst->children, &src->children); + if(res != RES_OK) return res; + return RES_OK; +} + +static INLINE size_t +solparser_entity_get_anchors_count(const struct solparser_entity* entity) +{ + ASSERT(entity); + return darray_anchor_id_size_get(&entity->anchors); +} + +static INLINE struct solparser_anchor_id +solparser_entity_get_anchor(const struct solparser_entity* entity, const size_t i) +{ + ASSERT(entity && i < solparser_entity_get_anchors_count(entity)); + return darray_anchor_id_cdata_get(&entity->anchors)[i]; +} + +static INLINE size_t +solparser_entity_get_children_count(const struct solparser_entity* entity) +{ + ASSERT(entity); + return darray_child_id_size_get(&entity->children); +} + +static INLINE struct solparser_entity_id +solparser_entity_get_child(const struct solparser_entity* entity, const size_t i) +{ + ASSERT(entity && i < solparser_entity_get_children_count(entity)); + return darray_child_id_cdata_get(&entity->children)[i]; +} + +#endif /* SOLPARSER_ENTITY_H */ + diff --git a/src/parser/solparser_geometry.h b/src/parser/solparser_geometry.h @@ -0,0 +1,90 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_GEOMETRY_H +#define SOLPARSER_GEOMETRY_H + +#include "solparser_material.h" +#include "solparser_shape.h" + +#include <rsys/dynamic_array.h> + +struct solparser_object { + struct solparser_material_double_sided_id mtl2; + struct solparser_shape_id shape; + double rotation[3]; + double translation[3]; +}; + +struct solparser_object_id { size_t i; }; + +#define DARRAY_NAME object_id +#define DARRAY_DATA struct solparser_object_id +#include <rsys/dynamic_array.h> + +struct solparser_geometry { + /* Internal data. Should not be acceded directly. */ + struct darray_object_id objects; +}; + +struct solparser_geometry_id { size_t i; }; + +static INLINE void +solparser_geometry_init + (struct mem_allocator* allocator, struct solparser_geometry* geom) +{ + ASSERT(geom); + darray_object_id_init(allocator, &geom->objects); +} + +static INLINE void +solparser_geometry_release(struct solparser_geometry* geom) +{ + ASSERT(geom); + darray_object_id_release(&geom->objects); +} + +static INLINE res_T +solparser_geometry_copy + (struct solparser_geometry* dst, const struct solparser_geometry* src) +{ + ASSERT(dst && src); + return darray_object_id_copy(&dst->objects, &src->objects); +} + +static INLINE res_T +solparser_geometry_copy_and_release + (struct solparser_geometry* dst, struct solparser_geometry* src) +{ + ASSERT(dst && src); + return darray_object_id_copy_and_release(&dst->objects, &src->objects); +} + +static FINLINE size_t +solparser_geometry_get_objects_count(const struct solparser_geometry* geom) +{ + ASSERT(geom); + return darray_object_id_size_get(&geom->objects); +} + +static FINLINE struct solparser_object_id +solparser_geometry_get_object + (const struct solparser_geometry* geom, const size_t i) +{ + ASSERT(geom && i < solparser_geometry_get_objects_count(geom)); + return darray_object_id_cdata_get(&geom->objects)[i]; +} + +#endif /* SOLPARSER_GEOMETRY_H */ diff --git a/src/parser/solparser_material.h b/src/parser/solparser_material.h @@ -0,0 +1,56 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_MATERIAL_H +#define SOLPARSER_MATERIAL_H + +#include <stddef.h> + +enum solparser_material_type { + SOLPARSER_MATERIAL_MATTE, + SOLPARSER_MATERIAL_MIRROR +}; + +struct solparser_material_matte { + double reflectivity; /* In [0, 1] */ +}; + +struct solparser_material_matte_id { size_t i; }; + +struct solparser_material_mirror { + double roughness; /* In [0, 1] */ + double reflectivity; /* In [0, 1] */ +}; + +struct solparser_material_mirror_id { size_t i; }; + +struct solparser_material { + enum solparser_material_type type; + union { + struct solparser_material_matte_id matte; + struct solparser_material_mirror_id mirror; + } data; +}; + +struct solparser_material_id { size_t i; }; + +struct solparser_material_double_sided { + struct solparser_material_id front; + struct solparser_material_id back; +}; + +struct solparser_material_double_sided_id { size_t i; }; + +#endif /* SOLPARSER_MATERIAL_H */ diff --git a/src/parser/solparser_pivot.h b/src/parser/solparser_pivot.h @@ -0,0 +1,84 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_PIVOT_H +#define SOLPARSER_PIVOT_H + +#include <rsys/double3.h> + +enum solparser_target_type { + SOLPARSER_TARGET_ANCHOR, + SOLPARSER_TARGET_DIRECTION, + SOLPARSER_TARGET_POSITION, + SOLPARSER_TARGET_SUN +}; + +struct solparser_anchor_id { size_t i; }; + +struct solparser_anchor { + struct str name; + double position[3]; +}; + +static INLINE void +solparser_anchor_init + (struct mem_allocator* allocator, struct solparser_anchor* anchor) +{ + ASSERT(anchor); + str_init(allocator, &anchor->name); +} + +static INLINE void +solparser_anchor_release(struct solparser_anchor* anchor) +{ + ASSERT(anchor); + str_release(&anchor->name); +} + +static INLINE res_T +solparser_anchor_copy + (struct solparser_anchor* dst, const struct solparser_anchor* src) +{ + ASSERT(dst && src); + d3_set(dst->position, src->position); + return str_copy(&dst->name, &src->name); +} + +static INLINE res_T +solparser_anchor_copy_and_release + (struct solparser_anchor* dst, struct solparser_anchor* src) +{ + ASSERT(dst && src); + d3_set(dst->position, src->position); + return str_copy_and_release(&dst->name, &src->name); +} + +struct solparser_pivot { + double point[3]; + double normal[3]; + double rotation[3]; + double translation[3]; + enum solparser_target_type target_type; + union { + double position[3]; /* World space position */ + double direction[3]; /* World space direction */ + struct solparser_anchor_id anchor; + } target; +}; + +struct solparser_pivot_id { size_t i; }; + +#endif /* SOLPARSER_PIVOT_H */ + diff --git a/src/parser/solparser_shape.h b/src/parser/solparser_shape.h @@ -0,0 +1,260 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_SHAPE_H +#define SOLPARSER_SHAPE_H + +#include "solparser_material.h" + +#include <rsys/dynamic_array_double.h> +#include <rsys/str.h> + +enum solparser_clip_op { + SOLPARSER_CLIP_OP_AND, + SOLPARSER_CLIP_OP_SUB +}; + +enum solparser_shape_type { + SOLPARSER_SHAPE_CUBOID, + SOLPARSER_SHAPE_CYLINDER, + SOLPARSER_SHAPE_OBJ, /* Imported Alias Wavefront obj */ + SOLPARSER_SHAPE_PARABOL, + SOLPARSER_SHAPE_PARABOLIC_CYLINDER, + SOLPARSER_SHAPE_PLANE, + SOLPARSER_SHAPE_SPHERE, + SOLPARSER_SHAPE_STL /* Imported STereo Lithography */ +}; + +/******************************************************************************* + * Clipping polygon + ******************************************************************************/ +struct solparser_polyclip { + enum solparser_clip_op op; + struct darray_double vertices; +}; + +static INLINE void +solparser_polyclip_init + (struct mem_allocator* allocator, + struct solparser_polyclip* polyclip) +{ + ASSERT(polyclip); + darray_double_init(allocator, &polyclip->vertices); +} + +static INLINE void +solparser_polyclip_release(struct solparser_polyclip* polyclip) +{ + ASSERT(polyclip); + darray_double_release(&polyclip->vertices); +} + +static INLINE res_T +solparser_polyclip_copy + (struct solparser_polyclip* dst, const struct solparser_polyclip* src) +{ + ASSERT(dst && src); + dst->op = src->op; + return darray_double_copy(&dst->vertices, &src->vertices); +} + +static INLINE res_T +solparser_polyclip_copy_and_release + (struct solparser_polyclip* dst, struct solparser_polyclip* src) +{ + ASSERT(dst && src); + dst->op = src->op; + return darray_double_copy_and_release(&dst->vertices, &src->vertices); +} + +/* Declare the array of clipping polygons */ +#define DARRAY_NAME polyclip +#define DARRAY_DATA struct solparser_polyclip +#define DARRAY_FUNCTOR_INIT solparser_polyclip_init +#define DARRAY_FUNCTOR_RELEASE solparser_polyclip_release +#define DARRAY_FUNCTOR_COPY solparser_polyclip_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE solparser_polyclip_copy_and_release +#include <rsys/dynamic_array.h> + +/******************************************************************************* + * Imported geometry shape + ******************************************************************************/ +struct solparser_shape_imported_geometry { + struct str filename; +}; + +static INLINE void +solparser_shape_imported_geometry_init + (struct mem_allocator* allocator, + struct solparser_shape_imported_geometry* impgeom) +{ + ASSERT(impgeom); + str_init(allocator, &impgeom->filename); +} + +static INLINE void +solparser_shape_imported_geometry_release + (struct solparser_shape_imported_geometry* impgeom) +{ + ASSERT(impgeom); + str_release(&impgeom->filename); +} + +static INLINE res_T +solparser_shape_imported_geometry_copy + (struct solparser_shape_imported_geometry* dst, + const struct solparser_shape_imported_geometry* src) +{ + ASSERT(dst && src); + return str_copy(&dst->filename, &src->filename); +} + +static INLINE res_T +solparser_shape_imported_geometry_copy_and_release + (struct solparser_shape_imported_geometry* dst, + struct solparser_shape_imported_geometry* src) +{ + ASSERT(dst && src); + return str_copy_and_release(&dst->filename, &src->filename); +} + +/******************************************************************************* + * Paraboloid shape + ******************************************************************************/ +struct solparser_shape_paraboloid { + double focal; + struct darray_polyclip polyclips; +}; + +static INLINE void +solparser_shape_paraboloid_init + (struct mem_allocator* allocator, + struct solparser_shape_paraboloid* paraboloid) +{ + ASSERT(paraboloid); + darray_polyclip_init(allocator, &paraboloid->polyclips); +} + +static INLINE void +solparser_shape_paraboloid_release(struct solparser_shape_paraboloid* paraboloid) +{ + ASSERT(paraboloid); + darray_polyclip_release(&paraboloid->polyclips); +} + +static INLINE res_T +solparser_shape_paraboloid_copy + (struct solparser_shape_paraboloid* dst, + const struct solparser_shape_paraboloid* src) +{ + ASSERT(dst && src); + dst->focal = src->focal; + return darray_polyclip_copy(&dst->polyclips, &src->polyclips); +} + +static INLINE res_T +solparser_shape_paraboloid_copy_and_release + (struct solparser_shape_paraboloid* dst, + struct solparser_shape_paraboloid* src) +{ + ASSERT(dst && src); + dst->focal = src->focal; + return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); +} + +/******************************************************************************* + * Plane shape + ******************************************************************************/ +struct solparser_shape_plane { + struct darray_polyclip polyclips; +}; + +static INLINE void +solparser_shape_plane_init + (struct mem_allocator* allocator, + struct solparser_shape_plane* plane) +{ + ASSERT(plane); + darray_polyclip_init(allocator, &plane->polyclips); +} + +static INLINE void +solparser_shape_plane_release(struct solparser_shape_plane* plane) +{ + ASSERT(plane); + darray_polyclip_release(&plane->polyclips); +} + +static INLINE res_T +solparser_shape_plane_copy + (struct solparser_shape_plane* dst, + const struct solparser_shape_plane* src) +{ + ASSERT(dst && src); + return darray_polyclip_copy(&dst->polyclips, &src->polyclips); +} + +static INLINE res_T +solparser_shape_plane_copy_and_release + (struct solparser_shape_plane* dst, + struct solparser_shape_plane* src) +{ + ASSERT(dst && src); + return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); +} + +/******************************************************************************* + * POD shape data + ******************************************************************************/ +struct solparser_shape_cuboid { + double size[3]; /* Size along the X, Y and Z dimension */ +}; + +struct solparser_shape_cylinder { + double height; + double radius; + long nslices; +}; + +struct solparser_shape_sphere { + double radius; + long nslices; +}; + +struct solparser_shape_cuboid_id { size_t i; }; +struct solparser_shape_cylinder_id { size_t i; }; +struct solparser_shape_imported_geometry_id { size_t i; }; +struct solparser_shape_paraboloid_id { size_t i; }; +struct solparser_shape_plane_id { size_t i; }; +struct solparser_shape_sphere_id { size_t i; }; + +struct solparser_shape { + enum solparser_shape_type type; + union { + struct solparser_shape_cuboid_id cuboid; + struct solparser_shape_cylinder_id cylinder; + struct solparser_shape_imported_geometry_id obj; + struct solparser_shape_paraboloid_id parabol; + struct solparser_shape_paraboloid_id parabolic_cylinder; + struct solparser_shape_plane_id plane; + struct solparser_shape_sphere_id sphere; + struct solparser_shape_imported_geometry_id stl; + } data; +}; + +struct solparser_shape_id { size_t i; }; + +#endif /* SOLPARSER_SHAPE_H */ + diff --git a/src/parser/solparser_sun.h b/src/parser/solparser_sun.h @@ -0,0 +1,88 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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/>. */ + +#ifndef SOLPARSER_SUN_H +#define SOLPARSER_SUN_H + +#include <rsys/dynamic_array.h> + +enum solparser_sun_radang_distrib_type { /* Radial Angular distribution */ + SOLPARSER_SUN_RADANG_DISTRIB_BUIE, + SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL, + SOLPARSER_SUN_RADANG_DISTRIB_PILLBOX +}; + +struct solparser_spectrum_data { + double wavelength; + double data; +}; + +#define DARRAY_NAME spectrum_data +#define DARRAY_DATA struct solparser_spectrum_data +#include <rsys/dynamic_array.h> + +struct solparser_sun_buie { double csr; }; +struct solparser_sun_pillbox { double aperture; }; + +struct solparser_sun { + double dni; /* In ]0, INF) */ + struct darray_spectrum_data spectrum; + enum solparser_sun_radang_distrib_type radang_distrib_type; + union { + struct solparser_sun_buie buie; + struct solparser_sun_pillbox pillbox; + } radang_distrib; +}; + +static INLINE void +solparser_sun_init(struct mem_allocator* allocator, struct solparser_sun* sun) +{ + ASSERT(sun); + sun->dni = 1.0; + sun->radang_distrib_type = SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL; + darray_spectrum_data_init(allocator, &sun->spectrum); +} + +static INLINE void +solparser_sun_release(struct solparser_sun* sun) +{ + ASSERT(sun); + darray_spectrum_data_release(&sun->spectrum); +} + +static INLINE res_T +solparser_sun_copy(struct solparser_sun* dst, const struct solparser_sun* src) +{ + ASSERT(dst && src); + return darray_spectrum_data_copy(&dst->spectrum, &src->spectrum); +} + +static INLINE res_T +solparser_sun_copy_and_release + (struct solparser_sun* dst, struct solparser_sun* src) +{ + ASSERT(dst && src); + return darray_spectrum_data_copy_and_release(&dst->spectrum, &src->spectrum); +} + +static INLINE void +solparser_sun_clear(struct solparser_sun* sun) +{ + ASSERT(sun); + darray_spectrum_data_clear(&sun->spectrum); +} + +#endif /* SOLPARSER_SUN_H */ + diff --git a/src/parser/solstice_entity.h b/src/parser/solstice_entity.h @@ -1,202 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_ENTITY_H -#define SOLSTICE_ENTITY_H - -#include "solstice_geometry.h" -#include "solstice_pivot.h" -#include "solstice_shape.h" - -#include <rsys/double3.h> -#include <rsys/dynamic_array.h> -#include <rsys/hash_table.h> -#include <rsys/list.h> -#include <rsys/str.h> - -enum solstice_entity_type { - SOLSTICE_ENTITY_EMPTY, - SOLSTICE_ENTITY_GEOMETRY, - SOLSTICE_ENTITY_PIVOT -}; - -struct solstice_entity_id { size_t i; }; - -#define DARRAY_NAME child_id -#define DARRAY_DATA struct solstice_entity_id -#include <rsys/dynamic_array.h> - -#define DARRAY_NAME anchor_id -#define DARRAY_DATA struct solstice_anchor_id -#include <rsys/dynamic_array.h> - -/* Declare the hash table that map an entity name to the index of its in memory - * solstice representation. */ -#define HTABLE_NAME str2sols -#define HTABLE_KEY struct str -#define HTABLE_KEY_FUNCTOR_INIT str_init -#define HTABLE_KEY_FUNCTOR_RELEASE str_release -#define HTABLE_KEY_FUNCTOR_COPY str_copy -#define HTABLE_KEY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release -#define HTABLE_KEY_FUNCTOR_EQ str_eq -#define HTABLE_KEY_FUNCTOR_HASH str_hash -#define HTABLE_DATA size_t -#include <rsys/hash_table.h> - -struct solstice_entity { - double rotation[3]; - double translation[3]; - - struct str name; - - enum solstice_entity_type type; - union { - struct solstice_geometry_id geometry; - struct solstice_pivot_id pivot; - } data; - - /* Internal data. Should not be acceded directly. */ - struct htable_str2sols str2anchors; - struct htable_str2sols str2children; - struct darray_anchor_id anchors; /* List of anchors */ - struct darray_child_id children; /* List of children nodes */ -}; - -static INLINE void -solstice_entity_init - (struct mem_allocator* allocator, struct solstice_entity* entity) -{ - ASSERT(entity); - d3_splat(entity->rotation, 0); - d3_splat(entity->translation, 0); - entity->type = SOLSTICE_ENTITY_GEOMETRY; - entity->data.geometry.i = SIZE_MAX; - str_init(allocator, &entity->name); - htable_str2sols_init(allocator, &entity->str2anchors); - htable_str2sols_init(allocator, &entity->str2children); - darray_anchor_id_init(allocator, &entity->anchors); - darray_child_id_init(allocator, &entity->children); -} - -static INLINE void -solstice_entity_release(struct solstice_entity* entity) -{ - ASSERT(entity); - str_release(&entity->name); - htable_str2sols_release(&entity->str2anchors); - htable_str2sols_release(&entity->str2children); - darray_anchor_id_release(&entity->anchors); - darray_child_id_release(&entity->children); -} - -static INLINE res_T -solstice_entity_copy - (struct solstice_entity* dst, const struct solstice_entity* src) -{ - res_T res = RES_OK; - ASSERT(dst && src); - d3_set(dst->translation, src->translation); - d3_set(dst->rotation, src->rotation); - dst->type = src->type; - dst->data = src->data; - res = str_copy(&dst->name, &src->name); - if(res != RES_OK) return res; - res = htable_str2sols_copy(&dst->str2anchors, &src->str2anchors); - if(res != RES_OK) return res; - res = htable_str2sols_copy(&dst->str2children, &src->str2children); - if(res != RES_OK) return res; - res = darray_anchor_id_copy(&dst->anchors, &src->anchors); - if(res != RES_OK) return res; - res = darray_child_id_copy(&dst->children, &src->children); - if(res != RES_OK) return res; - return RES_OK; -} - -static INLINE res_T -solstice_entity_copy_and_release - (struct solstice_entity* dst, struct solstice_entity* src) -{ - res_T res = RES_OK; - ASSERT(dst && src); - d3_set(dst->translation, src->translation); - d3_set(dst->rotation, src->rotation); - dst->type = src->type; - dst->data = src->data; - res = str_copy_and_release(&dst->name, &src->name); - if(res != RES_OK) return res; - res = htable_str2sols_copy_and_release(&dst->str2anchors, &src->str2anchors); - if(res != RES_OK) return res; - res = htable_str2sols_copy_and_release(&dst->str2children, &src->str2children); - if(res != RES_OK) return res; - res = darray_anchor_id_copy_and_release(&dst->anchors, &src->anchors); - if(res != RES_OK) return res; - res = darray_child_id_copy_and_release(&dst->children, &src->children); - if(res != RES_OK) return res; - return RES_OK; -} - -static INLINE res_T -solstice_entity_copy_and_clear - (struct solstice_entity* dst, struct solstice_entity* src) -{ - res_T res = RES_OK; - ASSERT(dst && src); - d3_set(dst->translation, src->translation); - d3_set(dst->rotation, src->rotation); - dst->type = src->type; - dst->data = src->data; - res = str_copy_and_clear(&dst->name, &src->name); - if(res != RES_OK) return res; - res = htable_str2sols_copy_and_clear(&dst->str2anchors, &src->str2anchors); - if(res != RES_OK) return res; - res = htable_str2sols_copy_and_clear(&dst->str2children, &src->str2children); - if(res != RES_OK) return res; - res = darray_anchor_id_copy_and_clear(&dst->anchors, &src->anchors); - if(res != RES_OK) return res; - res = darray_child_id_copy_and_clear(&dst->children, &src->children); - if(res != RES_OK) return res; - return RES_OK; -} - -static INLINE size_t -solstice_entity_get_anchors_count(const struct solstice_entity* entity) -{ - ASSERT(entity); - return darray_anchor_id_size_get(&entity->anchors); -} - -static INLINE struct solstice_anchor_id -solstice_entity_get_anchor(const struct solstice_entity* entity, const size_t i) -{ - ASSERT(entity && i < solstice_entity_get_anchors_count(entity)); - return darray_anchor_id_cdata_get(&entity->anchors)[i]; -} - -static INLINE size_t -solstice_entity_get_children_count(const struct solstice_entity* entity) -{ - ASSERT(entity); - return darray_child_id_size_get(&entity->children); -} - -static INLINE struct solstice_entity_id -solstice_entity_get_child(const struct solstice_entity* entity, const size_t i) -{ - ASSERT(entity && i < solstice_entity_get_children_count(entity)); - return darray_child_id_cdata_get(&entity->children)[i]; -} - -#endif /* SOLSTICE_ENTITY_H */ - diff --git a/src/parser/solstice_geometry.h b/src/parser/solstice_geometry.h @@ -1,90 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_GEOMETRY_H -#define SOLSTICE_GEOMETRY_H - -#include "solstice_material.h" -#include "solstice_shape.h" - -#include <rsys/dynamic_array.h> - -struct solstice_object { - struct solstice_material_double_sided_id mtl2; - struct solstice_shape_id shape; - double rotation[3]; - double translation[3]; -}; - -struct solstice_object_id { size_t i; }; - -#define DARRAY_NAME object_id -#define DARRAY_DATA struct solstice_object_id -#include <rsys/dynamic_array.h> - -struct solstice_geometry { - /* Internal data. Should not be acceded directly. */ - struct darray_object_id objects; -}; - -struct solstice_geometry_id { size_t i; }; - -static INLINE void -solstice_geometry_init - (struct mem_allocator* allocator, struct solstice_geometry* geom) -{ - ASSERT(geom); - darray_object_id_init(allocator, &geom->objects); -} - -static INLINE void -solstice_geometry_release(struct solstice_geometry* geom) -{ - ASSERT(geom); - darray_object_id_release(&geom->objects); -} - -static INLINE res_T -solstice_geometry_copy - (struct solstice_geometry* dst, const struct solstice_geometry* src) -{ - ASSERT(dst && src); - return darray_object_id_copy(&dst->objects, &src->objects); -} - -static INLINE res_T -solstice_geometry_copy_and_release - (struct solstice_geometry* dst, struct solstice_geometry* src) -{ - ASSERT(dst && src); - return darray_object_id_copy_and_release(&dst->objects, &src->objects); -} - -static FINLINE size_t -solstice_geometry_get_objects_count(const struct solstice_geometry* geom) -{ - ASSERT(geom); - return darray_object_id_size_get(&geom->objects); -} - -static FINLINE struct solstice_object_id -solstice_geometry_get_object - (const struct solstice_geometry* geom, const size_t i) -{ - ASSERT(geom && i < solstice_geometry_get_objects_count(geom)); - return darray_object_id_cdata_get(&geom->objects)[i]; -} - -#endif /* SOLSTICE_GEOMETRY_H */ diff --git a/src/parser/solstice_material.h b/src/parser/solstice_material.h @@ -1,56 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_MATERIAL_H -#define SOLSTICE_MATERIAL_H - -#include <stddef.h> - -enum solstice_material_type { - SOLSTICE_MATERIAL_MATTE, - SOLSTICE_MATERIAL_MIRROR -}; - -struct solstice_material_matte { - double reflectivity; /* In [0, 1] */ -}; - -struct solstice_material_matte_id { size_t i; }; - -struct solstice_material_mirror { - double roughness; /* In [0, 1] */ - double reflectivity; /* In [0, 1] */ -}; - -struct solstice_material_mirror_id { size_t i; }; - -struct solstice_material { - enum solstice_material_type type; - union { - struct solstice_material_matte_id matte; - struct solstice_material_mirror_id mirror; - } data; -}; - -struct solstice_material_id { size_t i; }; - -struct solstice_material_double_sided { - struct solstice_material_id front; - struct solstice_material_id back; -}; - -struct solstice_material_double_sided_id { size_t i; }; - -#endif /* SOLSTICE_MATERIAL_H */ diff --git a/src/parser/solstice_parser.c b/src/parser/solstice_parser.c @@ -1,3402 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#define _POSIX_C_SOURCE 200112L /* nextafter support */ - -#include "solstice_entity.h" -#include "solstice_material.h" -#include "solstice_parser.h" -#include "solstice_pivot.h" -#include "solstice_shape.h" -#include "solstice_sun.h" - -#include <rsys/cstr.h> -#include <rsys/double3.h> -#include <rsys/dynamic_array.h> -#include <rsys/hash_table.h> -#include <rsys/ref_count.h> -#include <rsys/str.h> - -#include <stdarg.h> -#include <stdio.h> -#include <string.h> -#include <yaml.h> - -/* Declare the array of matte materials */ -#define DARRAY_NAME matte -#define DARRAY_DATA struct solstice_material_matte -#include <rsys/dynamic_array.h> - -/* Declare the array of mirror materials */ -#define DARRAY_NAME mirror -#define DARRAY_DATA struct solstice_material_mirror -#include <rsys/dynamic_array.h> - -/* Declare the array of materials */ -#define DARRAY_NAME material -#define DARRAY_DATA struct solstice_material -#include <rsys/dynamic_array.h> - -/* Declare the array of the double sided materials */ -#define DARRAY_NAME material2 -#define DARRAY_DATA struct solstice_material_double_sided -#include <rsys/dynamic_array.h> - -/* Declare the array of the shapes */ -#define DARRAY_NAME shape -#define DARRAY_DATA struct solstice_shape -#include <rsys/dynamic_array.h> - -/* Declare the array of cuboid */ -#define DARRAY_NAME cuboid -#define DARRAY_DATA struct solstice_shape_cuboid -#include <rsys/dynamic_array.h> - -/* Declare the array of cylinder */ -#define DARRAY_NAME cylinder -#define DARRAY_DATA struct solstice_shape_cylinder -#include <rsys/dynamic_array.h> - -/* Declare the array of imported geometries */ -#define DARRAY_NAME impgeom -#define DARRAY_DATA struct solstice_shape_imported_geometry -#define DARRAY_FUNCTOR_INIT solstice_shape_imported_geometry_init -#define DARRAY_FUNCTOR_RELEASE solstice_shape_imported_geometry_release -#define DARRAY_FUNCTOR_COPY solstice_shape_imported_geometry_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ - solstice_shape_imported_geometry_copy_and_release -#include <rsys/dynamic_array.h> - -/* Declare the array of paraboloids */ -#define DARRAY_NAME paraboloid -#define DARRAY_DATA struct solstice_shape_paraboloid -#define DARRAY_FUNCTOR_INIT solstice_shape_paraboloid_init -#define DARRAY_FUNCTOR_RELEASE solstice_shape_paraboloid_release -#define DARRAY_FUNCTOR_COPY solstice_shape_paraboloid_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE \ - solstice_shape_paraboloid_copy_and_release -#include <rsys/dynamic_array.h> - -/* Declare the array of planes */ -#define DARRAY_NAME plane -#define DARRAY_DATA struct solstice_shape_plane -#define DARRAY_FUNCTOR_INIT solstice_shape_plane_init -#define DARRAY_FUNCTOR_RELEASE solstice_shape_plane_release -#define DARRAY_FUNCTOR_COPY solstice_shape_plane_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE solstice_shape_plane_copy_and_release -#include <rsys/dynamic_array.h> - -/* Declare the array of spheres */ -#define DARRAY_NAME sphere -#define DARRAY_DATA struct solstice_shape_sphere -#include <rsys/dynamic_array.h> - -/* Declare the array of objects */ -#define DARRAY_NAME object -#define DARRAY_DATA struct solstice_object -#include <rsys/dynamic_array.h> - -/* Declare the array of geometries */ -#define DARRAY_NAME geometry -#define DARRAY_DATA struct solstice_geometry -#define DARRAY_FUNCTOR_INIT solstice_geometry_init -#define DARRAY_FUNCTOR_RELEASE solstice_geometry_release -#define DARRAY_FUNCTOR_COPY solstice_geometry_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE solstice_geometry_copy_and_release -#include <rsys/dynamic_array.h> - -/* Declare the array of entities */ -#define DARRAY_NAME entity -#define DARRAY_DATA struct solstice_entity -#define DARRAY_FUNCTOR_INIT solstice_entity_init -#define DARRAY_FUNCTOR_RELEASE solstice_entity_release -#define DARRAY_FUNCTOR_COPY solstice_entity_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE solstice_entity_copy_and_release -#include <rsys/dynamic_array.h> - -/* Declare the array of anchors */ -#define DARRAY_NAME anchor -#define DARRAY_DATA struct solstice_anchor -#define DARRAY_FUNCTOR_INIT solstice_anchor_init -#define DARRAY_FUNCTOR_RELEASE solstice_anchor_release -#define DARRAY_FUNCTOR_COPY solstice_anchor_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE solstice_anchor_copy_and_release -#include <rsys/dynamic_array.h> - -/* Declare the array of pivots */ -#define DARRAY_NAME pivot -#define DARRAY_DATA struct solstice_pivot -#include <rsys/dynamic_array.h> - -/* Declare the hash table that maps the address of a YAML node to the id of its - * in memory representation. */ -#define HTABLE_NAME yaml2sols -#define HTABLE_KEY yaml_node_t* -#define HTABLE_DATA size_t -#include <rsys/hash_table.h> - -struct solstice_parser { - yaml_parser_t parser; - struct str stream_name; - int parser_is_init; - - /* Materia data */ - struct htable_yaml2sols yaml2mtls; /* Cache of materials */ - struct darray_material mtls; - struct darray_material2 mtls2; /* Double sided materials */ - struct darray_matte mattes; - struct darray_mirror mirrors; - - /* Shape data */ - struct darray_shape shapes; /* Generic loaded shapes */ - struct darray_cuboid cuboids; - struct darray_cylinder cylinders; - struct darray_impgeom objs; - struct darray_paraboloid parabols; - struct darray_paraboloid parabolic_cylinders; - struct darray_plane planes; - struct darray_sphere spheres; - struct darray_impgeom stls; - - /* Geometries & objects */ - struct htable_yaml2sols yaml2geoms; /* Cache of geometries */ - struct darray_object objects; - struct darray_geometry geometries; - - /* Sun. Note that only one sun is supported */ - const yaml_node_t* sun_key; /* yaml_node_t ptr used to spawn the sun */ - struct solstice_sun sun; /* The loaded sun */ - - /* Entity */ - struct htable_yaml2sols yaml2entities; /* Cache of entities */ - struct htable_str2sols str2entities; - struct darray_entity entities; - - /* Miscellaneous */ - struct darray_anchor anchors; - struct darray_pivot pivots; - - ref_T ref; - struct mem_allocator* allocator; -}; - -static res_T -parse_entity - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* entity, - struct htable_str2sols* htable, - struct solstice_entity_id* solent); - -static res_T -parse_geometry - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* geometry, - struct solstice_geometry_id* solgeom); - -static res_T -parse_pivot - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* pivot, - struct solstice_pivot_id* out_isolpivot); - -static res_T -parse_sun - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* sun, - struct solstice_sun** solsun); - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static INLINE void -log_err - (const struct solstice_parser* parser, - const yaml_node_t* node, - const char* fmt, - ...) -{ - va_list vargs_list; - ASSERT(parser && node && fmt); - - fprintf(stderr, "%s:%lu:%lu: ", - str_cget(&parser->stream_name), - (unsigned long)node->start_mark.line+1, - (unsigned long)node->start_mark.column+1); - va_start(vargs_list, fmt); - vfprintf(stderr, fmt, vargs_list); - va_end(vargs_list); -} - -/* Clean up loaded data */ -static INLINE void -parser_clear(struct solstice_parser* parser) -{ - ASSERT(parser); - - /* Materials */ - htable_yaml2sols_clear(&parser->yaml2mtls); - darray_material_clear(&parser->mtls); - darray_material2_clear(&parser->mtls2); - darray_matte_clear(&parser->mattes); - darray_mirror_clear(&parser->mirrors); - - /* Shapes */ - darray_shape_clear(&parser->shapes); - darray_cuboid_clear(&parser->cuboids); - darray_cylinder_clear(&parser->cylinders); - darray_impgeom_clear(&parser->objs); - darray_paraboloid_clear(&parser->parabols); - darray_paraboloid_clear(&parser->parabolic_cylinders); - darray_plane_clear(&parser->planes); - darray_sphere_clear(&parser->spheres); - darray_impgeom_clear(&parser->stls); - - /* Geometries */ - htable_yaml2sols_clear(&parser->yaml2geoms); - darray_object_clear(&parser->objects); - darray_geometry_clear(&parser->geometries); - - /* Sun */ - solstice_sun_clear(&parser->sun); - parser->sun_key = 0; - - /* Entities */ - htable_yaml2sols_clear(&parser->yaml2entities); - htable_str2sols_clear(&parser->str2entities); - darray_entity_clear(&parser->entities); - - /* Miscellaneous */ - darray_anchor_clear(&parser->anchors); - darray_pivot_clear(&parser->pivots); -} - -static void -parser_release(ref_T* ref) -{ - struct solstice_parser* parser; - ASSERT(ref); - - parser = CONTAINER_OF(ref, struct solstice_parser, ref); - if(parser->parser_is_init) yaml_parser_delete(&parser->parser); - str_release(&parser->stream_name); - - /* Materials */ - htable_yaml2sols_release(&parser->yaml2mtls); - darray_material_release(&parser->mtls); - darray_material2_release(&parser->mtls2); - darray_matte_release(&parser->mattes); - darray_mirror_release(&parser->mirrors); - - /* Shapes */ - darray_shape_release(&parser->shapes); - darray_cuboid_release(&parser->cuboids); - darray_cylinder_release(&parser->cylinders); - darray_impgeom_release(&parser->objs); - darray_paraboloid_release(&parser->parabols); - darray_paraboloid_release(&parser->parabolic_cylinders); - darray_plane_release(&parser->planes); - darray_sphere_release(&parser->spheres); - darray_impgeom_release(&parser->stls); - - /* Geometries */ - htable_yaml2sols_release(&parser->yaml2geoms); - darray_object_release(&parser->objects); - darray_geometry_release(&parser->geometries); - - /* Sun */ - solstice_sun_release(&parser->sun); - - /* Entities */ - htable_yaml2sols_release(&parser->yaml2entities); - htable_str2sols_release(&parser->str2entities); - darray_entity_release(&parser->entities); - - /* Miscellaneous */ - darray_anchor_release(&parser->anchors); - darray_pivot_release(&parser->pivots); - - MEM_RM(parser->allocator, parser); -} - -/******************************************************************************* - * Miscellaneous parsing functions - ******************************************************************************/ -static res_T -parse_real - (struct solstice_parser* parser, - const yaml_node_t* real, - const double lower_bound, - const double upper_bound, - double* dst) -{ - res_T res = RES_OK; - ASSERT(real && dst && lower_bound < upper_bound); - - if(real->type != YAML_SCALAR_NODE - || !strlen((char*)real->data.scalar.value)) { - log_err(parser, real, "expect a floating point number.\n"); - res = RES_BAD_ARG; - goto error; - } - - res = cstr_to_double((char*)real->data.scalar.value, dst); - if(res != RES_OK) { - log_err(parser, real, "invalid floating point number `%s'.\n", - real->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - - if(*dst < lower_bound || *dst > upper_bound) { - log_err(parser, real, "%g is not in [%g, %g].\n", - *dst, lower_bound, upper_bound); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_real3 - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* real3, - const double lower_bound, - const double upper_bound, - double dst[3]) -{ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && real3 && dst); - - if(real3->type != YAML_SEQUENCE_NODE) { - log_err(parser, real3, "expect a sequence of 3 reals.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = real3->data.sequence.items.top - real3->data.sequence.items.start; - if(n != 3) { - log_err(parser, real3, "expect 3 reals while `%li' %s submitted.\n", - n, n > 1 ? "are" : "is"); - res = RES_BAD_ARG; - goto error; - } - - FOR_EACH(i, 0, n) { - yaml_node_t* real; - real = yaml_document_get_node(doc, real3->data.sequence.items.start[i]); - res = parse_real(parser, real, lower_bound, upper_bound, dst + i); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_integer - (struct solstice_parser* parser, - yaml_node_t* integer, - const long lower_bound, - const long upper_bound, - long* dst) -{ - res_T res = RES_OK; - ASSERT(integer && dst && lower_bound < upper_bound); - - if(integer->type != YAML_SCALAR_NODE - || !strlen((char*)integer->data.scalar.value)) { - log_err(parser, integer, "expect an integer.\n"); - res = RES_BAD_ARG; - goto error; - } - - res = cstr_to_long((char*)integer->data.scalar.value, dst); - if(res != RES_OK) { - log_err(parser, integer, "invalid integer `%s'.\n", - integer->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - - if(*dst < lower_bound || *dst > upper_bound) { - log_err(parser, integer, "%li is not in [%li, %li].\n", - *dst, lower_bound, upper_bound); - res = RES_BAD_ARG; - goto error; - } -exit: - return res; -error: - goto exit; -} - -static res_T -parse_string - (struct solstice_parser* parser, - yaml_node_t* string, - struct str* str) -{ - res_T res = RES_OK; - ASSERT(string && str); - - if(string->type != YAML_SCALAR_NODE - || !strlen((char*)string->data.scalar.value)) { - log_err(parser, string, "expect a character string.\n"); - res = RES_BAD_ARG; - goto error; - } - res = str_set(str, (char*)string->data.scalar.value); - if(res != RES_OK) { - log_err(parser, string, "could not register the string `%s'.\n", - string->data.scalar.value); - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_transform - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* transform, - double translation[3], - double rotation[3]) -{ - enum { ROTATION, TRANSLATION }; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && translation && rotation && transform); - - d3_splat(translation, 0); - d3_splat(rotation, 0); - - if(transform->type != YAML_MAPPING_NODE) { - log_err(parser, transform, "expect a mapping of transform parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = transform->data.mapping.pairs.top - transform->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, transform->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, transform->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect transform parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, "the transform `"Name"' is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "translation")) { - SETUP_MASK(TRANSLATION, "translation"); - res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, translation); - } else if(!strcmp((char*)key->data.scalar.value, "rotation")) { - SETUP_MASK(ROTATION, "rotation"); - res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, rotation); - } else { - log_err(parser, key, "unknown transform parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } -exit: - return res; -error: - goto exit; -} - -static res_T -parse_spectrum_data - (struct solstice_parser* parser, - yaml_document_t* doc, - const double lower_bound, - const double upper_bound, - const yaml_node_t* sdata, - struct solstice_spectrum_data* spectrum_data) -{ - enum { DATA, WAVELENGTH }; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && sdata && lower_bound < upper_bound && spectrum_data); - - if(sdata->type != YAML_MAPPING_NODE) { - log_err(parser, sdata, "expect the definition of a spectrum data.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = sdata->data.mapping.pairs.top - sdata->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, sdata->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, sdata->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a spectrum data parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the `"Name"' of the spectrum data is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "data")) { - SETUP_MASK(DATA, "data"); - res = parse_real(parser, val, lower_bound, upper_bound, &spectrum_data->data); - } else if(!strcmp((char*)key->data.scalar.value, "wavelength")) { - SETUP_MASK(WAVELENGTH, "wavelength"); - res = parse_real(parser, val, 0, DBL_MAX, &spectrum_data->wavelength); - } else { - log_err(parser, key, "unknown spectrum data parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, sdata,"the "Name" of the spectrum data is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(DATA, "data"); - CHECK_PARAM(WAVELENGTH, "wavelength"); - #undef CHECK_PARAM - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_spectrum - (struct solstice_parser* parser, - yaml_document_t* doc, - const double lower_bound, - const double upper_bound, - const yaml_node_t* spectrum, - struct darray_spectrum_data* data) -{ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && spectrum && lower_bound < upper_bound && data); - - if(spectrum->type != YAML_SEQUENCE_NODE) { - log_err(parser, spectrum, "expect a list of spectrum data.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = spectrum->data.sequence.items.top - spectrum->data.sequence.items.start; - res = darray_spectrum_data_resize(data, (size_t)n); - if(res != RES_OK) { - log_err(parser, spectrum, "could not allocate the list of spectrum data.\n"); - goto error; - } - - FOR_EACH(i, 0, n) { - yaml_node_t* sdata; - struct solstice_spectrum_data* spectrum_data; - - sdata = yaml_document_get_node(doc, spectrum->data.sequence.items.start[i]); - spectrum_data = darray_spectrum_data_data_get(data) + i; - res = parse_spectrum_data - (parser, doc, lower_bound, upper_bound, sdata, spectrum_data); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - darray_spectrum_data_clear(data); - goto exit; -} - -/******************************************************************************* - * Material - ******************************************************************************/ -static res_T -parse_material_matte - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* matte, - struct solstice_material_matte_id* out_imtl) -{ - enum { REFLECTIVITY }; - struct solstice_material_matte* mtl = NULL; - size_t imtl = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && matte && out_imtl); - - if(matte->type != YAML_MAPPING_NODE) { - log_err(parser, matte, "expect a mapping of matte material parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the matte material */ - imtl = darray_matte_size_get(&parser->mattes); - res = darray_matte_resize(&parser->mattes, imtl + 1); - if(res != RES_OK) { - log_err(parser, matte, "could not allocate the matte material.\n"); - goto error; - } - mtl = darray_matte_data_get(&parser->mattes) + imtl; - - n = matte->data.mapping.pairs.top - matte->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, matte->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, matte->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a matte material parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { - if(mask & BIT(REFLECTIVITY)) { - log_err(parser, key, "the matte reflectivity is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(REFLECTIVITY); - res = parse_real(parser, val, 0, 1, &mtl->reflectivity); - } else { - log_err(parser, key, "unknown matte parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - } - - if(!(mask & BIT(REFLECTIVITY))) { - log_err(parser, matte, "the matte reflectivity is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - out_imtl->i = imtl; - return res; -error: - if(mtl) { - darray_matte_pop_back(&parser->mattes); - imtl = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_material_mirror - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* mirror, - struct solstice_material_mirror_id* out_imtl) -{ - enum { REFLECTIVITY, ROUGHNESS }; - struct solstice_material_mirror* mtl = NULL; - size_t imtl = SIZE_MAX; - int mask = 0; /* Register the parsed attributes */ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && mirror && out_imtl); - - if(mirror->type != YAML_MAPPING_NODE) { - log_err(parser, mirror, - "expect a mapping of mirror material attributes .\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the mirror material */ - imtl = darray_mirror_size_get(&parser->mirrors); - res = darray_mirror_resize(&parser->mirrors, imtl + 1); - if(res != RES_OK) { - log_err(parser, mirror, "could not allocate the mirror material.\n"); - goto error; - } - mtl = darray_mirror_data_get(&parser->mirrors) + imtl; - - n = mirror->data.mapping.pairs.top - mirror->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, mirror->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, mirror->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a mirror material parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the "Name" of the mirror material is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "reflectivity")) { - SETUP_MASK(REFLECTIVITY, "reflectivity"); - res = parse_real(parser, val, 0, 1, &mtl->reflectivity); - } else if(!strcmp((char*)key->data.scalar.value, "roughness")) { - SETUP_MASK(ROUGHNESS, "roughness"); - res = parse_real(parser, val, 0, 1, &mtl->roughness); - } else { - log_err(parser, key, "unknown mirror attribute `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, mirror, "the mirror "Name" is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(REFLECTIVITY, "reflectivity"); - CHECK_PARAM(ROUGHNESS, "roughness"); - #undef CHECK_PARAM - -exit: - out_imtl->i = imtl; - return res; -error: - if(mtl) { - darray_mirror_pop_back(&parser->mirrors); - imtl = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_material_descriptor - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* desc, - struct solstice_material_id* out_imtl) -{ - enum { DESCRIPTOR }; - struct solstice_material* mtl = NULL; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - size_t* pimtl; - size_t imtl = SIZE_MAX; - res_T res = RES_OK; - ASSERT(doc && desc && out_imtl); - - /* Check whether or not the YAML descriptor alias an already created Solstice - * material */ - pimtl = htable_yaml2sols_find(&parser->yaml2mtls, &desc); - if(pimtl) { - imtl = *pimtl; - goto exit; - } - - /* Allocate the solstice material */ - imtl = darray_material_size_get(&parser->mtls); - res = darray_material_resize(&parser->mtls, imtl + 1); - if(res != RES_OK) { - log_err(parser, desc, "could not allocate the material descriptor.\n"); - goto error; - } - mtl = darray_material_data_get(&parser->mtls) + imtl; - - if(desc->type != YAML_MAPPING_NODE) { - log_err(parser, desc, "expect a material descriptor.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = desc->data.mapping.pairs.top - desc->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, desc->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a material name.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, "the material "Name" is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "matte")) { - SETUP_MASK(DESCRIPTOR, "descriptor"); - mtl->type = SOLSTICE_MATERIAL_MATTE; - res = parse_material_matte(parser, doc, val, &mtl->data.matte); - } else if(!strcmp((char*)key->data.scalar.value, "mirror")) { - SETUP_MASK(DESCRIPTOR, "descriptor"); - mtl->type = SOLSTICE_MATERIAL_MIRROR; - res = parse_material_mirror(parser, doc, val, &mtl->data.mirror); - } else { - log_err(parser, key, "unknown material descriptor `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - if(!(mask & BIT(DESCRIPTOR))) { - log_err(parser, desc, "the material descriptor is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Cache the material */ - res = htable_yaml2sols_set(&parser->yaml2mtls, &desc, &imtl); - if(res != RES_OK) { - log_err(parser, desc, "could not register the material.\n"); - goto error; - } - -exit: - out_imtl->i = imtl; - return res; -error: - if(mtl) { - darray_material_pop_back(&parser->mtls); - imtl = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_material - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* mtl, - struct solstice_material_double_sided_id* out_imtl2) -{ - enum { FRONT, BACK }; - struct solstice_material_double_sided* mtl2 = NULL; - size_t imtl2 = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && mtl && out_imtl2); - - if(mtl->type != YAML_MAPPING_NODE) { - log_err(parser, mtl, "expect a material definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the double sided material */ - imtl2 = darray_material2_size_get(&parser->mtls2); - res = darray_material2_resize(&parser->mtls2, imtl2 + 1); - if(res != RES_OK) { - log_err(parser, mtl, "could not allocate the material.\n"); - goto error; - } - mtl2 = darray_material2_data_get(&parser->mtls2) + imtl2; - - n = mtl->data.mapping.pairs.top - mtl->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, mtl->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, mtl->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, - "expect a material descriptor or a double sided material.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the "Name" material descriptor is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "front")) { - SETUP_MASK(FRONT, "front"); - res = parse_material_descriptor(parser, doc, val, &mtl2->front); - } else if(!strcmp((char*)key->data.scalar.value, "back")) { - SETUP_MASK(BACK, "back"); - res = parse_material_descriptor(parser, doc, val, &mtl2->back); - } else { - SETUP_MASK(FRONT, "front"); - SETUP_MASK(BACK, "back"); - res = parse_material_descriptor(parser, doc, mtl, &mtl2->front); - mtl2->back = mtl2->front; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, mtl, "the "Name" material descriptor is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(FRONT, "front"); - CHECK_PARAM(BACK, "back"); - #undef CHECK_PARAM - -exit: - out_imtl2->i = imtl2; - return res; -error: - if(mtl2) { - darray_material2_pop_back(&parser->mtls2); - imtl2 = SIZE_MAX; - } - goto exit; -} - -/******************************************************************************* - * Clipping polygon - ******************************************************************************/ -static res_T -parse_clip_op - (struct solstice_parser* parser, - const yaml_node_t* op, - enum solstice_clip_op* clip_op) -{ - res_T res = RES_OK; - ASSERT(op && clip_op); - - if(op->type != YAML_SCALAR_NODE) { - log_err(parser, op, "expect a clipping operation.\n"); - res = RES_BAD_ARG; - goto error; - } - - if(!strcmp((char*)op->data.scalar.value, "AND")) { - *clip_op = SOLSTICE_CLIP_OP_AND; - } else if(!strcmp((char*)op->data.scalar.value, "SUB")) { - *clip_op = SOLSTICE_CLIP_OP_SUB; - } else { - log_err(parser, op, "unknown clipping operation `%s'.\n", - op->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_vertices - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* vertices, - struct darray_double* coords) -{ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && vertices && coords); - - if(vertices->type != YAML_SEQUENCE_NODE) { - log_err(parser, vertices, "expect a list of vertices.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = vertices->data.sequence.items.top - vertices->data.sequence.items.start; - if(n < 3) { - log_err(parser, vertices, "expect at least 3 vertices.\n"); - res = RES_BAD_ARG; - goto error; - } - - res = darray_double_resize(coords, (size_t)n*3/*#coords per vertex*/); - if(res != RES_OK) { - log_err(parser, vertices, "could not allocate the array of vertices.\n"); - goto error; - } - - FOR_EACH(i, 0, n) { - yaml_node_t* vertex; - double* real3 = darray_double_data_get(coords) + i*3/*#coords per vertex*/; - - vertex = yaml_document_get_node(doc, vertices->data.sequence.items.start[i]); - res = parse_real3(parser, doc, vertex, -DBL_MAX, DBL_MAX, real3); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - darray_double_clear(coords); - goto exit; -} - -static res_T -parse_polyclip - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* polyclip, - struct solstice_polyclip* clip) -{ - enum { OPERATION, VERTICES }; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && polyclip && clip); - - if(polyclip->type != YAML_MAPPING_NODE) { - log_err(parser, polyclip, - "expect a mapping of clipping polygon parameters.\n"); - res = RES_OK; - goto error; - } - - n = polyclip->data.mapping.pairs.top - polyclip->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, polyclip->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, polyclip->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a clipping polygon parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the clipping polygon parameter `"Name"' is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "operation")) { - SETUP_MASK(OPERATION, "operation"); - res = parse_clip_op(parser, val, &clip->op); - } else if(!strcmp((char*)key->data.scalar.value, "vertices")) { - SETUP_MASK(VERTICES, "vertices"); - res = parse_vertices(parser, doc, val, &clip->vertices); - } else { - log_err(parser, key, "unknown clipping polygon parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, polyclip, \ - "the clipping polygon parameter `"Name"' is missing"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(OPERATION, "operation"); - CHECK_PARAM(VERTICES, "vertices"); - #undef CHECK_PARAM - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_clip - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* clip, - struct darray_polyclip* polyclips) -{ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && clip && polyclips); - - if(clip->type != YAML_SEQUENCE_NODE) { - log_err(parser, clip, "expect a list of clipping polygons.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = clip->data.sequence.items.top - clip->data.sequence.items.start; - - /* Allocate the clipping polygons */ - res = darray_polyclip_resize(polyclips, (size_t)n); - if(res != RES_OK) { - log_err(parser, clip, "could not allocate the list of clipping polygons.\n"); - goto error; - } - - FOR_EACH(i, 0, n) { - yaml_node_t* node; - struct solstice_polyclip* polyclip = darray_polyclip_data_get(polyclips) + i; - - node = yaml_document_get_node(doc, clip->data.sequence.items.start[i]); - res = parse_polyclip(parser, doc, node, polyclip); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - goto exit; -} - -/******************************************************************************* - * Shapes - ******************************************************************************/ -static res_T -parse_cuboid - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* cuboid, - struct solstice_shape_cuboid_id* out_ishape) -{ - enum { SIZE }; - struct solstice_shape_cuboid* shape = NULL; - size_t ishape = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && cuboid && out_ishape); - - if(cuboid->type != YAML_MAPPING_NODE) { - log_err(parser, cuboid, "expect a mapping of cuboid parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate a cuboid */ - ishape = darray_cuboid_size_get(&parser->cuboids); - res = darray_cuboid_resize(&parser->cuboids, ishape + 1); - if(res != RES_OK) { - log_err(parser, cuboid, "could not allocate the cuboid shape.\n"); - goto exit; - } - shape = darray_cuboid_data_get(&parser->cuboids) + ishape; - - n = cuboid->data.mapping.pairs.top - cuboid->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, cuboid->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, cuboid->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect cuboid parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - if(!strcmp((char*)key->data.scalar.value, "size")) { - if(mask & BIT(SIZE)) { - log_err(parser, key, "the cuboid size is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(SIZE); - res = parse_real3(parser, doc, val, 0, DBL_MAX, shape->size); - } else { - log_err(parser, key, "unknown cuboid parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - } - - if(!(mask & BIT(SIZE))) { - log_err(parser, cuboid, "the size of the cuboid is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - out_ishape->i = ishape; - return res; -error: - if(shape) { - darray_cuboid_pop_back(&parser->cuboids); - ishape = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_cylinder - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* cylinder, - struct solstice_shape_cylinder_id* out_ishape) -{ - enum { HEIGHT, RADIUS, SLICES }; - struct solstice_shape_cylinder* shape = NULL; - size_t ishape = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && cylinder && out_ishape); - - if(cylinder->type != YAML_MAPPING_NODE) { - log_err(parser, cylinder, "expect a mapping of cylinder parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate a cylinder */ - ishape = darray_cylinder_size_get(&parser->cylinders); - res = darray_cylinder_resize(&parser->cylinders, ishape + 1); - if(res != RES_OK) { - log_err(parser, cylinder, "could not alocate the cylinder shape.\n"); - goto exit; - } - shape = darray_cylinder_data_get(&parser->cylinders) + ishape; - - n = cylinder->data.mapping.pairs.top - cylinder->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, cylinder->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, cylinder->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect cylinder parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the cylinder parameter `"Name"' is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "height")) { - SETUP_MASK(HEIGHT, "height"); - res = parse_real(parser, val, 0, DBL_MAX, &shape->height); - } else if(!strcmp((char*)key->data.scalar.value, "radius")) { - SETUP_MASK(RADIUS, "radius"); - res = parse_real(parser, val, 0, DBL_MAX, &shape->radius); - } else if(!strcmp((char*)key->data.scalar.value, "slices")) { - SETUP_MASK(SLICES, "slices"); - res = parse_integer(parser, val, 4, 4096, &shape->nslices); - } else { - log_err(parser, key, "unknown cylinder parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, cylinder, \ - "the cylinder parameter `"Name"' is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(HEIGHT, "height"); - CHECK_PARAM(RADIUS, "radius"); - #undef CHECK_PARAM - -exit: - out_ishape->i = ishape; - return res; -error: - if(shape) { - darray_cylinder_pop_back(&parser->cylinders); - ishape = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_imported_geometry - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* geom, - const enum solstice_shape_type type, - struct solstice_shape_imported_geometry_id* out_ishape) -{ - enum { PATH }; - struct solstice_shape_imported_geometry* shape = NULL; - size_t ishape = SIZE_MAX; - const char* name; - struct darray_impgeom* impgeoms; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && geom && out_ishape); - - switch(type) { - case SOLSTICE_SHAPE_OBJ: name = "obj"; impgeoms = &parser->objs; break; - case SOLSTICE_SHAPE_STL: name = "stl"; impgeoms = &parser->stls; break; - default: FATAL("Unreachable code.\n"); break; - } - - if(geom->type != YAML_MAPPING_NODE) { - log_err(parser, geom, "expect a mapping of %s parameters.\n", name); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate an imported geometry */ - ishape = darray_impgeom_size_get(impgeoms); - res = darray_impgeom_resize(impgeoms, ishape + 1); - if(res != RES_OK) { - log_err(parser, geom, "could not allocate the %s shape.\n", name); - goto error; - } - shape = darray_impgeom_data_get(impgeoms) + ishape; - - n = geom->data.mapping.pairs.top - geom->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, geom->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, geom->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect %s parameters.\n", name); - res = RES_BAD_ARG; - goto error; - } - if(!strcmp((char*)key->data.scalar.value, "path")) { - if(mask & BIT(PATH)) { - log_err(parser, key, "the %s path is already defined.\n", name); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(PATH); - res = parse_string(parser, val, &shape->filename); - } else { - log_err(parser, key, "unknown %s parameter `%s'.\n", - name, key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - } - - if(!(mask & BIT(PATH))) { - log_err(parser, geom, "the path of the %s geometry is missing.\n", name); - res = RES_BAD_ARG; - goto error; - } - -exit: - out_ishape->i = ishape; - return res; -error: - if(shape) { - darray_impgeom_pop_back(impgeoms); - ishape = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_paraboloid - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* paraboloid, - const enum solstice_shape_type type, - struct solstice_shape_paraboloid_id* out_ishape) -{ - enum { CLIP, FOCAL }; - struct solstice_shape_paraboloid* shape = NULL; - struct darray_paraboloid* paraboloids; - const char* name; - size_t ishape = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && paraboloid && out_ishape); - - switch(type) { - case SOLSTICE_SHAPE_PARABOL: - name = "parabol"; - paraboloids = &parser->parabols; - break; - case SOLSTICE_SHAPE_PARABOLIC_CYLINDER: - name = "parabolic cylinder"; - paraboloids = &parser->parabolic_cylinders; - break; - default: FATAL("Unreachable code.\n"); break; - } - - if(paraboloid->type != YAML_MAPPING_NODE) { - log_err(parser, paraboloid, "expect a mapping of %s parameters.\n", name); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate a paraboloid shape */ - ishape = darray_paraboloid_size_get(paraboloids); - res = darray_paraboloid_resize(paraboloids, ishape + 1); - if(res != RES_OK) { - log_err(parser, paraboloid, "could not allocate the %s shape.\n", name); - goto error; - } - shape = darray_paraboloid_data_get(paraboloids) + ishape; - - n = paraboloid->data.mapping.pairs.top - paraboloid->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, paraboloid->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, paraboloid->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect %s parameters.\n", name); - res = RES_BAD_ARG; - goto error; - } - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the %s parameter `"Name"' is already defined.\n", name); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "clip")) { - SETUP_MASK(CLIP, "clip"); - res = parse_clip(parser, doc, val, &shape->polyclips); - } else if(!strcmp((char*)key->data.scalar.value, "focal")) { - SETUP_MASK(FOCAL, "focal"); - res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &shape->focal); - } else { - log_err(parser, key, "unknown %s parameter `%s'.\n", - name, key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, paraboloid, \ - "the %s parameter `"Name"' is missing.\n", name); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(CLIP, "clip"); - CHECK_PARAM(FOCAL, "focal"); - #undef CHECK_PARAM - -exit: - out_ishape->i = ishape; - return res; -error: - if(shape) { - darray_paraboloid_pop_back(paraboloids); - ishape = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_plane - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* plane, - struct solstice_shape_plane_id* out_ishape) -{ - enum { CLIP }; - struct solstice_shape_plane* shape = NULL; - size_t ishape = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && plane && out_ishape); - - if(plane->type != YAML_MAPPING_NODE) { - log_err(parser, plane, "expect a mapping of plane parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate a plane shape */ - ishape = darray_plane_size_get(&parser->planes); - res = darray_plane_resize(&parser->planes, ishape + 1); - if(res != RES_OK) { - log_err(parser, plane, "could not allocate the plane shape.\n"); - goto error; - } - shape = darray_plane_data_get(&parser->planes) + ishape; - - n = plane->data.mapping.pairs.top - plane->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, plane->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, plane->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect plane parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - if(!strcmp((char*)key->data.scalar.value, "clip")) { - if(mask & BIT(CLIP)) { - log_err(parser, key, "the plane clipping is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(CLIP); - res = parse_clip(parser, doc, val, &shape->polyclips); - } else { - log_err(parser, key, "unknown plane parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - } - if(!(mask & BIT(CLIP))) { - log_err(parser, plane, "the plane parameter `clip' is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - out_ishape->i = ishape; - return res; -error: - if(shape) { - darray_plane_pop_back(&parser->planes); - ishape = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_sphere - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* sphere, - struct solstice_shape_sphere_id* out_ishape) -{ - enum { RADIUS, SLICES }; - struct solstice_shape_sphere* shape = NULL; - size_t ishape = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && sphere && out_ishape); - - if(sphere->type != YAML_MAPPING_NODE) { - log_err(parser, sphere, "expect a mapping of sphere parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate a shpere shape */ - ishape = darray_sphere_size_get(&parser->spheres); - res = darray_sphere_resize(&parser->spheres, ishape + 1); - if(res != RES_OK) { - log_err(parser, sphere, "could not allocate the sphere shape.\n"); - goto error; - } - shape = darray_sphere_data_get(&parser->spheres) + ishape; - - n = sphere->data.mapping.pairs.top - sphere->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, sphere->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, sphere->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect sphere parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the sphere parameter `"Name"' is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "radius")) { - SETUP_MASK(RADIUS, "radius"); - res = parse_real(parser, val, 0, DBL_MAX, &shape->radius); - } else if(!strcmp((char*)key->data.scalar.value, "slices")) { - SETUP_MASK(SLICES, "slices"); - res = parse_integer(parser, val, 4, 4096, &shape->nslices); - } else { - log_err(parser, key, "unknown sphere parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - if(!(mask & BIT(RADIUS))) { - log_err(parser, sphere, "the sphere radius is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - out_ishape->i = ishape; - return res; -error: - if(shape) { - darray_sphere_pop_back(&parser->spheres); - ishape = SIZE_MAX; - } - goto exit; -} - -/******************************************************************************* - * Geometry - ******************************************************************************/ -static res_T -parse_object - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* object, - struct solstice_object_id* out_iobj) -{ - enum { MATERIAL, SHAPE, TRANSFORM }; - struct solstice_object* obj = NULL; - struct solstice_shape* shape = NULL; - size_t iobj = SIZE_MAX; - size_t ishape = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && object && out_iobj); - - if(object->type != YAML_MAPPING_NODE) { - log_err(parser, object, "expect an object definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate an object */ - iobj = darray_object_size_get(&parser->objects); - res = darray_object_resize(&parser->objects, iobj + 1); - if(res != RES_OK) { - log_err(parser, object, "could not allocate the object.\n"); - goto error; - } - obj = darray_object_data_get(&parser->objects) + iobj; - - /* Allocate a shape */ - ishape = darray_shape_size_get(&parser->shapes); - res = darray_shape_resize(&parser->shapes, ishape + 1); - if(res != RES_OK) { - log_err(parser, object, "could not allocate the object shape.\n"); - goto error; - } - shape = darray_shape_data_get(&parser->shapes) + ishape; - obj->shape.i = ishape; - - /* Setup default object transformation */ - d3_splat(obj->translation, 0); - d3_splat(obj->rotation, 0); - - n = object->data.mapping.pairs.top - object->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, object->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, object->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect an object parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the object "Name" is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "material")) { - SETUP_MASK(MATERIAL, "material"); - res = parse_material(parser, doc, val, &obj->mtl2); - } else if(!strcmp((char*)key->data.scalar.value, "cuboid")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_CUBOID; - res = parse_cuboid(parser, doc, val, &shape->data.cuboid); - } else if(!strcmp((char*)key->data.scalar.value, "cylinder")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_CYLINDER; - res = parse_cylinder(parser, doc, val, &shape->data.cylinder); - } else if(!strcmp((char*)key->data.scalar.value, "obj")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_OBJ; - res = parse_imported_geometry - (parser, doc, val, shape->type, &shape->data.obj); - } else if(!strcmp((char*)key->data.scalar.value, "parabol")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_PARABOL; - res = parse_paraboloid - (parser, doc, val, shape->type, &shape->data.parabol); - } else if(!strcmp((char*)key->data.scalar.value, "parabolic-cylinder")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_PARABOLIC_CYLINDER; - res = parse_paraboloid - (parser, doc, val, shape->type, &shape->data.parabolic_cylinder); - } else if(!strcmp((char*)key->data.scalar.value, "plane")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_PLANE; - res = parse_plane(parser, doc, val, &shape->data.plane); - } else if(!strcmp((char*)key->data.scalar.value, "sphere")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_SPHERE; - res = parse_sphere(parser, doc, val, &shape->data.sphere); - } else if(!strcmp((char*)key->data.scalar.value, "stl")) { - SETUP_MASK(SHAPE, "shape"); - shape->type = SOLSTICE_SHAPE_STL; - res = parse_imported_geometry - (parser, doc, val, shape->type, &shape->data.stl); - } else if(!strcmp((char*)key->data.scalar.value, "transform")) { - SETUP_MASK(TRANSFORM, "transform"); - res = parse_transform(parser, doc, val, obj->translation, obj->rotation); - } else { - log_err(parser, key, "unknown object parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, object, "the object "Name" is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(MATERIAL, "material"); - CHECK_PARAM(SHAPE, "shape"); - #undef CHECK_PARAM - -exit: - out_iobj->i = iobj; - return res; -error: - if(obj) { - if(shape) darray_shape_pop_back(&parser->shapes); - darray_object_pop_back(&parser->objects); - obj = NULL; - } - goto exit; -} - -static res_T -parse_geometry - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* geometry, - struct solstice_geometry_id* out_isolgeom) -{ - struct solstice_geometry* solgeom = NULL; - size_t* pisolgeom; - size_t isolgeom = SIZE_MAX; - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && geometry && out_isolgeom); - - if(geometry->type != YAML_SEQUENCE_NODE) { - log_err(parser, geometry, "expect a list of objects.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Check whether or not the YAML descriptor alias an already created Solstice - * geometry */ - pisolgeom = htable_yaml2sols_find(&parser->yaml2geoms, &geometry); - if(pisolgeom) { - isolgeom = *pisolgeom; - goto exit; - } - - /* Allocate the geometry */ - isolgeom = darray_geometry_size_get(&parser->geometries); - res = darray_geometry_resize(&parser->geometries, isolgeom + 1); - if(res != RES_OK) { - log_err(parser, geometry, "could not allocate the geometry.\n"); - goto error; - } - solgeom = darray_geometry_data_get(&parser->geometries) + isolgeom; - - n = geometry->data.sequence.items.top - geometry->data.sequence.items.start; - res = darray_object_id_resize(&solgeom->objects, (size_t)n); - if(res != RES_OK) { - log_err(parser, geometry, "could not allocate the objects list.\n"); - goto error; - } - - FOR_EACH(i, 0, n) { - struct solstice_object_id* obj_id; - yaml_node_t* obj; - - obj_id = darray_object_id_data_get(&solgeom->objects) + i; - obj = yaml_document_get_node(doc, geometry->data.sequence.items.start[i]); - res = parse_object(parser, doc, obj, obj_id); - if(res != RES_OK) goto error; - } - - /* Cache the geometry */ - res = htable_yaml2sols_set(&parser->yaml2geoms, &geometry, &isolgeom); - if(res != RES_OK) { - log_err(parser, geometry, "could not register the geometry.\n"); - goto error; - } - -exit: - out_isolgeom->i = isolgeom; - return res; -error: - if(solgeom) { - darray_geometry_pop_back(&parser->geometries); - isolgeom = SIZE_MAX; - } - goto exit; -} - - -/******************************************************************************* - * Entity - ******************************************************************************/ -static res_T -entity_register_name - (struct solstice_parser* parser, - const yaml_node_t* entity, - struct htable_str2sols* htable, - const size_t isolent) -{ - struct solstice_entity* solent; - size_t* pisolent; - res_T res = RES_OK; - ASSERT(parser && htable); - ASSERT(isolent < darray_entity_size_get(&parser->entities)); - - solent = darray_entity_data_get(&parser->entities) + isolent; - - pisolent = htable_str2sols_find(htable, &solent->name); - if(pisolent) { - log_err(parser, entity, - "an entity with the name `%s' is already defined in the current context.\n", - str_cget(&solent->name)); - return RES_BAD_ARG; - } - - res = htable_str2sols_set(htable, &solent->name, &isolent); - if(res != RES_OK) { - log_err(parser, entity, "could not register the entity.\n"); - return res; - } - return RES_OK; -} - -static res_T -anchor_register_name - (struct solstice_parser* parser, - const yaml_node_t* anchor, - struct htable_str2sols* htable, - const size_t isolanchor) -{ - struct solstice_anchor* solanchor; - size_t* pisolanchor; - res_T res = RES_OK; - ASSERT(parser && htable); - ASSERT(isolanchor < darray_anchor_size_get(&parser->anchors)); - - solanchor = darray_anchor_data_get(&parser->anchors) + isolanchor; - - pisolanchor = htable_str2sols_find(htable, &solanchor->name); - if(pisolanchor) { - log_err(parser, anchor, - "an anchor with the name `%s' is already defined in the cunrrent context.\n", - str_cget(&solanchor->name)); - return RES_BAD_ARG; - } - - res = htable_str2sols_set(htable, &solanchor->name, &isolanchor); - if(res != RES_OK) { - log_err(parser, anchor, "could not register the anchor.\n"); - return res; - } - return RES_OK; -} - -static res_T -parse_identifier_string - (struct solstice_parser* parser, - yaml_node_t* name, - struct str* str) -{ - res_T res = RES_OK; - ASSERT(parser && name && str); - - res = parse_string(parser, name, str); - if(res != RES_OK) goto error; - - if(strchr(str_cget(str), '.')) { - log_err(parser, name, "invalid character `.' in the name `%s'.\n", - str_cget(str)); - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_anchor - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* anchor, - struct htable_str2sols* htable, - struct solstice_anchor_id* out_isolanchor) -{ - enum { NAME, POSITION }; - struct solstice_anchor* solanchor = NULL; - size_t isolanchor = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(parser && anchor && out_isolanchor); - - if(anchor->type != YAML_MAPPING_NODE) { - log_err(parser, anchor, "expect an anchor definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the anchor */ - isolanchor = darray_anchor_size_get(&parser->anchors); - res = darray_anchor_resize(&parser->anchors, isolanchor + 1); - if(res != RES_OK) { - log_err(parser, anchor, "could not allocate the anchor.\n"); - goto error; - } - solanchor = darray_anchor_data_get(&parser->anchors) + isolanchor; - - n = anchor->data.mapping.pairs.top - anchor->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, anchor->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, anchor->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect an anchor attribute.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, "the anchor "Name" is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "name")) { - SETUP_MASK(NAME, "name"); - res = parse_identifier_string(parser, val, &solanchor->name); - } else if(!strcmp((char*)key->data.scalar.value, "position")) { - SETUP_MASK(POSITION, "position"); - res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solanchor->position); - } else { - log_err(parser, key, "unknown anchor parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, anchor, "the anchor "Name" is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(NAME, "name"); - CHECK_PARAM(POSITION, "position"); - #undef CHECK_PARAM - - res = anchor_register_name(parser, anchor, htable, isolanchor); - if(res != RES_OK) goto error; - -exit: - out_isolanchor->i = isolanchor; - return res; -error: - if(solanchor) { - darray_anchor_pop_back(&parser->anchors); - isolanchor = SIZE_MAX; - } - goto exit; -} - -static res_T -parse_anchors - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* anchors, - struct htable_str2sols* htable, - struct darray_anchor_id* solanchors) -{ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(parser && anchors); - - if(anchors->type != YAML_SEQUENCE_NODE) { - log_err(parser, anchors, "expect a list of anchors.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = anchors->data.sequence.items.top - anchors->data.sequence.items.start; - res = darray_anchor_id_resize(solanchors, (size_t)n); - if(res != RES_OK) { - log_err(parser, anchors, "could not allocate the anchors list.\n"); - goto error; - } - - FOR_EACH(i, 0, n) { - struct solstice_anchor_id* anchor_id; - yaml_node_t* anchor; - - anchor_id = darray_anchor_id_data_get(solanchors)+i; - anchor = yaml_document_get_node(doc, anchors->data.sequence.items.start[i]); - res = parse_anchor(parser, doc, anchor, htable, anchor_id); - if(res != RES_OK) goto error; - } -exit: - return res; -error: - goto exit; -} - -static res_T -parse_children - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* children, - struct htable_str2sols* htable, - struct darray_child_id* entities) -{ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(parser && children && htable && entities); - - if(children->type != YAML_SEQUENCE_NODE) { - log_err(parser, children, "expect a list of entities.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = children->data.sequence.items.top - children->data.sequence.items.start; - res = darray_child_id_resize(entities, (size_t)n); - if(res != RES_OK) { - log_err(parser, children, "could not allocate the children list.\n"); - goto error; - } - - FOR_EACH(i, 0, n) { - struct solstice_entity_id* entity_id = darray_child_id_data_get(entities) + i; - yaml_node_t* child; - - child = yaml_document_get_node(doc, children->data.sequence.items.start[i]); - res = parse_entity(parser, doc, child, htable, entity_id); - if(res != RES_OK) goto error; - } - -exit: - return res; -error: - darray_child_id_clear(entities); - goto exit; -} - -res_T -parse_entity - (struct solstice_parser* parser, - yaml_document_t* doc, - yaml_node_t* entity, - struct htable_str2sols* htable, - struct solstice_entity_id* out_isolent) -{ - enum { ANCHORS, CHILDREN, DATA, NAME, TRANSFORM }; - struct solstice_entity solent; - struct solstice_entity* psolent; - const size_t *pisolent; - size_t isolent = SIZE_MAX; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && entity && htable && out_isolent); - - solstice_entity_init(parser->allocator, &solent); - - pisolent = htable_yaml2sols_find(&parser->yaml2entities, &entity); - if(pisolent) { - isolent = *pisolent; - res = entity_register_name(parser, entity, htable, *pisolent); - if(res != RES_OK) goto error; - goto exit; - } - - if(entity->type != YAML_MAPPING_NODE) { - log_err(parser, entity, "expect an entity definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the entity but *DO NOT* retrieve a pointer onto it since the - * allocation of its children may update its memory location. Use the "on - * stack" entity `solent' instead. */ - isolent = darray_entity_size_get(&parser->entities); - res = darray_entity_resize(&parser->entities, isolent + 1); - if(res != RES_OK) { - log_err(parser, entity, "could not allocate the entity.\n"); - goto error; - } - - n = entity->data.mapping.pairs.top - entity->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, entity->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, entity->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect an entity attribute.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the entity "Name" is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "anchors")) { - SETUP_MASK(ANCHORS, "anchors"); - res = parse_anchors - (parser, doc, val, &solent.str2anchors, &solent.anchors); - } else if(!strcmp((char*)key->data.scalar.value, "children")) { - SETUP_MASK(CHILDREN, "children"); - res = parse_children - (parser, doc, val, &solent.str2children, &solent.children); - } else if(!strcmp((char*)key->data.scalar.value, "geometry")) { - SETUP_MASK(DATA, "data"); - solent.type = SOLSTICE_ENTITY_GEOMETRY; - res = parse_geometry(parser, doc, val, &solent.data.geometry); - } else if(!strcmp((char*)key->data.scalar.value, "name")) { - SETUP_MASK(NAME, "name"); - res = parse_identifier_string(parser, val, &solent.name); - } else if(!strcmp((char*)key->data.scalar.value, "pivot")) { - SETUP_MASK(DATA, "data"); - solent.type = SOLSTICE_ENTITY_PIVOT; - res = parse_pivot(parser, doc, val, &solent.data.pivot); - } else if(!strcmp((char*)key->data.scalar.value, "transform")) { - SETUP_MASK(TRANSFORM, "transform"); - res = parse_transform - (parser, doc, val, solent.translation, solent.rotation); - } else { - log_err(parser, key, "unknown entity parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - if(!(mask & BIT(DATA))) { - solent.type = SOLSTICE_ENTITY_EMPTY; - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, entity, "the entity "Name" is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(NAME, "name"); - #undef CHECK_PARAM - - psolent = darray_entity_data_get(&parser->entities) + isolent; - res = solstice_entity_copy_and_clear(psolent, &solent); - if(res != RES_OK) { - log_err(parser, entity, - "could not copy the loaded entity into the parser data structures.\n"); - goto error; - } - res = entity_register_name(parser, entity, htable, isolent); - if(res != RES_OK) goto error; - - res = htable_yaml2sols_set(&parser->yaml2entities, &entity, &isolent); - if(res != RES_OK) { - log_err(parser, entity, "could not register the entity.\n"); - goto error; - } - -exit: - solstice_entity_release(&solent); - out_isolent->i = isolent; - return res; -error: - if(isolent != SIZE_MAX) { - htable_str2sols_erase(htable, &solent.name); - darray_entity_pop_back(&parser->entities); - isolent = SIZE_MAX; - } - goto exit; -} - -/******************************************************************************* - * Pivot - ******************************************************************************/ -static res_T -parse_anchor_alias - (struct solstice_parser* parser, - const yaml_node_t* alias, - struct solstice_anchor_id* out_ianchor) -{ - const struct solstice_anchor* anchor = NULL; - intptr_t ianchor = INTPTR_MAX; - res_T res = RES_OK; - ASSERT(parser && alias && out_ianchor); - - if(alias->type != YAML_SCALAR_NODE) { - log_err(parser, alias, "expect an anchor idententifier.\n"); - res = RES_BAD_ARG; - goto error; - } - - anchor = solstice_parser_find_anchor(parser, (char*)alias->data.scalar.value); - if(!anchor) { - log_err(parser, alias, "undefined anchor `%s'.\n", - alias->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - - ianchor = anchor - darray_anchor_cdata_get(&parser->anchors); - ASSERT(ianchor >= 0); - ASSERT((size_t)ianchor < darray_anchor_size_get(&parser->anchors)); - -exit: - out_ianchor->i = (size_t)ianchor; - return res; -error: - ianchor = INTPTR_MAX; - goto exit; -} - -static res_T -parse_target - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* target, - struct solstice_pivot* pivot) -{ - enum { POLICY }; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && target && pivot); - - if(target->type != YAML_MAPPING_NODE) { - log_err(parser, target, "expect a target definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = target->data.mapping.pairs.top - target->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, target->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, target->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a target parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, "the target "Name" is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "anchor")) { - SETUP_MASK(POLICY, "policy"); - pivot->target_type = SOLSTICE_TARGET_ANCHOR; - res = parse_anchor_alias(parser, val, &pivot->target.anchor); - } else if(!strcmp((char*)key->data.scalar.value, "direction")) { - SETUP_MASK(POLICY, "policy"); - pivot->target_type = SOLSTICE_TARGET_DIRECTION; - res = parse_real3 - (parser, doc, val, -DBL_MAX, DBL_MAX, pivot->target.direction); - } else if(!strcmp((char*)key->data.scalar.value, "position")) { - SETUP_MASK(POLICY, "policy"); - pivot->target_type = SOLSTICE_TARGET_POSITION; - res = parse_real3 - (parser, doc, val, -DBL_MAX, DBL_MAX, pivot->target.position); - } else if(!strcmp((char*)key->data.scalar.value, "sun")) { - /* There is only one sun per YAML file. It is thus sufficient to define - * the target_type to SOLSTICE_TARGET_SUN to indentify which data is - * targeted, i.e. it is not necessary to store the identifier of the sun - * to target */ - struct solstice_sun* sun; - SETUP_MASK(POLICY, "policy"); - pivot->target_type = SOLSTICE_TARGET_SUN; - res = parse_sun(parser, doc, val, &sun); - } else { - log_err(parser, key, "unknown target parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - goto error; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - if(!(mask & BIT(POLICY))) { - log_err(parser, target, "the target policy is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_pivot - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* pivot, - struct solstice_pivot_id* out_isolpivot) -{ - enum { NORMAL, POINT, TARGET, TRANSFORM }; - struct solstice_pivot* solpivot = NULL; - size_t isolpivot = SIZE_MAX; - int mask = 0; /* Register the parsed attributes */ - intptr_t i, n; - res_T res = RES_OK; - ASSERT(doc && pivot && out_isolpivot); - - if(pivot->type != YAML_MAPPING_NODE) { - log_err(parser, pivot, "expect a pivot definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - /* Allocate the solstice pivot */ - isolpivot = darray_pivot_size_get(&parser->pivots); - res = darray_pivot_resize(&parser->pivots, isolpivot + 1); - if(res != RES_OK) { - log_err(parser, pivot, "could not allocate the pivot.\n"); - res = RES_BAD_ARG; - goto error; - } - solpivot = darray_pivot_data_get(&parser->pivots) + isolpivot; - - n = pivot->data.mapping.pairs.top - pivot->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, pivot->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, pivot->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect pivot parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, \ - "the pivot parameter `"Name"' is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "point")) { - SETUP_MASK(POINT, "point"); - res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solpivot->point); - } else if(!strcmp((char*)key->data.scalar.value, "normal")) { - SETUP_MASK(NORMAL, "normal"); - res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solpivot->normal); - } else if(!strcmp((char*)key->data.scalar.value, "target")) { - SETUP_MASK(TARGET, "target"); - res = parse_target(parser, doc, val, solpivot); - } else if(!strcmp((char*)key->data.scalar.value, "transform")) { - SETUP_MASK(TRANSFORM, "transform"); - res = parse_transform - (parser, doc, val, solpivot->translation, solpivot->rotation); - } else { - log_err(parser, key, "unknown pivot parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, pivot, "the pivot parameter `"Name"' is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(POINT, "point"); - CHECK_PARAM(NORMAL, "normal"); - CHECK_PARAM(TARGET, "target"); - #undef CHECK_PARAM - -exit: - out_isolpivot->i = isolpivot; - return res; -error: - if(solpivot) { - darray_pivot_pop_back(&parser->pivots); - isolpivot = SIZE_MAX; - } - goto exit; -} - -/******************************************************************************* - * Sun - ******************************************************************************/ -static res_T -parse_buie - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* buie, - struct solstice_sun_buie* sun) -{ - enum { CSR }; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && buie && sun); - - if(buie->type != YAML_MAPPING_NODE) { - log_err(parser, buie, - "expect a buie definition of the sun radial angular distribution.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = buie->data.mapping.pairs.top - buie->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, buie->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, buie->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a buie parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - - if(!strcmp((char*)key->data.scalar.value, "csr")) { - if(mask & BIT(CSR)) { - log_err(parser, key, "the buie `csr' is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(CSR); - res = parse_real(parser, val, nextafter(0, 1), nextafter(1, 0), &sun->csr); - } else { - log_err(parser, key, "unknown buie parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - } - - if(!(mask & BIT(CSR))) { - log_err(parser, buie, "the buie csr parameter is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -static res_T -parse_pillbox - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* pillbox, - struct solstice_sun_pillbox* sun) -{ - enum { APERTURE }; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && pillbox && sun); - - if(pillbox->type != YAML_MAPPING_NODE) { - log_err(parser, pillbox, - "expect a pillbox definition of the sun radial angular distribution.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = pillbox->data.mapping.pairs.top - pillbox->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, pillbox->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, pillbox->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect a pillbox parameter.\n"); - res = RES_BAD_ARG; - goto error; - } - if(!strcmp((char*)key->data.scalar.value, "aperture")) { - if(mask & BIT(APERTURE)) { - log_err(parser, key, "the pillbox `aperture' is already defined.\n"); - res = RES_BAD_ARG; - goto error; - } - mask |= BIT(APERTURE); - res = parse_real(parser, val, nextafter(0, 1), PI/2.0, &sun->aperture); - } else { - log_err(parser, pillbox, "unknown pillbox parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - } - - if(!(mask & BIT(APERTURE))) { - log_err(parser, pillbox, "the pillbox aperture parameter is missing.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - -res_T -parse_sun - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* sun, - struct solstice_sun** out_solsun) -{ - enum { DNI, RADIAL_ANGULAR_DISTRIB, SPECTRUM }; - struct solstice_sun* solsun = NULL; - intptr_t i, n; - int mask = 0; /* Register the parsed attributes */ - res_T res = RES_OK; - ASSERT(doc && sun && out_solsun); - - if(sun == parser->sun_key) { - solsun = &parser->sun; - goto exit; - } else if(parser->sun_key != 0) { - log_err(parser, sun, - "a sun is already defined. Previous definition is here %lu:%lu.\n", - (unsigned long)parser->sun_key->start_mark.line+1, - (unsigned long)parser->sun_key->start_mark.column+1); - res = RES_BAD_ARG; - goto error; - } else { - solsun = &parser->sun; - parser->sun_key = sun; - solsun->radang_distrib_type = SOLSTICE_SUN_RADANG_DISTRIB_DIRECTIONAL; - } - - if(sun->type != YAML_MAPPING_NODE) { - log_err(parser, sun, "expect a sun definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = sun->data.mapping.pairs.top - sun->data.mapping.pairs.start; - FOR_EACH(i, 0, n) { - yaml_node_t* key; - yaml_node_t* val; - - key = yaml_document_get_node(doc, sun->data.mapping.pairs.start[i].key); - val = yaml_document_get_node(doc, sun->data.mapping.pairs.start[i].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expect sun parameters.\n"); - res = RES_BAD_ARG; - goto error; - } - #define SETUP_MASK(Flag, Name) { \ - if(mask & BIT(Flag)) { \ - log_err(parser, key, "the sun "Name" is already defined.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } \ - mask |= BIT(Flag); \ - } (void)0 - if(!strcmp((char*)key->data.scalar.value, "dni")) { - SETUP_MASK(DNI, "dni"); - res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &solsun->dni); - } else if(!strcmp((char*)key->data.scalar.value, "buie")) { - SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution"); - solsun->radang_distrib_type = SOLSTICE_SUN_RADANG_DISTRIB_BUIE; - res = parse_buie(parser, doc, val, &solsun->radang_distrib.buie); - } else if(!strcmp((char*)key->data.scalar.value, "pillbox")) { - SETUP_MASK(RADIAL_ANGULAR_DISTRIB, "radial angular distribution"); - solsun->radang_distrib_type = SOLSTICE_SUN_RADANG_DISTRIB_PILLBOX; - res = parse_pillbox(parser, doc, val, &solsun->radang_distrib.pillbox); - } else if(!strcmp((char*)key->data.scalar.value, "spectrum")) { - SETUP_MASK(SPECTRUM, "spectrum"); - res = parse_spectrum(parser, doc, 0, DBL_MAX, val, &solsun->spectrum); - } else { - log_err(parser, key, "unknown sun parameter `%s'.\n", - key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - #undef SETUP_MASK - } - - #define CHECK_PARAM(Flag, Name) \ - if(!(mask & BIT(Flag))) { \ - log_err(parser, sun, "the sun "Name" is missing.\n"); \ - res = RES_BAD_ARG; \ - goto error; \ - } (void)0 - CHECK_PARAM(DNI, "dni"); - CHECK_PARAM(SPECTRUM, "spectrum"); - #undef CHECK_PARAM - -exit: - *out_solsun = solsun; - return res; -error: - if(solsun) { - solstice_sun_clear(solsun); - solsun = NULL; - parser->sun_key = 0; - } - goto exit; -} - -/******************************************************************************* - * Item - ******************************************************************************/ -static res_T -parse_item - (struct solstice_parser* parser, - yaml_document_t* doc, - const yaml_node_t* item) -{ - yaml_node_t* key; - yaml_node_t* val; - struct solstice_material_double_sided_id mtl2; /* TODO */ - struct solstice_entity_id entity; /* TODO */ - struct solstice_geometry_id geometry; /* TODO */ - struct solstice_sun* sun; /* TODO */ - intptr_t n; - res_T res = RES_OK; - ASSERT(doc && item); - - if(item->type != YAML_MAPPING_NODE) { - log_err(parser, item, "expect an item definition.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = item->data.mapping.pairs.top - item->data.mapping.pairs.start; - if(n != 1) { - log_err(parser, item, - "expect only one \"key:value\" pair while %li are provided.\n", n); - res = RES_BAD_ARG; - goto error; - } - - key = yaml_document_get_node(doc, item->data.mapping.pairs.start[0].key); - val = yaml_document_get_node(doc, item->data.mapping.pairs.start[0].value); - if(key->type != YAML_SCALAR_NODE) { - log_err(parser, key, "expecting an item name.\n"); - res = RES_BAD_ARG; - goto error; - } - - if(!strcmp((char*)key->data.scalar.value, "material")) { - res = parse_material(parser, doc, val, &mtl2); - } else if(!strcmp((char*)key->data.scalar.value, "entity")) { - res = parse_entity(parser, doc, val, &parser->str2entities, &entity); - } else if(!strcmp((char*)key->data.scalar.value, "template")) { - /* The parsing of the template data is deferred to its explicit used in the - * definition of an entity. If the parsing of the template becomes a - * bottleneck, parse the data only once here and cache them for reuse. */ - } else if(!strcmp((char*)key->data.scalar.value, "geometry")) { - res = parse_geometry(parser, doc, val, &geometry); - } else if(!strcmp((char*)key->data.scalar.value, "sun")) { - res = parse_sun(parser, doc, val, &sun); - } else { - log_err(parser, key, "unknown item `%s'.\n", key->data.scalar.value); - res = RES_BAD_ARG; - } - if(res != RES_OK) goto error; - -exit: - return res; -error: - goto exit; -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -res_T -solstice_parser_create - (struct mem_allocator* allocator, struct solstice_parser** out_parser) -{ - struct solstice_parser* parser = NULL; - struct mem_allocator* mem_allocator; - res_T res = RES_OK; - ASSERT(out_parser); - - mem_allocator = allocator ? allocator : &mem_default_allocator; - parser = MEM_CALLOC(mem_allocator, 1, sizeof(struct solstice_parser)); - if(!parser) { - fprintf(stderr, "Could not allocat the Solstice parser.\n"); - res = RES_MEM_ERR; - goto error; - } - parser->allocator = mem_allocator; - ref_init(&parser->ref); - str_init(mem_allocator, &parser->stream_name); - - /* Materials */ - htable_yaml2sols_init(mem_allocator, &parser->yaml2mtls); - darray_material_init(mem_allocator, &parser->mtls); - darray_material2_init(mem_allocator, &parser->mtls2); - darray_matte_init(mem_allocator, &parser->mattes); - darray_mirror_init(mem_allocator, &parser->mirrors); - - /* Shapes */ - darray_shape_init(mem_allocator, &parser->shapes); - darray_cuboid_init(mem_allocator, &parser->cuboids); - darray_cylinder_init(mem_allocator, &parser->cylinders); - darray_impgeom_init(mem_allocator, &parser->objs); - darray_paraboloid_init(mem_allocator, &parser->parabols); - darray_paraboloid_init(mem_allocator, &parser->parabolic_cylinders); - darray_plane_init(mem_allocator, &parser->planes); - darray_sphere_init(mem_allocator, &parser->spheres); - darray_impgeom_init(mem_allocator, &parser->stls); - - /* Geometries */ - htable_yaml2sols_init(mem_allocator, &parser->yaml2geoms); - darray_object_init(mem_allocator, &parser->objects); - darray_geometry_init(mem_allocator, &parser->geometries); - - /* Sun */ - solstice_sun_init(mem_allocator, &parser->sun); - - /* Entities */ - htable_yaml2sols_init(mem_allocator, &parser->yaml2entities); - htable_str2sols_init(mem_allocator, &parser->str2entities); - darray_entity_init(mem_allocator, &parser->entities); - - /* Anchors */ - darray_anchor_init(mem_allocator, &parser->anchors); - darray_pivot_init(mem_allocator, &parser->pivots); - -exit: - *out_parser = parser; - return res; -error: - if(parser) { - solstice_parser_ref_put(parser); - parser = NULL; - } - goto exit; -} - -void -solstice_parser_ref_get(struct solstice_parser* parser) -{ - ASSERT(parser); - ref_get(&parser->ref); -} - -void -solstice_parser_ref_put(struct solstice_parser* parser) -{ - ASSERT(parser); - ref_put(&parser->ref, parser_release); -} - -res_T -solstice_parser_setup - (struct solstice_parser* parser, - const char* stream_name, - FILE* stream) -{ - res_T res = RES_OK; - ASSERT(parser && stream ); - - if(parser->parser_is_init) { - yaml_parser_delete(&parser->parser); - parser->parser_is_init = 0; - } - res = str_set(&parser->stream_name, stream_name ? stream_name : "<stream>"); - if(res != RES_OK) { - fprintf(stderr, "Could not register the filename.\n"); - goto error; - } - if(!yaml_parser_initialize(&parser->parser)) { - fprintf(stderr, "Could not initialise the YAML parser.\n"); - res = RES_UNKNOWN_ERR; - goto error; - } - parser->parser_is_init = 1; - yaml_parser_set_input_file(&parser->parser, stream); - -exit: - return res; -error: - str_clear(&parser->stream_name); - if(parser->parser_is_init) { - yaml_parser_delete(&parser->parser); - parser->parser_is_init = 0; - } - goto exit; -} - -res_T -solstice_parser_load(struct solstice_parser* parser) -{ - yaml_document_t doc; - yaml_node_t* root; - const char* filename; - intptr_t i, n; - int doc_is_init = 0; - res_T res = RES_OK; - ASSERT(parser); - - filename = str_cget(&parser->stream_name); - - parser_clear(parser); /* Clean up previously loaded data */ - - if(!parser->parser_is_init) { - res = RES_BAD_OP; - goto error; - } - - if(!yaml_parser_load(&parser->parser, &doc)) { - fprintf(stderr, "%s:%lu:%lu: %s.\n", - filename, - (unsigned long)parser->parser.problem_mark.line+1, - (unsigned long)parser->parser.problem_mark.column+1, - parser->parser.problem); - yaml_parser_delete(&parser->parser); - parser->parser_is_init = 0; - res = RES_BAD_OP; - goto error; - } - doc_is_init = 1; - - root = yaml_document_get_root_node(&doc); - if(!root) { - yaml_parser_delete(&parser->parser); - parser->parser_is_init = 0; - res = RES_BAD_OP; - goto error; - } - - if(root->type != YAML_SEQUENCE_NODE) { - log_err(parser, root, "expect a list of items.\n"); - res = RES_BAD_ARG; - goto error; - } - - n = root->data.sequence.items.top - root->data.sequence.items.start; - FOR_EACH(i, 0, n) { - yaml_node_t* item; - - item = yaml_document_get_node(&doc, root->data.sequence.items.start[i]); - res = parse_item(parser, &doc, item); - if(res != RES_OK) goto error; - } - - if(!parser->sun_key) { - log_err(parser, root, "%s: no sun definition in the document.\n"); - res = RES_BAD_ARG; - goto error; - } - -exit: - if(doc_is_init) yaml_document_delete(&doc); - return res; -error: - parser_clear(parser); - goto exit; -} - -const struct solstice_anchor* -solstice_parser_find_anchor - (struct solstice_parser* parser, const char* name) -{ - struct str str; - struct str str_tk; - struct htable_str2sols* htable = NULL; - struct solstice_entity* entity = NULL; - struct solstice_anchor* anchor = NULL; - char* cstr; - char* tk; - char* tk_anchor; - res_T res = RES_OK; - ASSERT(parser && name); - - str_init(parser->allocator, &str); - str_init(parser->allocator, &str_tk); - - res = str_set(&str, name); - if(res != RES_OK) { - fprintf(stderr, "%s: could not copy the input string.\n", FUNC_NAME); - goto error; - } - res = str_reserve(&str_tk, str_len(&str)); - if(res != RES_OK) { - fprintf(stderr, "%s: could not allocate the temporary token string.\n", - FUNC_NAME); - goto error; - } - - cstr = str_get(&str); - tk_anchor = strrchr(cstr, '.'); - if(!tk_anchor) goto exit; - *tk_anchor='\0'; - ++tk_anchor; - - tk = strtok(cstr, "."); - htable = &parser->str2entities; - while(tk) { - size_t* pientity; - str_set(&str_tk, tk); - pientity = htable_str2sols_find(htable, &str_tk); - if(!pientity) { - tk = NULL; - entity = NULL; - } else { - tk = strtok(NULL, "."); - entity = darray_entity_data_get(&parser->entities) + *pientity; - htable = &entity->str2children; - } - } - - if(entity) { - size_t* pianchor; - str_set(&str_tk, tk_anchor); - pianchor = htable_str2sols_find(&entity->str2anchors, &str_tk); - if(pianchor) { - anchor = darray_anchor_data_get(&parser->anchors) + *pianchor; - } - } - -exit: - str_release(&str); - str_release(&str_tk); - return anchor; -error: - anchor = NULL; - goto exit; -} - -const struct solstice_entity* -solstice_parser_find_entity - (struct solstice_parser* parser, const char* name) -{ - struct htable_str2sols* htable = NULL; - struct solstice_entity* entity = NULL; - struct str str; - struct str str_tk; - char* cstr; - char* tk; - res_T res = RES_OK; - ASSERT(parser && name); - - str_init(parser->allocator, &str); - str_init(parser->allocator, &str_tk); - - res = str_set(&str, name); - if(res != RES_OK) { - fprintf(stderr, "%s: could not copy the input string.\n", FUNC_NAME); - goto error; - } - res = str_reserve(&str_tk, str_len(&str)); - if(res != RES_OK) { - fprintf(stderr, "%s: could not allocate the temporary token sting.\n", - FUNC_NAME); - goto error; - } - - cstr = str_get(&str); - tk = strtok(cstr, "."); - htable = &parser->str2entities; - while(tk) { - size_t* pientity; - str_set(&str_tk, tk); - pientity = htable_str2sols_find(htable, &str_tk); - if(!pientity) { - tk = NULL; - entity = NULL; - } else { - tk = strtok(NULL, "."); - entity = darray_entity_data_get(&parser->entities) + *pientity; - htable = &entity->str2children; - } - } - -exit: - str_release(&str); - str_release(&str_tk); - return entity; -error: - entity = NULL; - goto exit; -} - -const struct solstice_anchor* -solstice_parser_get_anchor - (const struct solstice_parser* parser, - const struct solstice_anchor_id anchor) -{ - ASSERT(parser && anchor.i < darray_anchor_size_get(&parser->anchors)); - return darray_anchor_cdata_get(&parser->anchors) + anchor.i; -} - -const struct solstice_entity* -solstice_parser_get_entity - (const struct solstice_parser* parser, - const struct solstice_entity_id entity) -{ - ASSERT(parser && entity.i < darray_entity_size_get(&parser->entities)); - return darray_entity_cdata_get(&parser->entities) + entity.i; -} - -const struct solstice_geometry* -solstice_parser_get_geometry - (const struct solstice_parser* parser, - const struct solstice_geometry_id geom) -{ - ASSERT(parser && geom.i < darray_geometry_size_get(&parser->geometries)); - return darray_geometry_cdata_get(&parser->geometries) + geom.i; -} - -const struct solstice_material* -solstice_parser_get_material - (const struct solstice_parser* parser, - const struct solstice_material_id mtl) -{ - ASSERT(parser && mtl.i < darray_material_size_get(&parser->mtls)); - return darray_material_cdata_get(&parser->mtls) + mtl.i; -} - -const struct solstice_material_double_sided* -solstice_parser_get_material_double_sided - (const struct solstice_parser* parser, - const struct solstice_material_double_sided_id mtl2) -{ - ASSERT(parser && mtl2.i < darray_material2_size_get(&parser->mtls2)); - return darray_material2_cdata_get(&parser->mtls2) + mtl2.i; -} - -const struct solstice_material_matte* -solstice_parser_get_material_matte - (const struct solstice_parser* parser, - const struct solstice_material_matte_id matte) -{ - ASSERT(parser && matte.i < darray_matte_size_get(&parser->mattes)); - return darray_matte_cdata_get(&parser->mattes) + matte.i; -} - -const struct solstice_material_mirror* -solstice_parser_get_material_mirror - (const struct solstice_parser* parser, - const struct solstice_material_mirror_id mirror) -{ - ASSERT(parser && mirror.i < darray_mirror_size_get(&parser->mirrors)); - return darray_mirror_cdata_get(&parser->mirrors) + mirror.i; -} - -const struct solstice_object* -solstice_parser_get_object - (const struct solstice_parser* parser, - const struct solstice_object_id obj) -{ - ASSERT(parser && obj.i < darray_object_size_get(&parser->objects)); - return darray_object_cdata_get(&parser->objects) + obj.i; -} - -const struct solstice_pivot* -solstice_parser_get_pivot - (const struct solstice_parser* parser, - const struct solstice_pivot_id pivot) -{ - ASSERT(parser && pivot.i < darray_pivot_size_get(&parser->pivots)); - return darray_pivot_cdata_get(&parser->pivots) + pivot.i; -} - -const struct solstice_shape* -solstice_parser_get_shape - (const struct solstice_parser* parser, - const struct solstice_shape_id shape) -{ - ASSERT(parser && shape.i < darray_shape_size_get(&parser->shapes)); - return darray_shape_cdata_get(&parser->shapes) + shape.i; -} - -const struct solstice_shape_cuboid* -solstice_parser_get_shape_cuboid - (const struct solstice_parser* parser, - const struct solstice_shape_cuboid_id cuboid) -{ - ASSERT(parser && cuboid.i < darray_cuboid_size_get(&parser->cuboids)); - return darray_cuboid_cdata_get(&parser->cuboids) + cuboid.i; -} - -const struct solstice_shape_cylinder* -solstice_parser_get_shape_cylinder - (const struct solstice_parser* parser, - const struct solstice_shape_cylinder_id cylinder) -{ - ASSERT(parser && cylinder.i < darray_cylinder_size_get(&parser->cylinders)); - return darray_cylinder_cdata_get(&parser->cylinders) + cylinder.i; -} - -const struct solstice_shape_imported_geometry* -solstice_parser_get_shape_obj - (const struct solstice_parser* parser, - const struct solstice_shape_imported_geometry_id impgeom) -{ - ASSERT(parser && impgeom.i < darray_impgeom_size_get(&parser->objs)); - return darray_impgeom_cdata_get(&parser->objs) + impgeom.i; -} - -const struct solstice_shape_paraboloid* -solstice_parser_get_shape_parabol - (const struct solstice_parser* parser, - const struct solstice_shape_paraboloid_id paraboloid) -{ - ASSERT(parser && paraboloid.i < darray_paraboloid_size_get(&parser->parabols)); - return darray_paraboloid_cdata_get(&parser->parabols) + paraboloid.i; -} - -const struct solstice_shape_paraboloid* -solstice_parser_get_shape_parabolic_cylinder - (const struct solstice_parser* parser, - const struct solstice_shape_paraboloid_id paraboloid) -{ - ASSERT(parser); - ASSERT(paraboloid.i<darray_paraboloid_size_get(&parser->parabolic_cylinders)); - return darray_paraboloid_cdata_get(&parser->parabolic_cylinders)+paraboloid.i; -} - -const struct solstice_shape_plane* -solstice_parser_get_shape_plane - (const struct solstice_parser* parser, - const struct solstice_shape_plane_id plane) -{ - ASSERT(parser && plane.i < darray_plane_size_get(&parser->planes)); - return darray_plane_cdata_get(&parser->planes) + plane.i; -} - -const struct solstice_shape_sphere* -solstice_parser_get_shape_sphere - (const struct solstice_parser* parser, - const struct solstice_shape_sphere_id sphere) -{ - ASSERT(parser && sphere.i < darray_sphere_size_get(&parser->spheres)); - return darray_sphere_cdata_get(&parser->spheres) + sphere.i; -} - -const struct solstice_shape_imported_geometry* -solstice_parser_get_shape_stl - (const struct solstice_parser* parser, - const struct solstice_shape_imported_geometry_id impgeom) -{ - ASSERT(parser && impgeom.i < darray_impgeom_size_get(&parser->stls)); - return darray_impgeom_cdata_get(&parser->stls) + impgeom.i; -} - -const struct solstice_sun* -solstice_parser_get_sun(const struct solstice_parser* parser) -{ - ASSERT(parser && parser->sun_key); - return &parser->sun; -} - -void -solstice_parser_entity_iterator_begin - (struct solstice_parser* parser, - struct solstice_entity_iterator* it) -{ - ASSERT(parser && it); - htable_str2sols_begin(&parser->str2entities, &it->it__); -} - -void -solstice_parser_entity_iterator_end - (struct solstice_parser* parser, - struct solstice_entity_iterator* it) -{ - ASSERT(parser && it); - htable_str2sols_end(&parser->str2entities, &it->it__); -} - -void -solstice_parser_material_iterator_begin - (struct solstice_parser* parser, struct solstice_material_iterator* it) -{ - ASSERT(parser && it); - it->mtls__ = darray_material_cdata_get(&parser->mtls); - it->imtl__ = 0; -} - -void -solstice_parser_material_iterator_end - (struct solstice_parser* parser, struct solstice_material_iterator* it) -{ - ASSERT(parser && it); - it->mtls__ = darray_material_cdata_get(&parser->mtls); - it->imtl__ = darray_material_size_get(&parser->mtls); -} - -void -solstice_parser_geometry_iterator_begin - (struct solstice_parser* parser, struct solstice_geometry_iterator* it) -{ - ASSERT(parser && it); - it->geoms__ = darray_geometry_cdata_get(&parser->geometries); - it->igeom__ = 0; -} - -void -solstice_parser_geometry_iterator_end - (struct solstice_parser* parser, struct solstice_geometry_iterator* it) -{ - ASSERT(parser && it); - it->geoms__ = darray_geometry_cdata_get(&parser->geometries); - it->igeom__ = darray_geometry_size_get(&parser->geometries); -} - diff --git a/src/parser/solstice_parser.h b/src/parser/solstice_parser.h @@ -1,289 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_PARSER_H -#define SOLSTICE_PARSER_H - -#include "solstice_entity.h" -#include <rsys/rsys.h> - -struct mem_allocator; -struct solstice_parser; - -struct solstice_entity_iterator { - struct htable_str2sols_iterator it__; /* Internal data */ -}; - -struct solstice_material_iterator { - /* Internal data */ - const struct solstice_material* mtls__; - size_t imtl__; -}; - -struct solstice_geometry_iterator { - /* Internal data */ - const struct solstice_geometry* geoms__; - size_t igeom__; -}; - -/******************************************************************************* - * Solstice parser API. - ******************************************************************************/ -extern LOCAL_SYM res_T -solstice_parser_create - (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ - struct solstice_parser** parser); - -extern LOCAL_SYM void -solstice_parser_ref_get - (struct solstice_parser* parser); - -extern LOCAL_SYM void -solstice_parser_ref_put - (struct solstice_parser* parser); - -extern LOCAL_SYM res_T -solstice_parser_setup - (struct solstice_parser* parser, - const char* stream_name, /* May be NULL */ - FILE* stream); - -/* Return RES_BAD_OP if there is no more YAML document to parse */ -extern LOCAL_SYM res_T -solstice_parser_load - (struct solstice_parser* parser); - -/* Return NULL if no entity is found */ -extern LOCAL_SYM const struct solstice_anchor* -solstice_parser_find_anchor - (struct solstice_parser* parser, - const char* anchor_name); - -/* Return NULL if no entity is found */ -extern LOCAL_SYM const struct solstice_entity* -solstice_parser_find_entity - (struct solstice_parser* parser, - const char* entity_name); - -extern LOCAL_SYM const struct solstice_anchor* -solstice_parser_get_anchor - (const struct solstice_parser* parser, - const struct solstice_anchor_id anchor); - -extern LOCAL_SYM const struct solstice_entity* -solstice_parser_get_entity - (const struct solstice_parser* parser, - const struct solstice_entity_id entity); - -extern LOCAL_SYM const struct solstice_geometry* -solstice_parser_get_geometry - (const struct solstice_parser* parser, - const struct solstice_geometry_id geom); - -extern LOCAL_SYM const struct solstice_material* -solstice_parser_get_material - (const struct solstice_parser* parser, - const struct solstice_material_id mtl); - -extern LOCAL_SYM const struct solstice_material_double_sided* -solstice_parser_get_material_double_sided - (const struct solstice_parser* parser, - const struct solstice_material_double_sided_id mtl2); - -extern LOCAL_SYM const struct solstice_material_matte* -solstice_parser_get_material_matte - (const struct solstice_parser* parser, - const struct solstice_material_matte_id matte); - -extern LOCAL_SYM const struct solstice_material_mirror* -solstice_parser_get_material_mirror - (const struct solstice_parser* parser, - const struct solstice_material_mirror_id mirror); - -extern LOCAL_SYM const struct solstice_object* -solstice_parser_get_object - (const struct solstice_parser* parser, - const struct solstice_object_id obj); - -extern LOCAL_SYM const struct solstice_pivot* -solstice_parser_get_pivot - (const struct solstice_parser* parser, - const struct solstice_pivot_id pivot); - -extern LOCAL_SYM const struct solstice_shape* -solstice_parser_get_shape - (const struct solstice_parser* parser, - const struct solstice_shape_id shape); - -extern LOCAL_SYM const struct solstice_shape_cuboid* -solstice_parser_get_shape_cuboid - (const struct solstice_parser* parser, - const struct solstice_shape_cuboid_id cuboid); - -extern LOCAL_SYM const struct solstice_shape_cylinder* -solstice_parser_get_shape_cylinder - (const struct solstice_parser* parser, - const struct solstice_shape_cylinder_id cylinder); - -extern LOCAL_SYM const struct solstice_shape_imported_geometry* -solstice_parser_get_shape_obj - (const struct solstice_parser* parser, - const struct solstice_shape_imported_geometry_id impgeom); - -extern LOCAL_SYM const struct solstice_shape_paraboloid* -solstice_parser_get_shape_parabol - (const struct solstice_parser* parser, - const struct solstice_shape_paraboloid_id paraboloid); - -extern LOCAL_SYM const struct solstice_shape_paraboloid* -solstice_parser_get_shape_parabolic_cylinder - (const struct solstice_parser* parser, - const struct solstice_shape_paraboloid_id paraboloid); - -extern LOCAL_SYM const struct solstice_shape_plane* -solstice_parser_get_shape_plane - (const struct solstice_parser* parser, - const struct solstice_shape_plane_id plane); - -extern LOCAL_SYM const struct solstice_shape_sphere* -solstice_parser_get_shape_sphere - (const struct solstice_parser* parser, - const struct solstice_shape_sphere_id sphere); - -extern LOCAL_SYM const struct solstice_shape_imported_geometry* -solstice_parser_get_shape_stl - (const struct solstice_parser* parser, - const struct solstice_shape_imported_geometry_id impgeom); - -extern LOCAL_SYM const struct solstice_sun* -solstice_parser_get_sun - (const struct solstice_parser* parser); - -/******************************************************************************* - * Entity interator - ******************************************************************************/ -extern LOCAL_SYM void -solstice_parser_entity_iterator_begin - (struct solstice_parser* parser, - struct solstice_entity_iterator* it); - -extern LOCAL_SYM void -solstice_parser_entity_iterator_end - (struct solstice_parser* parser, - struct solstice_entity_iterator* it); - -static FINLINE void -solstice_entity_iterator_next(struct solstice_entity_iterator* it) -{ - ASSERT(it); - htable_str2sols_iterator_next(&it->it__); -} - -static FINLINE int -solstice_entity_iterator_eq - (const struct solstice_entity_iterator* a, - const struct solstice_entity_iterator* b) -{ - ASSERT(a && b); - return htable_str2sols_iterator_eq(&a->it__, &b->it__); -} - -static FINLINE struct solstice_entity_id -solstice_entity_iterator_get(struct solstice_entity_iterator* it) -{ - struct solstice_entity_id id; - ASSERT(it); - id.i = *htable_str2sols_iterator_data_get(&it->it__); - return id; -} - -/******************************************************************************* - * Material iterator - ******************************************************************************/ -extern LOCAL_SYM void -solstice_parser_material_iterator_begin - (struct solstice_parser* parser, - struct solstice_material_iterator* it); - -extern LOCAL_SYM void -solstice_parser_material_iterator_end - (struct solstice_parser* parser, - struct solstice_material_iterator* it); - -static FINLINE void -solstice_material_iterator_next(struct solstice_material_iterator* it) -{ - ASSERT(it); - ++it->imtl__; -} - -static FINLINE int -solstice_material_iterator_eq - (const struct solstice_material_iterator* a, - const struct solstice_material_iterator* b) -{ - ASSERT(a && b); - return a->mtls__ == b->mtls__ && a->imtl__ == b->imtl__; -} - -static FINLINE struct solstice_material_id -solstice_material_iterator_get(struct solstice_material_iterator* it) -{ - struct solstice_material_id id; - ASSERT(it); - id.i = it->imtl__; - return id; -} - -/******************************************************************************* - * Geometry iterator - ******************************************************************************/ -extern LOCAL_SYM void -solstice_parser_geometry_iterator_begin - (struct solstice_parser* parser, - struct solstice_geometry_iterator* it); - -extern LOCAL_SYM void -solstice_parser_geometry_iterator_end - (struct solstice_parser* parser, - struct solstice_geometry_iterator* it); - -static FINLINE void -solstice_geometry_iterator_next(struct solstice_geometry_iterator* it) -{ - ASSERT(it); - ++it->igeom__; -} - -static FINLINE int -solstice_geometry_iterator_eq - (const struct solstice_geometry_iterator* a, - const struct solstice_geometry_iterator* b) -{ - ASSERT(a && b); - return a->geoms__ == b->geoms__ && a->igeom__ == b->igeom__; -} - -static FINLINE struct solstice_geometry_id -solstice_geometry_iterator_get(struct solstice_geometry_iterator* it) -{ - struct solstice_geometry_id id; - ASSERT(it); - id.i = it->igeom__; - return id; -} - -#endif /* SOLSTICE_PARSER_H */ - diff --git a/src/parser/solstice_pivot.h b/src/parser/solstice_pivot.h @@ -1,84 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_PIVOT_H -#define SOLSTICE_PIVOT_H - -#include <rsys/double3.h> - -enum solstice_target_type { - SOLSTICE_TARGET_ANCHOR, - SOLSTICE_TARGET_DIRECTION, - SOLSTICE_TARGET_POSITION, - SOLSTICE_TARGET_SUN -}; - -struct solstice_anchor_id { size_t i; }; - -struct solstice_anchor { - struct str name; - double position[3]; -}; - -static INLINE void -solstice_anchor_init - (struct mem_allocator* allocator, struct solstice_anchor* anchor) -{ - ASSERT(anchor); - str_init(allocator, &anchor->name); -} - -static INLINE void -solstice_anchor_release(struct solstice_anchor* anchor) -{ - ASSERT(anchor); - str_release(&anchor->name); -} - -static INLINE res_T -solstice_anchor_copy - (struct solstice_anchor* dst, const struct solstice_anchor* src) -{ - ASSERT(dst && src); - d3_set(dst->position, src->position); - return str_copy(&dst->name, &src->name); -} - -static INLINE res_T -solstice_anchor_copy_and_release - (struct solstice_anchor* dst, struct solstice_anchor* src) -{ - ASSERT(dst && src); - d3_set(dst->position, src->position); - return str_copy_and_release(&dst->name, &src->name); -} - -struct solstice_pivot { - double point[3]; - double normal[3]; - double rotation[3]; - double translation[3]; - enum solstice_target_type target_type; - union { - double position[3]; /* World space position */ - double direction[3]; /* World space direction */ - struct solstice_anchor_id anchor; - } target; -}; - -struct solstice_pivot_id { size_t i; }; - -#endif /* SOLSTICE_PIVOT_H */ - diff --git a/src/parser/solstice_shape.h b/src/parser/solstice_shape.h @@ -1,260 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_SHAPE_H -#define SOLSTICE_SHAPE_H - -#include "solstice_material.h" - -#include <rsys/dynamic_array_double.h> -#include <rsys/str.h> - -enum solstice_clip_op { - SOLSTICE_CLIP_OP_AND, - SOLSTICE_CLIP_OP_SUB -}; - -enum solstice_shape_type { - SOLSTICE_SHAPE_CUBOID, - SOLSTICE_SHAPE_CYLINDER, - SOLSTICE_SHAPE_OBJ, /* Imported Alias Wavefront obj */ - SOLSTICE_SHAPE_PARABOL, - SOLSTICE_SHAPE_PARABOLIC_CYLINDER, - SOLSTICE_SHAPE_PLANE, - SOLSTICE_SHAPE_SPHERE, - SOLSTICE_SHAPE_STL /* Imported STereo Lithography */ -}; - -/******************************************************************************* - * Clipping polygon - ******************************************************************************/ -struct solstice_polyclip { - enum solstice_clip_op op; - struct darray_double vertices; -}; - -static INLINE void -solstice_polyclip_init - (struct mem_allocator* allocator, - struct solstice_polyclip* polyclip) -{ - ASSERT(polyclip); - darray_double_init(allocator, &polyclip->vertices); -} - -static INLINE void -solstice_polyclip_release(struct solstice_polyclip* polyclip) -{ - ASSERT(polyclip); - darray_double_release(&polyclip->vertices); -} - -static INLINE res_T -solstice_polyclip_copy - (struct solstice_polyclip* dst, const struct solstice_polyclip* src) -{ - ASSERT(dst && src); - dst->op = src->op; - return darray_double_copy(&dst->vertices, &src->vertices); -} - -static INLINE res_T -solstice_polyclip_copy_and_release - (struct solstice_polyclip* dst, struct solstice_polyclip* src) -{ - ASSERT(dst && src); - dst->op = src->op; - return darray_double_copy_and_release(&dst->vertices, &src->vertices); -} - -/* Declare the array of clipping polygons */ -#define DARRAY_NAME polyclip -#define DARRAY_DATA struct solstice_polyclip -#define DARRAY_FUNCTOR_INIT solstice_polyclip_init -#define DARRAY_FUNCTOR_RELEASE solstice_polyclip_release -#define DARRAY_FUNCTOR_COPY solstice_polyclip_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE solstice_polyclip_copy_and_release -#include <rsys/dynamic_array.h> - -/******************************************************************************* - * Imported geometry shape - ******************************************************************************/ -struct solstice_shape_imported_geometry { - struct str filename; -}; - -static INLINE void -solstice_shape_imported_geometry_init - (struct mem_allocator* allocator, - struct solstice_shape_imported_geometry* impgeom) -{ - ASSERT(impgeom); - str_init(allocator, &impgeom->filename); -} - -static INLINE void -solstice_shape_imported_geometry_release - (struct solstice_shape_imported_geometry* impgeom) -{ - ASSERT(impgeom); - str_release(&impgeom->filename); -} - -static INLINE res_T -solstice_shape_imported_geometry_copy - (struct solstice_shape_imported_geometry* dst, - const struct solstice_shape_imported_geometry* src) -{ - ASSERT(dst && src); - return str_copy(&dst->filename, &src->filename); -} - -static INLINE res_T -solstice_shape_imported_geometry_copy_and_release - (struct solstice_shape_imported_geometry* dst, - struct solstice_shape_imported_geometry* src) -{ - ASSERT(dst && src); - return str_copy_and_release(&dst->filename, &src->filename); -} - -/******************************************************************************* - * Paraboloid shape - ******************************************************************************/ -struct solstice_shape_paraboloid { - double focal; - struct darray_polyclip polyclips; -}; - -static INLINE void -solstice_shape_paraboloid_init - (struct mem_allocator* allocator, - struct solstice_shape_paraboloid* paraboloid) -{ - ASSERT(paraboloid); - darray_polyclip_init(allocator, &paraboloid->polyclips); -} - -static INLINE void -solstice_shape_paraboloid_release(struct solstice_shape_paraboloid* paraboloid) -{ - ASSERT(paraboloid); - darray_polyclip_release(&paraboloid->polyclips); -} - -static INLINE res_T -solstice_shape_paraboloid_copy - (struct solstice_shape_paraboloid* dst, - const struct solstice_shape_paraboloid* src) -{ - ASSERT(dst && src); - dst->focal = src->focal; - return darray_polyclip_copy(&dst->polyclips, &src->polyclips); -} - -static INLINE res_T -solstice_shape_paraboloid_copy_and_release - (struct solstice_shape_paraboloid* dst, - struct solstice_shape_paraboloid* src) -{ - ASSERT(dst && src); - dst->focal = src->focal; - return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); -} - -/******************************************************************************* - * Plane shape - ******************************************************************************/ -struct solstice_shape_plane { - struct darray_polyclip polyclips; -}; - -static INLINE void -solstice_shape_plane_init - (struct mem_allocator* allocator, - struct solstice_shape_plane* plane) -{ - ASSERT(plane); - darray_polyclip_init(allocator, &plane->polyclips); -} - -static INLINE void -solstice_shape_plane_release(struct solstice_shape_plane* plane) -{ - ASSERT(plane); - darray_polyclip_release(&plane->polyclips); -} - -static INLINE res_T -solstice_shape_plane_copy - (struct solstice_shape_plane* dst, - const struct solstice_shape_plane* src) -{ - ASSERT(dst && src); - return darray_polyclip_copy(&dst->polyclips, &src->polyclips); -} - -static INLINE res_T -solstice_shape_plane_copy_and_release - (struct solstice_shape_plane* dst, - struct solstice_shape_plane* src) -{ - ASSERT(dst && src); - return darray_polyclip_copy_and_release(&dst->polyclips, &src->polyclips); -} - -/******************************************************************************* - * POD shape data - ******************************************************************************/ -struct solstice_shape_cuboid { - double size[3]; /* Size along the X, Y and Z dimension */ -}; - -struct solstice_shape_cylinder { - double height; - double radius; - long nslices; -}; - -struct solstice_shape_sphere { - double radius; - long nslices; -}; - -struct solstice_shape_cuboid_id { size_t i; }; -struct solstice_shape_cylinder_id { size_t i; }; -struct solstice_shape_imported_geometry_id { size_t i; }; -struct solstice_shape_paraboloid_id { size_t i; }; -struct solstice_shape_plane_id { size_t i; }; -struct solstice_shape_sphere_id { size_t i; }; - -struct solstice_shape { - enum solstice_shape_type type; - union { - struct solstice_shape_cuboid_id cuboid; - struct solstice_shape_cylinder_id cylinder; - struct solstice_shape_imported_geometry_id obj; - struct solstice_shape_paraboloid_id parabol; - struct solstice_shape_paraboloid_id parabolic_cylinder; - struct solstice_shape_plane_id plane; - struct solstice_shape_sphere_id sphere; - struct solstice_shape_imported_geometry_id stl; - } data; -}; - -struct solstice_shape_id { size_t i; }; - -#endif /* SOLSTICE_SHAPE_H */ - diff --git a/src/parser/solstice_sun.h b/src/parser/solstice_sun.h @@ -1,88 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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/>. */ - -#ifndef SOLSTICE_SUN_H -#define SOLSTICE_SUN_H - -#include <rsys/dynamic_array.h> - -enum solstice_sun_radang_distrib_type { /* Radial Angular distribution */ - SOLSTICE_SUN_RADANG_DISTRIB_BUIE, - SOLSTICE_SUN_RADANG_DISTRIB_DIRECTIONAL, - SOLSTICE_SUN_RADANG_DISTRIB_PILLBOX -}; - -struct solstice_spectrum_data { - double wavelength; - double data; -}; - -#define DARRAY_NAME spectrum_data -#define DARRAY_DATA struct solstice_spectrum_data -#include <rsys/dynamic_array.h> - -struct solstice_sun_buie { double csr; }; -struct solstice_sun_pillbox { double aperture; }; - -struct solstice_sun { - double dni; /* In ]0, INF) */ - struct darray_spectrum_data spectrum; - enum solstice_sun_radang_distrib_type radang_distrib_type; - union { - struct solstice_sun_buie buie; - struct solstice_sun_pillbox pillbox; - } radang_distrib; -}; - -static INLINE void -solstice_sun_init(struct mem_allocator* allocator, struct solstice_sun* sun) -{ - ASSERT(sun); - sun->dni = 1.0; - sun->radang_distrib_type = SOLSTICE_SUN_RADANG_DISTRIB_DIRECTIONAL; - darray_spectrum_data_init(allocator, &sun->spectrum); -} - -static INLINE void -solstice_sun_release(struct solstice_sun* sun) -{ - ASSERT(sun); - darray_spectrum_data_release(&sun->spectrum); -} - -static INLINE res_T -solstice_sun_copy(struct solstice_sun* dst, const struct solstice_sun* src) -{ - ASSERT(dst && src); - return darray_spectrum_data_copy(&dst->spectrum, &src->spectrum); -} - -static INLINE res_T -solstice_sun_copy_and_release - (struct solstice_sun* dst, struct solstice_sun* src) -{ - ASSERT(dst && src); - return darray_spectrum_data_copy_and_release(&dst->spectrum, &src->spectrum); -} - -static INLINE void -solstice_sun_clear(struct solstice_sun* sun) -{ - ASSERT(sun); - darray_spectrum_data_clear(&sun->spectrum); -} - -#endif /* SOLSTICE_SUN_H */ - diff --git a/src/parser/test_solparser.c b/src/parser/test_solparser.c @@ -0,0 +1,80 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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 "solparser.h" +#include "test_solstice_utils.h" + +#include <string.h> + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + int ifile = 1; + int i; + res_T load_res = RES_OK; + (void)argc, (void)argv; + + if(argc > 1) { + if(!strcmp(argv[1], "-e")) { + load_res = RES_BAD_ARG; + ifile = 2; + } else if(!strcmp(argv[1], "-h")) { + printf("Usage: %s [OPTIONS] [FILE ... ]\n", argv[0]); + printf( +"Check the parser API and that the submitted FILEs are valid. Use the `-e'\n" +"option to check that the FILEs are invalid.\n\n"); + printf("OPTIONS:\n"); + printf(" -h print this help and exit.\n"); + printf(" -e check that the submitted FILEs have errors.\n"); + return 0; + } + } + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + solparser_create(&allocator, &parser); + + CHECK(solparser_setup(parser, NULL, tmpfile()), RES_OK); + CHECK(solparser_setup(parser, "yop", tmpfile()), RES_OK); + CHECK(solparser_load(parser), RES_BAD_OP); /* Empty stream */ + + FOR_EACH(i, ifile, argc) { + FILE* file = fopen(argv[i], "rb"); + int count = 0; + NCHECK(file, NULL); + CHECK(solparser_setup(parser, argv[i], file), RES_OK); + for(;;) { + const res_T res = solparser_load(parser); + if(count == 0 && load_res == RES_OK) { + CHECK(res, RES_OK); + } else if(res == RES_BAD_OP) { + break; + } + CHECK(res, load_res); + ++count; + } + fclose(file); + } + + solparser_ref_get(parser); + solparser_ref_put(parser); + solparser_ref_put(parser); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/parser/test_solparser2.c b/src/parser/test_solparser2.c @@ -0,0 +1,215 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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 "solparser.h" +#include "solparser_sun.h" +#include "test_solstice_utils.h" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + struct solparser_entity_iterator it, end; + struct solparser_geometry_iterator geom_it, geom_it_end; + struct solparser_material_iterator mtl_it, mtl_it_end; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + struct solparser_geometry_id geom_id; + const struct solparser_geometry* geoms[2] = { NULL, NULL }; + const struct solparser_material* mtls[2] = { NULL, NULL }; + const struct solparser_entity* entity, *entity1a, *entity1b, *entity2, *entity3; + const struct solparser_geometry* geom; + const struct solparser_object* obj; + const struct solparser_shape* shape; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material* mtl; + const struct solparser_material_matte* matte; + const struct solparser_material_mirror* mirror; + const struct solparser_shape_sphere* sphere; + const struct solparser_sun* sun; + size_t nmtls = 0; + size_t ngeoms = 0; + double tmp[3]; + FILE* stream; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + solparser_create(&allocator, &parser); + + stream = tmpfile(); + NCHECK(stream, NULL); + + fprintf(stream, "- geometry: &sphere\n"); + fprintf(stream, " - sphere: { radius: 1 }\n"); + fprintf(stream, " material: { matte: { reflectivity: 1 } }\n"); + fprintf(stream, "- entity:\n"); + fprintf(stream, " name: lvl 0\n"); + fprintf(stream, " geometry: *sphere\n"); + fprintf(stream, " transform: { translation: [1,2,3], rotation: [4,5,6]}\n"); + fprintf(stream, " children:\n"); + fprintf(stream, " - name: lvl1a\n"); + fprintf(stream, " geometry: \n"); + fprintf(stream, " - sphere: {radius: 2}\n"); + fprintf(stream, " material:\n"); + fprintf(stream, " mirror: { reflectivity: 0.9, roughness: 0.1 }\n"); + fprintf(stream, " - name: lvl1b\n"); + fprintf(stream, " geometry: *sphere\n"); + fprintf(stream, " transform: { rotation: [3.14, 0, -1] }\n"); + fprintf(stream, " children:\n"); + fprintf(stream, " - name: lvl2\n"); + fprintf(stream, " geometry: *sphere\n"); + fprintf(stream, "- sun:\n"); + fprintf(stream, " dni: 1\n"); + fprintf(stream, " spectrum: [ { wavelength: 1, data: 1} ]\n"); + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_geometry_iterator_begin(parser, &geom_it); + solparser_geometry_iterator_end(parser, &geom_it_end); + ngeoms = 0; + while(!solparser_geometry_iterator_eq(&geom_it, &geom_it_end)) { + CHECK(ngeoms < 2, 1); + geom_id = solparser_geometry_iterator_get(&geom_it); + solparser_geometry_iterator_next(&geom_it); + geoms[ngeoms] = solparser_get_geometry(parser, geom_id); + ++ngeoms; + } + CHECK(ngeoms, 2); + + solparser_material_iterator_begin(parser, &mtl_it); + solparser_material_iterator_end(parser, &mtl_it_end); + nmtls = 0; + while(!solparser_material_iterator_eq(&mtl_it, &mtl_it_end)) { + struct solparser_material_id mtl_id; + CHECK(nmtls < 2, 1); + mtl_id = solparser_material_iterator_get(&mtl_it); + solparser_material_iterator_next(&mtl_it); + mtls[nmtls] = solparser_get_material(parser, mtl_id); + ++nmtls; + } + CHECK(nmtls, 2); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &end); + CHECK(solparser_entity_iterator_eq(&it, &end), 0); + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + + CHECK(strcmp("lvl 0", str_cget(&entity->name)), 0); + CHECK(solparser_entity_get_children_count(entity), 2); + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + geom_id = entity->data.geometry; + geom = solparser_get_geometry(parser, entity->data.geometry); + CHECK(geom == geoms[0] || geom == geoms[1], 1); + CHECK(solparser_geometry_get_objects_count(geom), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + sphere = solparser_get_shape_sphere(parser, shape->data.sphere); + CHECK(sphere->radius, 1); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl == mtls[0] || mtl == mtls[1], 1); + CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE); + matte = solparser_get_material_matte(parser, mtl->data.matte); + CHECK(matte->reflectivity, 1); + + entity_id = solparser_entity_get_child(entity, 0); + entity1a = solparser_get_entity(parser, entity_id); + CHECK(d3_eq(entity1a->translation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity1a->rotation, d3_splat(tmp, 0)), 1); + CHECK(strcmp("lvl1a", str_cget(&entity1a->name)), 0); + CHECK(solparser_entity_get_children_count(entity1a), 0); + CHECK(entity1a->type, SOLPARSER_ENTITY_GEOMETRY); + NCHECK(entity1a->data.geometry.i, geom_id.i); + geom = solparser_get_geometry(parser, entity1a->data.geometry); + CHECK(geom == geoms[0] || geom == geoms[1], 1); + CHECK(solparser_geometry_get_objects_count(geom), 1); + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_SPHERE); + sphere = solparser_get_shape_sphere(parser, shape->data.sphere); + CHECK(sphere->radius, 2); + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl == mtls[0] || mtl == mtls[1], 1); + CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR); + mirror = solparser_get_material_mirror(parser, mtl->data.mirror); + CHECK(mirror->reflectivity, 0.9); + CHECK(mirror->roughness, 0.1); + + entity_id = solparser_entity_get_child(entity, 1); + entity1b = solparser_get_entity(parser, entity_id); + CHECK(d3_eq(entity1b->translation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity1b->rotation, d3(tmp, 3.14, 0, -1)), 1); + CHECK(strcmp("lvl1b", str_cget(&entity1b->name)), 0); + CHECK(solparser_entity_get_children_count(entity1b), 1); + CHECK(entity1b->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(entity1b->data.geometry.i, geom_id.i); + + entity_id = solparser_entity_get_child(entity1b, 0); + entity2 = solparser_get_entity(parser, entity_id); + CHECK(d3_eq(entity2->translation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity2->rotation, d3_splat(tmp, 0)), 1); + CHECK(strcmp("lvl2", str_cget(&entity2->name)), 0); + CHECK(solparser_entity_get_children_count(entity2), 0); + CHECK(entity2->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(entity2->data.geometry.i, geom_id.i); + + entity3 = solparser_find_entity(parser, "lvl 0"); + CHECK(entity3, entity); + entity3 = solparser_find_entity(parser, "lvl1a"); + CHECK(entity3, NULL); + entity3 = solparser_find_entity(parser, "lvl 0.lvl1a"); + CHECK(entity3, entity1a); + entity3 = solparser_find_entity(parser, "lvl 0.lvl1b"); + CHECK(entity3, entity1b); + entity3 = solparser_find_entity(parser, "lvl 0.lvl1b.lvl2"); + CHECK(entity3, entity2); + entity3 = solparser_find_entity(parser,"lvl 0.lvl1b.bad_name"); + CHECK(entity3, NULL); + + sun = solparser_get_sun(parser); + NCHECK(sun, NULL); + CHECK(sun->dni, 1.0); + CHECK(sun->radang_distrib_type, SOLPARSER_SUN_RADANG_DISTRIB_DIRECTIONAL); + CHECK(darray_spectrum_data_size_get(&sun->spectrum), 1); + CHECK(darray_spectrum_data_cdata_get(&sun->spectrum)[0].wavelength, 1.0); + CHECK(darray_spectrum_data_cdata_get(&sun->spectrum)[0].data, 1.0); + + CHECK(solparser_load(parser), RES_BAD_OP); + solparser_ref_put(parser); + + fclose(stream); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} + diff --git a/src/parser/test_solparser3.c b/src/parser/test_solparser3.c @@ -0,0 +1,246 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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 "solparser.h" +#include "test_solstice_utils.h" + +static const char* input[] = { + "- material: &lambertian\n", + " matte: { reflectivity: 0.5 }\n", + "- geometry: &cylinder\n", + " - cylinder: { radius: 1, height: 10, slices: 128 }\n", + " material: *lambertian\n", + "- sun: \n", + " dni: 1\n", + " spectrum: [{wavelength: 1, data: 1}]\n", + "- entity:\n", + " name: entity0\n", + " geometry: *cylinder\n", + " anchors:\n", + " - name: anchor0\n", + " position: [1, 2, 3]\n", + " - name: anchor1\n", + " position: [4, 5, 6]\n", + " children:\n", + " - name: entity0a\n", + " geometry: *cylinder\n", + " - name: entity0b\n", + " geometry: *cylinder\n", + " anchors:\n\n", + " - name: anchor0\n", + " position: [4, 5, 6]\n", + " - name: entity0b\n", + " position: [7, 8, 9]\n", + "- entity:\n", + " name: entity1\n", + " pivot:\n", + " point: [1, 2, 3]\n", + " normal: [4, 5, 6]\n", + " target: { anchor: \"entity0.entity0b.anchor0\" }\n", + NULL +}; + +const struct solparser_anchor* entity0_anchor0; +const struct solparser_anchor* entity0_anchor1; +const struct solparser_anchor* entity0_entity0b_anchor0; +const struct solparser_anchor* entity0_entity0b_entity0b; +const struct solparser_geometry* geom; +const struct solparser_pivot* pivot; + +static void +check_entity0 + (struct solparser* parser, const struct solparser_entity* entity0) +{ + struct solparser_anchor_id anchor_id; + struct solparser_entity_id entity_id; + struct solparser_object_id obj_id; + const struct solparser_entity *entity0a, *entity0b; + const struct solparser_material_matte* matte; + const struct solparser_material* mtl; + const struct solparser_material_double_sided* mtl2; + const struct solparser_object* obj; + const struct solparser_shape* shape; + const struct solparser_shape_cylinder* cylinder; + double tmp[3]; + + NCHECK(parser, NULL); + NCHECK(entity0, NULL); + + CHECK(strcmp(str_cget(&entity0->name), "entity0"), 0); + CHECK(d3_eq(entity0->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity0->translation, d3_splat(tmp, 0)), 1); + CHECK(entity0->type, SOLPARSER_ENTITY_GEOMETRY); + + geom = solparser_get_geometry(parser, entity0->data.geometry); + CHECK(solparser_geometry_get_objects_count(geom), 1); + + obj_id = solparser_geometry_get_object(geom, 0); + obj = solparser_get_object(parser, obj_id); + CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); + + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_CYLINDER); + + cylinder = solparser_get_shape_cylinder(parser, shape->data.cylinder); + CHECK(cylinder->height, 10); + CHECK(cylinder->radius, 1); + CHECK(cylinder->nslices, 128); + + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_MATTE); + + matte = solparser_get_material_matte(parser, mtl->data.matte); + CHECK(matte->reflectivity, 0.5); + + CHECK(solparser_entity_get_children_count(entity0), 2); + CHECK(solparser_entity_get_anchors_count(entity0), 2); + + anchor_id = solparser_entity_get_anchor(entity0, 0); + entity0_anchor0 = solparser_get_anchor(parser, anchor_id); + CHECK(strcmp(str_cget(&entity0_anchor0->name), "anchor0"), 0); + CHECK(d3_eq(entity0_anchor0->position, d3(tmp, 1, 2, 3)), 1); + + anchor_id = solparser_entity_get_anchor(entity0, 1); + entity0_anchor1 = solparser_get_anchor(parser, anchor_id); + CHECK(strcmp(str_cget(&entity0_anchor1->name), "anchor1"), 0); + CHECK(d3_eq(entity0_anchor1->position, d3(tmp, 4, 5, 6)), 1); + + entity_id = solparser_entity_get_child(entity0, 0); + entity0a = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity0a->name), "entity0a"), 0); + CHECK(entity0a->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(entity0->data.geometry.i, entity0a->data.geometry.i); + CHECK(solparser_entity_get_anchors_count(entity0a), 0); + CHECK(solparser_entity_get_children_count(entity0a), 0); + + entity_id = solparser_entity_get_child(entity0, 1); + entity0b = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity0b->name), "entity0b"), 0); + CHECK(entity0b->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(entity0->data.geometry.i, entity0b->data.geometry.i); + CHECK(solparser_entity_get_anchors_count(entity0b), 2); + CHECK(solparser_entity_get_children_count(entity0b), 0); + + anchor_id = solparser_entity_get_anchor(entity0b, 0); + entity0_entity0b_anchor0 = solparser_get_anchor(parser, anchor_id); + CHECK(strcmp(str_cget(&entity0_entity0b_anchor0->name), "anchor0"), 0); + CHECK(d3_eq(entity0_entity0b_anchor0->position, d3(tmp, 4, 5, 6)), 1); + + anchor_id = solparser_entity_get_anchor(entity0b, 1); + entity0_entity0b_entity0b = solparser_get_anchor(parser, anchor_id); + CHECK(strcmp(str_cget(&entity0_entity0b_entity0b->name), "entity0b"), 0); + CHECK(d3_eq(entity0_entity0b_entity0b->position, d3(tmp, 7, 8, 9)), 1); +} + +static void +check_entity1 + (struct solparser* parser, const struct solparser_entity* entity1) +{ + double tmp[3]; + + NCHECK(parser, NULL); + NCHECK(entity1, NULL); + + CHECK(strcmp(str_cget(&entity1->name), "entity1"), 0); + CHECK(entity1->type, SOLPARSER_ENTITY_PIVOT); + CHECK(solparser_entity_get_anchors_count(entity1), 0); + CHECK(solparser_entity_get_children_count(entity1), 0); + + pivot = solparser_get_pivot(parser, entity1->data.pivot); + CHECK(d3_eq(pivot->point, d3(tmp, 1, 2, 3)), 1); + CHECK(d3_eq(pivot->normal, d3(tmp, 4, 5, 6)), 1); + CHECK(pivot->target_type, SOLPARSER_TARGET_ANCHOR); +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct solparser* parser; + struct solparser_entity_iterator it, it_end; + const struct solparser_anchor* anchor; + FILE* stream; + size_t i; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + solparser_create(&allocator, &parser); + + stream = tmpfile(); + NCHECK(stream, NULL); + i = 0; + while(input[i]) { + const size_t len = strlen(input[i]); + CHECK(fwrite(input[i], 1, len, stream), len); + ++i; + } + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &it_end); + CHECK(solparser_entity_iterator_eq(&it, &it_end), 0); + + while(!solparser_entity_iterator_eq(&it, &it_end)) { + struct solparser_entity_id entity_id; + const struct solparser_entity* entity; + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + if(!strcmp(str_cget(&entity->name), "entity0")) { + check_entity0(parser, entity); + } else if(!strcmp(str_cget(&entity->name), "entity1")) { + check_entity1(parser, entity); + } else { + FATAL("Unexpected entity name.\n"); + } + + solparser_entity_iterator_next(&it); + } + + anchor = solparser_get_anchor(parser, pivot->target.anchor); + CHECK(anchor, entity0_entity0b_anchor0); + + anchor = solparser_find_anchor(parser, "entity0"); + CHECK(anchor, NULL); + anchor = solparser_find_anchor(parser, "entity0.anchor0"); + CHECK(anchor, entity0_anchor0); + anchor = solparser_find_anchor(parser, "entity0.anchor1"); + CHECK(anchor, entity0_anchor1); + anchor = solparser_find_anchor(parser, "entity0.entity0a.anchor0"); + CHECK(anchor, NULL); + anchor = solparser_find_anchor(parser, "entity0.entity0b.anchor0"); + CHECK(anchor, entity0_entity0b_anchor0); + anchor = solparser_find_anchor(parser, "entity0.entity0b.entity0b"); + CHECK(anchor, entity0_entity0b_entity0b); + anchor = solparser_find_anchor(parser, "entity1.entity0b.anchor1"); + CHECK(anchor, NULL); + + CHECK(solparser_load(parser), RES_BAD_OP); + solparser_ref_put(parser); + fclose(stream); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/parser/test_solparser4.c b/src/parser/test_solparser4.c @@ -0,0 +1,208 @@ +/* Copyright (C) CNRS 2016 + * + * This program 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. + * + * This program 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 "solparser.h" +#include "test_solstice_utils.h" + +const struct solparser_geometry* geometry; + +static const char* input[] = { + "- sun: \n", + " dni: 1\n", + " spectrum: [{wavelength: 1, data: 1}]\n", + "- material: &lambertian\n", + " mirror: { reflectivity: 0.2, roughness: 0.1 }\n", + "- geometry: &cuboid\n", + " - cuboid: { size: [1, 2, 3] }\n", + " material: *lambertian\n", + "- template: &template\n", + " name: template0\n", + " geometry: *cuboid\n", + "- entity:\n", + " name: entity0\n", + " transform: { translation: [1, 2, 3] }\n", + " children: [ *template ]\n", + "- entity:\n", + " name: entity1\n", + " transform: { translation: [3, 4, 5] }\n", + " children: [ *template ]\n", + NULL +}; + +static void +check_entity0 + (struct solparser* parser, const struct solparser_entity* entity0) +{ + const struct solparser_entity* entity; + struct solparser_entity_id entity_id; + double tmp[3]; + + NCHECK(parser, NULL); + NCHECK(entity0, NULL); + + CHECK(strcmp(str_cget(&entity0->name), "entity0"), 0); + CHECK(d3_eq(entity0->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity0->translation, d3(tmp, 1, 2, 3)), 1); + CHECK(entity0->type, SOLPARSER_ENTITY_EMPTY); + + CHECK(solparser_entity_get_children_count(entity0), 1); + CHECK(solparser_entity_get_anchors_count(entity0), 0); + + entity_id = solparser_entity_get_child(entity0, 0); + entity = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity->name), "template0"), 0); + CHECK(d3_eq(entity->translation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity->rotation, d3_splat(tmp, 0)), 1); + + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(solparser_get_geometry(parser, entity->data.geometry), geometry); + CHECK(solparser_find_entity(parser, "entity0.template0"), entity); +} + +static void +check_entity1 + (struct solparser* parser, const struct solparser_entity* entity1) +{ + const struct solparser_entity* entity; + struct solparser_entity_id entity_id; + double tmp[3]; + + NCHECK(parser, NULL); + NCHECK(entity1, NULL); + + CHECK(strcmp(str_cget(&entity1->name), "entity1"), 0); + CHECK(d3_eq(entity1->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity1->translation, d3(tmp, 3, 4, 5)), 1); + CHECK(entity1->type, SOLPARSER_ENTITY_EMPTY); + + CHECK(solparser_entity_get_children_count(entity1), 1); + CHECK(solparser_entity_get_anchors_count(entity1), 0); + + entity_id = solparser_entity_get_child(entity1, 0); + entity = solparser_get_entity(parser, entity_id); + CHECK(strcmp(str_cget(&entity->name), "template0"), 0); + CHECK(d3_eq(entity->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(entity->translation, d3_splat(tmp, 0)), 1); + + CHECK(entity->type, SOLPARSER_ENTITY_GEOMETRY); + CHECK(solparser_get_geometry(parser, entity->data.geometry), geometry); + CHECK(solparser_find_entity(parser, "entity1.template0"), entity); +} + +int +main(int argc, char** argv) +{ + struct solparser_entity_iterator it, it_end; + struct solparser_geometry_iterator it_geom, it_end_geom; + struct mem_allocator allocator; + struct solparser* parser; + const struct solparser_material* mtl; + const struct solparser_material_double_sided* mtl2; + const struct solparser_material_mirror* mirror; + const struct solparser_object* obj; + const struct solparser_shape* shape; + const struct solparser_shape_cuboid* cuboid; + struct solparser_geometry_id geom_id; + struct solparser_object_id obj_id; + double tmp[3]; + FILE* stream; + size_t i; + int entity0 = 0; + int entity1 = 0; + (void)argc, (void)argv; + + CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); + solparser_create(&allocator, &parser); + + stream = tmpfile(); + NCHECK(stream, NULL); + i = 0; + while(input[i]) { + const size_t len = strlen(input[i]); + CHECK(fwrite(input[i], 1, len, stream), len); + ++i; + } + rewind(stream); + + CHECK(solparser_setup(parser, NULL, stream), RES_OK); + CHECK(solparser_load(parser), RES_OK); + + solparser_geometry_iterator_begin(parser, &it_geom); + solparser_geometry_iterator_end(parser, &it_end_geom); + CHECK(solparser_geometry_iterator_eq(&it_geom, &it_end_geom), 0); + geom_id = solparser_geometry_iterator_get(&it_geom); + geometry = solparser_get_geometry(parser, geom_id); + solparser_geometry_iterator_next(&it_geom); + CHECK(solparser_geometry_iterator_eq(&it_geom, &it_end_geom), 1); + + CHECK(solparser_geometry_get_objects_count(geometry), 1); + obj_id = solparser_geometry_get_object(geometry, 0); + obj = solparser_get_object(parser, obj_id); + CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); + CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); + + mtl2 = solparser_get_material_double_sided(parser, obj->mtl2); + CHECK(mtl2->front.i, mtl2->back.i); + mtl = solparser_get_material(parser, mtl2->front); + CHECK(mtl->type, SOLPARSER_MATERIAL_MIRROR); + mirror = solparser_get_material_mirror(parser, mtl->data.mirror); + CHECK(mirror->reflectivity, 0.2); + CHECK(mirror->roughness, 0.1); + + shape = solparser_get_shape(parser, obj->shape); + CHECK(shape->type, SOLPARSER_SHAPE_CUBOID); + cuboid = solparser_get_shape_cuboid(parser, shape->data.cuboid); + CHECK(cuboid->size[0], 1); + CHECK(cuboid->size[1], 2); + CHECK(cuboid->size[2], 3); + + solparser_entity_iterator_begin(parser, &it); + solparser_entity_iterator_end(parser, &it_end); + CHECK(solparser_entity_iterator_eq(&it, &it_end), 0); + + while(!solparser_entity_iterator_eq(&it, &it_end)) { + struct solparser_entity_id entity_id; + const struct solparser_entity* entity; + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(parser, entity_id); + + if(!strcmp(str_cget(&entity->name), "entity0")) { + CHECK(entity0, 0); + entity0 = 1; + check_entity0(parser, entity); + } else if(!strcmp(str_cget(&entity->name), "entity1")) { + CHECK(entity1, 0); + entity1 = 1; + check_entity1(parser, entity); + } else { + FATAL("Unexpected entity name.\n"); + } + + solparser_entity_iterator_next(&it); + } + CHECK(entity0, 1); + CHECK(entity1, 1); + + CHECK(solparser_load(parser), RES_BAD_OP); + solparser_ref_put(parser); + fclose(stream); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} + diff --git a/src/parser/test_solstice_parser.c b/src/parser/test_solstice_parser.c @@ -1,80 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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 "solstice_parser.h" -#include "test_solstice_utils.h" - -#include <string.h> - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct solstice_parser* parser; - int ifile = 1; - int i; - res_T load_res = RES_OK; - (void)argc, (void)argv; - - if(argc > 1) { - if(!strcmp(argv[1], "-e")) { - load_res = RES_BAD_ARG; - ifile = 2; - } else if(!strcmp(argv[1], "-h")) { - printf("Usage: %s [OPTIONS] [FILE ... ]\n", argv[0]); - printf( -"Check the parser API and that the submitted FILEs are valid. Use the `-e'\n" -"option to check that the FILEs are invalid.\n\n"); - printf("OPTIONS:\n"); - printf(" -h print this help and exit.\n"); - printf(" -e check that the submitted FILEs have errors.\n"); - return 0; - } - } - - CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); - solstice_parser_create(&allocator, &parser); - - CHECK(solstice_parser_setup(parser, NULL, tmpfile()), RES_OK); - CHECK(solstice_parser_setup(parser, "yop", tmpfile()), RES_OK); - CHECK(solstice_parser_load(parser), RES_BAD_OP); /* Empty stream */ - - FOR_EACH(i, ifile, argc) { - FILE* file = fopen(argv[i], "rb"); - int count = 0; - NCHECK(file, NULL); - CHECK(solstice_parser_setup(parser, argv[i], file), RES_OK); - for(;;) { - const res_T res = solstice_parser_load(parser); - if(count == 0 && load_res == RES_OK) { - CHECK(res, RES_OK); - } else if(res == RES_BAD_OP) { - break; - } - CHECK(res, load_res); - ++count; - } - fclose(file); - } - - solstice_parser_ref_get(parser); - solstice_parser_ref_put(parser); - solstice_parser_ref_put(parser); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); - return 0; -} diff --git a/src/parser/test_solstice_parser2.c b/src/parser/test_solstice_parser2.c @@ -1,215 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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 "solstice_parser.h" -#include "solstice_sun.h" -#include "test_solstice_utils.h" - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct solstice_parser* parser; - struct solstice_entity_iterator it, end; - struct solstice_geometry_iterator geom_it, geom_it_end; - struct solstice_material_iterator mtl_it, mtl_it_end; - struct solstice_entity_id entity_id; - struct solstice_object_id obj_id; - struct solstice_geometry_id geom_id; - const struct solstice_geometry* geoms[2] = { NULL, NULL }; - const struct solstice_material* mtls[2] = { NULL, NULL }; - const struct solstice_entity* entity, *entity1a, *entity1b, *entity2, *entity3; - const struct solstice_geometry* geom; - const struct solstice_object* obj; - const struct solstice_shape* shape; - const struct solstice_material_double_sided* mtl2; - const struct solstice_material* mtl; - const struct solstice_material_matte* matte; - const struct solstice_material_mirror* mirror; - const struct solstice_shape_sphere* sphere; - const struct solstice_sun* sun; - size_t nmtls = 0; - size_t ngeoms = 0; - double tmp[3]; - FILE* stream; - (void)argc, (void)argv; - - CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); - solstice_parser_create(&allocator, &parser); - - stream = tmpfile(); - NCHECK(stream, NULL); - - fprintf(stream, "- geometry: &sphere\n"); - fprintf(stream, " - sphere: { radius: 1 }\n"); - fprintf(stream, " material: { matte: { reflectivity: 1 } }\n"); - fprintf(stream, "- entity:\n"); - fprintf(stream, " name: lvl 0\n"); - fprintf(stream, " geometry: *sphere\n"); - fprintf(stream, " transform: { translation: [1,2,3], rotation: [4,5,6]}\n"); - fprintf(stream, " children:\n"); - fprintf(stream, " - name: lvl1a\n"); - fprintf(stream, " geometry: \n"); - fprintf(stream, " - sphere: {radius: 2}\n"); - fprintf(stream, " material:\n"); - fprintf(stream, " mirror: { reflectivity: 0.9, roughness: 0.1 }\n"); - fprintf(stream, " - name: lvl1b\n"); - fprintf(stream, " geometry: *sphere\n"); - fprintf(stream, " transform: { rotation: [3.14, 0, -1] }\n"); - fprintf(stream, " children:\n"); - fprintf(stream, " - name: lvl2\n"); - fprintf(stream, " geometry: *sphere\n"); - fprintf(stream, "- sun:\n"); - fprintf(stream, " dni: 1\n"); - fprintf(stream, " spectrum: [ { wavelength: 1, data: 1} ]\n"); - rewind(stream); - - CHECK(solstice_parser_setup(parser, NULL, stream), RES_OK); - CHECK(solstice_parser_load(parser), RES_OK); - - solstice_parser_geometry_iterator_begin(parser, &geom_it); - solstice_parser_geometry_iterator_end(parser, &geom_it_end); - ngeoms = 0; - while(!solstice_geometry_iterator_eq(&geom_it, &geom_it_end)) { - CHECK(ngeoms < 2, 1); - geom_id = solstice_geometry_iterator_get(&geom_it); - solstice_geometry_iterator_next(&geom_it); - geoms[ngeoms] = solstice_parser_get_geometry(parser, geom_id); - ++ngeoms; - } - CHECK(ngeoms, 2); - - solstice_parser_material_iterator_begin(parser, &mtl_it); - solstice_parser_material_iterator_end(parser, &mtl_it_end); - nmtls = 0; - while(!solstice_material_iterator_eq(&mtl_it, &mtl_it_end)) { - struct solstice_material_id mtl_id; - CHECK(nmtls < 2, 1); - mtl_id = solstice_material_iterator_get(&mtl_it); - solstice_material_iterator_next(&mtl_it); - mtls[nmtls] = solstice_parser_get_material(parser, mtl_id); - ++nmtls; - } - CHECK(nmtls, 2); - - solstice_parser_entity_iterator_begin(parser, &it); - solstice_parser_entity_iterator_end(parser, &end); - CHECK(solstice_entity_iterator_eq(&it, &end), 0); - - entity_id = solstice_entity_iterator_get(&it); - entity = solstice_parser_get_entity(parser, entity_id); - - - CHECK(strcmp("lvl 0", str_cget(&entity->name)), 0); - CHECK(solstice_entity_get_children_count(entity), 2); - CHECK(entity->type, SOLSTICE_ENTITY_GEOMETRY); - geom_id = entity->data.geometry; - geom = solstice_parser_get_geometry(parser, entity->data.geometry); - CHECK(geom == geoms[0] || geom == geoms[1], 1); - CHECK(solstice_geometry_get_objects_count(geom), 1); - obj_id = solstice_geometry_get_object(geom, 0); - obj = solstice_parser_get_object(parser, obj_id); - CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); - shape = solstice_parser_get_shape(parser, obj->shape); - CHECK(shape->type, SOLSTICE_SHAPE_SPHERE); - sphere = solstice_parser_get_shape_sphere(parser, shape->data.sphere); - CHECK(sphere->radius, 1); - mtl2 = solstice_parser_get_material_double_sided(parser, obj->mtl2); - CHECK(mtl2->front.i, mtl2->back.i); - mtl = solstice_parser_get_material(parser, mtl2->front); - CHECK(mtl == mtls[0] || mtl == mtls[1], 1); - CHECK(mtl->type, SOLSTICE_MATERIAL_MATTE); - matte = solstice_parser_get_material_matte(parser, mtl->data.matte); - CHECK(matte->reflectivity, 1); - - entity_id = solstice_entity_get_child(entity, 0); - entity1a = solstice_parser_get_entity(parser, entity_id); - CHECK(d3_eq(entity1a->translation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity1a->rotation, d3_splat(tmp, 0)), 1); - CHECK(strcmp("lvl1a", str_cget(&entity1a->name)), 0); - CHECK(solstice_entity_get_children_count(entity1a), 0); - CHECK(entity1a->type, SOLSTICE_ENTITY_GEOMETRY); - NCHECK(entity1a->data.geometry.i, geom_id.i); - geom = solstice_parser_get_geometry(parser, entity1a->data.geometry); - CHECK(geom == geoms[0] || geom == geoms[1], 1); - CHECK(solstice_geometry_get_objects_count(geom), 1); - obj_id = solstice_geometry_get_object(geom, 0); - obj = solstice_parser_get_object(parser, obj_id); - CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); - shape = solstice_parser_get_shape(parser, obj->shape); - CHECK(shape->type, SOLSTICE_SHAPE_SPHERE); - sphere = solstice_parser_get_shape_sphere(parser, shape->data.sphere); - CHECK(sphere->radius, 2); - mtl2 = solstice_parser_get_material_double_sided(parser, obj->mtl2); - CHECK(mtl2->front.i, mtl2->back.i); - mtl = solstice_parser_get_material(parser, mtl2->front); - CHECK(mtl == mtls[0] || mtl == mtls[1], 1); - CHECK(mtl->type, SOLSTICE_MATERIAL_MIRROR); - mirror = solstice_parser_get_material_mirror(parser, mtl->data.mirror); - CHECK(mirror->reflectivity, 0.9); - CHECK(mirror->roughness, 0.1); - - entity_id = solstice_entity_get_child(entity, 1); - entity1b = solstice_parser_get_entity(parser, entity_id); - CHECK(d3_eq(entity1b->translation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity1b->rotation, d3(tmp, 3.14, 0, -1)), 1); - CHECK(strcmp("lvl1b", str_cget(&entity1b->name)), 0); - CHECK(solstice_entity_get_children_count(entity1b), 1); - CHECK(entity1b->type, SOLSTICE_ENTITY_GEOMETRY); - CHECK(entity1b->data.geometry.i, geom_id.i); - - entity_id = solstice_entity_get_child(entity1b, 0); - entity2 = solstice_parser_get_entity(parser, entity_id); - CHECK(d3_eq(entity2->translation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity2->rotation, d3_splat(tmp, 0)), 1); - CHECK(strcmp("lvl2", str_cget(&entity2->name)), 0); - CHECK(solstice_entity_get_children_count(entity2), 0); - CHECK(entity2->type, SOLSTICE_ENTITY_GEOMETRY); - CHECK(entity2->data.geometry.i, geom_id.i); - - entity3 = solstice_parser_find_entity(parser, "lvl 0"); - CHECK(entity3, entity); - entity3 = solstice_parser_find_entity(parser, "lvl1a"); - CHECK(entity3, NULL); - entity3 = solstice_parser_find_entity(parser, "lvl 0.lvl1a"); - CHECK(entity3, entity1a); - entity3 = solstice_parser_find_entity(parser, "lvl 0.lvl1b"); - CHECK(entity3, entity1b); - entity3 = solstice_parser_find_entity(parser, "lvl 0.lvl1b.lvl2"); - CHECK(entity3, entity2); - entity3 = solstice_parser_find_entity(parser,"lvl 0.lvl1b.bad_name"); - CHECK(entity3, NULL); - - sun = solstice_parser_get_sun(parser); - NCHECK(sun, NULL); - CHECK(sun->dni, 1.0); - CHECK(sun->radang_distrib_type, SOLSTICE_SUN_RADANG_DISTRIB_DIRECTIONAL); - CHECK(darray_spectrum_data_size_get(&sun->spectrum), 1); - CHECK(darray_spectrum_data_cdata_get(&sun->spectrum)[0].wavelength, 1.0); - CHECK(darray_spectrum_data_cdata_get(&sun->spectrum)[0].data, 1.0); - - CHECK(solstice_parser_load(parser), RES_BAD_OP); - solstice_parser_ref_put(parser); - - fclose(stream); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); - return 0; -} - diff --git a/src/parser/test_solstice_parser3.c b/src/parser/test_solstice_parser3.c @@ -1,246 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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 "solstice_parser.h" -#include "test_solstice_utils.h" - -static const char* input[] = { - "- material: &lambertian\n", - " matte: { reflectivity: 0.5 }\n", - "- geometry: &cylinder\n", - " - cylinder: { radius: 1, height: 10, slices: 128 }\n", - " material: *lambertian\n", - "- sun: \n", - " dni: 1\n", - " spectrum: [{wavelength: 1, data: 1}]\n", - "- entity:\n", - " name: entity0\n", - " geometry: *cylinder\n", - " anchors:\n", - " - name: anchor0\n", - " position: [1, 2, 3]\n", - " - name: anchor1\n", - " position: [4, 5, 6]\n", - " children:\n", - " - name: entity0a\n", - " geometry: *cylinder\n", - " - name: entity0b\n", - " geometry: *cylinder\n", - " anchors:\n\n", - " - name: anchor0\n", - " position: [4, 5, 6]\n", - " - name: entity0b\n", - " position: [7, 8, 9]\n", - "- entity:\n", - " name: entity1\n", - " pivot:\n", - " point: [1, 2, 3]\n", - " normal: [4, 5, 6]\n", - " target: { anchor: \"entity0.entity0b.anchor0\" }\n", - NULL -}; - -const struct solstice_anchor* entity0_anchor0; -const struct solstice_anchor* entity0_anchor1; -const struct solstice_anchor* entity0_entity0b_anchor0; -const struct solstice_anchor* entity0_entity0b_entity0b; -const struct solstice_geometry* geom; -const struct solstice_pivot* pivot; - -static void -check_entity0 - (struct solstice_parser* parser, const struct solstice_entity* entity0) -{ - struct solstice_anchor_id anchor_id; - struct solstice_entity_id entity_id; - struct solstice_object_id obj_id; - const struct solstice_entity *entity0a, *entity0b; - const struct solstice_material_matte* matte; - const struct solstice_material* mtl; - const struct solstice_material_double_sided* mtl2; - const struct solstice_object* obj; - const struct solstice_shape* shape; - const struct solstice_shape_cylinder* cylinder; - double tmp[3]; - - NCHECK(parser, NULL); - NCHECK(entity0, NULL); - - CHECK(strcmp(str_cget(&entity0->name), "entity0"), 0); - CHECK(d3_eq(entity0->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity0->translation, d3_splat(tmp, 0)), 1); - CHECK(entity0->type, SOLSTICE_ENTITY_GEOMETRY); - - geom = solstice_parser_get_geometry(parser, entity0->data.geometry); - CHECK(solstice_geometry_get_objects_count(geom), 1); - - obj_id = solstice_geometry_get_object(geom, 0); - obj = solstice_parser_get_object(parser, obj_id); - CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); - - shape = solstice_parser_get_shape(parser, obj->shape); - CHECK(shape->type, SOLSTICE_SHAPE_CYLINDER); - - cylinder = solstice_parser_get_shape_cylinder(parser, shape->data.cylinder); - CHECK(cylinder->height, 10); - CHECK(cylinder->radius, 1); - CHECK(cylinder->nslices, 128); - - mtl2 = solstice_parser_get_material_double_sided(parser, obj->mtl2); - CHECK(mtl2->front.i, mtl2->back.i); - - mtl = solstice_parser_get_material(parser, mtl2->front); - CHECK(mtl->type, SOLSTICE_MATERIAL_MATTE); - - matte = solstice_parser_get_material_matte(parser, mtl->data.matte); - CHECK(matte->reflectivity, 0.5); - - CHECK(solstice_entity_get_children_count(entity0), 2); - CHECK(solstice_entity_get_anchors_count(entity0), 2); - - anchor_id = solstice_entity_get_anchor(entity0, 0); - entity0_anchor0 = solstice_parser_get_anchor(parser, anchor_id); - CHECK(strcmp(str_cget(&entity0_anchor0->name), "anchor0"), 0); - CHECK(d3_eq(entity0_anchor0->position, d3(tmp, 1, 2, 3)), 1); - - anchor_id = solstice_entity_get_anchor(entity0, 1); - entity0_anchor1 = solstice_parser_get_anchor(parser, anchor_id); - CHECK(strcmp(str_cget(&entity0_anchor1->name), "anchor1"), 0); - CHECK(d3_eq(entity0_anchor1->position, d3(tmp, 4, 5, 6)), 1); - - entity_id = solstice_entity_get_child(entity0, 0); - entity0a = solstice_parser_get_entity(parser, entity_id); - CHECK(strcmp(str_cget(&entity0a->name), "entity0a"), 0); - CHECK(entity0a->type, SOLSTICE_ENTITY_GEOMETRY); - CHECK(entity0->data.geometry.i, entity0a->data.geometry.i); - CHECK(solstice_entity_get_anchors_count(entity0a), 0); - CHECK(solstice_entity_get_children_count(entity0a), 0); - - entity_id = solstice_entity_get_child(entity0, 1); - entity0b = solstice_parser_get_entity(parser, entity_id); - CHECK(strcmp(str_cget(&entity0b->name), "entity0b"), 0); - CHECK(entity0b->type, SOLSTICE_ENTITY_GEOMETRY); - CHECK(entity0->data.geometry.i, entity0b->data.geometry.i); - CHECK(solstice_entity_get_anchors_count(entity0b), 2); - CHECK(solstice_entity_get_children_count(entity0b), 0); - - anchor_id = solstice_entity_get_anchor(entity0b, 0); - entity0_entity0b_anchor0 = solstice_parser_get_anchor(parser, anchor_id); - CHECK(strcmp(str_cget(&entity0_entity0b_anchor0->name), "anchor0"), 0); - CHECK(d3_eq(entity0_entity0b_anchor0->position, d3(tmp, 4, 5, 6)), 1); - - anchor_id = solstice_entity_get_anchor(entity0b, 1); - entity0_entity0b_entity0b = solstice_parser_get_anchor(parser, anchor_id); - CHECK(strcmp(str_cget(&entity0_entity0b_entity0b->name), "entity0b"), 0); - CHECK(d3_eq(entity0_entity0b_entity0b->position, d3(tmp, 7, 8, 9)), 1); -} - -static void -check_entity1 - (struct solstice_parser* parser, const struct solstice_entity* entity1) -{ - double tmp[3]; - - NCHECK(parser, NULL); - NCHECK(entity1, NULL); - - CHECK(strcmp(str_cget(&entity1->name), "entity1"), 0); - CHECK(entity1->type, SOLSTICE_ENTITY_PIVOT); - CHECK(solstice_entity_get_anchors_count(entity1), 0); - CHECK(solstice_entity_get_children_count(entity1), 0); - - pivot = solstice_parser_get_pivot(parser, entity1->data.pivot); - CHECK(d3_eq(pivot->point, d3(tmp, 1, 2, 3)), 1); - CHECK(d3_eq(pivot->normal, d3(tmp, 4, 5, 6)), 1); - CHECK(pivot->target_type, SOLSTICE_TARGET_ANCHOR); -} - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct solstice_parser* parser; - struct solstice_entity_iterator it, it_end; - const struct solstice_anchor* anchor; - FILE* stream; - size_t i; - (void)argc, (void)argv; - - CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); - solstice_parser_create(&allocator, &parser); - - stream = tmpfile(); - NCHECK(stream, NULL); - i = 0; - while(input[i]) { - const size_t len = strlen(input[i]); - CHECK(fwrite(input[i], 1, len, stream), len); - ++i; - } - rewind(stream); - - CHECK(solstice_parser_setup(parser, NULL, stream), RES_OK); - CHECK(solstice_parser_load(parser), RES_OK); - - solstice_parser_entity_iterator_begin(parser, &it); - solstice_parser_entity_iterator_end(parser, &it_end); - CHECK(solstice_entity_iterator_eq(&it, &it_end), 0); - - while(!solstice_entity_iterator_eq(&it, &it_end)) { - struct solstice_entity_id entity_id; - const struct solstice_entity* entity; - - entity_id = solstice_entity_iterator_get(&it); - entity = solstice_parser_get_entity(parser, entity_id); - - if(!strcmp(str_cget(&entity->name), "entity0")) { - check_entity0(parser, entity); - } else if(!strcmp(str_cget(&entity->name), "entity1")) { - check_entity1(parser, entity); - } else { - FATAL("Unexpected entity name.\n"); - } - - solstice_entity_iterator_next(&it); - } - - anchor = solstice_parser_get_anchor(parser, pivot->target.anchor); - CHECK(anchor, entity0_entity0b_anchor0); - - anchor = solstice_parser_find_anchor(parser, "entity0"); - CHECK(anchor, NULL); - anchor = solstice_parser_find_anchor(parser, "entity0.anchor0"); - CHECK(anchor, entity0_anchor0); - anchor = solstice_parser_find_anchor(parser, "entity0.anchor1"); - CHECK(anchor, entity0_anchor1); - anchor = solstice_parser_find_anchor(parser, "entity0.entity0a.anchor0"); - CHECK(anchor, NULL); - anchor = solstice_parser_find_anchor(parser, "entity0.entity0b.anchor0"); - CHECK(anchor, entity0_entity0b_anchor0); - anchor = solstice_parser_find_anchor(parser, "entity0.entity0b.entity0b"); - CHECK(anchor, entity0_entity0b_entity0b); - anchor = solstice_parser_find_anchor(parser, "entity1.entity0b.anchor1"); - CHECK(anchor, NULL); - - CHECK(solstice_parser_load(parser), RES_BAD_OP); - solstice_parser_ref_put(parser); - fclose(stream); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); - return 0; -} diff --git a/src/parser/test_solstice_parser4.c b/src/parser/test_solstice_parser4.c @@ -1,208 +0,0 @@ -/* Copyright (C) CNRS 2016 - * - * This program 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. - * - * This program 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 "solstice_parser.h" -#include "test_solstice_utils.h" - -const struct solstice_geometry* geometry; - -static const char* input[] = { - "- sun: \n", - " dni: 1\n", - " spectrum: [{wavelength: 1, data: 1}]\n", - "- material: &lambertian\n", - " mirror: { reflectivity: 0.2, roughness: 0.1 }\n", - "- geometry: &cuboid\n", - " - cuboid: { size: [1, 2, 3] }\n", - " material: *lambertian\n", - "- template: &template\n", - " name: template0\n", - " geometry: *cuboid\n", - "- entity:\n", - " name: entity0\n", - " transform: { translation: [1, 2, 3] }\n", - " children: [ *template ]\n", - "- entity:\n", - " name: entity1\n", - " transform: { translation: [3, 4, 5] }\n", - " children: [ *template ]\n", - NULL -}; - -static void -check_entity0 - (struct solstice_parser* parser, const struct solstice_entity* entity0) -{ - const struct solstice_entity* entity; - struct solstice_entity_id entity_id; - double tmp[3]; - - NCHECK(parser, NULL); - NCHECK(entity0, NULL); - - CHECK(strcmp(str_cget(&entity0->name), "entity0"), 0); - CHECK(d3_eq(entity0->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity0->translation, d3(tmp, 1, 2, 3)), 1); - CHECK(entity0->type, SOLSTICE_ENTITY_EMPTY); - - CHECK(solstice_entity_get_children_count(entity0), 1); - CHECK(solstice_entity_get_anchors_count(entity0), 0); - - entity_id = solstice_entity_get_child(entity0, 0); - entity = solstice_parser_get_entity(parser, entity_id); - CHECK(strcmp(str_cget(&entity->name), "template0"), 0); - CHECK(d3_eq(entity->translation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity->rotation, d3_splat(tmp, 0)), 1); - - CHECK(entity->type, SOLSTICE_ENTITY_GEOMETRY); - CHECK(solstice_parser_get_geometry(parser, entity->data.geometry), geometry); - CHECK(solstice_parser_find_entity(parser, "entity0.template0"), entity); -} - -static void -check_entity1 - (struct solstice_parser* parser, const struct solstice_entity* entity1) -{ - const struct solstice_entity* entity; - struct solstice_entity_id entity_id; - double tmp[3]; - - NCHECK(parser, NULL); - NCHECK(entity1, NULL); - - CHECK(strcmp(str_cget(&entity1->name), "entity1"), 0); - CHECK(d3_eq(entity1->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity1->translation, d3(tmp, 3, 4, 5)), 1); - CHECK(entity1->type, SOLSTICE_ENTITY_EMPTY); - - CHECK(solstice_entity_get_children_count(entity1), 1); - CHECK(solstice_entity_get_anchors_count(entity1), 0); - - entity_id = solstice_entity_get_child(entity1, 0); - entity = solstice_parser_get_entity(parser, entity_id); - CHECK(strcmp(str_cget(&entity->name), "template0"), 0); - CHECK(d3_eq(entity->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(entity->translation, d3_splat(tmp, 0)), 1); - - CHECK(entity->type, SOLSTICE_ENTITY_GEOMETRY); - CHECK(solstice_parser_get_geometry(parser, entity->data.geometry), geometry); - CHECK(solstice_parser_find_entity(parser, "entity1.template0"), entity); -} - -int -main(int argc, char** argv) -{ - struct solstice_entity_iterator it, it_end; - struct solstice_geometry_iterator it_geom, it_end_geom; - struct mem_allocator allocator; - struct solstice_parser* parser; - const struct solstice_material* mtl; - const struct solstice_material_double_sided* mtl2; - const struct solstice_material_mirror* mirror; - const struct solstice_object* obj; - const struct solstice_shape* shape; - const struct solstice_shape_cuboid* cuboid; - struct solstice_geometry_id geom_id; - struct solstice_object_id obj_id; - double tmp[3]; - FILE* stream; - size_t i; - int entity0 = 0; - int entity1 = 0; - (void)argc, (void)argv; - - CHECK(mem_init_proxy_allocator(&allocator, &mem_default_allocator), RES_OK); - solstice_parser_create(&allocator, &parser); - - stream = tmpfile(); - NCHECK(stream, NULL); - i = 0; - while(input[i]) { - const size_t len = strlen(input[i]); - CHECK(fwrite(input[i], 1, len, stream), len); - ++i; - } - rewind(stream); - - CHECK(solstice_parser_setup(parser, NULL, stream), RES_OK); - CHECK(solstice_parser_load(parser), RES_OK); - - solstice_parser_geometry_iterator_begin(parser, &it_geom); - solstice_parser_geometry_iterator_end(parser, &it_end_geom); - CHECK(solstice_geometry_iterator_eq(&it_geom, &it_end_geom), 0); - geom_id = solstice_geometry_iterator_get(&it_geom); - geometry = solstice_parser_get_geometry(parser, geom_id); - solstice_geometry_iterator_next(&it_geom); - CHECK(solstice_geometry_iterator_eq(&it_geom, &it_end_geom), 1); - - CHECK(solstice_geometry_get_objects_count(geometry), 1); - obj_id = solstice_geometry_get_object(geometry, 0); - obj = solstice_parser_get_object(parser, obj_id); - CHECK(d3_eq(obj->rotation, d3_splat(tmp, 0)), 1); - CHECK(d3_eq(obj->translation, d3_splat(tmp, 0)), 1); - - mtl2 = solstice_parser_get_material_double_sided(parser, obj->mtl2); - CHECK(mtl2->front.i, mtl2->back.i); - mtl = solstice_parser_get_material(parser, mtl2->front); - CHECK(mtl->type, SOLSTICE_MATERIAL_MIRROR); - mirror = solstice_parser_get_material_mirror(parser, mtl->data.mirror); - CHECK(mirror->reflectivity, 0.2); - CHECK(mirror->roughness, 0.1); - - shape = solstice_parser_get_shape(parser, obj->shape); - CHECK(shape->type, SOLSTICE_SHAPE_CUBOID); - cuboid = solstice_parser_get_shape_cuboid(parser, shape->data.cuboid); - CHECK(cuboid->size[0], 1); - CHECK(cuboid->size[1], 2); - CHECK(cuboid->size[2], 3); - - solstice_parser_entity_iterator_begin(parser, &it); - solstice_parser_entity_iterator_end(parser, &it_end); - CHECK(solstice_entity_iterator_eq(&it, &it_end), 0); - - while(!solstice_entity_iterator_eq(&it, &it_end)) { - struct solstice_entity_id entity_id; - const struct solstice_entity* entity; - - entity_id = solstice_entity_iterator_get(&it); - entity = solstice_parser_get_entity(parser, entity_id); - - if(!strcmp(str_cget(&entity->name), "entity0")) { - CHECK(entity0, 0); - entity0 = 1; - check_entity0(parser, entity); - } else if(!strcmp(str_cget(&entity->name), "entity1")) { - CHECK(entity1, 0); - entity1 = 1; - check_entity1(parser, entity); - } else { - FATAL("Unexpected entity name.\n"); - } - - solstice_entity_iterator_next(&it); - } - CHECK(entity0, 1); - CHECK(entity1, 1); - - CHECK(solstice_parser_load(parser), RES_BAD_OP); - solstice_parser_ref_put(parser); - fclose(stream); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHECK(mem_allocated_size(), 0); - return 0; -} - diff --git a/src/solstice.c b/src/solstice.c @@ -13,14 +13,14 @@ * 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 "parser/solstice_parser.h" +#include "parser/solparser.h" #include <rsys/rsys.h> int main(int argc, char** argv) { FILE* file = NULL; - struct solstice_parser* parser = NULL; + struct solparser* parser = NULL; res_T res; int err = 0; int i; @@ -31,7 +31,7 @@ main(int argc, char** argv) goto error; } - res = solstice_parser_create(NULL, &parser); + res = solparser_create(NULL, &parser); if(res != RES_OK) goto error; FOR_EACH(i, 1, argc) { @@ -41,11 +41,11 @@ main(int argc, char** argv) goto error; } - res = solstice_parser_setup(parser, argv[i], file); + res = solparser_setup(parser, argv[i], file); if(res != RES_OK) break; do { - res = solstice_parser_load(parser); + res = solparser_load(parser); } while(res != RES_BAD_OP); fclose(file); @@ -53,7 +53,7 @@ main(int argc, char** argv) } exit: - if(parser) solstice_parser_ref_put(parser); + if(parser) solparser_ref_put(parser); if(file) fclose(file); return err; error: