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 6e76f955c8948a2a9bc706014e75b74e683331c0
parent c256607daa65d61db0f0ec2742f67b00d5bd88a1
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 25 Nov 2016 18:23:30 +0100

Add Solstice core subproject.

Only to save work; builds but core tests fail.

Diffstat:
Mcmake/CMakeLists.txt | 13++++++++++---
Acmake/core/CMakeLists.txt | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core.h | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_device.c | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_device.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_node.c | 520+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_node.h | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_scene.c | 450+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_scene.h | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/solstice_core_solver.c | 33+++++++++++++++++++++++++++++++++
Asrc/core/test_core_device.c | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/test_core_node.c | 187+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/test_core_scene.c | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/test_core_solve1.c | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/test_core_utils.c | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/core/test_core_utils.h | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 files changed, 2624 insertions(+), 3 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -28,18 +28,25 @@ set(LibYAML_DIR ${_current_source_dir}/) find_package(LibYAML REQUIRED) find_package(RCMake 0.2.3 REQUIRED) -find_package(RSys 0.3 REQUIRED) +find_package(RSys 0.4 REQUIRED) +find_package(StarSP 0.4 REQUIRED) +find_package(SolAnim 0.1 REQUIRED) +find_package(SolSolver 0.1 REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR}) include(rcmake) include(rcmake_runtime) -include_directories(${RSys_INCLUDE_DIR}) +include_directories( + ${RSys_INCLUDE_DIR} + ${SolAnim_INCLUDE_DIR} + ${SolSolver_INCLUDE_DIR}) ################################################################################ # Build subprojects ################################################################################ add_subdirectory(parser) +add_subdirectory(core) ################################################################################ # Configure and define targets @@ -63,7 +70,7 @@ if(CMAKE_COMPILER_IS_GNUCC) endif() add_executable(solstice ${SOLSTICE_SOURCE_DIR}/solstice.c) -target_link_libraries(solstice LibYAML RSys ${MATH_LIB} solstice-parser) +target_link_libraries(solstice LibYAML RSys ${MATH_LIB} solstice-parser SolAnim SolSolver) set_target_properties(solstice PROPERTIES VERSION ${VERSION} SOVERSION ${VERSION_MAJOR}) diff --git a/cmake/core/CMakeLists.txt b/cmake/core/CMakeLists.txt @@ -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/>. + +cmake_minimum_required(VERSION 2.8) +project(solstice-core C) +enable_testing() + +set(CORE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../../src/core) + +################################################################################ +# Define include directories +################################################################################ +include_directories( + ${RSys_INCLUDE_DIR} + ${SolAnim_INCLUDE_DIR} + ${SolSolver_INCLUDE_DIR} + ${CORE_SOURCE_DIR}/../) + +################################################################################ +# Configure and define targets +################################################################################ +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) + +# Prepend each file in the `SOLSTICE_FILES_<SRC|INC>' list by `SOLSTICE_SOURCE_DIR' +rcmake_prepend_path(CORE_FILES_SRC ${CORE_SOURCE_DIR}) +rcmake_prepend_path(CORE_FILES_INC ${CORE_SOURCE_DIR}) +rcmake_prepend_path(CORE_FILES_DOC ${PROJECT_SOURCE_DIR}/../) + +if(CMAKE_COMPILER_IS_GNUCC) + set(MATH_LIB m) +endif() + +add_library(solstice-core STATIC ${CORE_FILES_SRC} ${CORE_FILES_INC}) + +################################################################################ +# Tests +################################################################################ +if(NOT NO_TEST) + function(new_test _name) + add_executable(${_name} + ${CORE_SOURCE_DIR}/test_core_utils.h + ${CORE_SOURCE_DIR}/test_core_utils.c + ${CORE_SOURCE_DIR}/${_name}.c) + target_link_libraries(${_name} RSys ${MATH_LIB} StarSP SolAnim SolSolver solstice-core) + add_test(${_name} ${_name}) + rcmake_set_test_runtime_dirs(${_name} _runtime_dirs) + endfunction() + + 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) +endif() diff --git a/src/core/solstice_core.h b/src/core/solstice_core.h @@ -0,0 +1,233 @@ +/* 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_CORE_H +#define SOLSTICE_CORE_H + +#include <rsys/rsys.h> +#include <rsys/dynamic_array.h> + +/* Forward declaration of external types */ +struct logger; +struct mem_allocator; +struct sanim_pivot; +struct sanim_tracking; +struct ssol_vertex_data; +struct ssol_object; +struct ssol_instance; +struct ssol_sun; +struct ssol_atmosphere; +struct ssol_estimator; +struct ssol_device; +struct ssp_rng; + +struct score_device; +struct score_node; +struct score_scene; + +/******************************************************************************* + * Device API - Main entry point of Solstice core. Applications + * use the score_device to create others Solstice core resources. + ******************************************************************************/ +extern LOCAL_SYM res_T +score_device_create + (struct logger* logger, /* May be NULL <=> use default logger */ + struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ + const unsigned nthreads_hint, /* Hint on the number of threads to use */ + const int verbose, /* Make the library more verbose */ + struct score_device** dev); + +extern LOCAL_SYM void +score_device_ref_get + (struct score_device* dev); + +extern LOCAL_SYM void +score_device_ref_put + (struct score_device* dev); + +extern LOCAL_SYM struct ssol_device* +score_device_get_solver_device + (struct score_device* dev); + +/******************************************************************************* + * Node API + ******************************************************************************/ +extern LOCAL_SYM res_T +score_node_template_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); + +extern LOCAL_SYM res_T +score_node_create_object +(struct score_device* dev, + struct score_node** node); + +extern LOCAL_SYM res_T +score_node_pivot_create + (struct score_device* dev, + struct score_node** node); + +extern LOCAL_SYM res_T +score_node_tracking_target_create + (struct score_device* dev, + struct score_node** node); + +extern LOCAL_SYM void +score_node_ref_get + (struct score_node* node); + +extern LOCAL_SYM void +score_node_ref_put + (struct score_node* node); + +extern LOCAL_SYM res_T +score_node_object_setup + (struct score_node* node, + struct ssol_object* object); + +extern LOCAL_SYM res_T +score_node_pivot_setup + (struct score_node* node, + const struct sanim_pivot* pivot, + const struct sanim_tracking* tracking); + +extern LOCAL_SYM void +score_node_track_me + (const struct score_node* node, + struct sanim_tracking* tracking); + +extern LOCAL_SYM res_T +score_node_add_child + (struct score_node* father, + struct score_node* child); + +extern LOCAL_SYM void +score_node_set_translation + (struct score_node* node, + const double translation[3]); + +extern LOCAL_SYM void +score_node_get_translation + (const struct score_node* node, + double translation[3]); + +extern LOCAL_SYM void +score_node_set_rotations + (struct score_node* node, + const double rotations[3]); + +extern LOCAL_SYM void +score_node_get_rotations + (const struct score_node* node, + double rotations[3]); + +extern LOCAL_SYM void +score_node_set_receiver + (struct score_node* node, + const int mask); + +/* Define whether or not the node is sampled. + * By default a node is sampled. */ +extern LOCAL_SYM void +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); + +extern LOCAL_SYM void +score_scene_clear + (struct score_scene* scene); + +extern LOCAL_SYM res_T +score_scene_reset_simulation + (struct score_scene* scene); + +extern LOCAL_SYM res_T +score_scene_update_simulation + (struct score_scene* scene); + +/******************************************************************************* + * Miscellaneous functions + ******************************************************************************/ +extern LOCAL_SYM res_T +score_solve + (struct score_scene* scene, + struct ssp_rng* rng, + const size_t realisations_count, + FILE* output, + struct ssol_estimator* estimator); + +#endif /* SOLSTICE_CORE_H */ + diff --git a/src/core/solstice_core_device.c b/src/core/solstice_core_device.c @@ -0,0 +1,144 @@ +/* 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_device.h" + +#include <rsys/logger.h> +#include <rsys/mem_allocator.h> + +#include <solstice/ssol.h> + +#include <omp.h> + +/******************************************************************************* +* Helper functions +******************************************************************************/ +static INLINE void +log_msg + (struct score_device* dev, + const enum log_type stream, + const char* msg, + va_list vargs) +{ + ASSERT(dev && msg); + if (dev->verbose) { + res_T res; (void) res; + res = logger_vprint(dev->logger, stream, msg, vargs); + ASSERT(res == RES_OK); + } +} + +static void +device_release(ref_T* ref) +{ + struct score_device* dev; + ASSERT(ref); + dev = CONTAINER_OF(ref, struct score_device, ref); + ASSERT(dev && dev->allocator); + if (dev->ssol) ssol_device_ref_put(dev->ssol); + MEM_RM(dev->allocator, dev); +} + +/******************************************************************************* + * Exported score_device functions + ******************************************************************************/ +res_T +score_device_create + (struct logger* logger, + struct mem_allocator* mem_allocator, + const unsigned nthreads_hint, + const int verbose, + struct score_device** out_dev) +{ + struct score_device* dev = NULL; + struct mem_allocator* allocator; + res_T res = RES_OK; + + ASSERT(nthreads_hint && out_dev); + + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + dev = MEM_CALLOC(allocator, 1, sizeof(struct score_device)); + if (!dev) { + res = RES_MEM_ERR; + goto error; + } + ref_init(&dev->ref); + dev->logger = logger ? logger : LOGGER_DEFAULT; + dev->allocator = allocator; + dev->verbose = verbose; + dev->nthreads = MMIN(nthreads_hint, (unsigned) omp_get_num_procs()); + omp_set_num_threads((int) dev->nthreads); + + res = ssol_device_create(logger, allocator, nthreads_hint, verbose, &dev->ssol); + if (res != RES_OK) goto error; + +exit: + if (out_dev) *out_dev = dev; + return res; +error: + if (dev) { + score_device_ref_put(dev); + dev = NULL; + } + goto exit; +} + +void +score_device_ref_get(struct score_device* dev) +{ + ASSERT(dev); + ref_get(&dev->ref); +} + +void +score_device_ref_put(struct score_device* dev) +{ + ASSERT(dev); + ref_put(&dev->ref, device_release); +} + +struct ssol_device* +score_device_get_solver_device(struct score_device* dev) +{ + ASSERT(dev); + return dev->ssol; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +void +log_error(struct score_device* dev, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(dev && msg); + + va_start(vargs_list, msg); + log_msg(dev, LOG_ERROR, msg, vargs_list); + va_end(vargs_list); +} + +void +log_warning(struct score_device* dev, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(dev && msg); + + va_start(vargs_list, msg); + log_msg(dev, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); +} + diff --git a/src/core/solstice_core_device.h b/src/core/solstice_core_device.h @@ -0,0 +1,60 @@ +/* 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_CORE_DEVICE_H +#define SOLSTICE_CORE_DEVICE_H + +#include <rsys/ref_count.h> +#include <rsys/mem_allocator.h> + +struct logger; +struct ssol_device; + +struct score_device { + struct logger* logger; + struct mem_allocator* allocator; + unsigned nthreads; + int verbose; + struct ssol_device* ssol; + + ref_T ref; +}; + +/* Conditionally log a message on the LOG_ERROR stream of the device logger, + * with respect to the device verbose flag */ +extern LOCAL_SYM void +log_error +(struct score_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + +/* Conditionally log a message on the LOG_WARNING stream of the device logger, + * with respect to the device verbose flag */ +extern LOCAL_SYM void +log_warning +(struct score_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + +#endif /* SOLSTICE_CORE_DEVICE_H */ + diff --git a/src/core/solstice_core_node.c b/src/core/solstice_core_node.c @@ -0,0 +1,520 @@ +/* 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_node.h" +#include "solstice_core_device.h" + +#include <rsys/mem_allocator.h> +#include <rsys/algorithm.h> + +#include <solstice/ssol.h> +#include <solstice/sanim.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ + +static void +node_release(ref_T* ref) +{ + struct score_device* dev; + struct score_node* node = CONTAINER_OF(ref, struct score_node, ref); + ASSERT(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)); + break; + case NODE_PIVOT: + break; + default: FATAL("Unreachable code.\n"); break; + } + node_ref_put_children(&node->anim); + SANIM(node_release(&node->anim)); + MEM_RM(dev->allocator, node); + score_device_ref_put(dev); +} + +struct data { + const struct ssol_object* searched; + 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 +******************************************************************************/ +res_T +node_create + (struct score_device* dev, + struct score_node** out_node, + enum node_type type) +{ + struct score_node* node = NULL; + res_T res = RES_OK; + + ASSERT(dev && out_node && type < NODE_TYPES_COUNT__); + + node = MEM_CALLOC(dev->allocator, 1, sizeof(struct score_node)); + if (!node) { + res = RES_MEM_ERR; + goto error; + } + + score_device_ref_get(dev); + node->device = dev; + ref_init(&node->ref); + node->type = type; + +exit: + if (out_node) *out_node = node; + return res; +error: + if (node) { + score_node_ref_put(node); + node = NULL; + } + goto exit; +} + +void +node_ref_put_children(struct sanim_node* node) +{ + size_t count, i; + int init; + ASSERT(node); + SANIM(node_is_initialized(node, &init)); + if (!init) return; + SANIM(node_get_children_count(node, &count)); + for (i = 0; i < count; i++) { + struct sanim_node* child_; + struct score_node *child; + SANIM(node_get_child(node, i, &child_)); + child = CONTAINER_OF(child_, struct score_node, anim); + score_node_ref_put(child); + } +} + +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: + res = RES_BAD_ARG; + 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: + res = RES_BAD_ARG; + 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 + (struct score_device* dev, + struct score_node** node) +{ + struct sanim_node* anim; + res_T res = RES_OK; + res = node_create(dev, node, NODE_TEMPLATE_ROOT); + 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 +score_node_create_object + (struct score_device* dev, + struct score_node** node) +{ + res_T res = RES_OK; + res = node_create(dev, node, NODE_TEMPLATE); + if (res != RES_OK) goto error; + (*node)->data.template_node.sample = 1; +exit: + return res; +error: + if (node && *node) { + score_node_ref_put(*node); + *node = NULL; + } + goto exit; +} + +res_T +score_node_pivot_create + (struct score_device* dev, + struct score_node** node) +{ + res_T res = RES_OK; + res = node_create(dev, node, NODE_PIVOT); + if (res != RES_OK) goto error; +exit: + return res; +error: + if (node && *node) { + score_node_ref_put(*node); + *node = NULL; + } + goto exit; +} + +res_T +score_node_tracking_target_create + (struct score_device* dev, + struct score_node** node) +{ + res_T res = RES_OK; + res = node_create(dev, node, NODE_TRACKING_TARGET); + if (res != RES_OK) goto error; + res = sanim_node_initialize((*node)->device->allocator, &(*node)->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 +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 + (struct score_node* node, + struct ssol_object* object) +{ + res_T res = RES_OK; + ASSERT(node && object && node->type != NODE_TEMPLATE); + /* 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)); +exit: + return res; +error: + if (node->data.template_node.solver_object) { + SSOL(object_ref_put(node->data.template_node.solver_object)); + } + if (node->anim.data) { + SANIM(node_release(&node->anim)); + } + goto exit; +} + +res_T +score_node_pivot_setup + (struct score_node* node, + const struct sanim_pivot* pivot, + const struct sanim_tracking* tracking) +{ + res_T res = RES_OK; + ASSERT(node && pivot && tracking && node->type != NODE_PIVOT); + /* TODO: deal with multiple setups */ + res = sanim_node_initialize_pivot( + node->device->allocator, pivot, tracking, &node->anim); + if (res != RES_OK) goto error; +exit: + return res; +error: + if (node->anim.data) { + SANIM(node_release(&node->anim)); + } + goto exit; +} + +void +score_node_track_me + (const struct score_node* node, + struct sanim_tracking* tracking) +{ + ASSERT(node && tracking && node->type != NODE_TRACKING_TARGET); + SANIM(node_track_me(&node->anim, tracking)); +} + +res_T +score_node_add_child + (struct score_node* father, + struct score_node* 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 + ); + res = sanim_node_add_child(&father->anim, &child->anim); + if (res != RES_OK) return res; + score_node_ref_get(child); + return RES_OK; +} + +void +score_node_ref_get(struct score_node* node) +{ + ASSERT(node) ; + ref_get(&node->ref); +} + +void +score_node_ref_put(struct score_node* node) +{ + ASSERT(node); + ref_put(&node->ref, node_release); +} + +void +score_node_set_translation + (struct score_node* node, + const double translation[3]) +{ + ASSERT(node && translation && node->type != NODE_TEMPLATE_ROOT); + SANIM(node_set_translation(&node->anim, translation)); +} + +void +score_node_get_translation + (const struct score_node* node, + double translation[3]) +{ + ASSERT(node && translation && node->type != NODE_TEMPLATE_ROOT); + SANIM(node_get_translation(&node->anim, translation)); +} + +void +score_node_set_rotations + (struct score_node* node, + const double rotations[3]) +{ + ASSERT(node && rotations + && node->type != NODE_TEMPLATE_ROOT + && node->type != NODE_TRACKING_TARGET); + SANIM(node_set_rotations(&node->anim, rotations)); +} + +void +score_node_get_rotations + (const struct score_node* node, + double rotations[3]) +{ + ASSERT(node && rotations + && node->type != NODE_TEMPLATE_ROOT + && node->type != NODE_TRACKING_TARGET); + SANIM(node_get_rotations(&node->anim, rotations)); +} + +void +score_node_set_receiver + (struct score_node* node, + const int mask) +{ + ASSERT(node && node->type == NODE_TEMPLATE); + node->data.template_node.receiver_mask = mask; +} + +void +score_node_sample + (struct score_node* node, + const int sample) +{ + ASSERT(node && node->type == NODE_TEMPLATE); + node->data.template_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 @@ -0,0 +1,96 @@ +/* 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_CORE_NODE_H +#define SOLSTICE_CORE_NODE_H + +#include <solstice/sanim.h> + +#include <rsys/ref_count.h> + +#ifndef SOLSTICE_DARRAY_NODES +#define SOLSTICE_DARRAY_NODES +#include <rsys/dynamic_array.h> +struct sanim_node; +/* Define the darray_nodes data structure */ +#define DARRAY_NAME nodes +#define DARRAY_DATA struct sanim_node* +#include <rsys/dynamic_array.h> +#endif + +struct score_device; +struct score_node; +struct score_scene; +struct ssol_object; +struct ssol_instance; + +enum node_type { + NODE_TEMPLATE_ROOT, + NODE_INSTANCE_ROOT, + NODE_TEMPLATE, + NODE_INSTANCE, + NODE_TRACKING_TARGET, + NODE_PIVOT, + + 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 ssol_instance* solver_instance; + struct score_node* model; + int receiver_mask; + int sample; +}; + +struct score_node { + enum node_type type; + 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; + } data; + ref_T ref; +}; + +res_T +node_create + (struct score_device* dev, + struct score_node** out_node, + enum node_type type); + +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 @@ -0,0 +1,450 @@ +/* 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 + ******************************************************************************/ + +FINLINE 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: + res = RES_BAD_ARG; + 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: + res = RES_BAD_ARG; + 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: + res = RES_BAD_ARG; + break; + case NODE_INSTANCE_ROOT: + res = RES_BAD_ARG; /* should only visit post-pivot nodes */ + break; + case NODE_TRACKING_TARGET: + /* not a solver-related item */ + break; + case NODE_TEMPLATE: + res = RES_BAD_ARG; + 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 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; + if (!dev || !out_scene) return RES_BAD_ARG; + + 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)); + if (!ok) return RES_BAD_ARG; + 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]; + if (!scene || !scene->sun) return RES_BAD_ARG; + 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]; + if (!scene || !scene->sun) return RES_BAD_ARG; + 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 @@ -0,0 +1,48 @@ +/* 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 <rsys/ref_count.h> + +#include "solstice_core.h" + +#ifndef SOLSTICE_DARRAY_NODES +#define SOLSTICE_DARRAY_NODES +#include <rsys/dynamic_array.h> +struct sanim_node; +/* Define the darray_nodes data structure */ +#define DARRAY_NAME nodes +#define DARRAY_DATA struct sanim_node* +#include <rsys/dynamic_array.h> +#endif + +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 @@ -0,0 +1,32 @@ +/* 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/ssol.h> + +res_T +score_solve + (struct score_scene* scene, + struct ssp_rng* rng, + const size_t realisations_count, + FILE* output, + struct ssol_estimator* estimator) +{ + if (!scene || !rng || !realisations_count || !output || !estimator) + return RES_BAD_ARG; + return ssol_solve(scene->solver, rng, realisations_count, output, estimator); +} +\ No newline at end of file diff --git a/src/core/test_core_device.c b/src/core/test_core_device.c @@ -0,0 +1,64 @@ +/* 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 "test_core_utils.h" + +#include <rsys/logger.h> + +int +main(int argc, char** argv) +{ + struct logger logger; + struct mem_allocator allocator; + struct score_device* dev; + (void) argc, (void) argv; + + CHECK(score_device_create(NULL, NULL, 0, 0, NULL), RES_BAD_ARG); + CHECK(score_device_create(NULL, NULL, 1, 0, &dev), RES_OK); + + score_device_ref_put(dev); + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + CHECK(MEM_ALLOCATED_SIZE(&allocator), 0); + CHECK(score_device_create(NULL, &allocator, 2, 0, NULL), RES_BAD_ARG); + CHECK(score_device_create(NULL, &allocator, 1, 0, &dev), RES_OK); + score_device_ref_put(dev); + CHECK(MEM_ALLOCATED_SIZE(&allocator), 0); + + CHECK(logger_init(&allocator, &logger), RES_OK); + logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); + logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); + logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); + + CHECK(score_device_create(&logger, NULL, 4, 0, NULL), RES_BAD_ARG); + CHECK(score_device_create(&logger, NULL, 1, 0, &dev), RES_OK); + score_device_ref_put(dev); + + CHECK(score_device_create(&logger, &allocator, 2, 0, NULL), RES_BAD_ARG); + CHECK(score_device_create(&logger, &allocator, 1, 0, &dev), RES_OK); + score_device_ref_put(dev); + + CHECK(score_device_create(&logger, &allocator, 0, 0, &dev), RES_BAD_ARG); + CHECK(score_device_create(&logger, &allocator, 1, 0, &dev), RES_OK); + score_device_ref_put(dev); + + logger_release(&logger); + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/core/test_core_node.c b/src/core/test_core_node.c @@ -0,0 +1,187 @@ +/* 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 "test_core_utils.h" + +#include <solstice/ssol.h> +#include <solstice/sanim.h> + +#include <rsys/logger.h> +#include <rsys/double3.h> + +int +main(int argc, char** argv) +{ + struct logger logger; + struct mem_allocator allocator; + struct score_device* dev = NULL; + struct score_node *temp = NULL, *inst = NULL, *piv = NULL, *piv2 = NULL, + *geom1 = NULL, *geom2 = NULL, *tgt = NULL; + struct sanim_pivot pivot = SANIM_PIVOT_NULL; + struct sanim_tracking tracking = SANIM_TRACKING_NULL; + struct ssol_device* sol_dev = NULL; + struct ssol_punched_surface punched = SSOL_PUNCHED_SURFACE_NULL; + struct ssol_carving carving = SSOL_CARVING_NULL; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + struct ssol_shape *shape1 = NULL, *shape2 = NULL; + struct ssol_material* mtl = NULL; + struct ssol_object *obj1 = NULL, *obj2 = NULL; + struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ }; + double polygon [] = { + -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 0.f, -2.f + }; + double transl[3], rot[3]; + const size_t npolygon_verts = sizeof(polygon) / sizeof(double[2]); + (void) argc, (void) argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + CHECK(logger_init(&allocator, &logger), RES_OK); + logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); + logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); + logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); + + CHECK(ssol_device_create( + &logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &sol_dev), RES_OK); + + score_device_create(&logger, &allocator, 1, 0, &dev); + + CHECK(score_node_template_create(NULL, &temp), RES_BAD_ARG); + CHECK(score_node_template_create(dev, NULL), RES_BAD_ARG); + CHECK(score_node_template_create(dev, &temp), RES_OK); + score_node_ref_put(temp); + + CHECK(score_node_create_object(NULL, &geom1), RES_BAD_ARG); + CHECK(score_node_create_object(dev, NULL), RES_BAD_ARG); + CHECK(score_node_create_object(dev, &geom1), RES_OK); + score_node_ref_put(geom1); + + CHECK(score_node_pivot_create(NULL, &piv), RES_BAD_ARG); + CHECK(score_node_pivot_create(dev, NULL), RES_BAD_ARG); + CHECK(score_node_pivot_create(dev, &piv), RES_OK); + score_node_ref_put(piv); + + CHECK(score_node_tracking_target_create(NULL, &tgt), RES_BAD_ARG); + CHECK(score_node_tracking_target_create(dev, NULL), RES_BAD_ARG); + CHECK(score_node_tracking_target_create(dev, &tgt), RES_OK); + score_node_ref_put(tgt); + + CHECK(score_node_template_create(dev, &temp), RES_OK); + CHECK(score_node_create_object(dev, &geom1), RES_OK); + CHECK(score_node_create_object(dev, &geom2), RES_OK); + CHECK(score_node_pivot_create(dev, &piv), RES_OK); + CHECK(score_node_pivot_create(dev, &piv2), RES_OK); + CHECK(score_node_tracking_target_create(dev, &tgt), RES_OK); + + tracking.data.node_target.tracked_node = NULL; + tracking.policy = TRACKING_NODE_TARGET; + score_node_track_me(tgt, &tracking); + CHECK(tracking.policy, TRACKING_NODE_TARGET); + /* cannot check tracking.data.node_target.tracked_node validity */ + + CHECK(score_node_instantiate(NULL, &inst), RES_BAD_ARG); + CHECK(score_node_instantiate(temp, NULL), RES_BAD_ARG); + CHECK(score_node_instantiate(geom1, &inst), RES_BAD_ARG); + CHECK(score_node_instantiate(temp, &inst), RES_OK); + score_node_ref_put(inst); + + CHECK(score_node_instantiate(temp, &inst), RES_OK); + + score_node_set_receiver(geom1, 0); + score_node_set_receiver(geom2, 0); + + score_node_sample(geom1, 0); + score_node_sample(geom2, 1); + + CHECK(ssol_material_create_virtual(sol_dev, &mtl), RES_OK); + CHECK(ssol_object_create(sol_dev, &obj1), RES_OK); + CHECK(ssol_object_create(sol_dev, &obj2), RES_OK); + + attribs[0].usage = SSOL_POSITION; + attribs[0].get = get_position; + CHECK(ssol_shape_create_mesh(sol_dev, &shape1), RES_OK); + CHECK(ssol_mesh_setup(shape1, RECT_NTRIS__, get_ids, RECT_NVERTS__, + attribs, 1, (void*) &RECT_DESC__), RES_OK); + CHECK(ssol_object_add_shaded_shape(obj1, shape1, mtl, mtl), RES_OK); + + tracking.policy = TRACKING_SUN; + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + CHECK(score_node_object_setup(NULL, obj1), RES_BAD_ARG); + CHECK(score_node_object_setup(geom1, NULL), RES_BAD_ARG); + CHECK(score_node_object_setup(geom1, obj1), RES_OK); + + CHECK(score_node_pivot_setup(piv, &pivot, &tracking), RES_OK); + CHECK(score_node_pivot_setup(piv2, &pivot, &tracking), RES_OK); + + carving.get = get_polygon_vertices; + carving.operation = SSOL_AND; + carving.nb_vertices = npolygon_verts; + carving.context = &polygon; + quadric.type = SSOL_QUADRIC_PLANE; + punched.nb_carvings = 1; + punched.quadric = &quadric; + punched.carvings = &carving; + CHECK(ssol_shape_create_punched_surface(sol_dev, &shape2), RES_OK); + CHECK(ssol_punched_surface_setup(shape2, &punched), RES_OK); + CHECK(ssol_object_add_shaded_shape(obj2, shape2, mtl, mtl), RES_OK); + CHECK(score_node_object_setup(geom2, obj2), RES_OK); + + CHECK(ssol_material_ref_put(mtl), RES_OK); + CHECK(ssol_object_ref_put(obj1), RES_OK); + CHECK(ssol_object_ref_put(obj2), RES_OK); + CHECK(ssol_shape_ref_put(shape1), RES_OK); + CHECK(ssol_shape_ref_put(shape2), RES_OK); + CHECK(ssol_device_ref_put(sol_dev), RES_OK); + + CHECK(score_node_add_child(NULL, geom1), RES_BAD_ARG); + CHECK(score_node_add_child(temp, NULL), RES_BAD_ARG); + CHECK(score_node_add_child(tgt, geom1), RES_BAD_ARG); + CHECK(score_node_add_child(inst, geom1), RES_BAD_ARG); + CHECK(score_node_add_child(geom1, temp), RES_BAD_ARG); + CHECK(score_node_add_child(geom1, inst), RES_BAD_ARG); + CHECK(score_node_add_child(temp, geom1), RES_OK); + CHECK(score_node_add_child(geom1, geom1), RES_BAD_ARG); + CHECK(score_node_add_child(geom1, piv), RES_OK); + CHECK(score_node_add_child(piv, piv2), RES_BAD_ARG); + score_node_ref_put(piv2); + + score_node_set_translation(inst, transl); + score_node_set_translation(piv, transl); + score_node_set_translation(geom1, transl); + score_node_set_translation(geom2, transl); + score_node_set_translation(tgt, transl); + + score_node_set_rotations(inst, rot); + score_node_set_rotations(piv, rot); + score_node_set_rotations(geom1, rot); + score_node_set_rotations(geom2, rot); + + score_node_ref_put(inst); + score_node_ref_put(piv); + score_node_ref_put(geom1); + score_node_ref_put(geom2); + score_node_ref_put(temp); + score_node_ref_put(tgt); + + score_device_ref_put(dev); + + logger_release(&logger); + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/core/test_core_scene.c b/src/core/test_core_scene.c @@ -0,0 +1,223 @@ +/* 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 "test_core_utils.h" + +#include <solstice/ssol.h> +#include <solstice/sanim.h> + +#include <star/ssp.h> + +#include <rsys/logger.h> +#include <rsys/double3.h> + +int +main(int argc, char** argv) +{ + struct logger logger; + struct mem_allocator allocator; + struct score_device* dev = NULL; + struct score_scene* scene = NULL; + struct score_node *temp1 = NULL, *inst1 = NULL, *temp2 = NULL, *inst2 = NULL, + *piv = NULL, *geom1 = NULL, *geom2 = NULL, *tgt = NULL; + struct sanim_pivot pivot = SANIM_PIVOT_NULL; + struct sanim_tracking tracking = SANIM_TRACKING_NULL; + struct ssol_device* sol_dev = NULL; + struct ssol_punched_surface punched = SSOL_PUNCHED_SURFACE_NULL; + struct ssol_carving carving = SSOL_CARVING_NULL; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + struct ssol_shape *shape1 = NULL, *shape2 = NULL; + struct ssol_material *v_mtl = NULL, *m_mtl = NULL; + struct ssol_object *obj1 = NULL, *obj2 = NULL; + struct ssol_sun* sun = NULL; + struct ssol_estimator* estimator = NULL; + struct ssol_spectrum* spectrum = NULL; + struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ }; + struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL; + struct ssp_rng* rng = NULL; + double sun_dir[3]; + double transl[3], rot[3]; + double polygon [] = { + -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 0.f, -2.f + }; + double wavelengths[3] = { 1, 2, 3 }; + double intensities[3] = { 1, 0.8, 1 }; + const size_t npolygon_verts = sizeof(polygon) / sizeof(double[2]); + FILE* tmp = NULL; + (void) argc, (void) argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + CHECK(logger_init(&allocator, &logger), RES_OK); + logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); + logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); + logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); + + CHECK(ssol_device_create( + &logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &sol_dev), RES_OK); + + CHECK(score_device_create(&logger, &allocator, 1, 0, &dev), RES_OK); + + /* create a template of a virtual 'target' */ + + attribs[0].usage = SSOL_POSITION; + attribs[0].get = get_position; + CHECK(ssol_shape_create_mesh(sol_dev, &shape2), RES_OK); + CHECK(ssol_mesh_setup(shape2, RECT_NTRIS__, get_ids, RECT_NVERTS__, + attribs, 1, (void*) &RECT_DESC__), RES_OK); + CHECK(ssol_material_create_virtual(sol_dev, &v_mtl), RES_OK); + CHECK(ssol_object_create(sol_dev, &obj2), RES_OK); + CHECK(ssol_object_add_shaded_shape(obj2, shape2, v_mtl, v_mtl), RES_OK); + CHECK(score_node_create_object(dev, &geom2), RES_OK); + CHECK(score_node_object_setup(geom2, obj2), RES_OK); + + CHECK(score_node_template_create(dev, &temp2), RES_OK); + CHECK(score_node_add_child(temp2, geom2), RES_OK); + /* define a tracking target at the geom2 center */ + CHECK(score_node_tracking_target_create(dev, &tgt), RES_OK); + CHECK(score_node_add_child(geom2, tgt), RES_OK); + score_node_set_receiver(geom2, SSOL_FRONT); + score_node_sample(geom2, 0); + d3(transl, 10, 0, 3); + score_node_set_translation(geom2, transl); + d3(rot, 0, PI / 2, 0); + score_node_set_rotations(geom2, rot); + CHECK(score_node_instantiate(temp2, &inst2), RES_OK); + + CHECK(ssol_material_ref_put(v_mtl), RES_OK); + CHECK(ssol_object_ref_put(obj2), RES_OK); + CHECK(ssol_shape_ref_put(shape2), RES_OK); + + /* create a template of a 'heliostat' */ + + carving.get = get_polygon_vertices; + carving.operation = SSOL_AND; + carving.nb_vertices = npolygon_verts; + carving.context = &polygon; + quadric.type = SSOL_QUADRIC_PLANE; + punched.nb_carvings = 1; + punched.quadric = &quadric; + punched.carvings = &carving; + CHECK(ssol_shape_create_punched_surface(sol_dev, &shape1), RES_OK); + CHECK(ssol_punched_surface_setup(shape1, &punched), RES_OK); + CHECK(ssol_object_create(sol_dev, &obj1), RES_OK); + CHECK(ssol_material_create_mirror(sol_dev, &m_mtl), RES_OK); + shader.normal = get_shader_normal; + shader.reflectivity = get_shader_reflectivity; + shader.roughness = get_shader_roughness; + CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK); + CHECK(ssol_object_add_shaded_shape(obj1, shape1, m_mtl, m_mtl), RES_OK); + CHECK(score_node_create_object(dev, &geom1), RES_OK); + + score_node_track_me(tgt, &tracking); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_point, 0, 0, 0); + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + CHECK(score_node_object_setup(geom1, obj1), RES_OK); + + CHECK(score_node_pivot_create(dev, &piv), RES_OK); + CHECK(score_node_pivot_setup(piv, &pivot, &tracking), RES_OK); + d3(transl, 0, 0, 3); + score_node_set_translation(piv, transl); + d3(rot, 0, 0, PI / 2); + score_node_set_rotations(piv, rot); + + CHECK(score_node_template_create(dev, &temp1), RES_OK); + CHECK(score_node_add_child(temp1, piv), RES_OK); + CHECK(score_node_add_child(piv, geom1), RES_OK); + CHECK(score_node_instantiate(temp1, &inst1), RES_OK); + + CHECK(ssol_material_ref_put(m_mtl), RES_OK); + CHECK(ssol_object_ref_put(obj1), RES_OK); + CHECK(ssol_shape_ref_put(shape1), RES_OK); + CHECK(ssol_device_ref_put(sol_dev), RES_OK); + + /* some scene API tests */ + + CHECK(score_scene_create(NULL, &scene), RES_BAD_ARG); + CHECK(score_scene_create(dev, NULL), RES_BAD_ARG); + CHECK(score_scene_create(dev, &scene), RES_OK); + score_scene_ref_put(scene); + + CHECK(score_scene_create(dev, &scene), RES_OK); + +#define N__ 10000 + NCHECK(tmp = tmpfile(), 0); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); + CHECK(ssol_estimator_create(sol_dev, &estimator), RES_OK); + CHECK(score_solve(scene, NULL, N__, tmp, estimator), RES_BAD_ARG); + CHECK(score_solve(scene, rng, 0, tmp, estimator), RES_BAD_ARG); + CHECK(score_solve(scene, rng, N__, NULL, estimator), RES_BAD_ARG); + CHECK(score_solve(scene, rng, N__, tmp, NULL), RES_BAD_ARG); + /* incomplete scene (see solver lib) */ + CHECK(score_solve(scene, rng, N__, tmp, estimator), RES_BAD_ARG); + + CHECK(score_scene_attach_instance(NULL, inst1), RES_BAD_ARG); + CHECK(score_scene_attach_instance(scene, NULL), RES_BAD_ARG); + CHECK(score_scene_attach_instance(scene, piv), RES_BAD_ARG); + CHECK(score_scene_attach_instance(scene, inst1), RES_OK); + CHECK(score_scene_attach_instance(scene, inst1), RES_BAD_ARG); + + score_scene_detach_instance(scene, inst1); + + /* create and attach a sun, including API tests */ + + CHECK(ssol_spectrum_create(sol_dev, &spectrum), RES_OK); + CHECK(ssol_spectrum_setup(spectrum, wavelengths, intensities, 3), RES_OK); + CHECK(ssol_sun_create_directional(sol_dev, &sun), RES_OK); + d3(sun_dir, 0, 0, -1); + CHECK(ssol_sun_set_direction(sun, sun_dir), RES_OK); + CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK); + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + score_scene_attach_sun(scene, sun); + score_scene_detach_sun(scene, sun); + + CHECK(ssol_spectrum_ref_put(spectrum), RES_OK); + + /* fill up the scene */ + + CHECK(score_scene_attach_instance(scene, inst1), RES_OK); + CHECK(score_scene_attach_instance(scene, inst2), RES_OK); + /* no sun to get a direction to track */ + score_scene_attach_sun(scene, sun); + CHECK(score_scene_reset_simulation(scene), RES_OK); + + CHECK(fclose(tmp), 0); + + /* clean up memory */ + + CHECK(ssol_sun_ref_put(sun), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); + CHECK(ssol_estimator_ref_put(estimator), RES_OK); + + score_scene_ref_put(scene); + + score_node_ref_put(inst1); + score_node_ref_put(inst2); + score_node_ref_put(piv); + score_node_ref_put(geom1); + score_node_ref_put(geom2); + score_node_ref_put(temp1); + score_node_ref_put(temp2); + score_node_ref_put(tgt); + score_device_ref_put(dev); + + logger_release(&logger); + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/core/test_core_solve1.c b/src/core/test_core_solve1.c @@ -0,0 +1,203 @@ +/* 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 "test_core_utils.h" + +#include <solstice/ssol.h> +#include <solstice/sanim.h> + +#include <star/ssp.h> + +#include <rsys/logger.h> +#include <rsys/double3.h> + +int +main(int argc, char** argv) +{ + struct logger logger; + struct mem_allocator allocator; + struct score_device* dev = NULL; + struct score_scene* scene = NULL; + struct score_node *temp1 = NULL, *inst1 = NULL, *temp2 = NULL, *inst2 = NULL, + *piv = NULL, *geom1 = NULL, *geom2 = NULL, *tgt = NULL; + struct sanim_pivot pivot = SANIM_PIVOT_NULL; + struct sanim_tracking tracking = SANIM_TRACKING_NULL; + struct ssol_device* sol_dev = NULL; + struct ssol_punched_surface punched = SSOL_PUNCHED_SURFACE_NULL; + struct ssol_carving carving = SSOL_CARVING_NULL; + struct ssol_quadric quadric = SSOL_QUADRIC_DEFAULT; + struct ssol_shape *shape1 = NULL, *shape2 = NULL; + struct ssol_material *v_mtl = NULL, *m_mtl = NULL; + struct ssol_object *obj1 = NULL, *obj2 = NULL; + struct ssol_sun* sun = NULL; + struct ssol_estimator* estimator = NULL; + struct ssol_spectrum* spectrum = NULL; + struct ssol_vertex_data attribs[1] = { SSOL_VERTEX_DATA_NULL__ }; + struct ssol_mirror_shader shader = SSOL_MIRROR_SHADER_NULL; + struct ssol_instance* solver_instance = NULL; + struct ssp_rng* rng = NULL; + double sun_dir[3]; + double transl[3], rot[3]; + double polygon [] = { + -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 0.f, -2.f + }; + double wavelengths[3] = { 1, 2, 3 }; + double intensities[3] = { 1, 0.8, 1 }; + const size_t npolygon_verts = sizeof(polygon) / sizeof(double[2]); + size_t count; + uint32_t r_id; + double m, std; + FILE* tmp = NULL; + (void) argc, (void) argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + CHECK(logger_init(&allocator, &logger), RES_OK); + logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); + logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); + logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); + + CHECK(score_device_create(&logger, &allocator, 1, 0, &dev), RES_OK); + + sol_dev = score_device_get_solver_device(dev); + + /* create a template of a virtual 'target' */ + + attribs[0].usage = SSOL_POSITION; + attribs[0].get = get_position; + CHECK(ssol_shape_create_mesh(sol_dev, &shape2), RES_OK); + CHECK(ssol_mesh_setup(shape2, RECT_NTRIS__, get_ids, RECT_NVERTS__, + attribs, 1, (void*) &RECT_DESC__), RES_OK); + CHECK(ssol_material_create_virtual(sol_dev, &v_mtl), RES_OK); + CHECK(ssol_object_create(sol_dev, &obj2), RES_OK); + CHECK(ssol_object_add_shaded_shape(obj2, shape2, v_mtl, v_mtl), RES_OK); + CHECK(score_node_create_object(dev, &geom2), RES_OK); + CHECK(score_node_object_setup(geom2, obj2), RES_OK); + + CHECK(score_node_template_create(dev, &temp2), RES_OK); + CHECK(score_node_add_child(temp2, geom2), RES_OK); + /* define a tracking target at the geom2 center */ + CHECK(score_node_tracking_target_create(dev, &tgt), RES_OK); + CHECK(score_node_add_child(geom2, tgt), RES_OK); + score_node_set_receiver(geom2, SSOL_FRONT); + score_node_sample(geom2, 0); + d3(transl, 10, 0, 3); + score_node_set_translation(geom2, transl); + d3(rot, 0, -PI / 2, 0); + score_node_set_rotations(geom2, rot); + CHECK(score_node_instantiate(temp2, &inst2), RES_OK); + + /* create a template of a 'heliostat' */ + + carving.get = get_polygon_vertices; + carving.operation = SSOL_AND; + carving.nb_vertices = npolygon_verts; + carving.context = &polygon; + quadric.type = SSOL_QUADRIC_PLANE; + punched.nb_carvings = 1; + punched.quadric = &quadric; + punched.carvings = &carving; + CHECK(ssol_shape_create_punched_surface(sol_dev, &shape1), RES_OK); + CHECK(ssol_punched_surface_setup(shape1, &punched), RES_OK); + CHECK(ssol_object_create(sol_dev, &obj1), RES_OK); + CHECK(ssol_material_create_mirror(sol_dev, &m_mtl), RES_OK); + shader.normal = get_shader_normal; + shader.reflectivity = get_shader_reflectivity; + shader.roughness = get_shader_roughness; + CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK); + CHECK(ssol_object_add_shaded_shape(obj1, shape1, m_mtl, m_mtl), RES_OK); + CHECK(score_node_create_object(dev, &geom1), RES_OK); + + score_node_track_me(tgt, &tracking); + pivot.type = PIVOT_SINGLE_AXIS; + d3(pivot.data.pivot1.ref_point, 0, 0, 0); + d3(pivot.data.pivot1.ref_normal, 0, 0, 1); + CHECK(score_node_object_setup(geom1, obj1), RES_OK); + + CHECK(score_node_pivot_create(dev, &piv), RES_OK); + CHECK(score_node_pivot_setup(piv, &pivot, &tracking), RES_OK); + d3(transl, 0, 0, 3); + score_node_set_translation(piv, transl); + d3(rot, 0, 0, PI / 2); + score_node_set_rotations(piv, rot); + + CHECK(score_node_template_create(dev, &temp1), RES_OK); + CHECK(score_node_add_child(temp1, piv), RES_OK); + CHECK(score_node_add_child(piv, geom1), RES_OK); + CHECK(score_node_instantiate(temp1, &inst1), RES_OK); + + /* create scene */ + + CHECK(score_scene_create(dev, &scene), RES_OK); + +#define N__ 10000 + NCHECK(tmp = tmpfile(), 0); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); + CHECK(ssol_estimator_create(sol_dev, &estimator), RES_OK); + + CHECK(ssol_spectrum_create(sol_dev, &spectrum), RES_OK); + CHECK(ssol_spectrum_setup(spectrum, wavelengths, intensities, 3), RES_OK); + CHECK(ssol_sun_create_directional(sol_dev, &sun), RES_OK); + d3(sun_dir, 0, 0, -1); + CHECK(ssol_sun_set_direction(sun, sun_dir), RES_OK); + CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK); + CHECK(ssol_sun_set_dni(sun, 1000), RES_OK); + + CHECK(score_scene_attach_instance(scene, inst1), RES_OK); + CHECK(score_scene_attach_instance(scene, inst2), RES_OK); + score_scene_attach_sun(scene, sun); + CHECK(score_scene_reset_simulation(scene), RES_OK); + + CHECK(score_solve(scene, rng, N__, tmp, estimator), RES_OK); + CHECK(ssol_estimator_get_count(estimator, &count), RES_OK); + CHECK(count, N__); + score_node_get_instance_of(inst2, geom2, &solver_instance); + NCHECK(solver_instance, NULL); + CHECK(ssol_instance_get_id(solver_instance, &r_id), RES_OK); + CHECK(pp_sum(tmp, (int32_t) r_id, count, &m, &std), RES_OK); + + CHECK(fclose(tmp), 0); + + /* clean up memory */ + + CHECK(ssol_material_ref_put(m_mtl), RES_OK); + CHECK(ssol_object_ref_put(obj1), RES_OK); + CHECK(ssol_shape_ref_put(shape1), RES_OK); + CHECK(ssol_material_ref_put(v_mtl), RES_OK); + CHECK(ssol_object_ref_put(obj2), RES_OK); + CHECK(ssol_shape_ref_put(shape2), RES_OK); + CHECK(ssol_spectrum_ref_put(spectrum), RES_OK); + CHECK(ssol_sun_ref_put(sun), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); + CHECK(ssol_estimator_ref_put(estimator), RES_OK); + + score_scene_ref_put(scene); + score_node_ref_put(inst1); + score_node_ref_put(inst2); + score_node_ref_put(piv); + score_node_ref_put(geom1); + score_node_ref_put(geom2); + score_node_ref_put(temp1); + score_node_ref_put(temp2); + score_node_ref_put(tgt); + score_device_ref_put(dev); + + logger_release(&logger); + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/core/test_core_utils.c b/src/core/test_core_utils.c @@ -0,0 +1,173 @@ +/* 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 "test_core_utils.h" + +#include <solstice/ssol.h> + +#include <rsys/mem_allocator.h> +#include <rsys/logger.h> + +#define _POSIX_C_SOURCE 200809L /* snprintf support */ +#include <math.h> +#include <stdio.h> +#include <string.h> + +void +log_stream(const char* msg, void* ctx) { + ASSERT(msg); + (void) msg, (void) ctx; + printf("%s\n", msg); +} + +void +check_memory_allocator(struct mem_allocator* allocator) { + if (MEM_ALLOCATED_SIZE(allocator)) { + char dump[512]; + MEM_DUMP(allocator, dump, sizeof(dump) / sizeof(char)); + fprintf(stderr, "%s\n", dump); + FATAL("Memory leaks\n"); + } +} + +const float VERTICES__ [] = { + -1, -1, 0.f, + 1, -1, 0.f, + 1, 1, 0.f, + -1, 1, 0.f +}; + +const unsigned RECT_NVERTS__ = sizeof(VERTICES__) / sizeof(float[3]); + +const unsigned TRG_IDS__ [] = { 0, 2, 1, 2, 0, 3 }; +const unsigned RECT_NTRIS__ = sizeof(TRG_IDS__) / sizeof(unsigned[3]); + +const struct desc RECT_DESC__ = { VERTICES__, TRG_IDS__ }; + +void +get_position(const unsigned ivert, float position[3], void* data) +{ + struct desc* desc = data; + NCHECK(desc, NULL); + NCHECK(position, NULL); + position[0] = desc->vertices[ivert * 3 + 0]; + position[1] = desc->vertices[ivert * 3 + 1]; + position[2] = desc->vertices[ivert * 3 + 2]; +} + +void +get_ids(const unsigned itri, unsigned ids[3], void* data) +{ + const unsigned id = itri * 3; + struct desc* desc = data; + NCHECK(desc, NULL); + NCHECK(ids, NULL); + ids[0] = desc->indices[id + 0]; + ids[1] = desc->indices[id + 1]; + ids[2] = desc->indices[id + 2]; +} + +void +get_polygon_vertices(const size_t ivert, double position[2], void* ctx) +{ + const double* verts = ctx; + NCHECK(position, NULL); + NCHECK(ctx, NULL); + position[0] = verts[ivert * 2 + 0]; + position[1] = verts[ivert * 2 + 1]; +} + +void +get_shader_normal + (struct ssol_device* dev, + const double wavelength, + const double P[3], + const double Ng[3], + const double Ns[3], + const double uv[2], + const double w[3], + double* val) +{ + int i; + (void) dev, (void) wavelength, (void) P, (void) Ng, (void) uv, (void) w; + FOR_EACH(i, 0, 3) val[i] = Ns[i]; +} + +void +get_shader_reflectivity + (struct ssol_device* dev, + const double wavelength, + const double P[3], + const double Ng[3], + const double Ns[3], + const double uv[2], + const double w[3], + double* val) +{ + (void) dev, (void) wavelength, (void) P, (void) Ng, (void) Ns, (void) uv, (void) w; + *val = 1; +} + +void +get_shader_roughness + (struct ssol_device* dev, + const double wavelength, + const double P[3], + const double Ng[3], + const double Ns[3], + const double uv[2], + const double w[3], + double* val) +{ + (void) dev, (void) wavelength, (void) P, (void) Ng, (void) Ns, (void) uv, (void) w; + *val = 0; +} + +res_T +pp_sum + (FILE* f, + const int32_t receiver_id, + const size_t count, + double* mean, + double* std) +{ + struct ssol_receiver_data hit; + double sum = 0; + double sum2 = 0; + double E, V, SE; + + if (!f || !mean || !std || !count) + return RES_BAD_ARG; + + rewind(f); + while (1 == fread(&hit, sizeof(struct ssol_receiver_data), 1, f)) { + if (ferror(f)) + return RES_BAD_ARG; + + if (receiver_id != hit.receiver_id) + continue; + + sum += hit.weight; + sum2 += hit.weight * hit.weight; + } + + E = sum / (double) count; + V = MMAX(sum2 / (double) count - E*E, 0); + SE = sqrt(V / (double) count); + + *mean = E; + *std = SE; + return RES_OK; +} diff --git a/src/core/test_core_utils.h b/src/core/test_core_utils.h @@ -0,0 +1,103 @@ +/* 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 test_core_utils_H +#define test_core_utils_H + +#include "solstice_core.h" + +#include <rsys/rsys.h> +#include <stdio.h> + +struct mem_allocator; +struct ssol_device; + +/******************************************************************************* +* Utilities +******************************************************************************/ +void +log_stream(const char* msg, void* ctx); + +void +check_memory_allocator(struct mem_allocator* allocator); + +/******************************************************************************* +* Mesh stuff +******************************************************************************/ +struct desc { + const float* vertices; + const unsigned* indices; +}; + +extern const float EDGES__ []; + +extern const unsigned RECT_NVERTS__; + +extern const unsigned TRG_IDS__ []; +extern const unsigned RECT_NTRIS__; + +extern const struct desc RECT_DESC__; + +void +get_position(const unsigned ivert, float position[3], void* data); + +void +get_ids(const unsigned itri, unsigned ids[3], void* data); + +void +get_polygon_vertices(const size_t ivert, double position[2], void* ctx); + +void +get_shader_normal + (struct ssol_device* dev, + const double wavelength, + const double P[3], + const double Ng[3], + const double Ns[3], + const double uv[2], + const double w[3], + double* val); + +void +get_shader_reflectivity + (struct ssol_device* dev, + const double wavelength, + const double P[3], + const double Ng[3], + const double Ns[3], + const double uv[2], + const double w[3], + double* val); + +void +get_shader_roughness + (struct ssol_device* dev, + const double wavelength, + const double P[3], + const double Ng[3], + const double Ns[3], + const double uv[2], + const double w[3], + double* val); + +res_T +pp_sum + (FILE* f, + const int32_t receiver_id, + const size_t count, + double* mean, + double* std); + +#endif /* test_core_utils_H */