solstice

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

commit 99b250ce4ed539d9c3e446374cc61feb69b721a8
parent b616ce8d0d5a84bb1470927497271fef284a1c38
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 19 Dec 2016 21:54:13 +0100

Merge remote-tracking branch 'origin/master'

Diffstat:
Mcmake/CMakeLists.txt | 44+++++++++++++++++++++++++++++++++++++++++++-
Mcmake/core/CMakeLists.txt | 16+++++++---------
Adoc/cli | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/core/solstice_core.h | 92++++++++++++++-----------------------------------------------------------------
Msrc/core/solstice_core_device.c | 9+++++++++
Msrc/core/solstice_core_device.h | 6++++++
Msrc/core/solstice_core_node.c | 244++++++++++---------------------------------------------------------------------
Msrc/core/solstice_core_node.h | 36+++++++-----------------------------
Dsrc/core/solstice_core_scene.c | 450-------------------------------------------------------------------------------
Dsrc/core/solstice_core_scene.h | 40----------------------------------------
Msrc/core/solstice_core_solver.c | 8++++----
Msrc/main.c | 35++++-------------------------------
Msrc/solstice.h | 15+++++++++++++++
Asrc/solstice_args.c | 283+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/solstice_args.h.in | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/solstice_c.h | 4++++
Msrc/solstice_entity.c | 217++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/solstice_material.c | 1-
Asrc/test_solstice_args.c | 130+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 889 insertions(+), 869 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -34,6 +34,11 @@ find_package(SolSolver 0.1 REQUIRED) find_package(Star3DUT REQUIRED) find_package(StarSP 0.4 REQUIRED) +if(MSVC) + find_package(MuslGetopt REQUIRED) + include_directories(${MuslGetopt_INCLUDE_DIR}) +endif() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) @@ -43,7 +48,8 @@ include_directories( ${SolAnim_INCLUDE_DIR} ${SolSolver_INCLUDE_DIR} ${StarSP_INCLUDE_DIR} - ${Star3DUT_INCLUDE_DIR}) + ${Star3DUT_INCLUDE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) ################################################################################ # Build subprojects @@ -52,6 +58,20 @@ add_subdirectory(parser) add_subdirectory(core) ################################################################################ +# Generate files +################################################################################ +set(SOLSTICE_ARGS_DEFAULT_NREALISATIONS "10000") +set(SOLSTICE_ARGS_DEFAULT_CAMERA_POS "0,0,0") +set(SOLSTICE_ARGS_DEFAULT_CAMERA_TGT "0,0,-1") +set(SOLSTICE_ARGS_DEFAULT_CAMERA_UP "0,1,0") +set(SOLSTICE_ARGS_DEFAULT_CAMERA_FOV "70") +set(SOLSTICE_ARGS_DEFAULT_IMG_WIDTH "800") +set(SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT "600") + +configure_file(${SOLSTICE_SOURCE_DIR}/solstice_args.h.in + ${CMAKE_CURRENT_BINARY_DIR}/solstice_args.h @ONLY) + +################################################################################ # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) @@ -61,11 +81,13 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SOLSTICE_FILES_SRC solstice.c + solstice_args.c solstice_entity.c solstice_material.c solstice_object.c) set(SOLSTICE_FILES_INC solstice.h + solstice_args.h.in solstice_c.h) set(SOLSTICE_FILES_DOC COPYING README.md) @@ -88,6 +110,26 @@ set_target_properties(solstice PROPERTIES rcmake_copy_runtime_libraries(solstice) ################################################################################ +# Tests +################################################################################ +if(NOT NO_TEST) + function(build_test _name) + add_executable(${_name} + ${SOLSTICE_SOURCE_DIR}/${_name}.c + ${SOLSTICE_SOURCE_DIR}/test_solstice_utils.h) + target_link_libraries(${_name} ${MATH_LIB} RSys sollib) + endfunction() + + function(new_test _name) + build_test(${_name}) + add_test(${_name} ${_name}) + endfunction() + + new_test(test_solstice_args) + +endif() + +################################################################################ # Define output & install directories ################################################################################ install(TARGETS solstice diff --git a/cmake/core/CMakeLists.txt b/cmake/core/CMakeLists.txt @@ -34,14 +34,12 @@ include_directories( set(CORE_FILES_SRC solstice_core_device.c solstice_core_node.c - solstice_core_scene.c solstice_core_solver.c) set(CORE_FILES_INC solstice_core.h solstice_core_device.h - solstice_core_node.h - solstice_core_scene.h) + solstice_core_node.h) # Prepend each file in the `SOLSTICE_FILES_<SRC|INC>' list by `SOLSTICE_SOURCE_DIR' rcmake_prepend_path(CORE_FILES_SRC ${CORE_SOURCE_DIR}) @@ -70,11 +68,11 @@ if(NOT NO_TEST) ${CORE_SOURCE_DIR}/test_core_utils.h ${CORE_SOURCE_DIR}/test_core_utils.c) - - new_test(test_core_device) - new_test(test_core_node) - new_test(test_core_scene) - new_test(test_core_solve1) +# TODO: tests need to be fixed +# new_test(test_core_device) +# new_test(test_core_node) +# new_test(test_core_scene) +# new_test(test_core_solve1) - rcmake_copy_runtime_libraries(test_core_solve1) +# rcmake_copy_runtime_libraries(test_core_solve1) endif() diff --git a/doc/cli b/doc/cli @@ -0,0 +1,51 @@ +solstice + -d <date-list>:<pos-on-earth> + -D <sun-dir-list> + -h # Short help and exit + -o OUTPUT # defaulting to stdout if not defined + -q # don't print a message if no INPUT is submitted + -n INTEGER # Realisations count + -r [rendering] # Switch in rendering mode + INPUT # Input scene in YAML + +solstice -r img=1280x720:pos=0,100,0:tgt=0,0,0:up=0,1,0:fov=70 + +<date-list> ::= + <date> [ ... ] + +<date> ::= + year:month:day:minutes:seconds:timezone # <=> UNIX format + +<sun-dir-list> ::= + <sun-dir> [ ... ] + +<sun-dir> ::= + REAL:REAL # azimuth:elevation + +<pos-on-earth> ::= + REAL:REAL:REAL # longititude:latitude:altitude + +<rendering> ::= + <rendering-option>[:<rendering-option> ... ] + +<rendering-option> ::= + <fov> | <img> | <position> | <target> | <up> + +<fov> ::= + fov=<real3> + +<img> ::= + img=INTEGERxINTEGER + +<position> ::= + pos=<real3> + +<target> ::= + tgt=<real3> + +<up> ::= + up=<real3> + +<real3> ::= + REAL,REAL,REAL + diff --git a/src/core/solstice_core.h b/src/core/solstice_core.h @@ -35,7 +35,6 @@ struct ssp_rng; struct score_device; struct score_node; -struct score_scene; /******************************************************************************* * Device API - Main entry point of Solstice core. Applications @@ -65,22 +64,17 @@ score_device_get_solver_device * Node API ******************************************************************************/ extern LOCAL_SYM res_T -score_node_template_create +score_node_geometry_create (struct score_device* dev, - struct score_node** node); - -extern LOCAL_SYM res_T -score_node_instantiate - (struct score_node* template, - struct score_node** instance); + struct score_node** geom); extern LOCAL_SYM res_T -score_node_create_object +score_node_pivot_create (struct score_device* dev, struct score_node** node); extern LOCAL_SYM res_T -score_node_pivot_create +score_node_empty_create (struct score_device* dev, struct score_node** node); @@ -98,9 +92,9 @@ score_node_ref_put (struct score_node* node); extern LOCAL_SYM res_T -score_node_object_setup +score_node_geometry_setup (struct score_node* node, - struct ssol_object* object); + struct ssol_instance* geom); extern LOCAL_SYM res_T score_node_pivot_setup @@ -150,80 +144,26 @@ score_node_sample (struct score_node* node, const int sample); -/* Temporary API for testing purpose - * Instance introspection. - * If the template tree from which instance was created contains node, - * find the corresponding node in instance */ -extern LOCAL_SYM void -score_node_get_instance_of - (const struct score_node* instance, - const struct score_node* node, - struct ssol_instance** solver); - /******************************************************************************* - * Scene API - ******************************************************************************/ -extern LOCAL_SYM res_T -score_scene_create - (struct score_device* dev, - struct score_scene** scene); - -extern LOCAL_SYM void -score_scene_ref_get - (struct score_scene* scene); - -extern LOCAL_SYM void -score_scene_ref_put - (struct score_scene* scene); - -extern LOCAL_SYM res_T -score_scene_attach_instance - (struct score_scene* scene, - struct score_node* instance); - -extern LOCAL_SYM void -score_scene_detach_instance - (struct score_scene* scene, - struct score_node* instance); - -extern LOCAL_SYM void -score_scene_attach_sun - (struct score_scene* scene, - struct ssol_sun* sun); - -extern LOCAL_SYM void -score_scene_detach_sun - (struct score_scene* scene, - struct ssol_sun* sun); - -extern LOCAL_SYM void -score_scene_attach_atmosphere - (struct score_scene* scene, - struct ssol_atmosphere* atm); - -extern LOCAL_SYM void -score_scene_detach_atmosphere - (struct score_scene* scene, - struct ssol_atmosphere* atm); - +* Miscellaneous functions +******************************************************************************/ extern LOCAL_SYM void score_scene_clear - (struct score_scene* scene); + (struct score_device* dev); extern LOCAL_SYM res_T -score_scene_reset_simulation - (struct score_scene* scene); +score_reset_simulation + (struct score_device* dev, + const double sun_dir[3]); extern LOCAL_SYM res_T -score_scene_update_simulation - (struct score_scene* scene); +score_update_simulation + (struct score_device* dev, + const double sun_dir[3]); -/******************************************************************************* - * Miscellaneous functions - ******************************************************************************/ extern LOCAL_SYM res_T score_solve - (struct score_scene* scene, + (struct score_device* dev, struct ssp_rng* rng, const size_t realisations_count, FILE* output, diff --git a/src/core/solstice_core_device.c b/src/core/solstice_core_device.c @@ -48,6 +48,9 @@ device_release(ref_T* ref) ASSERT(ref); dev = CONTAINER_OF(ref, struct score_device, ref); ASSERT(dev && dev->allocator); + if (dev->solver) SSOL(scene_ref_put(dev->solver)); + darray_nodes_release(&dev->instances); + darray_nodes_release(&dev->pivots); if (dev->ssol) ssol_device_ref_put(dev->ssol); MEM_RM(dev->allocator, dev); } @@ -83,6 +86,12 @@ score_device_create res = ssol_device_create(logger, allocator, nthreads_hint, verbose, &dev->ssol); if (res != RES_OK) goto error; + res = ssol_scene_create(dev->ssol, &dev->solver); + if (res != RES_OK) goto error; + + darray_nodes_init(dev->allocator, &dev->instances); + darray_nodes_init(dev->allocator, &dev->pivots); + exit: if (out_dev) *out_dev = dev; return res; diff --git a/src/core/solstice_core_device.h b/src/core/solstice_core_device.h @@ -16,6 +16,8 @@ #ifndef SOLSTICE_CORE_DEVICE_H #define SOLSTICE_CORE_DEVICE_H +#include "solstice_core_node.h" + #include <rsys/ref_count.h> #include <rsys/mem_allocator.h> @@ -28,6 +30,10 @@ struct score_device { int verbose; struct ssol_device* ssol; + struct darray_nodes instances; + struct darray_nodes pivots; + struct ssol_scene* solver; + ref_T ref; }; diff --git a/src/core/solstice_core_node.c b/src/core/solstice_core_node.c @@ -36,22 +36,11 @@ node_release(ref_T* ref) dev = node->device; ASSERT(dev && dev->allocator); switch (node->type) { - case NODE_TEMPLATE_ROOT: - break; - case NODE_INSTANCE_ROOT: - darray_nodes_release(&node->data.instance_root.pivots); - if (node->data.instance_root.template) - score_node_ref_put(node->data.instance_root.template); - break; case NODE_TRACKING_TARGET: break; - case NODE_TEMPLATE: - if (node->data.template_node.solver_object) - SSOL(object_ref_put(node->data.template_node.solver_object)); - break; - case NODE_INSTANCE: - if (node->data.instance_node.solver_instance) - SSOL(instance_ref_put(node->data.instance_node.solver_instance)); + case NODE_GEOMETRY: + if (node->data.geometry_node.solver_instance) + SSOL(instance_ref_put(node->data.geometry_node.solver_instance)); break; case NODE_PIVOT: break; @@ -68,27 +57,6 @@ struct data { struct ssol_instance* result; }; -static res_T -search(const struct sanim_node* n, void* data_, int* found) -{ - const struct score_node* node; - struct data* data; - ASSERT(n && data_ && found); - - data = data_; - node = CONTAINER_OF(n, struct score_node, anim); - if (node->type == NODE_INSTANCE) { - const struct ssol_object* solver_model; - ASSERT(node->data.instance_node.model->type == NODE_TEMPLATE); - solver_model = node->data.instance_node.model->data.template_node.solver_object; - if (solver_model == data->searched) { - data->result = node->data.instance_node.solver_instance; - *found = 1; - return RES_OK; - } - } - return RES_OK; -} /******************************************************************************* * Local functions @@ -144,139 +112,39 @@ node_ref_put_children(struct sanim_node* node) } } -static res_T -instance_internal_node_create - (struct score_device* dev, struct score_node** node) -{ - struct sanim_node* anim; - res_T res = RES_OK; - res = node_create(dev, node, NODE_INSTANCE); - if (res != RES_OK) goto error; - anim = &(*node)->anim; - res = sanim_node_initialize((*node)->device->allocator, anim); - if (res != RES_OK) goto error; -exit: - return res; -error: - if (node && *node) { - score_node_ref_put(*node); - *node = NULL; - } - goto exit; -} - -res_T -node_instanciate_any - (struct score_node* tp_node, - struct score_node** out_node) -{ - struct score_node* node = NULL; - struct score_device* dev; - double v[3]; - res_T res = RES_OK; - - ASSERT(tp_node && out_node); - - dev = tp_node->device; - ASSERT(dev && dev->allocator); - - switch (tp_node->type) { - case NODE_TEMPLATE_ROOT: - res = score_node_instantiate(tp_node, &node); - if (res != RES_OK) goto error; - break; - case NODE_INSTANCE_ROOT: - ASSERT(0); - goto error; - case NODE_TRACKING_TARGET: - res = score_node_tracking_target_create(dev, &node); - if (res != RES_OK) goto error; - SANIM(node_get_translation(&tp_node->anim, v)); - SANIM(node_set_translation(&node->anim, v)); - /* rotations have no meaning for a target */ - break; - case NODE_TEMPLATE: - res = instance_internal_node_create(dev, &node); - if (res != RES_OK) goto error; - res = ssol_object_instantiate( - tp_node->data.template_node.solver_object, - &node->data.instance_node.solver_instance); - if (res != RES_OK) goto error; - node->data.instance_node.model = tp_node; - node->data.instance_node.receiver_mask - = tp_node->data.template_node.receiver_mask; - node->data.instance_node.sample - = tp_node->data.template_node.sample; - SANIM(node_get_translation(&tp_node->anim, v)); - SANIM(node_set_translation(&node->anim, v)); - SANIM(node_get_rotations(&tp_node->anim, v)); - SANIM(node_set_rotations(&node->anim, v)); - break; - case NODE_INSTANCE: - ASSERT(0); - goto error; - case NODE_PIVOT: -#ifndef NDEBUG - { - int p; - ASSERT(sanim_node_is_pivot(&tp_node->anim, &p) == RES_OK && p); - } -#endif - res = score_node_pivot_create(dev, &node); - if (res != RES_OK) goto error; - res = sanim_node_copy_initialize( - dev->allocator, &tp_node->anim, &node->anim); - /* copy includes translation and rotations */ - if (res != RES_OK) goto error; - break; - default: FATAL("Unreachable code.\n"); break; - } - -exit: - if (out_node) *out_node = node; - return res; -error: - if (node) { - score_node_ref_put(node); - node = NULL; - } - goto exit; -} - /******************************************************************************* * Exported score_node functions ******************************************************************************/ res_T -score_node_template_create +score_node_geometry_create (struct score_device* dev, - struct score_node** node) + struct score_node** geom) { struct sanim_node* anim; res_T res = RES_OK; - res = node_create(dev, node, NODE_TEMPLATE_ROOT); + res = node_create(dev, geom, NODE_GEOMETRY); if (res != RES_OK) goto error; - anim = &(*node)->anim; - res = sanim_node_initialize((*node)->device->allocator, anim); + anim = &(*geom)->anim; + res = sanim_node_initialize((*geom)->device->allocator, anim); if (res != RES_OK) goto error; exit: return res; error: - if (node && *node) { - score_node_ref_put(*node); - *node = NULL; + if (geom && *geom) { + score_node_ref_put(*geom); + *geom = NULL; } goto exit; } res_T -score_node_create_object +score_node_pivot_create (struct score_device* dev, struct score_node** node) { res_T res = RES_OK; - res = node_create(dev, node, NODE_TEMPLATE); + res = node_create(dev, node, NODE_PIVOT); if (res != RES_OK) goto error; - (*node)->data.template_node.sample = 1; exit: return res; error: @@ -288,12 +156,12 @@ error: } res_T -score_node_pivot_create +score_node_empty_create (struct score_device* dev, struct score_node** node) { res_T res = RES_OK; - res = node_create(dev, node, NODE_PIVOT); + res = node_create(dev, node, NODE_EMPTY); if (res != RES_OK) goto error; exit: return res; @@ -326,52 +194,22 @@ error: } res_T -score_node_instantiate - (struct score_node* template, - struct score_node** out_instance) -{ - res_T res = RES_OK; - struct score_device* dev; - struct score_node* instance; - ASSERT(template && out_instance && template->type == NODE_TEMPLATE_ROOT); - dev = template->device; - ASSERT(dev); - res = node_create(dev, &instance, NODE_INSTANCE_ROOT); - if (res != RES_OK) goto error; - res = sanim_node_initialize(instance->device->allocator, &instance->anim); - if (res != RES_OK) goto error; - /* actual instantiation is deferred */ - instance->data.instance_root.template = template; - darray_nodes_init(dev->allocator, &instance->data.instance_root.pivots); - score_node_ref_get(template); -exit: - *out_instance = instance; - return res; -error: - if (instance) { - score_node_ref_put(instance); - instance = NULL; - } - goto exit; -} - -res_T -score_node_object_setup +score_node_geometry_setup (struct score_node* node, - struct ssol_object* object) + struct ssol_instance* instance) { res_T res = RES_OK; - ASSERT(node && object && node->type == NODE_TEMPLATE); + ASSERT(node && instance && node->type == NODE_GEOMETRY); /* TODO: deal with multiple setups */ res = sanim_node_initialize(node->device->allocator, &node->anim); if (res != RES_OK) goto error; - node->data.template_node.solver_object = object; - SSOL(object_ref_get(object)); + node->data.geometry_node.solver_instance = instance; + SSOL(instance_ref_put(instance)); exit: return res; error: - if (node->data.template_node.solver_object) { - SSOL(object_ref_put(node->data.template_node.solver_object)); + if (node->data.geometry_node.solver_instance) { + SSOL(instance_ref_put(node->data.geometry_node.solver_instance)); } if (node->anim.data) { SANIM(node_release(&node->anim)); @@ -416,11 +254,7 @@ score_node_add_child { res_T res = RES_OK; ASSERT(father && child - && father->type != NODE_INSTANCE_ROOT - && father->type != NODE_TRACKING_TARGET - && child->type != NODE_TEMPLATE_ROOT - && child->type != NODE_INSTANCE_ROOT - ); + && father->type != NODE_TRACKING_TARGET); res = sanim_node_add_child(&father->anim, &child->anim); if (res != RES_OK) return res; score_node_ref_get(child); @@ -446,7 +280,7 @@ score_node_set_translation (struct score_node* node, const double translation[3]) { - ASSERT(node && translation && node->type != NODE_TEMPLATE_ROOT); + ASSERT(node && translation); SANIM(node_set_translation(&node->anim, translation)); } @@ -455,7 +289,7 @@ score_node_get_translation (const struct score_node* node, double translation[3]) { - ASSERT(node && translation && node->type != NODE_TEMPLATE_ROOT); + ASSERT(node && translation); SANIM(node_get_translation(&node->anim, translation)); } @@ -465,7 +299,6 @@ score_node_set_rotations const double rotations[3]) { ASSERT(node && rotations - && node->type != NODE_TEMPLATE_ROOT && node->type != NODE_TRACKING_TARGET); SANIM(node_set_rotations(&node->anim, rotations)); } @@ -476,7 +309,6 @@ score_node_get_rotations double rotations[3]) { ASSERT(node && rotations - && node->type != NODE_TEMPLATE_ROOT && node->type != NODE_TRACKING_TARGET); SANIM(node_get_rotations(&node->anim, rotations)); } @@ -486,8 +318,8 @@ score_node_set_receiver (struct score_node* node, const int mask) { - ASSERT(node && node->type == NODE_TEMPLATE); - node->data.template_node.receiver_mask = mask; + ASSERT(node && node->type == NODE_GEOMETRY); + node->data.geometry_node.receiver_mask = mask; } void @@ -495,25 +327,7 @@ score_node_sample (struct score_node* node, const int sample) { - ASSERT(node && node->type == NODE_TEMPLATE); - node->data.template_node.sample = sample; + ASSERT(node && node->type == NODE_GEOMETRY); + node->data.geometry_node.sample = sample; } -void -score_node_get_instance_of - (const struct score_node* instance, - const struct score_node* node, - struct ssol_instance** solver) -{ - struct data data; - int found = 0; - ASSERT(instance && node && solver - && instance->type == NODE_INSTANCE_ROOT - && node->type == NODE_TEMPLATE); - - data.searched = node->data.template_node.solver_object; - data.result = NULL; - SANIM(node_search_tree(&instance->anim, &data, search, &found)); - ASSERT(data.result); - *solver = data.result; -} diff --git a/src/core/solstice_core_node.h b/src/core/solstice_core_node.h @@ -21,11 +21,11 @@ #include <rsys/dynamic_array.h> #include <rsys/ref_count.h> -struct sanim_node; +struct score_node; /* Define the darray_nodes data structure */ #define DARRAY_NAME nodes -#define DARRAY_DATA struct sanim_node* +#define DARRAY_DATA struct score_node* #include <rsys/dynamic_array.h> struct score_device; @@ -35,32 +35,16 @@ struct ssol_object; struct ssol_instance; enum node_type { - NODE_TEMPLATE_ROOT, - NODE_INSTANCE_ROOT, - NODE_TEMPLATE, - NODE_INSTANCE, + NODE_GEOMETRY, NODE_TRACKING_TARGET, NODE_PIVOT, + NODE_EMPTY, NODE_TYPES_COUNT__ }; -struct instance_root_data { - struct score_scene* scene_attachment; - struct score_node* template; - /* keep own pivots */ - struct darray_nodes pivots; -}; - -struct template_node_data { - struct ssol_object* solver_object; - int receiver_mask; - int sample; -}; - -struct instance_node_data { +struct geometry_node_data { struct ssol_instance* solver_instance; - struct score_node* model; int receiver_mask; int sample; }; @@ -70,9 +54,8 @@ struct score_node { struct score_device* device; struct sanim_node anim; union { - struct instance_root_data instance_root; - struct template_node_data template_node; - struct instance_node_data instance_node; + /* only types of nodes with specific data */ + struct geometry_node_data geometry_node; } data; ref_T ref; }; @@ -86,9 +69,4 @@ node_create void node_ref_put_children(struct sanim_node* node); -res_T -node_instanciate_any - (struct score_node* tp_node, - struct score_node** out_node); - #endif /* SOLSTICE_CORE_NODE_H */ diff --git a/src/core/solstice_core_scene.c b/src/core/solstice_core_scene.c @@ -1,450 +0,0 @@ -/* Copyright (C) CNRS 2016 -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "solstice_core.h" -#include "solstice_core_scene.h" -#include "solstice_core_node.h" -#include "solstice_core_device.h" - -#include <rsys/double3.h> - -#include <solstice/ssol.h> - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static INLINE struct sanim_node** -contains(struct darray_nodes* array, struct sanim_node* elt) -{ - size_t count, i; - struct sanim_node** data; - ASSERT(array && elt); - count = darray_nodes_size_get(array); - data = darray_nodes_data_get(array); - for (i = 0; i < count; i++) { - if (elt == data[i]) return &data[i]; - } - return NULL; -} - -static int -remove_if(struct darray_nodes* array, struct sanim_node* elt) -{ - size_t count; - struct sanim_node** data; - struct sanim_node** ptr; - ASSERT(array && elt); - ptr = contains(array, elt); - if (ptr == NULL) return 0; - count = darray_nodes_size_get(array); - data = darray_nodes_data_get(array); - *ptr = data[count - 1]; - darray_nodes_pop_back(array); - return 1; -} - -static res_T -create_instance_tree_ - (struct darray_nodes* pivots, - const struct score_node* t_node, - struct score_node* i_node) -{ - res_T res = RES_OK; - size_t count, i; - struct score_node* node = NULL; - int p; - ASSERT(pivots && t_node && i_node); - - SANIM(node_get_children_count(&t_node->anim, &count)); - for (i = 0; i < count; i++) { - struct sanim_node* t_child_; - struct score_node *t_child, *i_child; - SANIM(node_get_child(&t_node->anim, i, &t_child_)); - t_child = CONTAINER_OF(t_child_, struct score_node, anim); - res = node_instanciate_any(t_child, &i_child); - if (res != RES_OK) goto error; - res = sanim_node_add_child(&i_node->anim, &i_child->anim); - if (res != RES_OK) goto error; - create_instance_tree_(pivots, t_child, i_child); - } - - SANIM(node_is_pivot(&i_node->anim, &p)); - if (p) { - struct sanim_node* n = &i_node->anim; - res = darray_nodes_push_back(pivots, &n); - if (res != RES_OK) goto error; - } - -exit: - return res; -error: - if (node) { - node = NULL; - } - goto exit; -} - -static res_T -create_instance_tree(struct score_node* instance) -{ - res_T res = RES_OK; - struct score_node* temp; - ASSERT(instance && instance->type == NODE_INSTANCE_ROOT); - node_ref_put_children(&instance->anim); - darray_nodes_clear(&instance->data.instance_root.pivots); - temp = instance->data.instance_root.template; - ASSERT(temp->type == NODE_TEMPLATE_ROOT); - res = create_instance_tree_(&instance->data.instance_root.pivots, temp, instance); - if (res != RES_OK) goto error; -exit: - return res; -error: - node_ref_put_children(&instance->anim); - darray_nodes_clear(&instance->data.instance_root.pivots); - goto exit; -} - -static res_T -node_to_solver(const struct sanim_node* node_, const double transform[12], void* data) -{ - struct score_node* node; - struct ssol_scene* scene = data; - res_T res = RES_OK; - ASSERT(node_ && transform && data); - node = CONTAINER_OF(node_, struct score_node, anim); - switch (node->type) { - case NODE_TEMPLATE_ROOT: - ASSERT(0); - break; - case NODE_INSTANCE_ROOT: - /* the root doesn't include any solver-related item */ - break; - case NODE_TRACKING_TARGET: - /* not a solver-related item */ - break; - case NODE_TEMPLATE: - ASSERT(0); - break; - case NODE_INSTANCE: - SSOL(instance_set_transform( - node->data.instance_node.solver_instance, transform)); - SSOL(instance_set_receiver( - node->data.instance_node.solver_instance, - node->data.instance_node.receiver_mask)); - SSOL(instance_sample( - node->data.instance_node.solver_instance, - node->data.instance_node.sample)); - res = ssol_scene_attach_instance( - scene, node->data.instance_node.solver_instance); - break; - case NODE_PIVOT: - /* not a solver-related item */ - break; - default: FATAL("Unreachable code.\n"); break; - } - return res; -} - -static res_T -node_to_solver_update(const struct sanim_node* node_, const double transform[12], void* data) -{ - struct score_node* node; - res_T res = RES_OK; - (void) data; - ASSERT(node_ && transform); - node = CONTAINER_OF(node_, struct score_node, anim); - switch (node->type) { - case NODE_TEMPLATE_ROOT: - ASSERT(0); - break; - case NODE_INSTANCE_ROOT: - ASSERT(0); /* should only visit post-pivot nodes */ - break; - case NODE_TRACKING_TARGET: - /* not a solver-related item */ - break; - case NODE_TEMPLATE: - ASSERT(0); - break; - case NODE_INSTANCE: - SSOL(instance_set_transform( - node->data.instance_node.solver_instance, transform)); - break; - case NODE_PIVOT: - /* not a solver-related item */ - break; - default: FATAL("Unreachable code.\n"); break; - } - return res; -} - -static INLINE res_T -update_pivots(struct score_scene* scene, const double sun_dir[3]) -{ - size_t i_count, i; - struct sanim_node** instances; - res_T res = RES_OK; - ASSERT(scene && sun_dir); - i_count = darray_nodes_size_get(&scene->instances); - instances = darray_nodes_data_get(&scene->instances); - for (i = 0; i < i_count; i++) { - size_t p_count, p; - struct sanim_node** pivots; - struct score_node* instance = CONTAINER_OF(instances[i], struct score_node, anim); - ASSERT(instance->type == NODE_INSTANCE_ROOT); - p_count = darray_nodes_size_get(&instance->data.instance_root.pivots); - pivots = darray_nodes_data_get(&instance->data.instance_root.pivots); - for (p = 0; p < p_count; p++) { - struct score_node* pivot = CONTAINER_OF(pivots[p], struct score_node, anim); - res = sanim_node_solve_pivot(&pivot->anim, sun_dir); - if (res != RES_OK) return res; - } - } - return RES_OK; -} - -static void -scene_release(ref_T* ref) -{ - struct score_device* dev; - struct score_scene* scene = CONTAINER_OF(ref, struct score_scene, ref); - ASSERT(ref); - dev = scene->device; - ASSERT(dev && dev->allocator); - score_scene_clear(scene); - darray_nodes_release(&scene->instances); - if (scene->solver) SSOL(scene_ref_put(scene->solver)); - if (scene->sun) SSOL(sun_ref_put(scene->sun)); - if (scene->atmosphere) SSOL(atmosphere_ref_put(scene->atmosphere)); - MEM_RM(dev->allocator, scene); - score_device_ref_put(dev); -} - -/******************************************************************************* - * Exported score_scene functions - ******************************************************************************/ -res_T -score_scene_create - (struct score_device* dev, - struct score_scene** out_scene) -{ - struct score_scene* scene; - res_T res = RES_OK; - ASSERT(dev && out_scene); - - scene = MEM_CALLOC(dev->allocator, 1, sizeof(struct score_scene)); - if (!scene) { - res = RES_MEM_ERR; - goto error; - } - - score_device_ref_get(dev); - scene->device = dev; - ref_init(&scene->ref); - darray_nodes_init(dev->allocator, &scene->instances); - - res = ssol_scene_create(dev->ssol, &scene->solver); - if (res != RES_OK) goto error; - -exit: - if (out_scene) *out_scene = scene; - return res; -error: - if (scene) { - score_scene_ref_put(scene); - scene = NULL; - } - goto exit; -} - -void -score_scene_ref_get(struct score_scene* scene) -{ - ASSERT(scene); - ref_get(&scene->ref); -} - -void -score_scene_ref_put(struct score_scene* scene) -{ - ASSERT(scene); - ref_put(&scene->ref, scene_release); -} - -res_T -score_scene_attach_instance - (struct score_scene* scene, - struct score_node* instance) -{ - struct sanim_node* anim; - res_T res = RES_OK; - int ok; - ASSERT(scene && instance - && instance->type == NODE_INSTANCE_ROOT - && !instance->data.instance_root.scene_attachment); - anim = &instance->anim; - SANIM(node_is_initialized(anim, &ok)); - ASSERT(ok); - res = darray_nodes_push_back(&scene->instances, &anim); - if (res != RES_OK) goto error; - instance->data.instance_root.scene_attachment = scene; - score_node_ref_get(instance); -exit: - return res; -error: - remove_if(&scene->instances, anim); - goto exit; -} - -void -score_scene_detach_instance - (struct score_scene* scene, - struct score_node* instance) -{ - struct sanim_node* anim; - int ok; - ASSERT(scene && instance - && instance->type == NODE_INSTANCE_ROOT - && instance->data.instance_root.scene_attachment == scene); - anim = &instance->anim; - SANIM(node_is_initialized(anim, &ok)); - ASSERT(ok); - ok = remove_if(&scene->instances, anim); - ASSERT(ok); - instance->data.instance_root.scene_attachment = NULL; - score_node_ref_put(instance); -} - -void -score_scene_attach_sun - (struct score_scene* scene, - struct ssol_sun* sun) -{ - ASSERT(scene && sun); - SSOL(scene_attach_sun(scene->solver, sun)); - SSOL(sun_ref_get(sun)); - scene->sun = sun; -} - -void -score_scene_detach_sun - (struct score_scene* scene, - struct ssol_sun* sun) -{ - ASSERT(scene && sun); - SSOL(scene_detach_sun(scene->solver, sun)); - SSOL(sun_ref_put(sun)); - scene->sun = NULL; -} - -void -score_scene_attach_atmosphere - (struct score_scene* scene, - struct ssol_atmosphere* atm) -{ - ASSERT(scene && atm); - SSOL(scene_attach_atmosphere(scene->solver, atm)); - SSOL(atmosphere_ref_get(atm)); - scene->atmosphere = atm; -} - -void -score_scene_detach_atmosphere - (struct score_scene* scene, - struct ssol_atmosphere* atm) -{ - ASSERT(scene && atm); - SSOL(scene_detach_atmosphere(scene->solver, atm)); - SSOL(atmosphere_ref_put(atm)); - scene->atmosphere = NULL; -} - -void -score_scene_clear - (struct score_scene* scene) -{ - size_t count, i; - struct sanim_node** data; - ASSERT(scene); - count = darray_nodes_size_get(&scene->instances); - data = darray_nodes_data_get(&scene->instances); - for (i = 0; i < count; i++) { - struct score_node* node = CONTAINER_OF(data[i], struct score_node, anim); - score_node_ref_put(node); - } - darray_nodes_clear(&scene->instances); -} - -res_T -score_scene_reset_simulation(struct score_scene* scene) -{ - res_T res = RES_OK; - size_t count = 0, i; - struct sanim_node** instances; - double sun_dir[3]; - ASSERT(scene && scene->sun); - SSOL(sun_get_direction(scene->sun, sun_dir)); - count = darray_nodes_size_get(&scene->instances); - instances = darray_nodes_data_get(&scene->instances); - SSOL(scene_clear(scene->solver)); - SSOL(scene_attach_sun(scene->solver, scene->sun)); - if (scene->atmosphere) - SSOL(scene_attach_atmosphere(scene->solver, scene->atmosphere)); - for (i = 0; i < count; i++) { - struct score_node* inst = CONTAINER_OF(instances[i], struct score_node, anim); - ASSERT(inst->type == NODE_INSTANCE_ROOT); - res = create_instance_tree(inst); - if (res != RES_OK) goto error; - res = sanim_node_visit_tree( - instances[i], sun_dir, scene->solver, &node_to_solver); - if (res != RES_OK) goto error; - } -exit: - return res; -error: - for (i = 0; i < count; i++) node_ref_put_children(instances[i]); - goto exit; -} - -res_T -score_scene_update_simulation(struct score_scene* scene) -{ - res_T res = RES_OK; - size_t count = 0, i; - size_t p_count = 0, p; - struct sanim_node** instances; - double sun_dir[3]; - ASSERT(scene && scene->sun); - SSOL(sun_get_direction(scene->sun, sun_dir)); - count = darray_nodes_size_get(&scene->instances); - instances = darray_nodes_data_get(&scene->instances); - for (i = 0; i < count; i++) { - struct sanim_node** pivots; - struct score_node* inst = CONTAINER_OF(instances[i], struct score_node, anim); - ASSERT(inst->type == NODE_INSTANCE_ROOT); - p_count = darray_nodes_size_get(&inst->data.instance_root.pivots); - pivots = darray_nodes_data_get(&inst->data.instance_root.pivots); - for (p = 0; p < p_count; p++) { - res = sanim_node_visit_tree( - pivots[p], sun_dir, NULL, &node_to_solver_update); - if (res != RES_OK) goto error; - } - } -exit: - return res; -error: - goto exit; -} - diff --git a/src/core/solstice_core_scene.h b/src/core/solstice_core_scene.h @@ -1,40 +0,0 @@ -/* Copyright (C) CNRS 2016 -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifndef SCORE_SCENE_H -#define SCORE_SCENE_H - -#include "solstice_core.h" -#include "solstice_core_node.h" - -#include <rsys/dynamic_array.h> -#include <rsys/ref_count.h> - -struct ssol_scene; -struct ssol_sun; -struct ssol_atmosphere; - -struct score_device; - -struct score_scene { - struct score_device* device; - struct darray_nodes instances; - struct ssol_scene* solver; - struct ssol_sun* sun; - struct ssol_atmosphere* atmosphere; - ref_T ref; -}; - -#endif /* SCORE_SCENE_H */ diff --git a/src/core/solstice_core_solver.c b/src/core/solstice_core_solver.c @@ -14,18 +14,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "solstice_core.h" -#include "solstice_core_scene.h" +#include "solstice_core_device.h" #include <solstice/ssol.h> res_T score_solve - (struct score_scene* scene, + (struct score_device* dev, struct ssp_rng* rng, const size_t realisations_count, FILE* output, struct ssol_estimator* estimator) { - ASSERT(scene && rng && realisations_count && output && estimator); - return ssol_solve(scene->solver, rng, realisations_count, output, estimator); + ASSERT(dev && rng && realisations_count && output && estimator); + return ssol_solve(dev->solver, rng, realisations_count, output, estimator); } \ No newline at end of file diff --git a/src/main.c b/src/main.c @@ -13,48 +13,21 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "parser/solparser.h" +#include "solstice_args.h" #include <rsys/rsys.h> int main(int argc, char** argv) { - FILE* file = NULL; - struct solparser* parser = NULL; + struct solstice_args args; res_T res; int err = 0; - int i; - if(argc < 2) { - fprintf(stderr, "Usage: %s FILE [FILE ...]\n", argv[0]); - err = 1; - goto error; - } - - res = solparser_create(NULL, &parser); + res = solstice_args_init(&args, argc, argv); if(res != RES_OK) goto error; - FOR_EACH(i, 1, argc) { - file = fopen(argv[i], "rb"); - if(!file) { - fprintf(stderr, "Could not open the file `%s'.\n", argv[i]); - goto error; - } - - res = solparser_setup(parser, argv[i], file); - if(res != RES_OK) break; - - do { - res = solparser_load(parser); - } while(res != RES_BAD_OP); - - fclose(file); - file = NULL; - } - exit: - if(parser) solparser_ref_put(parser); - if(file) fclose(file); + solstice_args_release(&args); return err; error: err = -1; diff --git a/src/solstice.h b/src/solstice.h @@ -25,23 +25,38 @@ struct solparser; struct ssol_device; struct ssol_material; struct ssol_object; +struct sanim_node; +struct score_device; +struct score_node; #define HTABLE_NAME material #define HTABLE_KEY size_t #define HTABLE_DATA struct ssol_material* #include <rsys/hash_table.h> +#include <rsys/dynamic_array.h> #define HTABLE_NAME object #define HTABLE_KEY size_t #define HTABLE_DATA struct ssol_object* #include <rsys/hash_table.h> +#define HTABLE_NAME anchor +#define HTABLE_KEY size_t +#define HTABLE_DATA struct score_node* +#include <rsys/hash_table.h> + +#include "core/solstice_core_node.h" + struct solstice { struct ssol_device* ssol; struct solparser* parser; + struct score_device* score; struct htable_material materials; struct htable_object objects; + struct htable_anchor anchors; + struct darray_nodes roots; + struct darray_nodes pivots; struct mem_allocator* allocator; }; diff --git a/src/solstice_args.c b/src/solstice_args.c @@ -0,0 +1,283 @@ +/* Copyright (C) CNRS 2016 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#define _POSIX_C_SOURCE 2 + +#include "solstice_args.h" + +#include <rsys/cstr.h> +#include <rsys/double3.h> + +#ifdef COMPILER_CL + #include <getopt.h> + #define strtok_r strtok_s +#else + #include <unistd.h> +#endif + +#include <string.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +print_help(const char* program) +{ + printf( +"Usage: %s [OPTIONS] [FILE]\n" +"Integrate the solar flux in complex solar facilities.\n", + program); + /* TODO print short help for the options */ +} + +static res_T +parse_fov(const char* str, double* out_fov) +{ + double fov; + res_T res = RES_OK; + ASSERT(str && out_fov); + + res = cstr_to_double(str, &fov); + if(res != RES_OK) { + fprintf(stderr, "Invalid field of view `%s'.\n", str); + return RES_BAD_ARG; + } + + if(fov < 30 || fov > 120) { + fprintf(stderr, "The field of view %g is not in [30, 120].\n", fov); + return RES_BAD_ARG; + } + *out_fov = MDEG2RAD(fov); + return RES_OK; +} + + +static res_T +parse_double3(const char* str, double dbl3[3]) +{ + char buf[64]; + char* tk; + char* ctx; + res_T res = RES_OK; + ASSERT(str && dbl3); + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the string `%s'.\n", str); + return RES_MEM_ERR; + } + strncpy(buf, str, sizeof(buf)); + + tk = strtok_r(buf, ",", &ctx); + res = cstr_to_double(tk, dbl3+0); + if(res != RES_OK) return res; + + tk = strtok_r(NULL, ",", &ctx); + res = cstr_to_double(tk, dbl3+1); + if(res != RES_OK) return res; + + tk = strtok_r(NULL, "", &ctx); + res = cstr_to_double(tk, dbl3+2); + if(res != RES_OK) return res; + + return RES_OK; +} + +static res_T +parse_image_definition + (const char* str, + unsigned long* width, + unsigned long* height) +{ + char buf[64]; + char* tk; + char* ctx; + res_T res = RES_OK; + ASSERT(str && width && height); + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the image definition string `%s'.\n", str); + return RES_MEM_ERR; + } + strncpy(buf, str, sizeof(buf)); + + tk = strtok_r(buf, "x", &ctx); + res = cstr_to_ulong(tk, width); + if(res != RES_OK) { + fprintf(stderr, "Invalid image width `%s'\n", tk); + return res; + } + + tk = strtok_r(NULL, "", &ctx); + res = cstr_to_ulong(tk, height); + if(res != RES_OK) { + fprintf(stderr, "Invalid image height `%s'\n", tk); + return res; + } + + return res; +} + +static res_T +parse_rendering_option(const char* str, struct solstice_args* args) +{ + char buf[128]; + char* key; + char* val; + char* ctx; + res_T res; + ASSERT(str && args); + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the rendering option string `%s'\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + key = strtok_r(buf, "=", &ctx); + val = strtok_r(NULL, "", &ctx); + + if(!strcmp(key, "fov")) { + res = parse_fov(val, &args->camera.fov_x); + if(res != RES_OK) goto error; + } else if(!strcmp(key, "img")) { + res = parse_image_definition(val, &args->img.width, &args->img.height); + if(res != RES_OK) goto error; + } else if(!strcmp(key, "pos")) { + res = parse_double3(val, args->camera.pos); + if(res != RES_OK) { + fprintf(stderr, "Invalid camera position `%s'.\n", val); + goto error; + } + } else if(!strcmp(key, "tgt")) { + res = parse_double3(val, args->camera.tgt); + if(res != RES_OK) { + fprintf(stderr, "Invalid camera target `%s'.\n", val); + goto error; + } + } else if(!strcmp(key, "up")) { + res = parse_double3(val, args->camera.up); + if(res != RES_OK) { + fprintf(stderr, "Invalid camera up vector `%s'.\n", val); + goto error; + } + } else { + fprintf(stderr, "Invalid rendering option `%s'.\n", val); + res = RES_BAD_ARG; + goto error; + } + args->rendering = 1; + +exit: + return res; +error: + goto exit; +} + +static res_T +parse_rendering_options(const char* str, struct solstice_args* args) +{ + char buf[512]; + char* tk; + char* ctx; + res_T res = RES_OK; + ASSERT(args); + (void)str, (void)args; + + /* Setup default values of the rendering parameters */ + d3(args->camera.pos, 0, 0, 0); + d3(args->camera.tgt, 0, 0, -1); + d3(args->camera.up, 0, 1, 0); + args->camera.fov_x = MDEG2RAD(70); + args->img.width = 800; + args->img.height = 600; + + if(!str) goto exit; + + if(strlen(str) >= sizeof(buf) - 1/*NULL char*/) { + fprintf(stderr, + "Could not duplicate the rendering options string `%s'.\n", str); + res = RES_MEM_ERR; + goto error; + } + strncpy(buf, str, sizeof(buf)); + + tk = strtok_r(buf, ":", &ctx); + do { + res = parse_rendering_option(tk, args); + tk = strtok_r(NULL, ":", &ctx); + } while(tk); + +exit: + return res; +error: + goto exit; +} + +/******************************************************************************* + * Local function + ******************************************************************************/ +res_T +solstice_args_init(struct solstice_args* args, const int argc, char** argv) +{ + int opt; + res_T res = RES_OK; + ASSERT(args && argc && argv); + + *args = SOLSTICE_ARGS_DEFAULT; + + optind = 1; + while((opt = getopt(argc, argv, "hn:o:qr:")) != -1) { + switch(opt) { + case 'h': + print_help(argv[0]); + solstice_args_release(args); + goto exit; + case 'n': + res = cstr_to_ulong(optarg, &args->nrealisations); + if(res != RES_OK && !args->nrealisations) res = RES_BAD_ARG; + break; + case 'o': args->output_filename = optarg; break; + case 'q': args->quiet = 1; break; + case 'r': res = parse_rendering_options(optarg, args); break; + default: res = RES_BAD_ARG; break; + } + if(res != RES_OK) { + if(optarg) { + fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n", + argv[0], optarg, opt); + } + goto error; + } + } + +exit: + optind = 1; + return res; +error: + solstice_args_release(args); + goto exit; +} + +void +solstice_args_release(struct solstice_args* args) +{ + ASSERT(args); + *args = SOLSTICE_ARGS_NULL; +} + diff --git a/src/solstice_args.h.in b/src/solstice_args.h.in @@ -0,0 +1,77 @@ +/* Copyright (C) CNRS 2016 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef SOLSTICE_ARGS_H +#define SOLSTICE_ARGS_H + +#include <rsys/math.h> + +struct solstice_args { + const char* output_filename; + unsigned long nrealisations; /* #realisations */ + + struct { + double pos[3]; + double tgt[3]; + double up[3]; + double fov_x; + } camera; + + struct { + unsigned long width; + unsigned long height; + } img; + + int rendering; + int quiet; +}; + +#define SOLSTICE_ARGS_NULL__ {0} +static const struct solstice_args SOLSTICE_ARGS_NULL = SOLSTICE_ARGS_NULL__; + +#define SOLSTICE_ARGS_DEFAULT__ { \ + NULL, /* Output_filename */ \ + @SOLSTICE_ARGS_DEFAULT_NREALISATIONS@, \ + \ + { /* Camera */ \ + { @SOLSTICE_ARGS_DEFAULT_CAMERA_POS@ }, \ + { @SOLSTICE_ARGS_DEFAULT_CAMERA_TGT@ }, \ + { @SOLSTICE_ARGS_DEFAULT_CAMERA_UP@ }, \ + MDEG2RAD(@SOLSTICE_ARGS_DEFAULT_CAMERA_FOV@) \ + }, \ + \ + { /* Image */ \ + @SOLSTICE_ARGS_DEFAULT_IMG_WIDTH@, \ + @SOLSTICE_ARGS_DEFAULT_IMG_HEIGHT@ \ + }, \ + \ + 0, /* Rendering */ \ + 0 /* Quiet */ \ +} +static const struct solstice_args SOLSTICE_ARGS_DEFAULT = + SOLSTICE_ARGS_DEFAULT__; + +extern LOCAL_SYM res_T +solstice_args_init + (struct solstice_args* args, + const int argc, + char** argv); + +extern LOCAL_SYM void +solstice_args_release + (struct solstice_args* args); + +#endif /* SOLSTICE_ARGS_H */ + diff --git a/src/solstice_c.h b/src/solstice_c.h @@ -22,6 +22,10 @@ struct ssol_instance; extern LOCAL_SYM res_T +solstice_setup_entities + (struct solstice* solstice); + +extern LOCAL_SYM res_T solstice_get_ssol_material (struct solstice* solstice, const struct solparser_material_id mtl_id, diff --git a/src/solstice_entity.c b/src/solstice_entity.c @@ -1,17 +1,208 @@ /* Copyright (C) CNRS 2016 -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation, either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. */ + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. */ #include "solstice.h" #include "solstice_c.h" + +#include <solstice/ssol.h> +#include <solstice/sanim.h> +#include "core/solstice_core.h" + +/******************************************************************************* + * Helper function + ******************************************************************************/ +static res_T +solstice_setup_entity + (struct solstice* solstice, + const struct solparser_entity* entity, + const char is_root, + struct score_node** out_node) +{ + struct score_node* root_node = NULL; + struct score_node* atchmnt_node = NULL; + struct ssol_instance* instance = NULL; + const struct solparser_anchor_id* anchors = NULL; + const struct solparser_entity_id* children = NULL; + size_t count, i; + res_T res = RES_OK; + ASSERT(solstice && solstice->parser && solstice->score && entity); + + /* TODO Split the cases un sub-functions! */ + switch (entity->type) { + case SOLPARSER_ENTITY_EMPTY: + { + struct score_node* empty_node = NULL; + res = score_node_empty_create(solstice->score, &empty_node); + if (res != RES_OK) goto error; + score_node_set_translation(empty_node, entity->translation); + score_node_set_rotations(empty_node, entity->rotation); + atchmnt_node = root_node = empty_node; + break; + } + case SOLPARSER_ENTITY_GEOMETRY: + { + struct score_node* geometry_node = NULL; + res = score_node_geometry_create(solstice->score, &geometry_node); + if (res != RES_OK) goto error; + score_node_set_translation(geometry_node, entity->translation); + score_node_set_rotations(geometry_node, entity->rotation); + res = solstice_instantiate_geometry( + /* TODO: attach instance to solver */ + solstice, entity->data.geometry, &instance); + if (res != RES_OK) goto error; + res = score_node_geometry_setup(geometry_node, instance); + if (res != RES_OK) goto error; + atchmnt_node = root_node = geometry_node; + break; + } + case SOLPARSER_ENTITY_PIVOT: + { + /* Each entity introduces a new coordinate system + * and each object or pivot has some positionning in this system. + * This behaviour is implemented through 2 levels of sanim_node. */ + /* TODO: remove pivot positionning? */ + struct score_node* entity_node = NULL; + struct score_node* pivot_node = NULL; + const struct solparser_pivot* parser_pivot = NULL; + struct sanim_pivot anim_pivot = SANIM_PIVOT_NULL; + struct sanim_tracking anim_tracking = SANIM_TRACKING_NULL; + res = score_node_empty_create(solstice->score, &entity_node); + if (res != RES_OK) goto error; + score_node_set_translation(entity_node, entity->translation); + score_node_set_rotations(entity_node, entity->rotation); + res = score_node_pivot_create(solstice->score, &pivot_node); + if (res != RES_OK) goto error; + parser_pivot = solparser_get_pivot(solstice->parser, entity->data.pivot); + ASSERT(parser_pivot); + score_node_set_translation(pivot_node, parser_pivot->translation); + score_node_set_rotations(pivot_node, parser_pivot->rotation); + /* TODO: 2-axis pivots */ + anim_pivot.type = PIVOT_SINGLE_AXIS; + d3_set(anim_pivot.data.pivot1.ref_normal, parser_pivot->normal); + d3_set(anim_pivot.data.pivot1.ref_point, parser_pivot->point); + switch (parser_pivot->target_type) { + case SOLPARSER_TARGET_ANCHOR: + { + struct score_node** ptgt = NULL; + const struct solparser_anchor_id id = parser_pivot->target.anchor; + anim_tracking.policy = TRACKING_NODE_TARGET; + ptgt = htable_anchor_find(&solstice->anchors, &id.i); + score_node_track_me(*ptgt, &anim_tracking); + break; + } + case SOLPARSER_TARGET_DIRECTION: + anim_tracking.policy = TRACKING_OUT_DIR; + d3_set(anim_tracking.data.out_dir.u, parser_pivot->target.direction); + break; + case SOLPARSER_TARGET_POSITION: + anim_tracking.policy = TRACKING_POINT; + d3_set(anim_tracking.data.point.target, parser_pivot->target.position); + anim_tracking.data.point.target_is_local = 0; /* TODO */ + break; + case SOLPARSER_TARGET_SUN: + anim_tracking.policy = TRACKING_SUN; + break; + default: FATAL("Unreachable code.\n"); break; + } + res = score_node_pivot_setup(pivot_node, &anim_pivot, &anim_tracking); + if (res != RES_OK) goto error; + res = darray_nodes_push_back(&solstice->pivots, &pivot_node); + if (res != RES_OK) goto error; + root_node = entity_node; + atchmnt_node = pivot_node; + break; + } + default: FATAL("Unreachable code.\n"); break; + } + + ASSERT(root_node && atchmnt_node); + if (is_root) darray_nodes_push_back(&solstice->roots, &root_node); + + /* register anchors */ + count = darray_anchor_id_size_get(&entity->anchors); + anchors = darray_anchor_id_cdata_get(&entity->anchors); + for (i = 0; i < count; i++) { + struct score_node* tgt; + const struct solparser_anchor* anchor = NULL; + res = score_node_tracking_target_create(solstice->score, &tgt); + if (res != RES_OK) goto error; + anchor = solparser_get_anchor(solstice->parser, anchors[i]); + ASSERT(anchor); + res = htable_anchor_set(&solstice->anchors, &anchors[i].i, &tgt); + if (res != RES_OK) goto error; + score_node_set_translation(tgt, anchor->position); + res = score_node_add_child(atchmnt_node, tgt); + if (res != RES_OK) goto error; + } + + /* TODO: setup children */ + count = solparser_entity_get_children_count(entity); + children = darray_child_id_cdata_get(&entity->children); + for (i = 0; i < count; i++) { + const struct solparser_entity* child; + struct score_node* child_root = NULL; + child = solparser_get_entity(solstice->parser, children[i]); + ASSERT(child); + res = solstice_setup_entity(solstice, child, 0, &child_root); + if (res != RES_OK) goto error; + ASSERT(child_root); + res = score_node_add_child(atchmnt_node, child_root); + if (res != RES_OK) goto error; + } + +end: + if (out_node) *out_node = root_node; + return res; + +error: + goto end; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +solstice_setup_entities + (struct solstice* solstice) +{ + struct solparser_entity_iterator it, it_end; + res_T res = RES_OK; + ASSERT(solstice && solstice->parser && solstice->score); + + /* Release possible previous roots (incomplete, TODO) */ + score_scene_clear(solstice->score); + + /* (re) create the list of roots from entities */ + solparser_entity_iterator_begin(solstice->parser, &it); + solparser_entity_iterator_end(solstice->parser, &it); + while (!solparser_entity_iterator_eq(&it, &it_end)) { + struct solparser_entity_id entity_id; + const struct solparser_entity* entity; + + entity_id = solparser_entity_iterator_get(&it); + entity = solparser_get_entity(solstice->parser, entity_id); + + res = solstice_setup_entity(solstice, entity, 1, NULL); + if (res != RES_OK) goto error; + + solparser_entity_iterator_next(&it); + } + +end: + return res; +error: + goto end; +} + diff --git a/src/solstice_material.c b/src/solstice_material.c @@ -122,7 +122,6 @@ create_material_mirror res = RES_MEM_ERR; goto error; } - param->reflectivity = mirror->reflectivity; param->roughness = mirror->roughness; diff --git a/src/test_solstice_args.c b/src/test_solstice_args.c @@ -0,0 +1,130 @@ +/* Copyright (C) CNRS 2016 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "solstice_args.h" +#include "test_solstice_utils.h" + +#include <rsys/double3.h> +#include <rsys/stretchy_array.h> + +#include <stdarg.h> +#include <string.h> + +static char** +cmd_create(int dummy, ...) +{ + va_list ap; + va_list ap_cp; + const char* str; + size_t i, n = 0; + char** cmd = NULL; + + va_start(ap, dummy); + VA_COPY(ap_cp, ap); + while((str = va_arg(ap, const char*))) ++n; + va_end(ap); + + NCHECK(cmd = sa_add(cmd, n), NULL); + i = 0; + while((str = va_arg(ap_cp, const char*))) { + cmd[i] = NULL; + NCHECK(cmd[i] = sa_add(cmd[i], strlen(str)+1), NULL); + strcpy(cmd[i], str); + ++i; + } + va_end(ap_cp); + return cmd; +} + +static void +cmd_delete(char** cmd) +{ + size_t i = 0; + const size_t n = sa_size(cmd); + FOR_EACH(i, 0, n) sa_release(cmd[i]); + sa_release(cmd); +} + +static FINLINE int +cmd_size(char** cmd) +{ + return (int)sa_size(cmd); +} + +int +main(int argc, char** argv) +{ + struct solstice_args args = SOLSTICE_ARGS_NULL; + char** cmd = NULL; + double tmp[3]; + (void)argc, (void)argv; + + cmd = cmd_create(0, "test", "-r", "img=1280x720", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.rendering, 1); + CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(d3_eq(args.camera.pos, SOLSTICE_ARGS_DEFAULT.camera.pos), 1); + CHECK(d3_eq(args.camera.tgt, SOLSTICE_ARGS_DEFAULT.camera.tgt), 1); + CHECK(d3_eq(args.camera.up, SOLSTICE_ARGS_DEFAULT.camera.up), 1); + CHECK(args.camera.fov_x, SOLSTICE_ARGS_DEFAULT.camera.fov_x); + CHECK(args.img.width, 1280); + CHECK(args.img.height, 720); + CHECK(args.quiet, 0); + CHECK(args.output_filename, NULL); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-q", "-r", "img=640x480:fov=70:pos=1,2,3", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.rendering, 1); + CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(d3_eq(args.camera.pos, d3(tmp, 1, 2, 3)), 1); + CHECK(d3_eq(args.camera.tgt, SOLSTICE_ARGS_DEFAULT.camera.tgt), 1); + CHECK(d3_eq(args.camera.up, SOLSTICE_ARGS_DEFAULT.camera.up), 1); + CHECK(args.img.width, 640); + CHECK(args.img.height, 480); + CHECK(args.quiet, 1); + CHECK(eq_eps(args.camera.fov_x, MDEG2RAD(70), 1.e-6), 1); + CHECK(args.output_filename, NULL); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "up=0,0,1:tgt=0,-10,0", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(args.nrealisations, SOLSTICE_ARGS_DEFAULT.nrealisations); + CHECK(d3_eq(args.camera.pos, SOLSTICE_ARGS_DEFAULT.camera.pos), 1); + CHECK(d3_eq(args.camera.tgt, d3(tmp, 0,-10, 0)), 1); + CHECK(d3_eq(args.camera.up, d3(tmp, 0, 0, 1)), 1); + CHECK(args.img.width, SOLSTICE_ARGS_DEFAULT.img.width); + CHECK(args.img.height, SOLSTICE_ARGS_DEFAULT.img.height); + CHECK(args.rendering, 1); + CHECK(args.quiet, 0); + CHECK(args.output_filename, NULL); + solstice_args_release(&args); + cmd_delete(cmd); + + cmd = cmd_create(0, "test", "-r", "up=0,10,0", "-o", "my_output", NULL); + CHECK(solstice_args_init(&args, cmd_size(cmd), cmd), RES_OK); + CHECK(d3_eq(args.camera.up, d3(tmp, 0, 10, 0)), 1); + CHECK(args.rendering, 1); + CHECK(args.quiet, 0); + CHECK(strcmp(args.output_filename, "my_output"), 0); + solstice_args_release(&args); + cmd_delete(cmd); + + CHECK(mem_allocated_size(), 0); + return 0; +} +