commit 684edd4dc5ba7d4e43f09e0f66d5396e2300b446
parent 82ac79788359da79eeef64cb26da3a80ae817787
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 28 Mar 2017 10:54:56 +0200
Refactoring of the solstice parser
Split the solparser main file in several files.
Diffstat:
11 files changed, 3654 insertions(+), 3380 deletions(-)
diff --git a/cmake/parser/CMakeLists.txt b/cmake/parser/CMakeLists.txt
@@ -30,14 +30,23 @@ include_directories(
# Configure and define targets
################################################################################
set(SOLPARSER_FILES_SRC
- solparser.c)
+ solparser.c
+ solparser_entity.c
+ solparser_geometry.c
+ solparser_material.c
+ solparser_pivot.c
+ solparser_sun.c
+ solparser_spectrum.c)
set(SOLPARSER_FILES_INC
solparser.h
+ solparser_c.h
solparser_entity.h
+ solparser_geometry.h
solparser_material.h
solparser_pivot.h
solparser_shape.h
- solparser_sun.h)
+ solparser_sun.h
+ solparser_spectrum.h)
# Prepend each file in the `SOLPARSER_FILES_<SRC|INC>' list by `SOLPARSER_SOURCE_DIR'
rcmake_prepend_path(SOLPARSER_FILES_SRC ${SOLPARSER_SOURCE_DIR})
diff --git a/src/parser/solparser.c b/src/parser/solparser.c
@@ -15,299 +15,18 @@
#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 "solparser_c.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>
-struct target_alias {
- struct solparser_pivot_id pivot;
- const yaml_node_t* alias; /* Anchor */
-};
-
-/* Declare the target_alias array */
-#define DARRAY_NAME tgtalias
-#define DARRAY_DATA struct target_alias
-#include <rsys/dynamic_array.h>
-
-/* Declare the array of mediums */
-#define DARRAY_NAME medium
-#define DARRAY_DATA struct solparser_medium
-#include <rsys/dynamic_array.h>
-
-/* Declare the array of dielectric materials */
-#define DARRAY_NAME dielectric
-#define DARRAY_DATA struct solparser_material_dielectric
-#include <rsys/dynamic_array.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 thin_dielectric materials */
-#define DARRAY_NAME thin_dielectric
-#define DARRAY_DATA struct solparser_material_thin_dielectric
-#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 hyperboloids */
-#define DARRAY_NAME hyperboloid
-#define DARRAY_DATA struct solparser_shape_hyperboloid
-#define DARRAY_FUNCTOR_INIT solparser_shape_hyperboloid_init
-#define DARRAY_FUNCTOR_RELEASE solparser_shape_hyperboloid_release
-#define DARRAY_FUNCTOR_COPY solparser_shape_hyperboloid_copy
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE \
- solparser_shape_hyperboloid_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 x_pivots */
-#define DARRAY_NAME x_pivot
-#define DARRAY_DATA struct solparser_x_pivot
-#define DARRAY_FUNCTOR_INIT solparser_x_pivot_init
-#include <rsys/dynamic_array.h>
-
-/* Declare the array of zx_pivots */
-#define DARRAY_NAME zx_pivot
-#define DARRAY_DATA struct solparser_zx_pivot
-#define DARRAY_FUNCTOR_INIT solparser_zx_pivot_init
-#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_medium mediums;
- struct darray_dielectric dielectrics;
- struct darray_matte mattes;
- struct darray_mirror mirrors;
- struct darray_thin_dielectric thin_dielectrics;
-
- /* Use to deferred the setup of the anchor targeted by a pivot */
- struct darray_tgtalias tgtaliases;
-
- /* 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_hyperboloid hyperbols;
- 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_str2sols str2entities;
- struct darray_entity entities;
-
- /* Miscellaneous */
- struct darray_anchor anchors;
- struct darray_x_pivot x_pivots;
- struct darray_zx_pivot zx_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_x_pivot
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* x_pivot,
- struct solparser_pivot_id* out_isolpivot);
-
-static res_T
-parse_zx_pivot
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* zx_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);
-}
-
-static INLINE void
-log_node(const struct solparser* parser, const yaml_node_t* node)
-{
- fprintf(stderr, "\tby %s:%lu:%lu\n",
- str_cget(&parser->stream_name),
- (unsigned long)node->start_mark.line+1,
- (unsigned long)node->start_mark.column+1);
-}
-
static res_T
flush_deferred_target_aliases
(struct solparser* parser,
@@ -388,6 +107,77 @@ error:
goto exit;
}
+static res_T
+parse_item
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* item)
+{
+ /* Temporary dummy variables */
+ struct solparser_material_double_sided_id mtl2;
+ struct solparser_entity_id entity;
+ struct solparser_geometry_id geometry;
+ struct solparser_sun* sun;
+
+ yaml_node_t* key;
+ yaml_node_t* val;
+ 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);
+ if(res == RES_OK) {
+ res = flush_deferred_target_aliases(parser, item, 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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
/* Clean up loaded data */
static INLINE void
parser_clear(struct solparser* parser)
@@ -494,9 +284,37 @@ parser_release(ref_T* ref)
}
/*******************************************************************************
- * Miscellaneous parsing functions
+ * Local functions
******************************************************************************/
-static res_T
+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);
+}
+
+void
+log_node(const struct solparser* parser, const yaml_node_t* node)
+{
+ fprintf(stderr, "\tby %s:%lu:%lu\n",
+ str_cget(&parser->stream_name),
+ (unsigned long)node->start_mark.line+1,
+ (unsigned long)node->start_mark.column+1);
+}
+
+res_T
parse_real
(struct solparser* parser,
const yaml_node_t* real,
@@ -550,7 +368,7 @@ error:
goto exit;
}
-static res_T
+res_T
parse_realX
(struct solparser* parser,
yaml_document_t* doc,
@@ -591,31 +409,7 @@ error:
goto exit;
}
-static FINLINE 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])
-{
- return parse_realX(parser, doc, real3, lower_bound, upper_bound, 3, dst);
-}
-
-static FINLINE res_T
-parse_real2
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* real2,
- const double lower_bound,
- const double upper_bound,
- double dst[2])
-{
- return parse_realX(parser, doc, real2, lower_bound, upper_bound, 2, dst);
-}
-
-static res_T
+res_T
parse_integer
(struct solparser* parser,
yaml_node_t* integer,
@@ -653,7 +447,7 @@ error:
goto exit;
}
-static res_T
+res_T
parse_string
(struct solparser* parser,
yaml_node_t* string,
@@ -681,7 +475,7 @@ error:
goto exit;
}
-static res_T
+res_T
parse_transform
(struct solparser* parser,
yaml_document_t* doc,
@@ -749,3064 +543,8 @@ 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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_medium
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* medium,
- struct solparser_medium_id* out_imedium)
-{
- enum { ABSORPTIVITY, REFRACTIVE_INDEX };
- struct solparser_medium* mdm = NULL;
- size_t imedium = SIZE_MAX;
- int mask = 0; /* Register the parsed attributes */
- intptr_t i, n;
- res_T res = RES_OK;
- ASSERT(doc && medium && out_imedium);
-
- if(medium->type != YAML_MAPPING_NODE) {
- log_err(parser, medium, "expect a mapping of medium attributes.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Allocate the medium */
- imedium = darray_medium_size_get(&parser->mediums);
- res = darray_medium_resize(&parser->mediums, imedium + 1);
- if(res != RES_OK) {
- log_err(parser, medium, "could not allocate the medium.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- mdm = darray_medium_data_get(&parser->mediums) + imedium;
-
- n = medium->data.mapping.pairs.top - medium->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].value);
- if(key->type != YAML_SCALAR_NODE) {
- log_err(parser, key, "expect a medium 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 medium is already defined.\n");\
- res = RES_BAD_ARG; \
- goto error; \
- } \
- mask |= BIT(Flag); \
- } (void)0
- if(!strcmp((char*)key->data.scalar.value, "absorptivity")) {
- SETUP_MASK(ABSORPTIVITY, "absorptivity");
- res = parse_real(parser, val, 0, DBL_MAX, &mdm->absorptivity);
- } else if(!strcmp((char*)key->data.scalar.value, "refractive_index")) {
- SETUP_MASK(REFRACTIVE_INDEX, "refractive_index");
- res = parse_real
- (parser, val, nextafter(0, 1), DBL_MAX, &mdm->refractive_index);
- } else {
- log_err(parser, key, "unknown medium parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
-
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, medium, "the "Name" of the medium is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(ABSORPTIVITY, "absorptivity");
- CHECK_PARAM(REFRACTIVE_INDEX, "refractive_index");
- #undef CHECK_PARAM
-
-exit:
- out_imedium->i = imedium;
- return res;
-error:
- if(imedium) {
- darray_medium_pop_back(&parser->mediums);
- imedium = SIZE_MAX;
- }
- goto exit;
-}
-
-static res_T
-parse_material_dielectric
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* dielec,
- struct solparser_material_dielectric_id* out_imtl)
-{
- enum { MEDIUM_I, MEDIUM_T };
- struct solparser_material_dielectric* 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 && dielec && out_imtl);
-
- if(dielec->type != YAML_MAPPING_NODE) {
- log_err(parser, dielec,
- "expect a mapping of dielec material attributes.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Allocate the dielec material */
- imtl = darray_dielectric_size_get(&parser->dielectrics);
- res = darray_dielectric_resize(&parser->dielectrics, imtl + 1);
- if(res != RES_OK) {
- log_err(parser, dielec,
- "could not allocate the dielec material.\n");
- goto error;
- }
- mtl = darray_dielectric_data_get(&parser->dielectrics) + imtl;
-
- n = dielec->data.mapping.pairs.top - dielec->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, dielec->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(doc, dielec->data.mapping.pairs.start[i].value);
- if(key->type != YAML_SCALAR_NODE) {
- log_err(parser, key, "expect a dielec 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 dielectric material is already defined.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } \
- mask |= BIT(Flag); \
- } (void)0
- if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
- SETUP_MASK(MEDIUM_I, "medium_i");
- res = parse_medium(parser, doc, val, &mtl->medium_i);
- } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) {
- SETUP_MASK(MEDIUM_T, "medium_t");
- res = parse_medium(parser, doc, val, &mtl->medium_t);
- } else {
- log_err(parser, key, "unknown dielectric parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
-
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, dielec, \
- "the "Name" of the dielectric material is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(MEDIUM_I, "medium_i");
- CHECK_PARAM(MEDIUM_T, "medium_t");
- #undef CHECK_PARAM
-
-exit:
- out_imtl->i = imtl;
- return res;
-error:
- if(imtl) {
- darray_dielectric_pop_back(&parser->dielectrics);
- imtl = SIZE_MAX;
- }
- goto exit;
-}
-
-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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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_thin_dielectric
- (struct solparser* parser,
- yaml_document_t* doc,
- yaml_node_t* thin,
- struct solparser_material_thin_dielectric_id* out_imtl)
-{
- enum { MEDIUM_I, MEDIUM_T, THICKNESS };
- struct solparser_material_thin_dielectric* 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 && thin && out_imtl);
-
- if(thin->type != YAML_MAPPING_NODE) {
- log_err(parser, thin,
- "expect a mapping of thin dielectric material attributes.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Allocate the thin dielectric material */
- imtl = darray_thin_dielectric_size_get(&parser->thin_dielectrics);
- res = darray_thin_dielectric_resize(&parser->thin_dielectrics, imtl + 1);
- if(res != RES_OK) {
- log_err(parser, thin,
- "could not allocate the thin dielectric material.\n");
- goto error;
- }
- mtl = darray_thin_dielectric_data_get(&parser->thin_dielectrics) + imtl;
-
- n = thin->data.mapping.pairs.top - thin->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, thin->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(doc, thin->data.mapping.pairs.start[i].value);
- if(key->type != YAML_SCALAR_NODE) {
- log_err(parser, key, "expect a thin dielectric 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 thin dielectric material is already defined.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } \
- mask |= BIT(Flag); \
- } (void)0
- if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
- SETUP_MASK(MEDIUM_I, "medium_i");
- res = parse_medium(parser, doc, val, &mtl->medium_i);
- } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) {
- SETUP_MASK(MEDIUM_T, "medium_t");
- res = parse_medium(parser, doc, val, &mtl->medium_t);
- } else if(!strcmp((char*)key->data.scalar.value, "thickness")) {
- SETUP_MASK(THICKNESS, "thickness");
- res = parse_real(parser, val, 0, DBL_MAX, &mtl->thickness);
- } else {
- log_err(parser, key, "unknown thin dielectric parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
-
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, thin, \
- "the "Name" of the thin dielectric material is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(MEDIUM_I, "medium_i");
- CHECK_PARAM(MEDIUM_T, "medium_t");
- CHECK_PARAM(THICKNESS, "thickness");
- #undef CHECK_PARAM
-
-exit:
- out_imtl->i = imtl;
- return res;
-error:
- if(mtl) {
- darray_thin_dielectric_pop_back(&parser->thin_dielectrics);
- imtl = SIZE_MAX;
- }
- goto exit;
-}
-
-static res_T
-parse_material_virtual(struct solparser* parser, yaml_node_t* virtual)
-{
- res_T res = RES_OK;
- ASSERT(virtual);
-
- if(virtual->type != YAML_SCALAR_NODE
- || ((char*)virtual->data.scalar.value)[0] != '\0') {
- log_err(parser, virtual,
- "virtual materials can have a null scalar value only.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
-exit:
- return res;
-error:
- 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, "dielectric")) {
- SETUP_MASK(DESCRIPTOR, "descriptor");
- mtl->type = SOLPARSER_MATERIAL_DIELECTRIC;
- res = parse_material_dielectric(parser, doc, val, &mtl->data.dielectric);
- } else 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 if(!strcmp((char*)key->data.scalar.value, "thin_dielectric")) {
- SETUP_MASK(DESCRIPTOR, "descriptor");
- mtl->type = SOLPARSER_MATERIAL_THIN_DIELECTRIC;
- res = parse_material_thin_dielectric
- (parser, doc, val, &mtl->data.thin_dielectric);
- } else if(!strcmp((char*)key->data.scalar.value, "virtual")) {
- SETUP_MASK(DESCRIPTOR, "descriptor");
- mtl->type = SOLPARSER_MATERIAL_VIRTUAL;
- res = parse_material_virtual(parser, val);
- } else {
- log_err(parser, key, "unknown material descriptor `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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; /* Discard log_node */
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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*2/*#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* real2 = darray_double_data_get(coords) + i*2/*#coords per vertex*/;
-
- vertex = yaml_document_get_node(doc, vertices->data.sequence.items.start[i]);
- res = parse_real2(parser, doc, vertex, -DBL_MAX, DBL_MAX, real2);
- 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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.\n"); \
- 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, nextafter(0, 1), DBL_MAX, shape->size);
- } else {
- log_err(parser, key, "unknown cuboid parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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, nextafter(0, 1), DBL_MAX, &shape->height);
- } else if(!strcmp((char*)key->data.scalar.value, "radius")) {
- SETUP_MASK(RADIUS, "radius");
- res = parse_real(parser, val, nextafter(0, 1), 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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
-
- #define DEFAULT_PARAM(Flag, Ptr, Value) \
- if(!(mask & BIT(Flag))) { \
- *(Ptr) = Value; \
- } (void)0
- DEFAULT_PARAM(SLICES, &shape->nslices, 16);
- #undef DEFAULT_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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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, SLICES };
- 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 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 %s parameter `%s'.\n",
- name, key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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_focals_description
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* desc,
- struct solparser_hyperboloid_focals* focals)
-{
- enum { REAL, IMAGE };
- intptr_t i, n;
- int mask = 0; /* Register the parsed attributes */
- res_T res = RES_OK;
- ASSERT(doc && desc && focals);
-
- if(desc->type != YAML_MAPPING_NODE) {
- log_err(parser, desc, "expect a mapping of focal parameters.\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 focal parameters.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- #define SETUP_MASK(Flag, Name) { \
- if(mask & BIT(Flag)) { \
- log_err(parser, key, \
- "the focal parameter `"Name"' is already defined.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } \
- mask |= BIT(Flag); \
- } (void)0
- if(!strcmp((char*) key->data.scalar.value, "real")) {
- SETUP_MASK(REAL, "real");
- res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->real);
- } else if(!strcmp((char*) key->data.scalar.value, "image")) {
- SETUP_MASK(IMAGE, "image");
- res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->image);
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- }
- #undef SETUP_MASK
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, desc, \
- "the focal parameter `"Name"' is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(REAL, "real");
- CHECK_PARAM(IMAGE, "image");
- #undef CHECK_PARAM
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-parse_hyperboloid
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* hyperboloid,
- struct solparser_shape_hyperboloid_id* out_ishape)
-{
- enum { CLIP, FOCAL, SLICES };
- struct solparser_shape_hyperboloid* 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 && hyperboloid && out_ishape);
-
- if(hyperboloid->type != YAML_MAPPING_NODE) {
- log_err(parser, hyperboloid, "expect a mapping of hyperbol parameters.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Allocate a hyperboloid shape */
- ishape = darray_hyperboloid_size_get(&parser->hyperbols);
- res = darray_hyperboloid_resize(&parser->hyperbols, ishape + 1);
- if(res != RES_OK) {
- log_err(parser, hyperboloid, "could not allocate the hyperbol shape.\n");
- goto error;
- }
- shape = darray_hyperboloid_data_get(&parser->hyperbols) + ishape;
-
- n = hyperboloid->data.mapping.pairs.top - hyperboloid->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].value);
- if(key->type != YAML_SCALAR_NODE) {
- log_err(parser, key, "expect hyperbol parameters.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- #define SETUP_MASK(Flag, Name) { \
- if(mask & BIT(Flag)) { \
- log_err(parser, key, \
- "the hyperbol parameter `"Name"' is already defined.\n"); \
- 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, "focals")) {
- SETUP_MASK(FOCAL, "focals");
- res = parse_focals_description(parser, doc, val, &shape->focals);
- } 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 hyperbol parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, hyperboloid, \
- "the hyperbol parameter `"Name"' is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(CLIP, "clip");
- CHECK_PARAM(FOCAL, "focals");
- #undef CHECK_PARAM
-
-exit :
- out_ishape->i = ishape;
- return res;
-error:
- if(shape) {
- darray_hyperboloid_pop_back(&parser->hyperbols);
- 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, SLICES };
- 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;
- }
- #define SETUP_MASK(Flag, Name) { \
- if(mask & BIT(Flag)) { \
- log_err(parser, key, \
- "the plane parameter `"Name"' is already defined.\n"); \
- 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, "slices")) {
- SETUP_MASK(SLICES, "slices");
- res = parse_integer(parser, val, 1, 4096, &shape->nslices);
- } else {
- log_err(parser, key, "unknown plane parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
- 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, nextafter(0, 1), 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
-
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, sphere, \
- "the sphere parameter `"Name"' is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(RADIUS, "radius");
- #undef CHECK_PARAM
-
- #define DEFAULT_PARAM(Flag, Ptr, Value) \
- if(!(mask & BIT(Flag))) { \
- *(Ptr) = Value; \
- } (void)0
- DEFAULT_PARAM(SLICES, &shape->nslices, 16);
- #undef DEFAULT_PARAM
-
-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, "hyperbol")) {
- SETUP_MASK(SHAPE, "shape");
- shape->type = SOLPARSER_SHAPE_HYPERBOL;
- res = parse_hyperboloid(parser, doc, val, &shape->data.hyperbol);
- } 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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 description");
- res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solanchor->position);
- } else if(!strcmp((char*) key->data.scalar.value, "hyperboloid_image_focals")) {
- struct solparser_hyperboloid_focals focals;
- SETUP_MASK(POSITION, "position description");
- res = parse_focals_description(parser, doc, val, &focals);
- if(res != RES_OK) goto error;
- d3(solanchor->position, 0, 0, focals.image);
- } else {
- log_err(parser, key, "unknown anchor parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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 description");
- #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, PRIMARY };
- struct solparser_entity solent;
- struct solparser_entity* psolent;
- 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);
-
- 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);
- if(!strcmp(str_get(&solent.name), "self")) {
- /* self is a reserved keyword */
- log_err(parser, key, "Reserved keywords cannot be used as names: %s.\n",
- str_get(&solent.name));
- res = RES_BAD_ARG;
- goto error;
- }
- } else if(!strcmp((char*)key->data.scalar.value, "x_pivot")) {
- SETUP_MASK(DATA, "data");
- solent.type = SOLPARSER_ENTITY_X_PIVOT;
- res = parse_x_pivot(parser, doc, val, &solent.data.x_pivot);
- } else if(!strcmp((char*) key->data.scalar.value, "zx_pivot")) {
- SETUP_MASK(DATA, "data");
- solent.type = SOLPARSER_ENTITY_ZX_PIVOT;
- res = parse_zx_pivot(parser, doc, val, &solent.data.zx_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 if(!strcmp((char*) key->data.scalar.value, "primary")) {
- long tmp;
- SETUP_MASK(PRIMARY, "primary");
- res = parse_integer(parser, val, 0, 1, &tmp);
- solent.primary = (int)tmp;
- } else {
- log_err(parser, key, "unknown entity parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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" parameter is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(NAME, "name");
- if(solent.type == SOLPARSER_ENTITY_GEOMETRY) {
- CHECK_PARAM(PRIMARY, "primary");
- } else if(mask & BIT(PRIMARY)) {
- log_err(parser, entity,
- "the entity primary parameter is invalid in this context.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- #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;
-
-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,
- const struct solparser_pivot_id pivot,
- 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;
- }
-
- if(!strncmp((char*)alias->data.scalar.value, "self.", 5)) {
- struct target_alias tgt;
- tgt.pivot = pivot;
- tgt.alias = alias;
- res = darray_tgtalias_push_back(&parser->tgtaliases, &tgt);
- if(res != RES_OK) {
- log_err(parser, alias, "could not register the anchor alias.\n");
- goto error;
- }
- } else {
- 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_node,
- struct solparser_target* target,
- struct solparser_pivot_id pivot_id)
-{
- enum { POLICY };
- intptr_t i, n;
- int mask = 0; /* Register the parsed attributes */
- res_T res = RES_OK;
- ASSERT(doc && target_node && target);
-
- if(target_node->type != YAML_MAPPING_NODE) {
- log_err(parser, target_node, "expect a target definition.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- n = target_node->data.mapping.pairs.top - target_node->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, target_node->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(doc, target_node->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");
- target->type = SOLPARSER_TARGET_ANCHOR;
- res = parse_anchor_alias(parser, val, pivot_id, &target->data.anchor);
- } else if(!strcmp((char*)key->data.scalar.value, "direction")) {
- SETUP_MASK(POLICY, "policy");
- target->type = SOLPARSER_TARGET_DIRECTION;
- res = parse_real3
- (parser, doc, val, -DBL_MAX, DBL_MAX, target->data.direction);
- } else if(!strcmp((char*)key->data.scalar.value, "position")) {
- SETUP_MASK(POLICY, "policy");
- target->type = SOLPARSER_TARGET_POSITION;
- res = parse_real3
- (parser, doc, val, -DBL_MAX, DBL_MAX, target->data.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");
- 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) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
-
- if(!(mask & BIT(POLICY))) {
- log_err(parser, target_node, "the target policy is missing.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-static res_T
-parse_x_pivot
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* x_pivot,
- struct solparser_pivot_id* out_isolpivot)
-{
- enum { REF_POINT, TARGET };
- struct solparser_x_pivot* solxpivot = NULL;
- size_t isolpivot = SIZE_MAX;
- int mask = 0; /* Register the parsed attributes */
- intptr_t i, n;
- res_T res = RES_OK;
- ASSERT(doc && x_pivot && out_isolpivot);
-
- if(x_pivot->type != YAML_MAPPING_NODE) {
- log_err(parser, x_pivot, "expect a x_pivot definition.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Allocate the solstice pivot */
- isolpivot = darray_x_pivot_size_get(&parser->x_pivots);
- res = darray_x_pivot_resize(&parser->x_pivots, isolpivot + 1);
- if(res != RES_OK) {
- log_err(parser, x_pivot, "could not allocate the x_pivot.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- solxpivot = darray_x_pivot_data_get(&parser->x_pivots) + isolpivot;
-
- n = x_pivot->data.mapping.pairs.top - x_pivot->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, x_pivot->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(doc, x_pivot->data.mapping.pairs.start[i].value);
- if(key->type != YAML_SCALAR_NODE) {
- log_err(parser, key, "expect x_pivot parameters.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- #define SETUP_MASK(Flag, Name) { \
- if(mask & BIT(Flag)) { \
- log_err(parser, key, \
- "the x_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, "ref_point")) {
- SETUP_MASK(REF_POINT, "point");
- res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solxpivot->ref_point);
- } else if(!strcmp((char*)key->data.scalar.value, "target")) {
- struct solparser_pivot_id pivot_id;
- pivot_id.i = (size_t) (solxpivot - darray_x_pivot_cdata_get(&parser->x_pivots));
- SETUP_MASK(TARGET, "target");
- res = parse_target(parser, doc, val, &solxpivot->target, pivot_id);
- } else {
- log_err(parser, key, "unknown x_pivot parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, x_pivot, "the x_pivot parameter `"Name"' is missing.\n");\
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(TARGET, "target");
- #undef CHECK_PARAM
-
- #define DEFAULT_PARAM(Flag, Ptr, Value) \
- if(!(mask & BIT(Flag))) { \
- *(Ptr) = Value; \
- } (void)0
- DEFAULT_PARAM(REF_POINT, solxpivot->ref_point, 0);
- DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+1, 0);
- DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+2, 0);
- #undef DEFAULT_PARAM
-
-exit:
- out_isolpivot->i = isolpivot;
- return res;
-error:
- if(solxpivot) {
- darray_x_pivot_pop_back(&parser->x_pivots);
- isolpivot = SIZE_MAX;
- }
- goto exit;
-}
-
-static res_T
-parse_zx_pivot
- (struct solparser* parser,
- yaml_document_t* doc,
- const yaml_node_t* zx_pivot,
- struct solparser_pivot_id* out_isolpivot)
-{
- enum { SPACING, REF_POINT, TARGET };
- struct solparser_zx_pivot* solxzpivot = NULL;
- size_t isolpivot = SIZE_MAX;
- int mask = 0; /* Register the parsed attributes */
- intptr_t i, n;
- res_T res = RES_OK;
- ASSERT(doc && zx_pivot && out_isolpivot);
-
- if(zx_pivot->type != YAML_MAPPING_NODE) {
- log_err(parser, zx_pivot, "expect a zx_pivot definition.\n");
- res = RES_BAD_ARG;
- goto error;
- }
-
- /* Allocate the solstice pivot */
- isolpivot = darray_zx_pivot_size_get(&parser->zx_pivots);
- res = darray_zx_pivot_resize(&parser->zx_pivots, isolpivot + 1);
- if(res != RES_OK) {
- log_err(parser, zx_pivot, "could not allocate the zx_pivot.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- solxzpivot = darray_zx_pivot_data_get(&parser->zx_pivots) + isolpivot;
-
- n = zx_pivot->data.mapping.pairs.top - zx_pivot->data.mapping.pairs.start;
- FOR_EACH(i, 0, n) {
- yaml_node_t* key;
- yaml_node_t* val;
-
- key = yaml_document_get_node(doc, zx_pivot->data.mapping.pairs.start[i].key);
- val = yaml_document_get_node(
- doc, zx_pivot->data.mapping.pairs.start[i].value);
- if(key->type != YAML_SCALAR_NODE) {
- log_err(parser, key, "expect zx_pivot parameters.\n");
- res = RES_BAD_ARG;
- goto error;
- }
- #define SETUP_MASK(Flag, Name) { \
- if(mask & BIT(Flag)) { \
- log_err(parser, key, \
- "the zx_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, "spacing")) {
- SETUP_MASK(SPACING, "spacing");
- res = parse_real(parser, val, 0, DBL_MAX, &solxzpivot->spacing);
- } else if(!strcmp((char*) key->data.scalar.value, "ref_point")) {
- SETUP_MASK(REF_POINT, "ref_point");
- res = parse_real3(
- parser, doc, val, -DBL_MAX, DBL_MAX, solxzpivot->ref_point);
- } else if(!strcmp((char*) key->data.scalar.value, "target")) {
- struct solparser_pivot_id pivot_id;
- pivot_id.i =
- (size_t) (solxzpivot - darray_zx_pivot_cdata_get(&parser->zx_pivots));
- SETUP_MASK(TARGET, "target");
- res = parse_target(parser, doc, val, &solxzpivot->target, pivot_id);
- } else {
- log_err(parser, key, "unknown zx_pivot parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
- #undef SETUP_MASK
- }
- #define CHECK_PARAM(Flag, Name) \
- if(!(mask & BIT(Flag))) { \
- log_err(parser, zx_pivot, \
- "the zx_pivot parameter `"Name"' is missing.\n"); \
- res = RES_BAD_ARG; \
- goto error; \
- } (void)0
- CHECK_PARAM(TARGET, "target");
- #undef CHECK_PARAM
-
- #define DEFAULT_PARAM(Flag, Ptr, Value) \
- if(!(mask & BIT(Flag))) { \
- *(Ptr) = Value; \
- } (void)0
- DEFAULT_PARAM(SPACING, &solxzpivot->spacing, 0);
- DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point, 0);
- DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+1, 0);
- DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+2, 0);
- #undef DEFAULT_PARAM
-
-exit:
- out_isolpivot->i = isolpivot;
- return res;
-error:
- if(solxzpivot) {
- darray_zx_pivot_pop_back(&parser->zx_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, 1e-6, 0.849, &sun->csr);
- } else {
- log_err(parser, key, "unknown buie parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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), 90, &sun->aperture);
- } else {
- log_err(parser, pillbox, "unknown pillbox parameter `%s'.\n",
- key->data.scalar.value);
- res = RES_BAD_ARG;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- 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)
-{
- /* Temporary dummy variables */
- struct solparser_material_double_sided_id mtl2;
- struct solparser_entity_id entity;
- struct solparser_geometry_id geometry;
- struct solparser_sun* sun;
-
- yaml_node_t* key;
- yaml_node_t* val;
- 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);
- if(res == RES_OK) {
- res = flush_deferred_target_aliases(parser, item, 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;
- goto error;
- }
- if(res != RES_OK) {
- log_node(parser, key);
- goto error;
- }
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-/*******************************************************************************
- * Local functions
+ * Exported functions
******************************************************************************/
res_T
solparser_create
diff --git a/src/parser/solparser_c.h b/src/parser/solparser_c.h
@@ -0,0 +1,389 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_C_H
+#define SOLPARSER_C_H
+
+#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/dynamic_array.h>
+#include <rsys/hash_table.h>
+#include <rsys/ref_count.h>
+#include <rsys/str.h>
+
+#include <yaml.h>
+
+struct target_alias {
+ struct solparser_pivot_id pivot;
+ const yaml_node_t* alias; /* Anchor */
+};
+
+/* Declare the target_alias array */
+#define DARRAY_NAME tgtalias
+#define DARRAY_DATA struct target_alias
+#include <rsys/dynamic_array.h>
+
+/* Declare the array of mediums */
+#define DARRAY_NAME medium
+#define DARRAY_DATA struct solparser_medium
+#include <rsys/dynamic_array.h>
+
+/* Declare the array of dielectric materials */
+#define DARRAY_NAME dielectric
+#define DARRAY_DATA struct solparser_material_dielectric
+#include <rsys/dynamic_array.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 thin_dielectric materials */
+#define DARRAY_NAME thin_dielectric
+#define DARRAY_DATA struct solparser_material_thin_dielectric
+#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 hyperboloids */
+#define DARRAY_NAME hyperboloid
+#define DARRAY_DATA struct solparser_shape_hyperboloid
+#define DARRAY_FUNCTOR_INIT solparser_shape_hyperboloid_init
+#define DARRAY_FUNCTOR_RELEASE solparser_shape_hyperboloid_release
+#define DARRAY_FUNCTOR_COPY solparser_shape_hyperboloid_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE \
+ solparser_shape_hyperboloid_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 x_pivots */
+#define DARRAY_NAME x_pivot
+#define DARRAY_DATA struct solparser_x_pivot
+#define DARRAY_FUNCTOR_INIT solparser_x_pivot_init
+#include <rsys/dynamic_array.h>
+
+/* Declare the array of zx_pivots */
+#define DARRAY_NAME zx_pivot
+#define DARRAY_DATA struct solparser_zx_pivot
+#define DARRAY_FUNCTOR_INIT solparser_zx_pivot_init
+#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_medium mediums;
+ struct darray_dielectric dielectrics;
+ struct darray_matte mattes;
+ struct darray_mirror mirrors;
+ struct darray_thin_dielectric thin_dielectrics;
+
+ /* Use to deferred the setup of the anchor targeted by a pivot */
+ struct darray_tgtalias tgtaliases;
+
+ /* 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_hyperboloid hyperbols;
+ 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_str2sols str2entities;
+ struct darray_entity entities;
+
+ /* Miscellaneous */
+ struct darray_anchor anchors;
+ struct darray_x_pivot x_pivots;
+ struct darray_zx_pivot zx_pivots;
+
+ ref_T ref;
+ struct mem_allocator* allocator;
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+extern LOCAL_SYM void
+log_err
+ (const struct solparser* parser,
+ const yaml_node_t* node,
+ const char* fmt,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 3, 4)))
+#endif
+ ;
+
+extern LOCAL_SYM void
+log_node
+ (const struct solparser* parser,
+ const yaml_node_t* node);
+
+
+/*******************************************************************************
+ * Miscellaneous parsing functions
+ ******************************************************************************/
+extern LOCAL_SYM res_T
+parse_real
+ (struct solparser* parser,
+ const yaml_node_t* real,
+ const double lower_bound,
+ const double upper_bound,
+ double* dst);
+
+extern LOCAL_SYM res_T
+parse_realX
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* realX,
+ const double lower_bound,
+ const double upper_bound,
+ const size_t dim,
+ double dst[]);
+
+static FINLINE res_T
+parse_real2
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* real2,
+ const double lower_bound,
+ const double upper_bound,
+ double dst[2])
+{
+ return parse_realX(parser, doc, real2, lower_bound, upper_bound, 2, dst);
+}
+
+static FINLINE 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])
+{
+ return parse_realX(parser, doc, real3, lower_bound, upper_bound, 3, dst);
+}
+
+extern LOCAL_SYM res_T
+parse_integer
+ (struct solparser* parser,
+ yaml_node_t* integer,
+ const long lower_bound,
+ const long upper_bound,
+ long* dst);
+
+extern LOCAL_SYM res_T
+parse_string
+ (struct solparser* parser,
+ yaml_node_t* string,
+ struct str* str);
+
+extern LOCAL_SYM res_T
+parse_transform
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* transform,
+ double translation[3],
+ double rotation[3]);
+
+/*******************************************************************************
+ * Main parsing functions
+ ******************************************************************************/
+extern LOCAL_SYM res_T
+parse_material
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ yaml_node_t* mtl,
+ struct solparser_material_double_sided_id* out_imtl2);
+
+extern LOCAL_SYM 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);
+
+extern LOCAL_SYM res_T
+parse_focals_description
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* desc,
+ struct solparser_hyperboloid_focals* focals);
+
+extern LOCAL_SYM res_T
+parse_geometry
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ yaml_node_t* geometry,
+ struct solparser_geometry_id* out_isolgeom);
+
+extern LOCAL_SYM res_T
+parse_x_pivot
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* x_pivot,
+ struct solparser_pivot_id* out_isolpivot);
+
+extern LOCAL_SYM res_T
+parse_zx_pivot
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* zx_pivot,
+ struct solparser_pivot_id* out_isolpivot);
+
+extern LOCAL_SYM res_T
+parse_sun
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* sun,
+ struct solparser_sun** out_solsun);
+
+extern LOCAL_SYM 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);
+
+#endif /* SOLPARSER_C_H */
diff --git a/src/parser/solparser_entity.c b/src/parser/solparser_entity.c
@@ -0,0 +1,446 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_c.h"
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+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 description");
+ res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solanchor->position);
+ } else if(!strcmp((char*) key->data.scalar.value, "hyperboloid_image_focals")) {
+ struct solparser_hyperboloid_focals focals;
+ SETUP_MASK(POSITION, "position description");
+ res = parse_focals_description(parser, doc, val, &focals);
+ if(res != RES_OK) goto error;
+ d3(solanchor->position, 0, 0, focals.image);
+ } else {
+ log_err(parser, key, "unknown anchor parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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 description");
+ #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;
+}
+
+
+/*******************************************************************************
+ * Local function
+ ******************************************************************************/
+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, PRIMARY };
+ struct solparser_entity solent;
+ struct solparser_entity* psolent;
+ 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);
+
+ 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);
+ if(!strcmp(str_get(&solent.name), "self")) {
+ /* Self is a reserved keyword */
+ log_err(parser, key, "Reserved keywords cannot be used as names: %s.\n",
+ str_get(&solent.name));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ } else if(!strcmp((char*)key->data.scalar.value, "x_pivot")) {
+ SETUP_MASK(DATA, "data");
+ solent.type = SOLPARSER_ENTITY_X_PIVOT;
+ res = parse_x_pivot(parser, doc, val, &solent.data.x_pivot);
+ } else if(!strcmp((char*) key->data.scalar.value, "zx_pivot")) {
+ SETUP_MASK(DATA, "data");
+ solent.type = SOLPARSER_ENTITY_ZX_PIVOT;
+ res = parse_zx_pivot(parser, doc, val, &solent.data.zx_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 if(!strcmp((char*) key->data.scalar.value, "primary")) {
+ long tmp;
+ SETUP_MASK(PRIMARY, "primary");
+ res = parse_integer(parser, val, 0, 1, &tmp);
+ solent.primary = (int)tmp;
+ } else {
+ log_err(parser, key, "unknown entity parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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" parameter is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(NAME, "name");
+ if(solent.type == SOLPARSER_ENTITY_GEOMETRY) {
+ CHECK_PARAM(PRIMARY, "primary");
+ } else if(mask & BIT(PRIMARY)) {
+ log_err(parser, entity,
+ "the entity primary parameter is invalid in this context.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ #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;
+
+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;
+}
+
+
diff --git a/src/parser/solparser_geometry.c b/src/parser/solparser_geometry.c
@@ -0,0 +1,1175 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_c.h"
+#include <math.h> /* nextafter */
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+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*2/*#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* real2 = darray_double_data_get(coords) + i*2/*#coords per vertex*/;
+
+ vertex = yaml_document_get_node(doc, vertices->data.sequence.items.start[i]);
+ res = parse_real2(parser, doc, vertex, -DBL_MAX, DBL_MAX, real2);
+ 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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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.\n"); \
+ 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;
+}
+
+
+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, nextafter(0, 1), DBL_MAX, shape->size);
+ } else {
+ log_err(parser, key, "unknown cuboid parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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, nextafter(0, 1), DBL_MAX, &shape->height);
+ } else if(!strcmp((char*)key->data.scalar.value, "radius")) {
+ SETUP_MASK(RADIUS, "radius");
+ res = parse_real(parser, val, nextafter(0, 1), 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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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
+
+ #define DEFAULT_PARAM(Flag, Ptr, Value) \
+ if(!(mask & BIT(Flag))) { \
+ *(Ptr) = Value; \
+ } (void)0
+ DEFAULT_PARAM(SLICES, &shape->nslices, 16);
+ #undef DEFAULT_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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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, SLICES };
+ 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 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 %s parameter `%s'.\n",
+ name, key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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_hyperboloid
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* hyperboloid,
+ struct solparser_shape_hyperboloid_id* out_ishape)
+{
+ enum { CLIP, FOCAL, SLICES };
+ struct solparser_shape_hyperboloid* 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 && hyperboloid && out_ishape);
+
+ if(hyperboloid->type != YAML_MAPPING_NODE) {
+ log_err(parser, hyperboloid, "expect a mapping of hyperbol parameters.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate a hyperboloid shape */
+ ishape = darray_hyperboloid_size_get(&parser->hyperbols);
+ res = darray_hyperboloid_resize(&parser->hyperbols, ishape + 1);
+ if(res != RES_OK) {
+ log_err(parser, hyperboloid, "could not allocate the hyperbol shape.\n");
+ goto error;
+ }
+ shape = darray_hyperboloid_data_get(&parser->hyperbols) + ishape;
+
+ n = hyperboloid->data.mapping.pairs.top - hyperboloid->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, hyperboloid->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect hyperbol parameters.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the hyperbol parameter `"Name"' is already defined.\n"); \
+ 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, "focals")) {
+ SETUP_MASK(FOCAL, "focals");
+ res = parse_focals_description(parser, doc, val, &shape->focals);
+ } 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 hyperbol parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, hyperboloid, \
+ "the hyperbol parameter `"Name"' is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(CLIP, "clip");
+ CHECK_PARAM(FOCAL, "focals");
+ #undef CHECK_PARAM
+
+exit :
+ out_ishape->i = ishape;
+ return res;
+error:
+ if(shape) {
+ darray_hyperboloid_pop_back(&parser->hyperbols);
+ 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, SLICES };
+ 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;
+ }
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the plane parameter `"Name"' is already defined.\n"); \
+ 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, "slices")) {
+ SETUP_MASK(SLICES, "slices");
+ res = parse_integer(parser, val, 1, 4096, &shape->nslices);
+ } else {
+ log_err(parser, key, "unknown plane parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+ 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, nextafter(0, 1), 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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, sphere, \
+ "the sphere parameter `"Name"' is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(RADIUS, "radius");
+ #undef CHECK_PARAM
+
+ #define DEFAULT_PARAM(Flag, Ptr, Value) \
+ if(!(mask & BIT(Flag))) { \
+ *(Ptr) = Value; \
+ } (void)0
+ DEFAULT_PARAM(SLICES, &shape->nslices, 16);
+ #undef DEFAULT_PARAM
+
+exit:
+ out_ishape->i = ishape;
+ return res;
+error:
+ if(shape) {
+ darray_sphere_pop_back(&parser->spheres);
+ ishape = SIZE_MAX;
+ }
+ goto exit;
+}
+
+
+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, "hyperbol")) {
+ SETUP_MASK(SHAPE, "shape");
+ shape->type = SOLPARSER_SHAPE_HYPERBOL;
+ res = parse_hyperboloid(parser, doc, val, &shape->data.hyperbol);
+ } 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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+parse_focals_description
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* desc,
+ struct solparser_hyperboloid_focals* focals)
+{
+ enum { REAL, IMAGE };
+ intptr_t i, n;
+ int mask = 0; /* Register the parsed attributes */
+ res_T res = RES_OK;
+ ASSERT(doc && desc && focals);
+
+ if(desc->type != YAML_MAPPING_NODE) {
+ log_err(parser, desc, "expect a mapping of focal parameters.\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 focal parameters.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the focal parameter `"Name"' is already defined.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ mask |= BIT(Flag); \
+ } (void)0
+ if(!strcmp((char*) key->data.scalar.value, "real")) {
+ SETUP_MASK(REAL, "real");
+ res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->real);
+ } else if(!strcmp((char*) key->data.scalar.value, "image")) {
+ SETUP_MASK(IMAGE, "image");
+ res = parse_real(parser, val, nextafter(0, 1), DBL_MAX, &focals->image);
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ }
+ #undef SETUP_MASK
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, desc, \
+ "the focal parameter `"Name"' is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(REAL, "real");
+ CHECK_PARAM(IMAGE, "image");
+ #undef CHECK_PARAM
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+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;
+}
+
+
+
diff --git a/src/parser/solparser_material.c b/src/parser/solparser_material.c
@@ -0,0 +1,716 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_c.h"
+#include <math.h> /* nextafter */
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static res_T
+parse_medium
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* medium,
+ struct solparser_medium_id* out_imedium)
+{
+ enum { ABSORPTIVITY, REFRACTIVE_INDEX };
+ struct solparser_medium* mdm = NULL;
+ size_t imedium = SIZE_MAX;
+ int mask = 0; /* Register the parsed attributes */
+ intptr_t i, n;
+ res_T res = RES_OK;
+ ASSERT(doc && medium && out_imedium);
+
+ if(medium->type != YAML_MAPPING_NODE) {
+ log_err(parser, medium, "expect a mapping of medium attributes.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate the medium */
+ imedium = darray_medium_size_get(&parser->mediums);
+ res = darray_medium_resize(&parser->mediums, imedium + 1);
+ if(res != RES_OK) {
+ log_err(parser, medium, "could not allocate the medium.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ mdm = darray_medium_data_get(&parser->mediums) + imedium;
+
+ n = medium->data.mapping.pairs.top - medium->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, medium->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect a medium 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 medium is already defined.\n");\
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ mask |= BIT(Flag); \
+ } (void)0
+ if(!strcmp((char*)key->data.scalar.value, "absorptivity")) {
+ SETUP_MASK(ABSORPTIVITY, "absorptivity");
+ res = parse_real(parser, val, 0, DBL_MAX, &mdm->absorptivity);
+ } else if(!strcmp((char*)key->data.scalar.value, "refractive_index")) {
+ SETUP_MASK(REFRACTIVE_INDEX, "refractive_index");
+ res = parse_real
+ (parser, val, nextafter(0, 1), DBL_MAX, &mdm->refractive_index);
+ } else {
+ log_err(parser, key, "unknown medium parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, medium, "the "Name" of the medium is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(ABSORPTIVITY, "absorptivity");
+ CHECK_PARAM(REFRACTIVE_INDEX, "refractive_index");
+ #undef CHECK_PARAM
+
+exit:
+ out_imedium->i = imedium;
+ return res;
+error:
+ if(imedium) {
+ darray_medium_pop_back(&parser->mediums);
+ imedium = SIZE_MAX;
+ }
+ goto exit;
+}
+
+static res_T
+parse_material_dielectric
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* dielec,
+ struct solparser_material_dielectric_id* out_imtl)
+{
+ enum { MEDIUM_I, MEDIUM_T };
+ struct solparser_material_dielectric* 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 && dielec && out_imtl);
+
+ if(dielec->type != YAML_MAPPING_NODE) {
+ log_err(parser, dielec,
+ "expect a mapping of dielec material attributes.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate the dielec material */
+ imtl = darray_dielectric_size_get(&parser->dielectrics);
+ res = darray_dielectric_resize(&parser->dielectrics, imtl + 1);
+ if(res != RES_OK) {
+ log_err(parser, dielec,
+ "could not allocate the dielec material.\n");
+ goto error;
+ }
+ mtl = darray_dielectric_data_get(&parser->dielectrics) + imtl;
+
+ n = dielec->data.mapping.pairs.top - dielec->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, dielec->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, dielec->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect a dielec 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 dielectric material is already defined.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ mask |= BIT(Flag); \
+ } (void)0
+ if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
+ SETUP_MASK(MEDIUM_I, "medium_i");
+ res = parse_medium(parser, doc, val, &mtl->medium_i);
+ } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) {
+ SETUP_MASK(MEDIUM_T, "medium_t");
+ res = parse_medium(parser, doc, val, &mtl->medium_t);
+ } else {
+ log_err(parser, key, "unknown dielectric parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, dielec, \
+ "the "Name" of the dielectric material is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(MEDIUM_I, "medium_i");
+ CHECK_PARAM(MEDIUM_T, "medium_t");
+ #undef CHECK_PARAM
+
+exit:
+ out_imtl->i = imtl;
+ return res;
+error:
+ if(imtl) {
+ darray_dielectric_pop_back(&parser->dielectrics);
+ imtl = SIZE_MAX;
+ }
+ goto exit;
+}
+
+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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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_thin_dielectric
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ yaml_node_t* thin,
+ struct solparser_material_thin_dielectric_id* out_imtl)
+{
+ enum { MEDIUM_I, MEDIUM_T, THICKNESS };
+ struct solparser_material_thin_dielectric* 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 && thin && out_imtl);
+
+ if(thin->type != YAML_MAPPING_NODE) {
+ log_err(parser, thin,
+ "expect a mapping of thin dielectric material attributes.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate the thin dielectric material */
+ imtl = darray_thin_dielectric_size_get(&parser->thin_dielectrics);
+ res = darray_thin_dielectric_resize(&parser->thin_dielectrics, imtl + 1);
+ if(res != RES_OK) {
+ log_err(parser, thin,
+ "could not allocate the thin dielectric material.\n");
+ goto error;
+ }
+ mtl = darray_thin_dielectric_data_get(&parser->thin_dielectrics) + imtl;
+
+ n = thin->data.mapping.pairs.top - thin->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, thin->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, thin->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect a thin dielectric 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 thin dielectric material is already defined.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } \
+ mask |= BIT(Flag); \
+ } (void)0
+ if(!strcmp((char*)key->data.scalar.value, "medium_i")) {
+ SETUP_MASK(MEDIUM_I, "medium_i");
+ res = parse_medium(parser, doc, val, &mtl->medium_i);
+ } else if(!strcmp((char*)key->data.scalar.value, "medium_t")) {
+ SETUP_MASK(MEDIUM_T, "medium_t");
+ res = parse_medium(parser, doc, val, &mtl->medium_t);
+ } else if(!strcmp((char*)key->data.scalar.value, "thickness")) {
+ SETUP_MASK(THICKNESS, "thickness");
+ res = parse_real(parser, val, 0, DBL_MAX, &mtl->thickness);
+ } else {
+ log_err(parser, key, "unknown thin dielectric parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, thin, \
+ "the "Name" of the thin dielectric material is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(MEDIUM_I, "medium_i");
+ CHECK_PARAM(MEDIUM_T, "medium_t");
+ CHECK_PARAM(THICKNESS, "thickness");
+ #undef CHECK_PARAM
+
+exit:
+ out_imtl->i = imtl;
+ return res;
+error:
+ if(mtl) {
+ darray_thin_dielectric_pop_back(&parser->thin_dielectrics);
+ imtl = SIZE_MAX;
+ }
+ goto exit;
+}
+
+static res_T
+parse_material_virtual(struct solparser* parser, yaml_node_t* virtual)
+{
+ res_T res = RES_OK;
+ ASSERT(virtual);
+
+ if(virtual->type != YAML_SCALAR_NODE
+ || ((char*)virtual->data.scalar.value)[0] != '\0') {
+ log_err(parser, virtual,
+ "virtual materials can have a null scalar value only.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ 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, "dielectric")) {
+ SETUP_MASK(DESCRIPTOR, "descriptor");
+ mtl->type = SOLPARSER_MATERIAL_DIELECTRIC;
+ res = parse_material_dielectric(parser, doc, val, &mtl->data.dielectric);
+ } else 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 if(!strcmp((char*)key->data.scalar.value, "thin_dielectric")) {
+ SETUP_MASK(DESCRIPTOR, "descriptor");
+ mtl->type = SOLPARSER_MATERIAL_THIN_DIELECTRIC;
+ res = parse_material_thin_dielectric
+ (parser, doc, val, &mtl->data.thin_dielectric);
+ } else if(!strcmp((char*)key->data.scalar.value, "virtual")) {
+ SETUP_MASK(DESCRIPTOR, "descriptor");
+ mtl->type = SOLPARSER_MATERIAL_VIRTUAL;
+ res = parse_material_virtual(parser, val);
+ } else {
+ log_err(parser, key, "unknown material descriptor `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+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; /* Discard log_node */
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+}
+
diff --git a/src/parser/solparser_pivot.c b/src/parser/solparser_pivot.c
@@ -0,0 +1,372 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_c.h"
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static res_T
+parse_anchor_alias
+ (struct solparser* parser,
+ const yaml_node_t* alias,
+ const struct solparser_pivot_id pivot,
+ 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;
+ }
+
+ if(!strncmp((char*)alias->data.scalar.value, "self.", 5)) {
+ struct target_alias tgt;
+ tgt.pivot = pivot;
+ tgt.alias = alias;
+ res = darray_tgtalias_push_back(&parser->tgtaliases, &tgt);
+ if(res != RES_OK) {
+ log_err(parser, alias, "could not register the anchor alias.\n");
+ goto error;
+ }
+ } else {
+ 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_node,
+ struct solparser_target* target,
+ struct solparser_pivot_id pivot_id)
+{
+ enum { POLICY };
+ intptr_t i, n;
+ int mask = 0; /* Register the parsed attributes */
+ res_T res = RES_OK;
+ ASSERT(doc && target_node && target);
+
+ if(target_node->type != YAML_MAPPING_NODE) {
+ log_err(parser, target_node, "expect a target definition.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ n = target_node->data.mapping.pairs.top - target_node->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, target_node->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, target_node->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");
+ target->type = SOLPARSER_TARGET_ANCHOR;
+ res = parse_anchor_alias(parser, val, pivot_id, &target->data.anchor);
+ } else if(!strcmp((char*)key->data.scalar.value, "direction")) {
+ SETUP_MASK(POLICY, "policy");
+ target->type = SOLPARSER_TARGET_DIRECTION;
+ res = parse_real3
+ (parser, doc, val, -DBL_MAX, DBL_MAX, target->data.direction);
+ } else if(!strcmp((char*)key->data.scalar.value, "position")) {
+ SETUP_MASK(POLICY, "policy");
+ target->type = SOLPARSER_TARGET_POSITION;
+ res = parse_real3
+ (parser, doc, val, -DBL_MAX, DBL_MAX, target->data.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");
+ 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) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+
+ if(!(mask & BIT(POLICY))) {
+ log_err(parser, target_node, "the target policy is missing.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+parse_x_pivot
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* x_pivot,
+ struct solparser_pivot_id* out_isolpivot)
+{
+ enum { REF_POINT, TARGET };
+ struct solparser_x_pivot* solxpivot = NULL;
+ size_t isolpivot = SIZE_MAX;
+ int mask = 0; /* Register the parsed attributes */
+ intptr_t i, n;
+ res_T res = RES_OK;
+ ASSERT(doc && x_pivot && out_isolpivot);
+
+ if(x_pivot->type != YAML_MAPPING_NODE) {
+ log_err(parser, x_pivot, "expect a x_pivot definition.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate the solstice pivot */
+ isolpivot = darray_x_pivot_size_get(&parser->x_pivots);
+ res = darray_x_pivot_resize(&parser->x_pivots, isolpivot + 1);
+ if(res != RES_OK) {
+ log_err(parser, x_pivot, "could not allocate the x_pivot.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ solxpivot = darray_x_pivot_data_get(&parser->x_pivots) + isolpivot;
+
+ n = x_pivot->data.mapping.pairs.top - x_pivot->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, x_pivot->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(doc, x_pivot->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect x_pivot parameters.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the x_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, "ref_point")) {
+ SETUP_MASK(REF_POINT, "point");
+ res = parse_real3(parser, doc, val, -DBL_MAX, DBL_MAX, solxpivot->ref_point);
+ } else if(!strcmp((char*)key->data.scalar.value, "target")) {
+ struct solparser_pivot_id pivot_id;
+ pivot_id.i = (size_t) (solxpivot - darray_x_pivot_cdata_get(&parser->x_pivots));
+ SETUP_MASK(TARGET, "target");
+ res = parse_target(parser, doc, val, &solxpivot->target, pivot_id);
+ } else {
+ log_err(parser, key, "unknown x_pivot parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, x_pivot, "the x_pivot parameter `"Name"' is missing.\n");\
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(TARGET, "target");
+ #undef CHECK_PARAM
+
+ #define DEFAULT_PARAM(Flag, Ptr, Value) \
+ if(!(mask & BIT(Flag))) { \
+ *(Ptr) = Value; \
+ } (void)0
+ DEFAULT_PARAM(REF_POINT, solxpivot->ref_point, 0);
+ DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+1, 0);
+ DEFAULT_PARAM(REF_POINT, solxpivot->ref_point+2, 0);
+ #undef DEFAULT_PARAM
+
+exit:
+ out_isolpivot->i = isolpivot;
+ return res;
+error:
+ if(solxpivot) {
+ darray_x_pivot_pop_back(&parser->x_pivots);
+ isolpivot = SIZE_MAX;
+ }
+ goto exit;
+}
+
+res_T
+parse_zx_pivot
+ (struct solparser* parser,
+ yaml_document_t* doc,
+ const yaml_node_t* zx_pivot,
+ struct solparser_pivot_id* out_isolpivot)
+{
+ enum { SPACING, REF_POINT, TARGET };
+ struct solparser_zx_pivot* solxzpivot = NULL;
+ size_t isolpivot = SIZE_MAX;
+ int mask = 0; /* Register the parsed attributes */
+ intptr_t i, n;
+ res_T res = RES_OK;
+ ASSERT(doc && zx_pivot && out_isolpivot);
+
+ if(zx_pivot->type != YAML_MAPPING_NODE) {
+ log_err(parser, zx_pivot, "expect a zx_pivot definition.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ /* Allocate the solstice pivot */
+ isolpivot = darray_zx_pivot_size_get(&parser->zx_pivots);
+ res = darray_zx_pivot_resize(&parser->zx_pivots, isolpivot + 1);
+ if(res != RES_OK) {
+ log_err(parser, zx_pivot, "could not allocate the zx_pivot.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ solxzpivot = darray_zx_pivot_data_get(&parser->zx_pivots) + isolpivot;
+
+ n = zx_pivot->data.mapping.pairs.top - zx_pivot->data.mapping.pairs.start;
+ FOR_EACH(i, 0, n) {
+ yaml_node_t* key;
+ yaml_node_t* val;
+
+ key = yaml_document_get_node(doc, zx_pivot->data.mapping.pairs.start[i].key);
+ val = yaml_document_get_node(
+ doc, zx_pivot->data.mapping.pairs.start[i].value);
+ if(key->type != YAML_SCALAR_NODE) {
+ log_err(parser, key, "expect zx_pivot parameters.\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ #define SETUP_MASK(Flag, Name) { \
+ if(mask & BIT(Flag)) { \
+ log_err(parser, key, \
+ "the zx_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, "spacing")) {
+ SETUP_MASK(SPACING, "spacing");
+ res = parse_real(parser, val, 0, DBL_MAX, &solxzpivot->spacing);
+ } else if(!strcmp((char*) key->data.scalar.value, "ref_point")) {
+ SETUP_MASK(REF_POINT, "ref_point");
+ res = parse_real3(
+ parser, doc, val, -DBL_MAX, DBL_MAX, solxzpivot->ref_point);
+ } else if(!strcmp((char*) key->data.scalar.value, "target")) {
+ struct solparser_pivot_id pivot_id;
+ pivot_id.i =
+ (size_t) (solxzpivot - darray_zx_pivot_cdata_get(&parser->zx_pivots));
+ SETUP_MASK(TARGET, "target");
+ res = parse_target(parser, doc, val, &solxzpivot->target, pivot_id);
+ } else {
+ log_err(parser, key, "unknown zx_pivot parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ goto error;
+ }
+ #undef SETUP_MASK
+ }
+ #define CHECK_PARAM(Flag, Name) \
+ if(!(mask & BIT(Flag))) { \
+ log_err(parser, zx_pivot, \
+ "the zx_pivot parameter `"Name"' is missing.\n"); \
+ res = RES_BAD_ARG; \
+ goto error; \
+ } (void)0
+ CHECK_PARAM(TARGET, "target");
+ #undef CHECK_PARAM
+
+ #define DEFAULT_PARAM(Flag, Ptr, Value) \
+ if(!(mask & BIT(Flag))) { \
+ *(Ptr) = Value; \
+ } (void)0
+ DEFAULT_PARAM(SPACING, &solxzpivot->spacing, 0);
+ DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point, 0);
+ DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+1, 0);
+ DEFAULT_PARAM(REF_POINT, solxzpivot->ref_point+2, 0);
+ #undef DEFAULT_PARAM
+
+exit:
+ out_isolpivot->i = isolpivot;
+ return res;
+error:
+ if(solxzpivot) {
+ darray_zx_pivot_pop_back(&parser->zx_pivots);
+ isolpivot = SIZE_MAX;
+ }
+ goto exit;
+}
+
+
diff --git a/src/parser/solparser_spectrum.c b/src/parser/solparser_spectrum.c
@@ -0,0 +1,145 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_c.h"
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+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;
+}
+
diff --git a/src/parser/solparser_spectrum.h b/src/parser/solparser_spectrum.h
@@ -0,0 +1,31 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_SPECTRUM_H
+#define SOLPARSER_SPECTRUM_H
+
+#include <rsys/dynamic_array.h>
+
+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>
+
+#endif /* SOLPARSER_SPECTRUM_H */
+
diff --git a/src/parser/solparser_sun.c b/src/parser/solparser_sun.c
@@ -0,0 +1,261 @@
+/* Copyright (C) CNRS 2016-2017
+ *
+ * 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_c.h"
+#include <math.h> /* nextafter */
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+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, 1e-6, 0.849, &sun->csr);
+ } else {
+ log_err(parser, key, "unknown buie parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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), 90, &sun->aperture);
+ } else {
+ log_err(parser, pillbox, "unknown pillbox parameter `%s'.\n",
+ key->data.scalar.value);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+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;
+ goto error;
+ }
+ if(res != RES_OK) {
+ log_node(parser, key);
+ 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;
+}
+
+
diff --git a/src/parser/solparser_sun.h b/src/parser/solparser_sun.h
@@ -16,6 +16,7 @@
#ifndef SOLPARSER_SUN_H
#define SOLPARSER_SUN_H
+#include "solparser_spectrum.h"
#include <rsys/dynamic_array.h>
enum solparser_sun_radang_distrib_type { /* Radial Angular distribution */
@@ -24,15 +25,6 @@ enum solparser_sun_radang_distrib_type { /* Radial Angular distribution */
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; };