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:
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 */