commit 89b83bee0801f0b36c17f56ea5d3e099f11af7d4
parent f714362a43df38fc2418344e8153905dcbd9f44c
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 1 May 2020 16:46:13 +0200
Merge branch 'feature_no_add' into develop
Diffstat:
62 files changed, 12700 insertions(+), 7207 deletions(-)
diff --git a/README.md b/README.md
@@ -1,10 +1,10 @@
-StarEnclosures
-==============
+Star-enclosures-3d
+==================
Overview
--------
-The purpose of Star-enclosures is to extract enclosures from raw
+The purpose of Star-enclosures-3d is to extract enclosures from raw
geometry. An enclosure is a set of triangles enclosing a given volume.
The enclosure notion extends to open enclosures for which there is no
inside or outside. For every detected enclosure, the library provides
@@ -22,7 +22,7 @@ triangles can be set.
How to build
------------
-StarEnclosures relies on the [CMake](http://www.cmake.org) and the
+Star-enclosures-3d relies on the [CMake](http://www.cmake.org) and the
[RCMake](https://gitlab.com/vaplv/rcmake/) package to build. It also
depends on the [RSys](https://gitlab.com/vaplv/rsys/) and
[Star-3D](https://gitlab.com/meso-star/star-3d/) libraries. Additionaly,
@@ -91,7 +91,7 @@ Release notes
License
-------
-StarEnclosures is Copyright (C) |Méso|Star> 2018
+Star-enclosures-3d is Copyright (C) |Méso|Star> 2019-2020
(<a href="mailto:contact@meso-star.com" class="email">contact@meso-star.com</a>).
It is free software released under the GPLv3+ license. You are welcome
to redistribute it under certain conditions; refer to the COPYING files
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) |Meso|Star> 2016-2018
+# Copyright (C) |Meso|Star> 2016-2020
#
# 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
@@ -13,101 +13,134 @@
# 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 3.0)
-project(Star-Enclosures C)
+cmake_minimum_required(VERSION 3.1)
+project(star-enclosures-3d C)
enable_testing()
-set(SENC_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
+include(CMakeDependentOption)
+
+set(SENC3D_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
option(NO_TEST "Do not build tests" OFF)
-################################################################################
+cmake_dependent_option(HUGE_ADDITIONAL_TESTS
+ "Build additional tests that involve millions of triangles" OFF
+ "NOT NO_TEST" OFF)
+
+###############################################################################
# Check dependencies
-################################################################################
+###############################################################################
find_package(RCMake 0.4 REQUIRED)
-find_package(Star3D 0.6 REQUIRED)
+find_package(Star3D 0.7.1 REQUIRED)
find_package(RSys 0.8.1 REQUIRED)
find_package(OpenMP 2.0 REQUIRED)
if(NOT NO_TEST)
-find_package(StarSP 0.7 REQUIRED)
-find_package(Star3DUT 0.3.1 REQUIRED)
+ find_package(StarSP 0.7 REQUIRED)
+endif()
+
+if(HUGE_ADDITIONAL_TESTS)
+ find_package(Star3DUT 0.3.1 REQUIRED)
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
include(rcmake_runtime)
-
+
if(NO_TEST)
-rcmake_append_runtime_dirs(_runtime_dirs RSys Star3D)
+ include_directories(
+ ${RSys_INCLUDE_DIR}
+ ${Star3D_INCLUDE_DIR})
+
+ rcmake_append_runtime_dirs(_runtime_dirs RSys Star3D)
else()
-rcmake_append_runtime_dirs(_runtime_dirs RSys StarSP Star3DUT Star3D)
+ include_directories(
+ ${RSys_INCLUDE_DIR}
+ ${Star3D_INCLUDE_DIR}
+ ${Star3DUT_INCLUDE_DIR}
+ ${StarSP_INCLUDE_DIR})
+
+ if(HUGE_ADDITIONAL_TESTS)
+ rcmake_append_runtime_dirs(_runtime_dirs RSys StarSP Star3DUT Star3D)
+ endif()
endif()
-################################################################################
+###############################################################################
# Configure and define targets
-################################################################################
+###############################################################################
set(VERSION_MAJOR 0)
set(VERSION_MINOR 4)
set(VERSION_PATCH 2)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-set(SENC_FILES_SRC
- senc_descriptor.c
- senc_device.c
- senc_enclosure.c
- senc_scene.c
- senc_scene_analyze.c)
-
-set(SENC_FILES_INC_API
- senc.h
- senc_s3d_wrapper.h)
-
-set(SENC_FILES_INC
- senc_descriptor_c.h
- senc_device_c.h
- senc_enclosure_c.h
- senc_enclosure_data.h
- senc_internal_types.h
- senc_scene_c.h
- senc_scene_analyze_c.h)
-
-set(SENC_FILES_DOC COPYING README.md)
-
-# Prepend each file by `SENC_SOURCE_DIR'
-rcmake_prepend_path(SENC_FILES_SRC ${SENC_SOURCE_DIR})
-rcmake_prepend_path(SENC_FILES_INC ${SENC_SOURCE_DIR})
-rcmake_prepend_path(SENC_FILES_INC_API ${SENC_SOURCE_DIR})
-rcmake_prepend_path(SENC_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
-
-add_library(senc SHARED
- ${SENC_FILES_SRC}
- ${SENC_FILES_INC}
- ${SENC_FILES_INC_API})
-target_link_libraries(senc RSys Star3D)
-
-set_target_properties(senc PROPERTIES
- DEFINE_SYMBOL SENC_SHARED_BUILD
+set(SENC3D_FILES_SRC
+ senc3d_descriptor.c
+ senc3d_device.c
+ senc3d_enclosure.c
+ senc3d_scene.c
+ senc3d_scene_analyze.c)
+
+set(SENC3D_FILES_INC_API
+ senc3d.h
+ senc3d_sXd_helper.h
+ sencX3d.h
+ sencX3d_undefs.h)
+
+set(SENC3D_FILES_INC
+ senc3d_device_c.h
+ senc3d_enclosure_c.h
+ senc3d_enclosure_data.h
+ senc3d_internal_types.h
+ senc3d_scene_c.h
+ senc3d_scene_analyze_c.h
+ senc3d_side_range.h)
+
+set(SENC3D_FILES_DOC COPYING README.md)
+
+# Prepend each file by `SENC3D_SOURCE_DIR'
+rcmake_prepend_path(SENC3D_FILES_SRC ${SENC3D_SOURCE_DIR})
+rcmake_prepend_path(SENC3D_FILES_INC ${SENC3D_SOURCE_DIR})
+rcmake_prepend_path(SENC3D_FILES_INC_API ${SENC3D_SOURCE_DIR})
+rcmake_prepend_path(SENC3D_FILES_DOC ${PROJECT_SOURCE_DIR}/../)
+
+if(CMAKE_COMPILER_IS_GNUCC)
+ set(MATH_LIB m)
+endif()
+
+add_library(senc3d SHARED
+ ${SENC3D_FILES_SRC}
+ ${SENC3D_FILES_INC}
+ ${SENC3D_FILES_INC_API})
+target_link_libraries(senc3d RSys Star3D ${MATH_LIB})
+
+set_target_properties(senc3d PROPERTIES
+# C99 needed in case of printf %zu used
+# C_STANDARD 99
+ DEFINE_SYMBOL SENC3D_SHARED_BUILD
VERSION ${VERSION}
COMPILE_FLAGS ${OpenMP_C_FLAGS}
SOVERSION ${VERSION_MAJOR})
-rcmake_copy_runtime_libraries(senc)
+rcmake_copy_runtime_libraries(senc3d)
if(CMAKE_COMPILER_IS_GNUCC)
- set_target_properties(senc PROPERTIES LINK_FLAGS "${OpenMP_C_FLAGS}")
- target_link_libraries(senc m)
+ set_target_properties(senc3d PROPERTIES LINK_FLAGS "${OpenMP_C_FLAGS}")
+ target_link_libraries(senc3d m)
endif()
-rcmake_setup_devel(senc StarEnc ${VERSION} star/senc_version.h)
+rcmake_setup_devel(senc3d StarEnc3D ${VERSION} star/senc3d_version.h)
-################################################################################
+###############################################################################
# Add tests
-################################################################################
+###############################################################################
if(NOT NO_TEST)
function(build_test _name)
add_executable(${_name}
- ${SENC_SOURCE_DIR}/test_senc_utils.h
- ${SENC_SOURCE_DIR}/${_name}.c)
- target_link_libraries(${_name} RSys senc)
+ ${SENC3D_SOURCE_DIR}/test_senc3d_utils.h
+ ${SENC3D_SOURCE_DIR}/${_name}.c)
+ foreach(other ${ARGN})
+ target_sources(${_name}
+ PUBLIC ${SENC3D_SOURCE_DIR}/${other})
+ endforeach()
+ target_link_libraries(${_name} RSys senc3d)
endfunction()
function(register_test _name)
@@ -116,38 +149,45 @@ if(NOT NO_TEST)
endfunction()
function(new_test _name)
- build_test(${_name})
+ build_test(${_name} ${ARGN})
register_test(${_name} ${_name})
endfunction()
- new_test(test_senc_add_n_merge)
- new_test(test_senc_cube_behind_cube)
- new_test(test_senc_cube_in_cube)
- new_test(test_senc_cube_on_cube)
- new_test(test_senc_descriptor)
- new_test(test_senc_device)
- new_test(test_senc_enclosure)
- new_test(test_senc_inconsistant_cube)
- new_test(test_senc_many_enclosures)
- new_test(test_senc_many_triangles)
- new_test(test_senc_sample_enclosure)
- new_test(test_senc_scene)
- new_test(test_senc_undefined_medium)
- new_test(test_senc_undefined_medium_attr)
+ new_test(test_senc3d_cube_behind_cube)
+ new_test(test_senc3d_cube_in_cube)
+ new_test(test_senc3d_cube_on_cube)
+ new_test(test_senc3d_device)
+ new_test(test_senc3d_enclosure)
+ new_test(test_senc3d_inconsistant_cube)
+ new_test(test_senc3d_sample_enclosure)
+ new_test(test_senc3d_scene)
+ new_test(test_senc3d_some_enclosures)
+ new_test(test_senc3d_some_triangles)
+ new_test(test_senc3d_unspecified_medium)
+
+ target_link_libraries(test_senc3d_enclosure Star3D)
+ target_link_libraries(test_senc3d_sample_enclosure StarSP Star3D)
+
+ rcmake_copy_runtime_libraries(test_senc3d_sample_enclosure)
+
+ if(HUGE_ADDITIONAL_TESTS)
+ new_test(test_senc3d_many_enclosures test_senc3d_utils2.h)
+ new_test(test_senc3d_many_triangles test_senc3d_utils2.h)
+
+ target_link_libraries(test_senc3d_many_enclosures Star3DUT)
+ target_link_libraries(test_senc3d_many_triangles Star3DUT)
- target_link_libraries(test_senc_sample_enclosure StarSP)
- target_link_libraries(test_senc_many_enclosures Star3DUT)
- target_link_libraries(test_senc_many_triangles Star3DUT)
- rcmake_copy_runtime_libraries(test_senc_sample_enclosure)
- rcmake_copy_runtime_libraries(test_senc_many_triangles)
+ rcmake_copy_runtime_libraries(test_senc3d_many_enclosures)
+ rcmake_copy_runtime_libraries(test_senc3d_many_triangles)
+ endif()
endif()
-################################################################################
+###############################################################################
# Define output & install directories
-################################################################################
-install(TARGETS senc
+###############################################################################
+install(TARGETS senc3d
ARCHIVE DESTINATION bin
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
-install(FILES ${SENC_FILES_INC_API} DESTINATION include/star)
-install(FILES ${SENC_FILES_DOC} DESTINATION share/doc/star-enc)
+install(FILES ${SENC3D_FILES_INC_API} DESTINATION include/star)
+install(FILES ${SENC3D_FILES_DOC} DESTINATION share/doc/star-enclosures-3d)
diff --git a/src/senc.h b/src/senc.h
@@ -1,487 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 SENC_H
-#define SENC_H
-
-#include <rsys/rsys.h>
-
-#include <limits.h>
-
-/* Library symbol management */
-#if defined(SENC_SHARED_BUILD)
- #define SENC_API extern EXPORT_SYM
-#elif defined(SENC_STATIC_BUILD)
- #define SENC_API extern LOCAL_SYM
-#else /* Use shared library */
- #define SENC_API extern IMPORT_SYM
-#endif
-
-/* Helper macro that asserts if the invocation of the StarEnc function `Func'
- * returns an error. One should use this macro on StarEnc function calls for
- * which no explicit error checking is performed. */
-#ifndef NDEBUG
- #define SENC(Func) ASSERT(senc_ ## Func == RES_OK)
-#else
- #define SENC(Func) senc_ ## Func
-#endif
-
-/* Syntactic sugar used to inform the library that it can use as many threads
- * as CPU cores */
-#define SENC_NTHREADS_DEFAULT (~0u)
-
-/* A constant to specify an undefined medium */
-#define SENC_UNDEFINED_MEDIUM UINT_MAX
-
-/* Forward declaration of external opaque data types */
-struct logger;
-struct mem_allocator;
-
-/* Forward declaration of StarEnclosures opaque data types. These data types
- * are ref counted. Once created with the appropriated `senc_<TYPE>_create'
- * function, the caller implicitly owns the created data, i.e. its reference
- * counter is set to 1. The senc_<TYPE>_ref_<get|put> functions get or release
- * a reference on the data, i.e. they increment or decrement the reference
- * counter, respectively. When this counter reaches 0, the object is silently
- * destroyed and cannot be used anymore. */
-struct senc_descriptor;
-struct senc_device;
-struct senc_scene;
-struct senc_enclosure;
-
-/* A type to discriminate triangle sides */
-enum senc_side {
- SENC_FRONT,
- SENC_BACK
-};
-
-/* Enclosure header type */
-struct senc_enclosure_header {
- /* The ID of the enclosure; 0, 1, ... */
- unsigned enclosure_id;
- /* Number of triangles; a triangle can be accounted for twice, once by side */
- unsigned triangle_count;
- /* Number of triangles; a triangle cannot be accounted for twice */
- unsigned unique_triangle_count;
- /* Number of vertices */
- unsigned vertices_count;
- /* The number of media inside the enclosure,
- * SENC_UNDEFINED_MEDIUM included */
- unsigned enclosed_media_count;
- /* Is the enclosure open/infinite?
- * Only the outermost enclosure is infinite. */
- char is_infinite;
-};
-
-/* We consider the geometrical normal Ng to a triangle V0 V1 V2
- * that verifies "(V0, V0V1, V0V2, Ng) is a direct system"
- * (right-handed system).
- *
- * The user can set the convention used to determine which side of
- * a triangle is to be considered front/back by using the flags :
- * SENC_CONVENTION_NORMAL_FRONT => Ng points toward the front side,
- * SENC_CONVENTION_NORMAL_BACK => Ng points toward the back side.
- *
- * Additionaly the user can set the convention used to output enclosures
- * so that Ng points toward the enclosure or on the opposite direction
- * (for a closed enclosure Ng points toward the inside or toward the outside)
- * by using the flags :
- * SENC_CONVENTION_NORMAL_INSIDE => Ng points toward the enclosure,
- * SENC_CONVENTION_NORMAL_OUTSIDE => Ng points to the opposite of the enclosure.
- *
- * Note that normals in output data can be opposite to normals in input data
- * (vertices are then given in reverse order).
- *
- * Also note that both sides of a triangle can be part of the same enclosure;
- * in this case the 2 sides will be given with opposite Ng (meaning they
- * will be given with opposite vertices order).
- */
-enum senc_convention {
- /*
- * Convention regarding FRONT/BACK sides in input data
- */
-
- /* Geometrical normals point toward the front side */
- SENC_CONVENTION_NORMAL_FRONT = BIT(0),
- /* Geometrical normals point toward the back side */
- SENC_CONVENTION_NORMAL_BACK = BIT(1),
-
- /*
- * Convention regarding geometrical normals in output data
- */
-
- /* Geometrical normals point toward the enclosure */
- SENC_CONVENTION_NORMAL_INSIDE = BIT(2),
- /* Geometrical normals point to the opposite of the enclosure */
- SENC_CONVENTION_NORMAL_OUTSIDE = BIT(3)
-};
-
-BEGIN_DECLS
-
-/*******************************************************************************
- * StarEnclosures device. It is an handle toward the StarEnc library.
- * It manages the lib resources.
- * If provided, the allocator has to be suitable for parallel high frequency
- * allocations. As a consequence, a rsys proxy allocator should be avoided.
- ******************************************************************************/
-SENC_API res_T
-senc_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,
- const int verbose,
- struct senc_device** device);
-
-SENC_API res_T
-senc_device_ref_get
- (struct senc_device* device);
-
-SENC_API res_T
-senc_device_ref_put
- (struct senc_device* device);
-
-/*******************************************************************************
- * StarEnclosures scene. A scene is a collection of triangles. Each triangle is
- * defined with a medium on each side.
- ******************************************************************************/
-/* Creates an empty scene */
-SENC_API res_T
-senc_scene_create
- (struct senc_device* device,
- const int convention,
- struct senc_scene** scene);
-
-/* Reserve memory according to anticipated scene size. */
-SENC_API res_T
-senc_scene_reserve
- (struct senc_scene* scene,
- const unsigned vertices_count,
- const unsigned triangles_count,
- const unsigned media_count);
-
-/* Add a new set of vertices and triangles to the scene.
- * Vertices can be duplicates and are silently deduplicated on the fly.
- * Triangles can be duplicates as long as media are compatible on both sides.
- * Valid triangle duplicates are silently deduplicated, invalid duplicates
- * trigger an error (add_geometry returns RES_BAD_ARG).
- * The special value SENC_UNDEFINED_MEDIUM denotes an undefined medium.
- * It can be used to define the 2 sides of a triangle at different times.
- * Media on duplicate triangles are consider compatible if:
- * - the merge_triangle callback is provided and returns RES_OK,
- * - or media are identical or SENC_UNDEFINED_MEDIUM.
- * When deduplicating triangles, the first occurence remains (with its
- * original index in user world, regardless of deduplication); the only
- * situation where deduplication changes a previously recorded media is from
- * SENC_UNDEFINED_MEDIUM to any defined medium.
- * The add_triangle and merge_triangle callbacks can be used for attribute
- * management (including triangle IDs) and to record media incompatibilities
- * for a subsequent report; they allow the client app to store its own data.
- * By returning an error, they can also stop the add_geometry call. */
-SENC_API res_T
-senc_scene_add_geometry
- (struct senc_scene* scene,
- /* Number of added triangles */
- const unsigned triangles_count,
- /* User function that provides vertices ids for added triangles */
- void(*indices)(const unsigned itri, unsigned ids[3], void* context),
- /* User function that provides media ids for added triangles */
- void(*media) /* Can be NULL <=> SENC_UNDEFINED_MEDIUM medium used */
- (const unsigned itri, unsigned med[2], void* context),
- /* Number of added vertices */
- const unsigned vertices_count,
- /* User function that provides coordinates for added vertices */
- void(*position)(const unsigned ivert, double pos[3], void* context),
- /* Called for each new triangle so that the client app can manage its own
- * triangle data/properties/attributes.
- * If return is not RES_OK, add_geometry stops immediately and returns
- * whatever value add_triangle returned. */
- res_T(*add_triangle) /* Can be NULL */
- (const unsigned global_id, const unsigned itri, void* context),
- /* Called if the IVERTth triangle of the current add_geometry is equal to
- * the global_id_th global triangle so that the client app can try to merge
- * its own triangle data or record a possible media conflict.
- * The reversed_triangle arg indicates if the triangle vertices' order is
- * the same it was when the triangle was first added.
- * triangle_media and merge_media contain the involved media.
- * If those media are incompatible and merge_triangle returns RES_OK the
- * process will continue with the next triangle and possibly end in success.
- * If return is not RES_OK, add_geometry stops immediately and returns
- * whatever value merge_triangle returned.
- * If merge_triangle is NULL, a strict media compatibility is required for
- * add_geometry to success: add_geometry would stop and return RES_BAD_ARG
- * on the first occurence of duplicate triangle with incompatible media. */
- res_T(*merge_triangle) /* Can be NULL */
- (const unsigned global_id, const unsigned itri, const int reversed_triangle,
- const unsigned triangle_media[2], const unsigned merge_media[2],
- void* context),
- void* context);
-
-/* Returns a descriptor of the scene that holds the analysis' result. */
-SENC_API res_T
-senc_scene_analyze
- (struct senc_scene* scene,
- struct senc_descriptor** descriptor);
-
-/* Returns the convention flags in use with the scene. */
-SENC_API res_T
-senc_scene_get_convention
- (const struct senc_scene* scene,
- int* convention);
-
-/* Returns the number of triangles in the scene. */
-SENC_API res_T
-senc_scene_get_triangles_count
- (const struct senc_scene* scene,
- unsigned* count);
-
-/* Returns the number of unique triangles in the scene (remaining
- * triangles after deduplication). */
-SENC_API res_T
-senc_scene_get_unique_triangles_count
- (const struct senc_scene* scene,
- unsigned* count);
-
-/* Returns the number of unique sides with SENC_UNDEFINED_MEDIUM medium. */
-SENC_API res_T
-senc_scene_get_unique_sides_without_medium_count
- (const struct senc_scene* scene,
- unsigned* count);
-
-/* Returns the itri_th unique triangle; the returned indices are
- * unique vertex indices.
- * Can be called anytime, before or after a call to analyze. */
-SENC_API res_T
-senc_scene_get_unique_triangle
- (const struct senc_scene* scene,
- const unsigned itri,
- unsigned indices[3]);
-
-/* Returns the itri_th unique triangle; the returned indices are
- * unique vertex indices.
- * Can be called anytime, before or after a call to analyze. */
-SENC_API res_T
-senc_scene_get_unique_triangle_media
- (const struct senc_scene* scene,
- const unsigned itri,
- unsigned media[2]);
-
-/* Returns the number of vertices in the scene. */
-SENC_API res_T
-senc_scene_get_vertices_count
- (const struct senc_scene* scene,
- unsigned* count);
-
-/* Returns the number of unique vertices in the scene (remaining
- * vertices after deduplication). */
-SENC_API res_T
-senc_scene_get_unique_vertices_count
- (const struct senc_scene* scene,
- unsigned* count);
-
-/* Returns the coordinates of the ivert_th unique vertex.
- * Can be called anytime, before or after a call to analyze. */
-SENC_API res_T
-senc_scene_get_unique_vertex
- (const struct senc_scene* scene,
- const unsigned ivert,
- double coord[3]);
-
-SENC_API res_T
-senc_scene_ref_get
- (struct senc_scene* scene);
-
-SENC_API res_T
-senc_scene_ref_put
- (struct senc_scene* scene);
-
-/*******************************************************************************
- * StarEnclosures descriptor. It is an handle toward an analyze result.
- ******************************************************************************/
-/* Returns the greater medium id found in added geometry. In API calls using a
- * medium, any value in the [0 max_medium_id[ range is valid. However there can
- * be unused ids (no geometry refered to this medium id). */
-SENC_API res_T
-senc_descriptor_get_max_medium
- (const struct senc_descriptor* descriptor,
- unsigned* max_medium_id);
-
-/* Returns the number of enclosures. */
-SENC_API res_T
-senc_descriptor_get_enclosure_count
- (const struct senc_descriptor* descriptor,
- unsigned* count);
-
-/* Returns the number of enclosures that have some geometry refering to the
- * imed_th medium. */
-SENC_API res_T
-senc_descriptor_get_enclosure_count_by_medium
- (const struct senc_descriptor* descriptor,
- const unsigned imed,
- unsigned* count);
-
-/* Returns the idx_th enclosure. */
-SENC_API res_T
-senc_descriptor_get_enclosure
- (struct senc_descriptor* descriptor,
- const unsigned idx,
- struct senc_enclosure** enclosure);
-
-/* Returns the idx_th enclosure using the imed_th medium. */
-SENC_API res_T
-senc_descriptor_get_enclosure_by_medium
- (struct senc_descriptor* descriptor,
- const unsigned imed,
- const unsigned idx,
- struct senc_enclosure** enclosure);
-
-/* Returns the number of unique triangles (no duplicates here) in the whole
- * geometry. */
-SENC_API res_T
-senc_descriptor_get_global_triangles_count
- (const struct senc_descriptor* descriptor,
- unsigned* count);
-
-/* Returns the number of unique vertices (no duplicates here) in the whole
- * geometry. */
-SENC_API res_T
-senc_descriptor_get_global_vertices_count
- (const struct senc_descriptor* descriptor,
- unsigned* count); /* Number of unique vertices. */
-
-/* Returns the itri_th global unique triangles; the returned indices are global
- * unique vertex indices. */
-SENC_API res_T
-senc_descriptor_get_global_triangle
- (const struct senc_descriptor* descriptor,
- const unsigned itri,
- unsigned indices[3]);
-
-/* Returns the coordinates of the ivert_th global unique vertex. */
-SENC_API res_T
-senc_descriptor_get_global_vertex
- (const struct senc_descriptor* descriptor,
- const unsigned ivert,
- double coord[3]);
-
-/* Returns the front and back media ids of the itri_th global unique
- * triangles. */
-SENC_API res_T
-senc_descriptor_get_global_triangle_media
- (const struct senc_descriptor* descriptor,
- const unsigned itri,
- unsigned media[2]);
-
-/* Returns the enclosures the itri_th global unique triangles front and back
- * sides are member of. */
-SENC_API res_T
-senc_descriptor_get_global_triangle_enclosures
- (const struct senc_descriptor* descriptor,
- const unsigned itri,
- unsigned enclosures[2]);
-
-/* Returns the global id of the itri_th global unique triangle, that is the
- * triangle index in user world regardless of deduplication. */
-SENC_API res_T
-senc_descriptor_get_global_triangle_global_id
- (const struct senc_descriptor* descriptor,
- const unsigned itri,
- unsigned* gid);
-
-/* Returns the number of segments that are frontier segments:
- * - that have arity 1 (single triangle using the segment)
- * - that connect 2 different media */
-SENC_API res_T
-senc_descriptor_get_frontier_segments_count
- (const struct senc_descriptor* descriptor,
- unsigned* count);
-
-/* Returns the iseg_th frontier segment; the returned indices are global unique
- * vertex indices. */
-SENC_API res_T
-senc_descriptor_get_frontier_segment
- (const struct senc_descriptor* descriptor,
- const unsigned iseg,
- unsigned vrtx_id[2]);
-
-SENC_API res_T
-senc_descriptor_ref_get
- (struct senc_descriptor* descriptor);
-
-SENC_API res_T
-senc_descriptor_ref_put
- (struct senc_descriptor* descriptor);
-
-/*******************************************************************************
- * StarEnclosures enclosure. It is an handle toward an enclosure.
- * Counts and other information on enclosures are not individually accessible,
- * but as a whole through header access.
- * An enclosure can list the "same" triangle twice if both sides are in. In this
- * case the 2 occurences of the triangle have reversed vertices order and
- * unique_triangle_count and triangle_count differ.
- * Vertices and triangles numbering schemes are specific to each enclosure:
- * the "same" item appearing in 2 different enclosures has no reason to get the
- * same index twice or to have the same index in the global numbering scheme.
- * By-index API accesses of triangles (or properties) visit unique triangles
- * for indices in the [0 unique_triangle_count[ range and back-faces of the
- * doubly-included triangles in the [unique_triangle_count triangle_count[ range.
- ******************************************************************************/
-/* Returns the header of an enclosure. */
-SENC_API res_T
-senc_enclosure_get_header
- (const struct senc_enclosure* enclosure,
- struct senc_enclosure_header* header);
-
-/* Returns the itri_th triangle of an enclosure.
- * Indices are local to the enclosure. */
-SENC_API res_T
-senc_enclosure_get_triangle
- (const struct senc_enclosure* enclosure,
- const unsigned itri,
- unsigned indices[3]);
-
-/* Returns the coordinates of the ivert_th vertex of an enclosure. */
-SENC_API res_T
-senc_enclosure_get_vertex
- (const struct senc_enclosure* enclosure,
- const unsigned ivert,
- double coord[3]);
-
-/* Returns the global id of the itri_th triangle of an enclosure
- * and the involved side. */
-SENC_API res_T
-senc_enclosure_get_triangle_global_id
- (const struct senc_enclosure* enclosure,
- const unsigned itri,
- unsigned* gid,
- enum senc_side* side);
-
-/* Returns the id of the imed_th medium of an enclosure. */
-SENC_API res_T
-senc_enclosure_get_medium
- (const struct senc_enclosure* enclosure,
- const unsigned imed,
- unsigned* medium);
-
-SENC_API res_T
-senc_enclosure_ref_get
- (struct senc_enclosure* enclosure);
-
-SENC_API res_T
-senc_enclosure_ref_put
- (struct senc_enclosure* enclosure);
-
-END_DECLS
-
-#endif /* SENC_H */
diff --git a/src/senc3d.h b/src/senc3d.h
@@ -0,0 +1,365 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC3D_H
+#define SENC3D_H
+
+#include <rsys/rsys.h>
+
+#include <limits.h>
+
+/* Library symbol management */
+#if defined(SENC3D_SHARED_BUILD)
+ #define SENC3D_API extern EXPORT_SYM
+#elif defined(SENC3D_STATIC_BUILD)
+ #define SENC3D_API extern LOCAL_SYM
+#else /* Use shared library */
+ #define SENC3D_API extern IMPORT_SYM
+#endif
+
+/* Helper macro that asserts if the invocation of the StarEnc function `Func'
+ * returns an error. One should use this macro on StarEnc function calls for
+ * which no explicit error checking is performed. */
+#ifndef NDEBUG
+ #define SENC3D(Func) ASSERT(senc3d_ ## Func == RES_OK)
+#else
+ #define SENC3D(Func) senc3d_ ## Func
+#endif
+
+/* Syntactic sugar used to inform the library that it can use as many threads
+ * as CPU cores */
+#define SENC3D_NTHREADS_DEFAULT (~0u)
+
+/* A constant to denote an unspecified medium */
+#define SENC3D_UNSPECIFIED_MEDIUM UINT_MAX
+
+/* Forward declaration of external opaque data types */
+struct logger;
+struct mem_allocator;
+
+/* Forward declaration of star_enclosures-3d opaque data types. These data
+ * types are ref counted. Once created with the appropriated
+ * `senc3d__<TYPE>_create' function, the caller implicitly owns the created
+ * data, i.e. its reference counter is set to 1.
+ * The senc3d__<TYPE>_ref_<get|put> functions get or release a reference on the
+ * data, i.e. they increment or decrement the reference counter, respectively.
+ * When this counter reaches 0, the object is silently destroyed and cannot be
+ * used anymore. */
+struct senc3d_device;
+struct senc3d_scene;
+struct senc3d_enclosure;
+
+/******************************************************************************
+ * The dimension of the geometry used in the library.
+ *****************************************************************************/
+#define SENC3D_GEOMETRY_DIMENSION 3
+
+/* A type to discriminate triangle sides */
+enum senc3d_side {
+ SENC3D_FRONT,
+ SENC3D_BACK
+};
+
+/* Enclosure header type */
+struct senc3d_enclosure_header {
+ /* The ID of the enclosure; 0, 1, ... */
+ unsigned enclosure_id;
+ /* Number of triangles; a triangle can be accounted for twice, once by side*/
+ unsigned primitives_count;
+ /* Number of unique triangles; a triangle cannot be accounted for twice */
+ unsigned unique_primitives_count;
+ /* Number of vertices */
+ unsigned vertices_count;
+ /* The number of media inside the enclosure,
+ * SENC3D_UNSPECIFIED_MEDIUM included */
+ unsigned enclosed_media_count;
+ /* Is the enclosure open/infinite?
+ * Only the outermost enclosure is infinite. */
+ int is_infinite;
+};
+
+/* We consider the geometrical normal Ng to a triangle V0 V1 V2
+ * that verifies "(V0, V0V1, V0V2, Ng) is a direct system"
+ * (right-handed system).
+ *
+ * The user can set the convention used to determine which side of
+ * a triangle is to be considered front/back by using the flags :
+ * SENC3D_CONVENTION_NORMAL_FRONT => Ng points toward the front side,
+ * SENC3D_CONVENTION_NORMAL_BACK => Ng points toward the back side.
+ *
+ * Additionaly the user can set the convention used to output enclosures
+ * so that Ng points toward the enclosure or on the opposite direction
+ * (for a closed enclosure Ng points toward the inside or toward the outside)
+ * by using the flags :
+ * SENC3D_CONVENTION_NORMAL_INSIDE => Ng points toward the enclosure,
+ * SENC3D_CONVENTION_NORMAL_OUTSIDE => Ng points toward the opposite of the
+ * enclosure.
+ *
+ * Note that normals in output data can be opposite to normals in input data
+ * (vertices are then given in reverse order).
+ *
+ * Also note that both sides of a triangle can be part of the same enclosure;
+ * in this case the 2 sides will be given with opposite Ng (meaning they
+ * will be given with opposite vertices order).
+ */
+enum senc3d_convention {
+ /*
+ * Convention regarding FRONT/BACK sides in input data
+ */
+
+ /* Geometrical normals point toward the front side */
+ SENC3D_CONVENTION_NORMAL_FRONT = BIT(0),
+ /* Geometrical normals point toward the back side */
+ SENC3D_CONVENTION_NORMAL_BACK = BIT(1),
+
+ /*
+ * Convention regarding geometrical normals in output data
+ */
+
+ /* Geometrical normals point toward the enclosure */
+ SENC3D_CONVENTION_NORMAL_INSIDE = BIT(2),
+ /* Geometrical normals point to the opposite of the enclosure */
+ SENC3D_CONVENTION_NORMAL_OUTSIDE = BIT(3)
+};
+
+BEGIN_DECLS
+
+/******************************************************************************
+ * star_enclosures-3d device. It is an handle toward the StarEnc library.
+ * It manages the lib resources.
+ * If provided, the allocator has to be suitable for parallel high frequency
+ * allocations. As a consequence, a rsys proxy allocator should be avoided.
+ *****************************************************************************/
+SENC3D_API res_T
+senc3d_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,
+ const int verbose,
+ struct senc3d_device** device);
+
+SENC3D_API res_T
+senc3d_device_ref_get
+ (struct senc3d_device* device);
+
+SENC3D_API res_T
+senc3d_device_ref_put
+ (struct senc3d_device* device);
+
+/******************************************************************************
+ * star_enclosures-3d scene. A scene is a collection of triangles. Each
+ * triangle is defined with a medium on each side.
+ *****************************************************************************/
+/* Creates a scene from some vertices and triangles.
+ * Neither vertices nor triangles can include duplicates.
+ * Triangles cannot be degenerated. */
+SENC3D_API res_T
+senc3d_scene_create
+ (struct senc3d_device* device,
+ const int convention,
+ /* Number of triangles */
+ const unsigned triangles_count,
+ /* User function that provides vertices ids for triangles */
+ void(*get_indices)(
+ const unsigned itri,
+ unsigned ids[SENC3D_GEOMETRY_DIMENSION],
+ void* context),
+ /* User function that provides media ids for triangles */
+ void(*get_media) /* Can be NULL <=> SENC3D_UNSPECIFIED_MEDIUM medium used */
+ (const unsigned itri, unsigned med[2], void* context),
+ /* Number of vertices */
+ const unsigned vertices_count,
+ /* User function that provides coordinates for vertices */
+ void(*get_position)(
+ const unsigned ivert,
+ double pos[SENC3D_GEOMETRY_DIMENSION],
+ void* context),
+ /* Context provided to user callbacks; can be NULL */
+ void* context,
+ /* The created scene */
+ struct senc3d_scene** scene);
+
+/* Returns the convention flags in use with the scene. */
+SENC3D_API res_T
+senc3d_scene_get_convention
+ (const struct senc3d_scene* scene,
+ int* convention);
+
+/* Returns the number of triangles in the scene. */
+SENC3D_API res_T
+senc3d_scene_get_triangles_count
+ (const struct senc3d_scene* scene,
+ unsigned* count);
+
+/* Returns the itri_th triangle vertices' indices. */
+SENC3D_API res_T
+senc3d_scene_get_triangle
+ (const struct senc3d_scene* scene,
+ const unsigned itri,
+ unsigned indices[SENC3D_GEOMETRY_DIMENSION]);
+
+/* Returns the media for the itri_th triangle. */
+SENC3D_API res_T
+senc3d_scene_get_triangle_media
+ (const struct senc3d_scene* scene,
+ const unsigned itri,
+ unsigned media[2]);
+
+/* Returns the number of vertices in the scene. */
+SENC3D_API res_T
+senc3d_scene_get_vertices_count
+ (const struct senc3d_scene* scene,
+ unsigned* count);
+
+/* Returns the coordinates of the ivert_th vertex. */
+SENC3D_API res_T
+senc3d_scene_get_vertex
+ (const struct senc3d_scene* scene,
+ const unsigned ivert,
+ double coord[SENC3D_GEOMETRY_DIMENSION]);
+
+/* Returns the greater medium id found in added geometry. In API calls using a
+ * medium, any value in the [0 max_medium_id[ range is valid. However there can
+ * be unused ids (no geometry refered to this medium id). */
+SENC3D_API res_T
+senc3d_scene_get_max_medium
+ (const struct senc3d_scene* scene,
+ unsigned* max_medium_id);
+
+/* Returns the number of enclosures. */
+SENC3D_API res_T
+senc3d_scene_get_enclosure_count
+ (const struct senc3d_scene* scene,
+ unsigned* count);
+
+/* Returns the number of enclosures that have some geometry refering to the
+ * imed_th medium or SENC3D_UNSPECIFIED_MEDIUM. */
+SENC3D_API res_T
+senc3d_scene_get_enclosure_count_by_medium
+ (const struct senc3d_scene* scene,
+ const unsigned imed,
+ unsigned* count);
+
+/* Returns the idx_th enclosure. */
+SENC3D_API res_T
+senc3d_scene_get_enclosure
+ (struct senc3d_scene* scene,
+ const unsigned idx,
+ struct senc3d_enclosure** enclosure);
+
+/* Returns the idx_th enclosure using the imed_th medium or
+ * SENC3D_UNSPECIFIED_MEDIUM. */
+SENC3D_API res_T
+senc3d_scene_get_enclosure_by_medium
+ (struct senc3d_scene* scene,
+ const unsigned imed,
+ const unsigned idx,
+ struct senc3d_enclosure** enclosure);
+
+/* Returns the enclosures the itri_th triangle front and back sides are member
+ * of. */
+SENC3D_API res_T
+senc3d_scene_get_triangle_enclosures
+ (const struct senc3d_scene* scene,
+ const unsigned itri,
+ unsigned enclosures[2]);
+
+/* Returns the number of segments that are frontier segments:
+ * - that have arity 1 (single triangle using the segment)
+ * - that connect 2 different media */
+SENC3D_API res_T
+senc3d_scene_get_frontier_segments_count
+ (const struct senc3d_scene* scene,
+ unsigned* count);
+
+/* Returns the iseg_th frontier segment (triangle and vertices global IDs). */
+SENC3D_API res_T
+senc3d_scene_get_frontier_segment
+ (const struct senc3d_scene* scene,
+ const unsigned iseg,
+ unsigned vrtx_id[SENC3D_GEOMETRY_DIMENSION-1],
+ unsigned* trg_id);
+
+SENC3D_API res_T
+senc3d_scene_ref_get
+ (struct senc3d_scene* scene);
+
+SENC3D_API res_T
+senc3d_scene_ref_put
+ (struct senc3d_scene* scene);
+
+/******************************************************************************
+ * star_enclosures-3d enclosure. It is an handle toward an enclosure.
+ * Counts and other information on enclosures are not individually accessible,
+ * but as a whole through header access.
+ * An enclosure can list the "same" triangle twice if both sides are in. In
+ * this case the 2 occurences of the triangle have reversed vertices order and
+ * unique_triangle_count and triangle_count differ.
+ * Vertices and triangles numbering schemes are specific to each enclosure:
+ * the "same" item appearing in 2 different enclosures has no reason to get the
+ * same index twice or to have the same index in the global numbering scheme.
+ * By-index API accesses of triangles (or properties) visit unique triangles
+ * for indices in the [0 unique_triangle_count[ range and back-faces of the
+ * doubly-included triangles in the [unique_triangle_count triangle_count[
+ * range.
+ *****************************************************************************/
+/* Returns the header of an enclosure. */
+SENC3D_API res_T
+senc3d_enclosure_get_header
+ (const struct senc3d_enclosure* enclosure,
+ struct senc3d_enclosure_header* header);
+
+/* Returns the itri_th triangle of an enclosure.
+ * Indices are local to the enclosure. */
+SENC3D_API res_T
+senc3d_enclosure_get_triangle
+ (const struct senc3d_enclosure* enclosure,
+ const unsigned itri,
+ unsigned indices[SENC3D_GEOMETRY_DIMENSION]);
+
+/* Returns the coordinates of the ivert_th vertex of an enclosure. */
+SENC3D_API res_T
+senc3d_enclosure_get_vertex
+ (const struct senc3d_enclosure* enclosure,
+ const unsigned ivert,
+ double coord[SENC3D_GEOMETRY_DIMENSION]);
+
+/* Returns the global id of the itri_th triangle of an enclosure
+ * and the involved side. */
+SENC3D_API res_T
+senc3d_enclosure_get_triangle_id
+ (const struct senc3d_enclosure* enclosure,
+ const unsigned itri,
+ unsigned* gid,
+ enum senc3d_side* side);
+
+/* Returns the id of the imed_th medium of an enclosure. */
+SENC3D_API res_T
+senc3d_enclosure_get_medium
+ (const struct senc3d_enclosure* enclosure,
+ const unsigned imed,
+ unsigned* medium);
+
+SENC3D_API res_T
+senc3d_enclosure_ref_get
+ (struct senc3d_enclosure* enclosure);
+
+SENC3D_API res_T
+senc3d_enclosure_ref_put
+ (struct senc3d_enclosure* enclosure);
+
+END_DECLS
+
+#endif /* SENC3D_H */
diff --git a/src/senc3d_descriptor.c b/src/senc3d_descriptor.c
@@ -0,0 +1,157 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 "senc3d_enclosure_c.h"
+#include "senc3d_scene_c.h"
+#include "senc3d.h"
+
+#include <rsys/rsys.h>
+#include <rsys/double3.h>
+#include <rsys/mem_allocator.h>
+
+/******************************************************************************
+ * Exported functions
+ *****************************************************************************/
+res_T
+senc3d_scene_get_max_medium
+ (const struct senc3d_scene* scn, medium_id_t* max_medium_id)
+{
+ if(!scn || !max_medium_id) return RES_BAD_ARG;
+ *max_medium_id = scn->next_medium_idx - 1;
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_enclosure_count
+ (const struct senc3d_scene* scn, enclosure_id_t* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ ASSERT(scn->analyze.enclosures_count ==
+ darray_enclosure_size_get(&scn->analyze.enclosures));
+ *count = scn->analyze.enclosures_count;
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_enclosure_count_by_medium
+ (const struct senc3d_scene* scn,
+ const medium_id_t imed,
+ enclosure_id_t* count)
+{
+ size_t tmp;
+ size_t m_idx;
+ const struct darray_enc_id* enc_ids;
+ if(!scn || !count
+ || (imed != SENC3D_UNSPECIFIED_MEDIUM && imed >= scn->next_medium_idx))
+ return RES_BAD_ARG;
+ ASSERT(darray_enc_ids_array_size_get(&scn->analyze.enc_ids_array_by_medium)
+ == 1 + scn->next_medium_idx);
+ m_idx = medium_id_2_medium_idx(imed);
+ enc_ids = darray_enc_ids_array_cdata_get(&scn->analyze.enc_ids_array_by_medium)
+ + m_idx;
+ tmp = darray_enc_id_size_get(enc_ids);
+ ASSERT(tmp <= ENCLOSURE_MAX__); /* API type */
+ *count = (enclosure_id_t)tmp;
+ return RES_OK;
+}
+
+FINLINE res_T
+senc3d_scene_get_enclosure
+ (struct senc3d_scene* scn,
+ const enclosure_id_t idx,
+ struct senc3d_enclosure** out_enc)
+{
+ struct senc3d_enclosure* enc;
+ if(!scn || idx >= darray_enclosure_size_get(&scn->analyze.enclosures)
+ || !out_enc)
+ return RES_BAD_ARG;
+ enc = enclosure_create(scn, idx);
+ if(!enc) return RES_MEM_ERR;
+ *out_enc = enc;
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_enclosure_by_medium
+ (struct senc3d_scene* scn,
+ const medium_id_t imed,
+ const enclosure_id_t idx,
+ struct senc3d_enclosure** out_enc)
+{
+ size_t m_idx;
+ const struct darray_enc_id* enc_ids;
+ enclosure_id_t index;
+ if(!scn || !out_enc
+ || (imed != SENC3D_UNSPECIFIED_MEDIUM && imed >= scn->next_medium_idx))
+ return RES_BAD_ARG;
+ ASSERT(darray_enc_ids_array_size_get(&scn->analyze.enc_ids_array_by_medium)
+ == 1 + scn->next_medium_idx);
+ m_idx = medium_id_2_medium_idx(imed);
+ enc_ids =
+ darray_enc_ids_array_cdata_get(&scn->analyze.enc_ids_array_by_medium) + m_idx;
+ if(idx >= darray_enc_id_size_get(enc_ids)) return RES_BAD_ARG;
+ index = darray_enc_id_cdata_get(enc_ids)[idx];
+ return senc3d_scene_get_enclosure(scn, index, out_enc);
+}
+
+res_T
+senc3d_scene_get_triangle_enclosures
+ (const struct senc3d_scene* scn,
+ const trg_id_t itri,
+ enclosure_id_t enclosures[2])
+{
+ const struct triangle_enc* trg;
+ int i;
+ if(!enclosures || !scn
+ || itri >= darray_triangle_enc_size_get(&scn->analyze.triangles_enc))
+ return RES_BAD_ARG;
+ trg = darray_triangle_enc_cdata_get(&scn->analyze.triangles_enc) + itri;
+ FOR_EACH(i, 0, 2) enclosures[i] = trg->enclosure[i];
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_frontier_segments_count
+ (const struct senc3d_scene* scn,
+ vrtx_id_t* count)
+{
+ size_t tmp;
+ if(!scn || !count)
+ return RES_BAD_ARG;
+ tmp = darray_frontier_edge_size_get(&scn->analyze.frontiers);
+ ASSERT(tmp <= VRTX_MAX__);
+ *count = (vrtx_id_t)tmp; /* Back to API type */
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_frontier_segment
+ (const struct senc3d_scene* scn,
+ const unsigned iseg, /* There is no defined type for segment IDs */
+ vrtx_id_t vrtx_id[2],
+ unsigned* trg_id)
+{
+ const struct frontier_edge* edge;
+ if(!vrtx_id || !scn || !trg_id
+ || iseg >= darray_frontier_edge_size_get(&scn->analyze.frontiers))
+ return RES_BAD_ARG;
+ edge = darray_frontier_edge_cdata_get(&scn->analyze.frontiers) + iseg;
+ ASSERT(edge->vrtx0 <= VRTX_MAX__);
+ ASSERT(edge->vrtx1 <= VRTX_MAX__);
+ vrtx_id[0] = edge->vrtx0;
+ vrtx_id[1] = edge->vrtx1;
+ *trg_id = edge->trg;
+ return RES_OK;
+}
diff --git a/src/senc3d_device.c b/src/senc3d_device.c
@@ -0,0 +1,148 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 "senc3d.h"
+#include "senc3d_device_c.h"
+
+#include <rsys/logger.h>
+#include <rsys/mem_allocator.h>
+
+#include <omp.h>
+
+/******************************************************************************
+ * Helper functions
+ *****************************************************************************/
+static void
+log_msg
+ (struct senc3d_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 senc3d_device* dev;
+ ASSERT(ref);
+ dev = CONTAINER_OF(ref, struct senc3d_device, ref);
+ MEM_RM(dev->allocator, dev);
+}
+
+/******************************************************************************
+ * Local functions
+ *****************************************************************************/
+void
+log_err(struct senc3d_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_warn(struct senc3d_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);
+}
+
+void
+log_info(struct senc3d_device* dev, const char* msg, ...)
+{
+ va_list vargs_list;
+ ASSERT(dev && msg);
+
+ va_start(vargs_list, msg);
+ log_msg(dev, LOG_OUTPUT, msg, vargs_list);
+ va_end(vargs_list);
+}
+
+/******************************************************************************
+ * Exported functions
+ *****************************************************************************/
+res_T
+senc3d_device_create
+ (struct logger* logger,
+ struct mem_allocator* mem_allocator,
+ const unsigned nthreads_hint,
+ const int verbose,
+ struct senc3d_device** out_dev)
+{
+ struct logger* log = NULL;
+ struct senc3d_device* dev = NULL;
+ struct mem_allocator* allocator = NULL;
+ res_T res = RES_OK;
+ if(nthreads_hint == 0 || !out_dev) return RES_BAD_ARG;
+
+ log = logger ? logger : LOGGER_DEFAULT;
+ allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ dev = MEM_CALLOC(allocator, 1, sizeof(struct senc3d_device));
+ if(!dev) {
+ if(verbose) {
+ /* Do not use helper log functions since dev is not initialised */
+ CHK(logger_print(log, LOG_ERROR,
+ "%s: could not allocate the star_enclosures-3d device.\n", FUNC_NAME) == RES_OK);
+ }
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ dev->logger = log;
+ dev->allocator = allocator;
+ dev->verbose = verbose;
+ /* Cannot use int args for MMIN here as default is -1 */
+ dev->nthreads = (int)MMIN(nthreads_hint, (unsigned)omp_get_num_procs());
+ ref_init(&dev->ref);
+
+exit:
+ if(dev) *out_dev = dev;
+ return res;
+error:
+ if(dev) {
+ SENC3D(device_ref_put(dev));
+ dev = NULL;
+ }
+ goto exit;
+}
+
+res_T
+senc3d_device_ref_get(struct senc3d_device* dev)
+{
+ if(!dev) return RES_BAD_ARG;
+ ref_get(&dev->ref);
+ return RES_OK;
+}
+
+res_T
+senc3d_device_ref_put(struct senc3d_device* dev)
+{
+ if(!dev) return RES_BAD_ARG;
+ ref_put(&dev->ref, device_release);
+ return RES_OK;
+}
diff --git a/src/senc3d_device_c.h b/src/senc3d_device_c.h
@@ -0,0 +1,71 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC3D_DEVICE_C_H
+#define SENC3D_DEVICE_C_H
+
+#include <rsys/free_list.h>
+#include <rsys/ref_count.h>
+
+struct name { FITEM; };
+#define FITEM_TYPE name
+#include <rsys/free_list.h>
+
+struct senc3d_device {
+ struct logger* logger;
+ struct mem_allocator* allocator;
+ int verbose;
+ int nthreads;
+
+ 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_err
+ (struct senc3d_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_warn
+ (struct senc3d_device* dev,
+ const char* msg,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 2, 3)))
+#endif
+;
+
+/* Conditionally log a message on the LOG_OUTPUT stream of the device logger,
+ * with respect to the device verbose flag */
+extern LOCAL_SYM void
+log_info
+ (struct senc3d_device* dev,
+ const char* msg,
+ ...)
+#ifdef COMPILER_GCC
+ __attribute((format(printf, 2, 3)))
+#endif
+ ;
+
+#endif /* SENC3D_DEVICE_C_H */
diff --git a/src/senc3d_enclosure.c b/src/senc3d_enclosure.c
@@ -0,0 +1,164 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 "senc3d_enclosure_c.h"
+#include "senc3d_enclosure_data.h"
+#include "senc3d_scene_c.h"
+#include "senc3d_device_c.h"
+#include "senc3d.h"
+
+#include <rsys/rsys.h>
+#include <rsys/double3.h>
+#include <rsys/mem_allocator.h>
+
+
+/******************************************************************************
+ * Helper function
+ *****************************************************************************/
+static void
+enclosure_release(ref_T * ref)
+{
+ struct senc3d_enclosure* enclosure = NULL;
+ struct senc3d_scene* scn = NULL;
+ ASSERT(ref);
+ enclosure = CONTAINER_OF(ref, struct senc3d_enclosure, ref);
+ scn = enclosure->scene;
+ MEM_RM(scn->dev->allocator, enclosure);
+ SENC3D(scene_ref_put(scn));
+}
+
+/******************************************************************************
+ * Local functions
+ *****************************************************************************/
+struct senc3d_enclosure*
+enclosure_create
+ (struct senc3d_scene* scn,
+ const enclosure_id_t idx)
+{
+ struct senc3d_enclosure* enc;
+ ASSERT(scn && idx < darray_enclosure_size_get(&scn->analyze.enclosures));
+ enc = MEM_CALLOC(scn->dev->allocator, 1, sizeof(struct senc3d_enclosure));
+ if(enc) {
+ const struct enclosure_data* data
+ = darray_enclosure_data_get(&scn->analyze.enclosures) + idx;
+ enc->scene = scn;
+ enc->data = data;
+ ref_init(&enc->ref);
+ SENC3D(scene_ref_get(scn));
+ }
+ return enc;
+}
+
+/******************************************************************************
+ * Exported functions
+ *****************************************************************************/
+res_T
+senc3d_enclosure_get_header
+ (const struct senc3d_enclosure* enclosure,
+ struct senc3d_enclosure_header* header)
+{
+ if(!enclosure || !header) return RES_BAD_ARG;
+ *header = enclosure->data->header;
+ return RES_OK;
+}
+
+res_T
+senc3d_enclosure_get_triangle
+ (const struct senc3d_enclosure* enclosure,
+ const trg_id_t itri,
+ vrtx_id_t indices[3])
+{
+ const struct side_enc* side;
+ int i;
+ if(!enclosure || !indices
+ || itri >= enclosure->data->header.primitives_count)
+ return RES_BAD_ARG;
+ ASSERT(darray_sides_enc_size_get(&enclosure->data->sides)
+ == enclosure->data->header.primitives_count);
+ side = darray_sides_enc_cdata_get(&enclosure->data->sides) + itri;
+ FOR_EACH(i, 0, 3) indices[i] = side->vertice_id[i];
+ return RES_OK;
+}
+
+res_T
+senc3d_enclosure_get_vertex
+ (const struct senc3d_enclosure* enclosure,
+ const vrtx_id_t ivert,
+ double coord[3])
+{
+ if(!enclosure || !coord
+ || ivert >= enclosure->data->header.vertices_count) {
+ return RES_BAD_ARG;
+ } else {
+ const vrtx_id_t idx
+ = darray_vrtx_id_cdata_get(&enclosure->data->vertices)[ivert];
+ const union double3* positions
+ = darray_position_cdata_get(&enclosure->scene->vertices);
+ ASSERT(darray_vrtx_id_size_get(&enclosure->data->vertices)
+ == enclosure->data->header.vertices_count);
+ d3_set(coord, positions[idx].vec);
+ return RES_OK;
+ }
+}
+
+res_T
+senc3d_enclosure_get_triangle_id
+ (const struct senc3d_enclosure* enclosure,
+ const trg_id_t itri,
+ trg_id_t* gid,
+ enum senc3d_side* sde)
+{
+ const struct side_enc* side;
+ if(!enclosure || !gid || !sde
+ || itri >= enclosure->data->header.primitives_count)
+ return RES_BAD_ARG;
+ ASSERT(darray_sides_enc_size_get(&enclosure->data->sides)
+ == enclosure->data->header.primitives_count);
+ side = darray_sides_enc_cdata_get(&enclosure->data->sides) + itri;
+ *gid = TRGSIDE_2_TRG(side->side_id);
+ *sde = TRGSIDE_2_SIDE(side->side_id);
+ return RES_OK;
+}
+
+res_T
+senc3d_enclosure_get_medium
+ (const struct senc3d_enclosure* enclosure,
+ const medium_id_t imed,
+ medium_id_t* medium)
+{
+ if(!enclosure || !medium
+ || imed >= enclosure->data->header.enclosed_media_count)
+ return RES_BAD_ARG;
+ ASSERT(enclosure->data->header.enclosed_media_count
+ == darray_media_size_get(&enclosure->data->enclosed_media));
+ *medium = darray_media_cdata_get(&enclosure->data->enclosed_media)[imed];
+ return RES_OK;
+}
+
+res_T
+senc3d_enclosure_ref_get(struct senc3d_enclosure* enc)
+{
+ if(!enc) return RES_BAD_ARG;
+ ref_get(&enc->ref);
+ return RES_OK;
+}
+
+res_T
+senc3d_enclosure_ref_put(struct senc3d_enclosure* enc)
+{
+ if(!enc) return RES_BAD_ARG;
+ ref_put(&enc->ref, enclosure_release);
+ return RES_OK;
+}
diff --git a/src/senc3d_enclosure_c.h b/src/senc3d_enclosure_c.h
@@ -0,0 +1,38 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 SENC3D_ENCLOSURE_C_H
+#define SENC3D_ENCLOSURE_C_H
+
+#include <rsys/ref_count.h>
+
+#include "senc3d.h"
+#include "senc3d_internal_types.h"
+
+struct enclosure_data;
+struct senc3d_scene;
+
+struct senc3d_enclosure {
+ const struct enclosure_data* data;
+ struct senc3d_scene* scene;
+ ref_T ref;
+};
+
+struct senc3d_enclosure*
+enclosure_create
+ (struct senc3d_scene* scene,
+ const enclosure_id_t idx);
+
+#endif /* SENC3D_ENCLOSURE_C_H */
diff --git a/src/senc3d_enclosure_data.h b/src/senc3d_enclosure_data.h
@@ -0,0 +1,233 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 SENC3D_ENCLOSURE_DATA_H
+#define SENC3D_ENCLOSURE_DATA_H
+
+#include "senc3d.h"
+#include "senc3d_internal_types.h"
+#include "senc3d_side_range.h"
+
+#include <rsys/rsys.h>
+#include <rsys/ref_count.h>
+#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
+#include <rsys/hash_table.h>
+
+#include <limits.h>
+
+#define DARRAY_NAME vrtx_id
+#define DARRAY_DATA vrtx_id_t
+#include <rsys/dynamic_array.h>
+
+#define HTABLE_NAME vrtx_id
+#define HTABLE_KEY vrtx_id_t
+#define HTABLE_DATA vrtx_id_t
+#include <rsys/hash_table.h>
+
+struct side_enc {
+ vrtx_id_t vertice_id[3];
+ side_id_t side_id;
+};
+
+#define DARRAY_NAME sides_enc
+#define DARRAY_DATA struct side_enc
+#include <rsys/dynamic_array.h>
+
+/* uchar array with init to zero */
+static FINLINE void
+zero_init_uchar
+ (struct mem_allocator* alloc, uchar* data)
+{
+ ASSERT(data); (void) alloc;
+ *data = 0;
+}
+#define DARRAY_FUNCTOR_INIT zero_init_uchar
+#include <rsys/dynamic_array_uchar.h>
+
+static void
+init_header(struct senc3d_enclosure_header* header)
+{
+ ASSERT(header);
+ header->enclosure_id = ENCLOSURE_NULL__;
+ header->primitives_count = 0;
+ header->unique_primitives_count = 0;
+ header->vertices_count = 0;
+ header->enclosed_media_count = 0;
+ header->is_infinite = CHAR_MAX;
+}
+
+#define DARRAY_NAME media
+#define DARRAY_DATA medium_id_t
+#include <rsys/dynamic_array.h>
+
+static FINLINE res_T
+bool_array_of_media_merge
+ (struct darray_uchar* dst,
+ const uchar* src,
+ const medium_id_t sz)
+{
+ res_T res = RES_OK;
+ medium_id_t i;
+ uchar* data_dst;
+
+ ASSERT(src && dst);
+
+ OK(darray_uchar_resize(dst, sz));
+ data_dst = darray_uchar_data_get(dst);
+ FOR_EACH(i, 0, sz) {
+ if(!src[i]) continue;
+ data_dst[i] = 1;
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+static FINLINE res_T
+bool_array_of_media_to_darray_media
+ (struct darray_media* dst,
+ const struct darray_uchar* src,
+ const medium_id_t next_medium_idx)
+{
+ res_T res = RES_OK;
+ int64_t m_idx;
+ const uchar* data;
+
+ ASSERT(src && dst);
+
+ data = darray_uchar_cdata_get(src);
+ ASSERT(next_medium_idx + 1 == darray_uchar_size_get(src));
+ darray_media_clear(dst);
+ if(res != RES_OK) goto error;
+ ASSERT(next_medium_idx <= MEDIUM_MAX__ + 1);
+ FOR_EACH(m_idx, 0, 1 + (int64_t)next_medium_idx) {
+ medium_id_t medium = medium_idx_2_medium_id(m_idx);
+ if(!data[m_idx]) continue;
+ res = darray_media_push_back(dst, &medium);
+ if(res != RES_OK) goto error;
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+struct enclosure_data {
+ struct senc3d_enclosure_header header;
+ /* Same triangle can appear twice if both sides */
+ struct darray_sides_enc sides;
+ /* Index of vertices in scene's unique vertices */
+ struct darray_vrtx_id vertices;
+ /* List of the enclosed media */
+ struct darray_uchar tmp_enclosed_media;
+ struct darray_media enclosed_media;
+ /* Number of components involved in this enclosure */
+ component_id_t cc_count;
+ /* Linked list of the components */
+ component_id_t first_component;
+ /* Range of triangles member of the enclosure */
+ struct side_range side_range;
+ /* Counts */
+ side_id_t side_count;
+};
+
+static FINLINE void
+enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) {
+ ASSERT(enc);
+ init_header(&enc->header);
+ enc->cc_count = 0;
+ enc->first_component = COMPONENT_NULL__;
+ enc->side_range.first = SIDE_NULL__;
+ enc->side_range.last = 0;
+ enc->side_count = 0;
+ darray_sides_enc_init(alloc, &enc->sides);
+ darray_vrtx_id_init(alloc, &enc->vertices);
+ darray_uchar_init(alloc, &enc->tmp_enclosed_media);
+ darray_media_init(alloc, &enc->enclosed_media);
+}
+
+static FINLINE res_T
+enclosure_data_copy
+ (struct enclosure_data* dst,
+ const struct enclosure_data* src)
+{
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ dst->header = src->header;
+ dst->cc_count = src->cc_count;
+ dst->first_component = src->first_component;
+ dst->side_range = src->side_range;
+ dst->side_count = src->side_count;
+ OK(darray_sides_enc_copy(&dst->sides, &src->sides));
+ OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices));
+ OK(darray_uchar_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media));
+ OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media));
+error:
+ return res;
+}
+
+static FINLINE void
+enclosure_data_release(struct enclosure_data* n) {
+ ASSERT(n);
+ darray_sides_enc_release(&n->sides);
+ darray_vrtx_id_release(&n->vertices);
+ darray_uchar_release(&n->tmp_enclosed_media);
+ darray_media_release(&n->enclosed_media);
+}
+
+static FINLINE res_T
+enclosure_data_copy_and_release
+ (struct enclosure_data* dst,
+ struct enclosure_data* src)
+{
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ dst->header = src->header;
+ dst->cc_count = src->cc_count;
+ dst->first_component = src->first_component;
+ dst->side_range = src->side_range;
+ dst->side_count = src->side_count;
+ OK(darray_sides_enc_copy_and_release(&dst->sides, &src->sides));
+ OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices));
+ OK(darray_uchar_copy_and_release(&dst->tmp_enclosed_media,
+ &src->tmp_enclosed_media));
+ OK(darray_media_copy_and_release(&dst->enclosed_media, &src->enclosed_media));
+error:
+ return res;
+}
+
+#define DARRAY_NAME enclosure
+#define DARRAY_DATA struct enclosure_data
+#define DARRAY_FUNCTOR_INIT enclosure_data_init
+#define DARRAY_FUNCTOR_COPY enclosure_data_copy
+#define DARRAY_FUNCTOR_RELEASE enclosure_data_release
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE enclosure_data_copy_and_release
+#include <rsys/dynamic_array.h>
+
+#define DARRAY_NAME enc_id
+#define DARRAY_DATA enclosure_id_t
+#include <rsys/dynamic_array.h>
+
+#define DARRAY_NAME enc_ids_array
+#define DARRAY_DATA struct darray_enc_id
+#define DARRAY_FUNCTOR_INIT darray_enc_id_init
+#define DARRAY_FUNCTOR_COPY darray_enc_id_copy
+#define DARRAY_FUNCTOR_RELEASE darray_enc_id_release
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_enc_id_copy_and_release
+#include <rsys/dynamic_array.h>
+
+#endif /* SENC3D_ENCLOSURE_DATA_H */
diff --git a/src/senc3d_internal_types.h b/src/senc3d_internal_types.h
@@ -0,0 +1,165 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 SENC3D_INTERNAL_TYPES_H
+#define SENC3D_INTERNAL_TYPES_H
+
+#include "senc3d.h"
+
+#include <rsys/math.h>
+
+#include <stdio.h>
+#include <stdint.h>
+
+/* Utility macros */
+#ifdef NDEBUG
+#define OK2(Expr)\
+ if((tmp_res = (Expr)) != RES_OK) goto tmp_error;
+
+#define OK(Expr)\
+ if((res = (Expr)) != RES_OK) goto error;
+#else
+#define OK2(Expr)\
+ if((tmp_res = (Expr)) != RES_OK) {\
+ fprintf(stderr, "%s: error code set to %d at line %d\n", FUNC_NAME,\
+ tmp_res, __LINE__);\
+ goto tmp_error;\
+ }
+
+#define OK(Expr)\
+ if((res = (Expr)) != RES_OK) {\
+ fprintf(stderr, "%s: error code set to %d at line %d\n", FUNC_NAME,\
+ res, __LINE__);\
+ goto error;\
+ }
+#endif
+
+/* Helper type */
+typedef unsigned char uchar;
+
+/* The following types must be defined accordingly with the types
+ * used in senc2d.h */
+
+/* Trg IDs use the same type than Side IDs */
+typedef unsigned trg_id_t;
+/* TRG_MAX__ is limited to half the max of the base type to allow to count
+ * sides */
+#define TRG_MAX__ (UINT_MAX/2)
+#define TRG_NULL__ UINT_MAX
+#define PRTF_TRG "%u"
+
+/* Side IDs type use the same base type than Trg IDs */
+typedef trg_id_t side_id_t;
+#define SIDE_MAX__ (2*TRG_MAX__)
+#define SIDE_NULL__ TRG_NULL__
+
+/* Vertex IDs type */
+typedef unsigned vrtx_id_t;
+#define VRTX_MAX__ (UINT_MAX-1)
+#define VRTX_NULL__ UINT_MAX
+#define PRTF_VRTX "%u"
+
+/* Edge IDs use the same type than vertex IDs */
+typedef vrtx_id_t edge_id_t;
+#define EDGE_MAX__ VRTX_MAX__
+#define EDGE_NULL__ VRTX_NULL__
+
+/* Medium IDs type */
+typedef unsigned medium_id_t;
+#define MEDIUM_MAX__ (UINT_MAX-1) /* MAX is for unspecified medium */
+#define MEDIUM_NULL__ UINT_MAX
+#define PRTF_MDM "%u"
+
+static FINLINE medium_id_t
+medium_idx_2_medium_id(int64_t m_idx) {
+ return m_idx ? (medium_id_t)(m_idx - 1) : SENC3D_UNSPECIFIED_MEDIUM;
+}
+
+static FINLINE unsigned
+medium_id_2_medium_idx(medium_id_t medium) {
+ uint64_t tmp = (medium == SENC3D_UNSPECIFIED_MEDIUM) ? 0 : medium + 1;
+ ASSERT(tmp <= UINT_MAX);
+ return (unsigned)tmp;
+}
+
+/* Enclosure IDs type */
+typedef unsigned enclosure_id_t;
+#define ENCLOSURE_MAX__ (UINT_MAX-1)
+#define ENCLOSURE_NULL__ UINT_MAX
+
+/* Component IDs use the same type than enclosure IDs */
+typedef enclosure_id_t component_id_t;
+#define COMPONENT_MAX__ (UINT_MAX-2) /* To allow special values */
+#define COMPONENT_NULL__ UINT_MAX
+/* Special values */
+#define CC_GROUP_ROOT_NONE UINT_MAX
+#define CC_GROUP_ROOT_INFINITE (UINT_MAX-1)
+#define CC_GROUP_ID_NONE UINT_MAX
+#define CC_ID_NONE UINT_MAX
+
+#if (MEDIUM_MAX__+1 != SENC3D_UNSPECIFIED_MEDIUM)
+#error "Inconsistant values"
+#endif
+
+/* This one is used as flag */
+enum side_flag {
+ FLAG_FRONT = BIT(0),
+ FLAG_BACK = BIT(1)
+};
+
+/* Utility macros */
+static FINLINE trg_id_t
+TRGSIDE_2_TRG(side_id_t s) {
+ ASSERT(((size_t)s >> 1) <= TRG_MAX__);
+ return s >> 1;
+}
+
+static FINLINE int
+TRGSIDE_IS_FRONT(side_id_t s) {
+ return (s & 1) == 0;
+}
+
+static FINLINE enum senc3d_side
+TRGSIDE_2_SIDE(side_id_t s) {
+ return (s & 1) ? SENC3D_BACK : SENC3D_FRONT;
+}
+
+static FINLINE enum side_flag
+TRGSIDE_2_SIDEFLAG(side_id_t s) {
+ return (s & 1) ? FLAG_BACK : FLAG_FRONT;
+}
+
+static FINLINE uchar
+SIDE_CANCELED_FLAG(enum side_flag f) {
+ ASSERT((f << 4) <= UCHAR_MAX);
+ return (uchar)(f << 4);
+}
+
+static FINLINE side_id_t
+TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum senc3d_side i) {
+ size_t r;
+ ASSERT(i == SENC3D_FRONT || i == SENC3D_BACK);
+ r = (t << 1) | (i == SENC3D_BACK);
+ ASSERT(r <= SIDE_MAX__);
+ return (side_id_t)r;
+}
+
+static FINLINE side_id_t
+TRGSIDE_OPPOSITE(side_id_t s) {
+ return TRGIDxSIDE_2_TRGSIDE(TRGSIDE_2_TRG(s),
+ TRGSIDE_IS_FRONT(s) ? SENC3D_BACK : SENC3D_FRONT);
+}
+
+#endif /* SENC3D_INTERNAL_TYPES_H */
diff --git a/src/senc3d_sXd_helper.h b/src/senc3d_sXd_helper.h
@@ -0,0 +1,85 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 SENC3D_S3D_WRAPPER_H
+#define SENC3D_S3D_WRAPPER_H
+
+#include "senc3d.h"
+
+#include <rsys/rsys.h>
+
+/* Get vertex indices for the itri_th triangle.
+ * Suitable for use as get_indice callback in s3d_mesh_setup_indexed_vertices
+ * calls. */
+static FINLINE void
+senc3d_sXd_scene_get_indices
+ (const unsigned itri,
+ unsigned indices[SENC3D_GEOMETRY_DIMENSION],
+ void* ctx)
+{
+ const struct senc3d_scene* scene = ctx;
+ ASSERT(indices && scene);
+ SENC3D(scene_get_triangle(scene, itri, indices));
+}
+
+/* Get coordinates for the ivert_th vertex.
+ * Suitable for use as s3d_vertex_data getter for S3D_POSITION s3d_attrib_usage
+ * in s3d_mesh_setup_indexed_vertices calls. */
+static FINLINE void
+senc3d_sXd_scene_get_position
+ (const unsigned ivert,
+ float coord[SENC3D_GEOMETRY_DIMENSION],
+ void* ctx)
+{
+ const struct senc3d_scene* scene = ctx;
+ double tmp[SENC3D_GEOMETRY_DIMENSION];
+ int i;
+ ASSERT(coord && scene);
+ SENC3D(scene_get_vertex(scene, ivert, tmp));
+ FOR_EACH(i, 0, SENC3D_GEOMETRY_DIMENSION) coord[i] = (float)tmp[i];
+}
+
+/* Get vertex indices for the itri_th triangle of the enclosure.
+ * Suitable for use as get_indice callback in s3d_mesh_setup_indexed_vertices
+ * calls. */
+static FINLINE void
+senc3d_sXd_enclosure_get_indices
+ (const unsigned itri,
+ unsigned indices[SENC3D_GEOMETRY_DIMENSION],
+ void* ctx)
+{
+ const struct senc3d_enclosure* enclosure = ctx;
+ ASSERT(indices && ctx);
+ SENC3D(enclosure_get_triangle(enclosure, itri, indices));
+}
+
+/* Get coordinates for the ivert_th vertex of the enclosure.
+ * Suitable for use as s3d_vertex_data getter for S3D_POSITION s3d_attrib_usage
+ * in s3d_mesh_setup_indexed_vertices calls. */
+static FINLINE void
+senc3d_sXd_enclosure_get_position
+ (const unsigned ivert,
+ float coord[SENC3D_GEOMETRY_DIMENSION],
+ void* ctx)
+{
+ const struct senc3d_enclosure* enclosure = ctx;
+ double tmp[SENC3D_GEOMETRY_DIMENSION];
+ int i;
+ ASSERT(coord && ctx);
+ SENC3D(enclosure_get_vertex(enclosure, ivert, tmp));
+ FOR_EACH(i, 0, SENC3D_GEOMETRY_DIMENSION) coord[i] = (float)tmp[i];
+}
+
+#endif /* SENC3D_S3D_WRAPPER_H */
diff --git a/src/senc3d_scene.c b/src/senc3d_scene.c
@@ -0,0 +1,327 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 "senc3d.h"
+#include "senc3d_device_c.h"
+#include "senc3d_scene_c.h"
+#include "senc3d_scene_analyze_c.h"
+
+#include <rsys/rsys.h>
+#include <rsys/double3.h>
+#include <rsys/mem_allocator.h>
+
+#include <limits.h>
+
+/******************************************************************************
+ * Helper function
+ *****************************************************************************/
+static void
+scene_release(ref_T * ref)
+{
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ ASSERT(ref);
+ scn = CONTAINER_OF(ref, struct senc3d_scene, ref);
+ dev = scn->dev;
+ darray_triangle_in_release(&scn->triangles_in);
+ darray_position_release(&scn->vertices);
+ darray_side_range_release(&scn->media_use);
+
+ darray_triangle_enc_release(&scn->analyze.triangles_enc);
+ darray_enclosure_release(&scn->analyze.enclosures);
+ darray_enc_ids_array_release(&scn->analyze.enc_ids_array_by_medium);
+ darray_frontier_edge_release(&scn->analyze.frontiers);
+
+ MEM_RM(dev->allocator, scn);
+ SENC3D(device_ref_put(dev));
+}
+
+static INLINE int
+compatible_medium
+ (const medium_id_t m1,
+ const medium_id_t m2)
+{
+ if(m1 == SENC3D_UNSPECIFIED_MEDIUM || m2 == SENC3D_UNSPECIFIED_MEDIUM) return 1;
+ return (m1 == m2);
+}
+
+/******************************************************************************
+ * Exported functions
+ *****************************************************************************/
+res_T
+senc3d_scene_create
+ (struct senc3d_device* dev,
+ const int conv,
+ const trg_id_t ntris,
+ void(*indices)(const trg_id_t, vrtx_id_t*, void*),
+ void(*media)(const trg_id_t, medium_id_t*, void*),
+ const vrtx_id_t nverts,
+ void(*position)(const vrtx_id_t, double*, void* ctx),
+ void* ctx,
+ struct senc3d_scene** out_scn)
+{
+ struct senc3d_scene* scn = NULL;
+ /* Tables to detect duplicates */
+ struct htable_vrtx unique_vertices;
+ struct htable_trg unique_triangles;
+ vrtx_id_t nv;
+ trg_id_t nt;
+ res_T res = RES_OK;
+
+ if(!dev || !out_scn || !indices || !position || !nverts || !ntris
+ /* Convention must be set both regarding FRONT/BACK and INSIDE/OUTSIDE */
+ || !(conv & (SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_BACK))
+ || !(conv & (SENC3D_CONVENTION_NORMAL_INSIDE | SENC3D_CONVENTION_NORMAL_OUTSIDE)))
+ return RES_BAD_ARG;
+
+ scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct senc3d_scene));
+ if(!scn) {
+ log_err(dev, "%s: could not allocate the star_enclosures-3d scene.\n", FUNC_NAME);
+ res = RES_MEM_ERR;
+ goto error;
+ }
+ ref_init(&scn->ref);
+ SENC3D(device_ref_get(dev));
+ scn->dev = dev;
+ scn->convention = conv;
+ scn->ntris = ntris;
+ scn->next_medium_idx = 0;
+ scn->nverts = nverts;
+ darray_triangle_in_init(dev->allocator, &scn->triangles_in);
+ darray_position_init(dev->allocator, &scn->vertices);
+ htable_vrtx_init(dev->allocator, &unique_vertices);
+ htable_trg_init(dev->allocator, &unique_triangles);
+ darray_side_range_init(dev->allocator, &scn->media_use);
+
+ darray_triangle_enc_init(scn->dev->allocator, &scn->analyze.triangles_enc);
+ darray_enclosure_init(scn->dev->allocator, &scn->analyze.enclosures);
+ darray_enc_ids_array_init(scn->dev->allocator,
+ &scn->analyze.enc_ids_array_by_medium);
+ darray_frontier_edge_init(scn->dev->allocator, &scn->analyze.frontiers);
+ /* Enclosure 0 is always defined for infinite */
+ OK(darray_enclosure_resize(&scn->analyze.enclosures, 1));
+ scn->analyze.enclosures_count = 1;
+
+ OK(darray_position_reserve(&scn->vertices, scn->nverts));
+ OK(darray_triangle_in_reserve(&scn->triangles_in, scn->ntris));
+ OK(htable_vrtx_reserve(&unique_vertices, scn->nverts));
+ OK(htable_trg_reserve(&unique_triangles, scn->ntris));
+
+ /* Get vertices */
+ FOR_EACH(nv, 0, nverts) {
+ vrtx_id_t* p_vrtx;
+ union double3 tmp;
+ /* API: position needs an api_t */
+ position(nv, tmp.vec, ctx);
+ p_vrtx = htable_vrtx_find(&unique_vertices, &tmp);
+ if(p_vrtx) {
+ /* Duplicate vertex */
+ log_err(scn->dev, "%s: vertex "PRTF_VRTX" is a duplicate.\n",
+ FUNC_NAME, nv);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ /* New vertex */
+ ASSERT(nv == htable_vrtx_size_get(&unique_vertices));
+ OK(darray_position_push_back(&scn->vertices, &tmp));
+ OK(htable_vrtx_set(&unique_vertices, &tmp, &nv));
+ }
+ /* Get triangles */
+ FOR_EACH(nt, 0, ntris) {
+ int j;
+ trg_id_t s;
+ medium_id_t med[2]
+ = { SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM };
+ vrtx_id_t ind[3];
+ union vrtx_id3 trg_key;
+ struct triangle_in tmp;
+ trg_id_t* p_trg;
+ indices(nt, ind, ctx);
+ FOR_EACH(j, 0, 3) {
+ if(ind[j] >= nverts) {
+ log_err(scn->dev,
+ "%s: triangle "PRTF_TRG" uses invalid vertex id "PRTF_VRTX".\n",
+ FUNC_NAME, nt, ind[j]);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ ASSERT(ind[j] <= VRTX_MAX__);
+ tmp.vertice_id[j] = (vrtx_id_t)ind[j];
+ }
+ if(tmp.vertice_id[0] == tmp.vertice_id[1]
+ || tmp.vertice_id[0] == tmp.vertice_id[2]
+ || tmp.vertice_id[1] == tmp.vertice_id[2])
+ {
+ log_err(scn->dev, "%s: triangle "PRTF_TRG" is degenerated.\n",
+ FUNC_NAME, nt);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ /* Get media */
+ if(media) {
+ media(nt, med, ctx);
+ for(s = SENC3D_FRONT; s <= SENC3D_BACK; s += SENC3D_BACK - SENC3D_FRONT) {
+ if(med[s] == SENC3D_UNSPECIFIED_MEDIUM || med[s] <= MEDIUM_MAX__)
+ continue;
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ }
+ trg_make_key(&trg_key, tmp.vertice_id);
+ p_trg = htable_trg_find(&unique_triangles, &trg_key);
+ if(p_trg) {
+ /* Duplicate triangle */
+ log_err(scn->dev, "%s: triangle "PRTF_TRG" is a duplicate.\n",
+ FUNC_NAME, nt);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ /* New triangle */
+ ASSERT(nt == htable_trg_size_get(&unique_triangles));
+ OK(htable_trg_set(&unique_triangles, &trg_key, &nt));
+ for(s = SENC3D_FRONT; s <= SENC3D_BACK; s += SENC3D_BACK - SENC3D_FRONT) {
+ struct side_range* media_use;
+ size_t m_idx = medium_id_2_medium_idx(med[s]);
+ tmp.medium[s] = med[s];
+ if(m_idx >= scn->next_medium_idx) {
+ medium_id_t medium;
+ medium = (medium_id_t)m_idx;
+ scn->next_medium_idx = medium;
+ OK(darray_side_range_resize(&scn->media_use, 1 + m_idx));
+ }
+ /* media_use 0 is for SENC3D_UNSPECIFIED_MEDIUM */
+ media_use = darray_side_range_data_get(&scn->media_use) + m_idx;
+ media_use->first =
+ MMIN(media_use->first, TRGIDxSIDE_2_TRGSIDE((trg_id_t)nt, s));
+ ASSERT(media_use->first < 2 * (scn->ntris + 1));
+ media_use->last =
+ MMAX(media_use->last, TRGIDxSIDE_2_TRGSIDE((trg_id_t)nt, s));
+ ASSERT(media_use->last < 2 * (scn->ntris + 1));
+ ASSERT(media_use->first <= media_use->last);
+ }
+ OK(darray_triangle_in_push_back(&scn->triangles_in, &tmp));
+ }
+
+ OK(darray_enc_ids_array_resize(&scn->analyze.enc_ids_array_by_medium,
+ 1 + scn->next_medium_idx)); /* +1 is for unspecified */
+ /* Proceed to the analyze */
+ OK(scene_analyze(scn));
+
+exit:
+ htable_vrtx_release(&unique_vertices);
+ htable_trg_release(&unique_triangles);
+ if(scn) *out_scn = scn;
+ return res;
+
+error:
+ if(scn) {
+ SENC3D(scene_ref_put(scn));
+ scn = NULL;
+ }
+ goto exit;
+}
+
+res_T
+senc3d_scene_get_convention
+ (const struct senc3d_scene* scn,
+ int* convention)
+{
+ if(!scn || !convention) return RES_BAD_ARG;
+ *convention = scn->convention;
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_triangles_count
+ (const struct senc3d_scene* scn,
+ trg_id_t* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ *count = scn->ntris;
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_triangle
+ (const struct senc3d_scene* scn,
+ const trg_id_t itri,
+ vrtx_id_t indices[3])
+{
+ const struct triangle_in* trg;
+ int i;
+ if(!scn || !indices
+ || itri >= darray_triangle_in_size_get(&scn->triangles_in))
+ return RES_BAD_ARG;
+ trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri;
+ FOR_EACH(i, 0, 3) indices[i] = trg->vertice_id[i];
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_triangle_media
+ (const struct senc3d_scene* scn,
+ const trg_id_t itri,
+ medium_id_t media[2])
+{
+ const struct triangle_in* trg;
+ int i;
+ if(!scn || !media
+ || itri >= darray_triangle_in_size_get(&scn->triangles_in))
+ return RES_BAD_ARG;
+ trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri;
+ FOR_EACH(i, 0, 2) media[i] = trg->medium[i];
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_vertices_count
+ (const struct senc3d_scene* scn,
+ vrtx_id_t* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ *count = scn->nverts;
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_get_vertex
+ (const struct senc3d_scene* scn,
+ const vrtx_id_t ivert,
+ double coord[3])
+{
+ const union double3* v;
+ if(!scn || !coord
+ || ivert >= darray_position_size_get(&scn->vertices))
+ return RES_BAD_ARG;
+ v = darray_position_cdata_get(&scn->vertices) + ivert;
+ d3_set(coord, v->vec);
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_ref_get(struct senc3d_scene* scn)
+{
+ if(!scn) return RES_BAD_ARG;
+ ref_get(&scn->ref);
+ return RES_OK;
+}
+
+res_T
+senc3d_scene_ref_put(struct senc3d_scene* scn)
+{
+ if(!scn) return RES_BAD_ARG;
+ ref_put(&scn->ref, scene_release);
+ return RES_OK;
+}
diff --git a/src/senc3d_scene_analyze.c b/src/senc3d_scene_analyze.c
@@ -0,0 +1,1382 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 "senc3d.h"
+#include "senc3d_device_c.h"
+#include "senc3d_scene_c.h"
+#include "senc3d_scene_analyze_c.h"
+#include "senc3d_internal_types.h"
+
+#include <rsys/rsys.h>
+#include <rsys/float3.h>
+#include <rsys/double33.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
+#include <rsys/dynamic_array_uchar.h>
+#include <rsys/clock_time.h>
+
+#include <star/s3d.h>
+
+#include <omp.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define CC_DESCRIPTOR_NULL__ {\
+ CHAR_MAX, VRTX_NULL__, 0,\
+ CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\
+ { TRG_NULL__, 0},\
+ NULL\
+}
+#ifdef COMPILER_GCC
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
+const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
+#ifdef COMPILER_GCC
+ #pragma GCC diagnostic pop
+#endif
+
+#define DARRAY_NAME component_id
+#define DARRAY_DATA component_id_t
+#include <rsys/dynamic_array.h>
+
+struct filter_ctx {
+ struct senc3d_scene* scn;
+ component_id_t origin_component;
+ struct darray_triangle_comp* triangles_comp;
+ /* Result of hit */
+ component_id_t hit_component;
+};
+
+/******************************************************************************
+ * Helper function
+ *****************************************************************************/
+static INLINE int
+neighbour_cmp(const void* w1, const void* w2)
+{
+ const double a1 = ((struct neighbour_info*)w1)->angle;
+ const double a2 = ((struct neighbour_info*)w2)->angle;
+ return (a1 > a2) - (a1 < a2);
+}
+
+static side_id_t
+get_side_not_in_connex_component
+ (const side_id_t last_side,
+ const struct trgside* trgsides,
+ const uchar* processed,
+ side_id_t* first_side_not_in_component,
+ const medium_id_t medium)
+{
+ ASSERT(trgsides && processed && first_side_not_in_component);
+ {
+ side_id_t i = *first_side_not_in_component;
+ while (i <= last_side
+ && (trgsides[i].medium != medium
+ || (processed[TRGSIDE_2_TRG(i)] & TRGSIDE_2_SIDEFLAG(i))))
+ ++i;
+
+ *first_side_not_in_component = i + 1;
+ if(i > last_side) return SIDE_NULL__;
+ return i;
+ }
+}
+
+/* Here unsigned are required by s3d API */
+static void
+get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) {
+ int i;
+ const struct senc3d_scene* scene = ctx;
+ const struct triangle_in* trg =
+ darray_triangle_in_cdata_get(&scene->triangles_in) + itri;
+ FOR_EACH(i, 0, 3) {
+ ASSERT(trg->vertice_id[i] < scene->nverts);
+ ASSERT(trg->vertice_id[i] <= UINT_MAX);
+ ids[i] = (unsigned)trg->vertice_id[i]; /* Back to s3d API type */
+ }
+}
+
+/* Here unsigned are required by s3d API */
+static void
+get_scn_position(const unsigned ivert, float pos[3], void* ctx) {
+ const struct senc3d_scene* scene = ctx;
+ const union double3* pt =
+ darray_position_cdata_get(&scene->vertices) + ivert;
+ f3_set_d3(pos, pt->vec);
+}
+
+static int
+self_hit_filter
+ (const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ void* ray_data,
+ void* filter_data)
+{
+ struct filter_ctx* filter_ctx = ray_data;
+ const struct triangle_comp* hit_trg_comp;
+ struct s3d_attrib pos;
+ float s, dir[3];
+ enum senc3d_side hit_side;
+
+ (void)ray_org; (void)ray_dir; (void)filter_data;
+ ASSERT(hit && filter_ctx);
+ ASSERT(hit->prim.prim_id
+ < darray_triangle_comp_size_get(filter_ctx->triangles_comp));
+ ASSERT(hit->uv[0] == CLAMP(hit->uv[0], 0, 1));
+ ASSERT(hit->uv[1] == CLAMP(hit->uv[1], 0, 1));
+ hit_trg_comp = darray_triangle_comp_cdata_get(filter_ctx->triangles_comp)
+ + hit->prim.prim_id;
+ /* No self hit */
+ if(hit_trg_comp->component[SENC3D_FRONT] == filter_ctx->origin_component
+ || hit_trg_comp->component[SENC3D_BACK] == filter_ctx->origin_component)
+ return 1; /* Reject */
+ if(hit->distance == 0) {
+ /* dir = + z; s = dir . n; */
+ s = hit->normal[2];
+ } else {
+ /* Cannot go downwards */
+ CHK(s3d_primitive_get_attrib(&hit->prim, S3D_POSITION, hit->uv, &pos)
+ == RES_OK);
+ if(pos.value[2] <= ray_org[2])
+ return 1; /* Reject */
+ /* In closest_point queries ray_dir is not informed */
+ f3_sub(dir, pos.value, ray_org);
+ s = f3_dot(dir, hit->normal);
+ }
+
+ if(s == 0) return 1; /* Reject */
+ /* Determine which side was hit */
+ hit_side =
+ ((s < 0) /* Facing geometrical normal of hit */
+ == ((filter_ctx->scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0))
+ /* Warning: following Embree 2 convention for geometrical normals,
+ * the Star3D hit normal is left-handed while star-enclosure uses
+ * right-handed convention */
+ ? SENC3D_BACK : SENC3D_FRONT;
+ filter_ctx->hit_component = hit_trg_comp->component[hit_side];
+ return 0; /* Keep */
+}
+
+static void
+extract_connex_components
+ (struct senc3d_scene* scn,
+ struct trgside* trgsides,
+ struct darray_ptr_component_descriptor* connex_components,
+ const struct darray_triangle_tmp* triangles_tmp_array,
+ struct darray_triangle_comp* triangles_comp_array,
+ struct s3d_scene_view** s3d_view,
+ ATOMIC* component_count,
+ /* Shared error status.
+ * We accept to overwrite an error with a different error */
+ res_T* p_res)
+{
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ struct mem_allocator* alloc;
+ int64_t m_idx; /* OpenMP requires a signed type for the for loop variable */
+ struct darray_side_id stack;
+ struct darray_side_id ids_of_sides_around_max_z_vertex;
+ const union double3* positions;
+ const struct triangle_tmp* triangles_tmp;
+ struct triangle_comp* triangles_comp;
+ /* An array to flag sides when processed */
+ uchar* processed;
+ /* An array to store the component being processed */
+ struct darray_side_id current_component;
+ /* A bool array to store media of the component being processed */
+ uchar* current_media = NULL;
+ size_t sz, ii;
+
+ ASSERT(scn && trgsides && connex_components && triangles_tmp_array
+ && triangles_comp_array && s3d_view && component_count && p_res);
+ alloc = scn->dev->allocator;
+ positions = darray_position_cdata_get(&scn->vertices);
+ triangles_tmp = darray_triangle_tmp_cdata_get(triangles_tmp_array);
+ triangles_comp = darray_triangle_comp_data_get(triangles_comp_array);
+ darray_side_id_init(alloc, &stack);
+ darray_side_id_init(alloc, &ids_of_sides_around_max_z_vertex);
+ darray_side_id_init(alloc, ¤t_component);
+ processed = MEM_CALLOC(alloc, scn->ntris, sizeof(uchar));
+ if(!processed) {
+ *p_res = RES_MEM_ERR;
+ return;
+ }
+
+#ifndef NDEBUG
+ #pragma omp single
+ {
+ trg_id_t t_;
+ int s;
+ ASSERT(darray_ptr_component_descriptor_size_get(connex_components) == 0);
+ FOR_EACH(t_, 0, scn->ntris) {
+ const struct triangle_in* trg_in =
+ darray_triangle_in_cdata_get(&scn->triangles_in) + t_;
+ const struct side_range* media_use
+ = darray_side_range_cdata_get(&scn->media_use);
+ FOR_EACH(s, 0, 2) {
+ const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t_, s);
+ medium_id_t medium = trg_in->medium[s];
+ m_idx = medium_id_2_medium_idx(medium);
+ ASSERT(media_use[m_idx].first <= side && side
+ <= media_use[m_idx].last);
+ }
+ }
+ } /* Implicit barrier here */
+#endif
+
+ /* We loop on sides to build connex components. */
+ #pragma omp for schedule(dynamic) nowait
+ /* Process all media, including unspecified */
+ for(m_idx = 0; m_idx < 1 + (int64_t)scn->next_medium_idx; m_idx++) {
+ const medium_id_t medium = medium_idx_2_medium_id(m_idx);
+ /* media_use 0 is for SENC3D_UNSPECIFIED_MEDIUM, n+1 is for n */
+ const struct side_range* media_use =
+ darray_side_range_cdata_get(&scn->media_use) + m_idx;
+ /* Any not-already-used side is used as a starting point */
+ side_id_t first_side_not_in_component = media_use->first;
+ double max_nz;
+ side_id_t max_nz_side_id = SIDE_NULL__;
+ const side_id_t last_side = media_use->last;
+ int component_canceled = 0;
+ res_T tmp_res = RES_OK;
+ ATOMIC id;
+
+ if(*p_res != RES_OK) continue;
+ if(first_side_not_in_component == SIDE_NULL__)
+ continue; /* Unused medium */
+ ASSERT(first_side_not_in_component < 2 * scn->ntris);
+ ASSERT(darray_side_id_size_get(&stack) == 0);
+ ASSERT(darray_side_id_size_get(¤t_component) == 0);
+ for(;;) { /* Process all components for this medium */
+ const side_id_t start_side_id = get_side_not_in_connex_component
+ (last_side, trgsides, processed, &first_side_not_in_component, medium);
+ side_id_t crt_side_id = start_side_id;
+ side_id_t last_side_id = start_side_id;
+ vrtx_id_t max_z_vrtx_id = VRTX_NULL__;
+ struct cc_descriptor *cc;
+ double max_z = -DBL_MAX;
+ component_canceled = 0;
+ ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->ntris);
+ darray_side_id_clear(¤t_component);
+
+ if(*p_res != RES_OK) break;
+ if(start_side_id == SIDE_NULL__)
+ break; /* start_side_id=SIDE_NULL__ => component done! */
+
+#ifndef NDEBUG
+ {
+ trg_id_t tid = TRGSIDE_2_TRG(start_side_id);
+ enum senc3d_side s = TRGSIDE_2_SIDE(start_side_id);
+ medium_id_t side_med
+ = darray_triangle_in_data_get(&scn->triangles_in)[tid].medium[s];
+ ASSERT(side_med == medium);
+ }
+#endif
+
+ /* Reuse array if possible, or create a new one */
+ if(current_media) {
+ /* current_media 0 is for SENC3D_UNSPECIFIED_MEDIUM, n+1 is for n */
+ memset(current_media, 0, 1 + scn->next_medium_idx);
+ } else {
+ current_media = MEM_CALLOC(alloc, 1 + scn->next_medium_idx,
+ sizeof(*current_media));
+ if(!current_media) {
+ *p_res = RES_MEM_ERR;
+ continue;
+ }
+ }
+ current_media[m_idx] = 1;
+ for(;;) { /* Process all sides of this component */
+ int i;
+ enum side_flag crt_side_flag = TRGSIDE_2_SIDEFLAG(crt_side_id);
+ struct trgside* crt_side = trgsides + crt_side_id;
+ const trg_id_t crt_trg_id = TRGSIDE_2_TRG(crt_side_id);
+ const struct triangle_in* trg_in =
+ darray_triangle_in_cdata_get(&scn->triangles_in) + crt_trg_id;
+ uchar* trg_used = processed + crt_trg_id;
+ const struct triangle_tmp* const trg_tmp = triangles_tmp + crt_trg_id;
+ ASSERT(crt_trg_id < scn->ntris);
+
+ if(*p_res != RES_OK) break;
+
+ /* Record Zmax information
+ * Keep track of the appropriate vertex of the component in order
+ * to cast a ray at the component grouping step of the algorithm.
+ * The most appropriate vertex is (the) one with the greater Z
+ * coordinate. */
+ if(max_z < trg_tmp->max_z) {
+ /* New best vertex */
+ max_z = trg_tmp->max_z;
+ /* New vertex: reset list of sides */
+ darray_side_id_clear(&ids_of_sides_around_max_z_vertex);
+
+ /* Select a vertex with z == max_z */
+ FOR_EACH(i, 0, 3) {
+ if(max_z == positions[trg_in->vertice_id[i]].pos.z) {
+ max_z_vrtx_id = trg_in->vertice_id[i];
+ break;
+ }
+ }
+ ASSERT(i < 3); /* Found one */
+ /* List of sides using the vertex */
+ OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex,
+ &crt_side_id));
+ } else if(max_z == trg_tmp->max_z) {
+ /* Does this triangle use the currently selected max_z vertex? */
+ FOR_EACH(i, 0, 3) {
+ if(max_z_vrtx_id == trg_in->vertice_id[i]) {
+ /* List of sides using the vertex */
+ OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex,
+ &crt_side_id));
+ break;
+ }
+ }
+ }
+
+ /* Record crt_side both as component and triangle level */
+ if((*trg_used & crt_side_flag) == 0) {
+ OK2(darray_side_id_push_back(¤t_component, &crt_side_id));
+ *trg_used = *trg_used | (uchar)crt_side_flag;
+ }
+
+ /* Store neighbour's sides in a waiting stack */
+ FOR_EACH(i, 0, 3) {
+ side_id_t neighbour_id = crt_side->facing_side_id[i];
+ trg_id_t nbour_trg_id = TRGSIDE_2_TRG(neighbour_id);
+ enum side_flag nbour_side_id = TRGSIDE_2_SIDEFLAG(neighbour_id);
+ uchar* nbour_used = processed + nbour_trg_id;
+ const struct trgside* neighbour = trgsides + neighbour_id;
+ medium_id_t nbour_med_idx = medium_id_2_medium_idx(neighbour->medium);
+ if((int64_t)nbour_med_idx < m_idx
+ || (*nbour_used & SIDE_CANCELED_FLAG(nbour_side_id)))
+ {
+ /* 1) Not the same medium.
+ * Neighbour's medium idx is less than current medium: the whole
+ * component is to be processed by another thread (possibly the one
+ * associated with neighbour's medium).
+ * 2) Neighbour was canceled: no need to replay the component
+ * again as it will eventually rediscover the side with low medium
+ * id and recancel all the work in progress */
+ component_canceled = 1;
+ darray_side_id_clear(&stack);
+ /* Don't cancel used flags as all these sides will get us back to
+ * (at least) the neighbour side we have just discovered, that will
+ * cancel them again and again */
+ sz = darray_side_id_size_get(¤t_component);
+ FOR_EACH(ii, 0, sz) {
+ side_id_t used_side
+ = darray_side_id_cdata_get(¤t_component)[ii];
+ trg_id_t used_trg_id = TRGSIDE_2_TRG(used_side);
+ enum side_flag used_side_flag
+ = TRGSIDE_2_SIDEFLAG(used_side);
+ uchar* used = processed + used_trg_id;
+ ASSERT(*used & (uchar)used_side_flag);
+ /* Set the used flag for sides in cancelled component as leading
+ * to further cancellations */
+ *used |= SIDE_CANCELED_FLAG(used_side_flag);
+ }
+
+ goto canceled;
+ }
+ if(*nbour_used & nbour_side_id) continue; /* Already processed */
+ /* Mark neighbour as processed and stack it */
+ *nbour_used |= (uchar)nbour_side_id;
+ OK2(darray_side_id_push_back(&stack, &neighbour_id));
+ OK2(darray_side_id_push_back(¤t_component, &neighbour_id));
+ current_media[nbour_med_idx] = 1;
+ }
+ sz = darray_side_id_size_get(&stack);
+ if(sz == 0) break; /* Empty stack => component is done! */
+ crt_side_id = darray_side_id_cdata_get(&stack)[sz - 1];
+ darray_side_id_pop_back(&stack);
+ last_side_id = MMAX(last_side_id, crt_side_id);
+ }
+ canceled:
+ if(component_canceled) continue;
+
+ /* Register the new component and get it initialized */
+ cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor));
+ if(!cc) *p_res = RES_MEM_ERR;
+ if(*p_res != RES_OK) break;
+
+ ASSERT(medium == trgsides[start_side_id].medium);
+ ASSERT(max_z_vrtx_id != VRTX_NULL__);
+ cc_descriptor_init(alloc, cc);
+ id = ATOMIC_INCR(component_count) - 1;
+ ASSERT(id <= COMPONENT_MAX__);
+ cc->cc_id = (component_id_t)id;
+ sz = darray_side_id_size_get(¤t_component);
+ ASSERT(sz > 0 && sz <= SIDE_MAX__);
+ cc->side_count = (side_id_t)sz;
+ cc->side_range.first = start_side_id;
+ cc->side_range.last = last_side_id;
+ cc->max_z_vrtx_id = max_z_vrtx_id;
+ /* Tranfer ownership of the array to component */
+ ASSERT(!cc->media && current_media);
+ cc->media = current_media;
+ current_media = NULL;
+
+ /* Write component membership in the global structure
+ * No need for sync here as an unique thread writes a given side */
+ {STATIC_ASSERT(sizeof(cc->cc_id) >= 4, Cannot_write_IDs_sync_free);}
+ ASSERT(IS_ALIGNED(triangles_comp->component, sizeof(cc->cc_id)));
+ FOR_EACH(ii, 0, sz) {
+ const side_id_t s = darray_side_id_cdata_get(¤t_component)[ii];
+ trg_id_t tid = TRGSIDE_2_TRG(s);
+ enum senc3d_side sid = TRGSIDE_2_SIDE(s);
+ component_id_t* cmp = triangles_comp[tid].component;
+ ASSERT(cmp[sid] == COMPONENT_NULL__);
+ ASSERT(medium_id_2_medium_idx(trgsides[s].medium)
+ >= medium_id_2_medium_idx(medium));
+ cmp[sid] = cc->cc_id;
+ }
+
+ /* Compute the normal at the max_z vertex. */
+ max_nz = 0;
+ sz = darray_side_id_size_get(&ids_of_sides_around_max_z_vertex);
+ ASSERT(sz > 0);
+ FOR_EACH(ii, 0, sz) {
+ const side_id_t side_id =
+ darray_side_id_cdata_get(&ids_of_sides_around_max_z_vertex)[ii];
+ const trg_id_t trg_id = TRGSIDE_2_TRG(side_id);
+ enum senc3d_side s = TRGSIDE_2_SIDE(side_id);
+ const struct triangle_in* trg_in =
+ darray_triangle_in_cdata_get(&scn->triangles_in) + trg_id;
+ const struct triangle_comp* trg_comp = triangles_comp + trg_id;
+ const union double3* vertices =
+ darray_position_cdata_get(&scn->vertices);
+ double edge0[3], edge1[3], normal[3], norm;
+
+ /* To ensure that triangles with 2 sides in the component total to 0
+ * regardless of numeric accuracy, we need to prevent them to
+ * contribute (remember than x + y - y == x can be false). */
+ ASSERT(trg_comp->component[s] == cc->cc_id); (void)s;
+ if(trg_comp->component[SENC3D_FRONT] == trg_comp->component[SENC3D_BACK])
+ continue;
+
+ d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec,
+ vertices[trg_in->vertice_id[0]].vec);
+ d3_sub(edge1, vertices[trg_in->vertice_id[2]].vec,
+ vertices[trg_in->vertice_id[0]].vec);
+ d3_cross(normal, edge0, edge1);
+ norm = d3_normalize(normal, normal);
+ ASSERT(norm); (void)norm;
+
+ if(fabs(max_nz) < fabs(normal[2])) {
+ max_nz_side_id = side_id;
+ max_nz = normal[2];
+ }
+ }
+ if(max_nz == 0) cc->is_outer_border = 0;
+ else {
+ if(TRGSIDE_IS_FRONT(max_nz_side_id)
+ == ((scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0)) {
+ /* Geom normal points towards the component */
+ cc->is_outer_border = (max_nz < 0);
+ } else {
+ /* Geom normal points away from the component */
+ cc->is_outer_border = (max_nz > 0);
+ }
+ }
+
+ /* Need to synchronize connex_components growth as this global structure
+ * is accessed by multipe threads */
+ #pragma omp critical
+ {
+ struct cc_descriptor** components;
+ sz = darray_ptr_component_descriptor_size_get(connex_components);
+ if(sz <= cc->cc_id) {
+ tmp_res = darray_ptr_component_descriptor_resize(connex_components,
+ 1 + cc->cc_id);
+ if(tmp_res != RES_OK) *p_res = tmp_res;
+ }
+ if(*p_res == RES_OK) {
+ /* Don't set the pointer before resize as this can lead to move data */
+ components =
+ darray_ptr_component_descriptor_data_get(connex_components);
+ ASSERT(components[cc->cc_id] == NULL);
+ components[cc->cc_id] = cc;
+ }
+ }
+ }
+ tmp_error:
+ if(tmp_res != RES_OK) *p_res = tmp_res;
+ } /* No barrier here */
+
+ MEM_RM(alloc, processed);
+ MEM_RM(alloc, current_media);
+ darray_side_id_release(¤t_component);
+ darray_side_id_release(&stack);
+ darray_side_id_release(&ids_of_sides_around_max_z_vertex);
+
+ /* The first thread here creates the s3d view */
+ #pragma omp single nowait
+ if(*p_res == RES_OK) {
+ res_T res = RES_OK;
+ struct s3d_device* s3d = NULL;
+ struct s3d_scene* s3d_scn = NULL;
+ struct s3d_shape* s3d_shp = NULL;
+ struct s3d_vertex_data attribs;
+
+ attribs.type = S3D_FLOAT3;
+ attribs.usage = S3D_POSITION;
+ attribs.get = get_scn_position;
+
+ /* Put geometry in a 3D view */
+ OK(s3d_device_create(scn->dev->logger, alloc, 0, &s3d));
+ OK(s3d_scene_create(s3d, &s3d_scn));
+ OK(s3d_shape_create_mesh(s3d, &s3d_shp));
+
+ /* Back to s3d API type for ntris and nverts */
+ ASSERT(scn->ntris <= UINT_MAX);
+ ASSERT(scn->nverts <= UINT_MAX);
+ OK(s3d_mesh_setup_indexed_vertices(s3d_shp,
+ (unsigned)scn->ntris, get_scn_indices,
+ (unsigned)scn->nverts, &attribs, 1, scn));
+ OK(s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter, NULL));
+ OK(s3d_scene_attach_shape(s3d_scn, s3d_shp));
+ OK(s3d_scene_view_create(s3d_scn, S3D_TRACE, s3d_view));
+ error:
+ if(res != RES_OK) *p_res = res;
+ if(s3d) S3D(device_ref_put(s3d));
+ if(s3d_scn) S3D(scene_ref_put(s3d_scn));
+ if(s3d_shp) S3D(shape_ref_put(s3d_shp));
+ }
+
+#ifndef NDEBUG
+ /* Need to wait for all threads done to be able to check stuff */
+ #pragma omp barrier
+ if(*p_res != RES_OK) return;
+ #pragma omp single
+ {
+ trg_id_t t_;
+ component_id_t c;
+ ASSERT(ATOMIC_GET(component_count) ==
+ (int)darray_ptr_component_descriptor_size_get(connex_components));
+ FOR_EACH(t_, 0, scn->ntris) {
+ struct triangle_comp* trg_comp =
+ darray_triangle_comp_data_get(triangles_comp_array) + t_;
+ ASSERT(trg_comp->component[SENC3D_FRONT] != COMPONENT_NULL__);
+ ASSERT(trg_comp->component[SENC3D_BACK] != COMPONENT_NULL__);
+ }
+ FOR_EACH(c, 0, (component_id_t)ATOMIC_GET(component_count)) {
+ struct cc_descriptor** components =
+ darray_ptr_component_descriptor_data_get(connex_components);
+ ASSERT(components[c] != NULL && components[c]->cc_id == c);
+ }
+ } /* Implicit barrier here */
+#endif
+}
+
+static void
+group_connex_components
+ (struct senc3d_scene* scn,
+ struct darray_triangle_comp* triangles_comp,
+ struct darray_ptr_component_descriptor* connex_components,
+ struct s3d_scene_view* s3d_view,
+ ATOMIC* next_enclosure_id,
+ /* Shared error status.
+ * We accept to overwrite an error with a different error */
+ res_T* res)
+{
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ struct cc_descriptor** descriptors;
+ const union double3* positions;
+ size_t tmp;
+ component_id_t cc_count;
+ int64_t ccc;
+ struct filter_ctx filter_ctx;
+ float lower[3], upper[3];
+
+ ASSERT(scn && triangles_comp && connex_components
+ && s3d_view && next_enclosure_id && res);
+ ASSERT(scn->analyze.enclosures_count == 1);
+
+ descriptors = darray_ptr_component_descriptor_data_get(connex_components);
+ tmp = darray_ptr_component_descriptor_size_get(connex_components);
+ ASSERT(tmp <= COMPONENT_MAX__);
+ cc_count = (component_id_t)tmp;
+ positions = darray_position_cdata_get(&scn->vertices);
+ filter_ctx.scn = scn;
+ filter_ctx.triangles_comp = triangles_comp;
+ *res = s3d_scene_view_get_aabb(s3d_view, lower, upper);
+ if(*res != RES_OK) return;
+ /* Cast rays to find links between connex components */
+ #pragma omp for
+ for(ccc = 0; ccc < (int64_t)cc_count; ccc++) {
+ res_T tmp_res = RES_OK;
+ component_id_t c = (component_id_t)ccc;
+ struct s3d_hit hit = S3D_HIT_NULL;
+ float origin[3], rrr[3], r;
+ struct cc_descriptor* const cc = descriptors[c];
+ const double* max_vrtx;
+ int i;
+
+ if(*res != RES_OK) continue;
+ ASSERT(cc->cc_id == c);
+ ASSERT(cc->cc_group_root == CC_GROUP_ID_NONE);
+ ASSERT(cc->max_z_vrtx_id < scn->nverts);
+
+ max_vrtx = positions[cc->max_z_vrtx_id].vec;
+ if(cc->is_outer_border) {
+ ATOMIC id;
+ /* Don't need to cast a ray */
+ cc->cc_group_root = cc->cc_id; /* New group with self as root */
+ id = ATOMIC_INCR(next_enclosure_id) - 1;
+ ASSERT(id <= ENCLOSURE_MAX__);
+ cc->enclosure_id = (enclosure_id_t)id;
+ continue;
+ }
+
+ f3_set_d3(origin, max_vrtx);
+ /* Self-hit data: self hit if hit this component "on the other side" */
+ filter_ctx.origin_component = cc->cc_id;
+ /* Limit search radius. Only +Z moves are permitted */
+ FOR_EACH(i, 0, 2) {
+ ASSERT(lower[i] <= origin[i] && origin[i] <= upper[i]);
+ rrr[i] = MMIN(origin[i] - lower[i], upper[i] - origin[i]);
+ }
+ ASSERT(lower[2] <= origin[2] && origin[2] <= upper[2]);
+ rrr[2] = upper[2] - origin[2];
+ r = f3_len(rrr) + FLT_EPSILON; /* Ensure r > 0 */
+ tmp_res = s3d_scene_view_closest_point(s3d_view, origin, r, &filter_ctx,
+ &hit);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ continue;
+ }
+ /* If no hit, the component is facing an infinite medium */
+ if(S3D_HIT_NONE(&hit)) {
+ cc->cc_group_root = CC_GROUP_ROOT_INFINITE;
+ cc->enclosure_id = 0;
+ } else {
+ /* If hit, group this component */
+ cc->cc_group_root = filter_ctx.hit_component;
+ ASSERT(cc->cc_group_root < cc_count);
+ }
+ }
+ /* Implicit barrier here */
+ if(*res != RES_OK) return;
+
+ /* One thread post-processes links to group connex components */
+ #pragma omp single
+ {
+ res_T tmp_res = RES_OK;
+ size_t ec = (size_t)ATOMIC_GET(next_enclosure_id);
+ ASSERT(ec <= ENCLOSURE_MAX__);
+ scn->analyze.enclosures_count = (enclosure_id_t)ec;
+ tmp_res = darray_enclosure_resize(&scn->analyze.enclosures,
+ scn->analyze.enclosures_count);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ } else {
+ struct enclosure_data* enclosures
+ = darray_enclosure_data_get(&scn->analyze.enclosures);
+ FOR_EACH(ccc, 0, (int64_t)cc_count) {
+ component_id_t c = (component_id_t)ccc;
+ struct cc_descriptor* const cc = descriptors[c];
+ const struct cc_descriptor* other_desc = cc;
+ struct enclosure_data* enc;
+#ifndef NDEBUG
+ component_id_t cc_cpt = 0;
+#endif
+
+ while(other_desc->enclosure_id == CC_GROUP_ID_NONE) {
+ ASSERT(other_desc->cc_group_root < cc_count);
+ other_desc = descriptors[other_desc->cc_group_root];
+ /* Cannot have more components in cc than cc_count! */
+ ASSERT(++cc_cpt <= cc_count);
+ }
+ ASSERT(other_desc->cc_group_root != CC_GROUP_ROOT_NONE);
+ ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE);
+ cc->cc_group_root = other_desc->cc_group_root;
+ cc->enclosure_id = other_desc->enclosure_id;
+ enc = enclosures + cc->enclosure_id;
+ ++enc->cc_count;
+ /* Linked list of componnents */
+ enc->first_component = cc->cc_id;
+ enc->side_range.first = MMIN(enc->side_range.first, cc->side_range.first);
+ enc->side_range.last = MMAX(enc->side_range.last, cc->side_range.last);
+ enc->side_count += cc->side_count;
+ tmp_res = bool_array_of_media_merge(&enc->tmp_enclosed_media, cc->media,
+ scn->next_medium_idx + 1);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
+ }
+ }
+ }
+ /* Implicit barrier here */
+}
+
+static void
+collect_and_link_neighbours
+ (struct senc3d_scene* scn,
+ struct trgside* trgsides,
+ struct darray_triangle_tmp* triangles_tmp_array,
+ struct darray_frontier_edge* frontiers,
+ /* Shared error status.
+ * We accept to overwrite an error with a different error */
+ res_T* res)
+{
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ const struct triangle_in* triangles_in;
+ struct triangle_tmp* triangles_tmp;
+ const union double3* vertices;
+ const int thread_count = omp_get_num_threads();
+ const int rank = omp_get_thread_num();
+ /* Htable used to give an id to edges */
+ struct htable_edge_id edge_ids;
+ /* Array to keep neighbourhood of edges
+ * Resize/Push operations on neighbourhood_by_edge are valid in the
+ * openmp block because a given neighbourhood is only processed
+ * by a single thread */
+ struct darray_neighbourhood neighbourhood_by_edge;
+ edge_id_t edge_count;
+ edge_id_t nbedges_guess;
+ edge_id_t e;
+ trg_id_t t;
+ size_t sz;
+ res_T tmp_res;
+
+ ASSERT(scn && trgsides && triangles_tmp_array && frontiers && res);
+ ASSERT((size_t)scn->nverts + (size_t)scn->ntris + 2 <= EDGE_MAX__);
+
+ htable_edge_id_init(scn->dev->allocator, &edge_ids);
+ darray_neighbourhood_init(scn->dev->allocator, &neighbourhood_by_edge);
+
+ triangles_in = darray_triangle_in_cdata_get(&scn->triangles_in);
+ triangles_tmp = darray_triangle_tmp_data_get(triangles_tmp_array);
+ vertices = darray_position_cdata_get(&scn->vertices);
+
+ ASSERT(scn->ntris == darray_triangle_tmp_size_get(triangles_tmp_array));
+
+ /* Make some room for edges. */
+ nbedges_guess = 4 + (thread_count == 1
+ ? (edge_id_t)(scn->nverts + scn->ntris)
+ : (edge_id_t)((scn->nverts + scn->ntris) / (0.75 * thread_count)));
+ OK2(darray_neighbourhood_reserve(&neighbourhood_by_edge, nbedges_guess));
+ OK2(htable_edge_id_reserve(&edge_ids, nbedges_guess));
+
+ /* Loop on triangles to register edges.
+ * All threads considering all the edges and processing some */
+ FOR_EACH(t, 0, scn->ntris) {
+ struct trg_edge edge;
+ uchar ee;
+ FOR_EACH(ee, 0, 3) {
+ edge_id_t* p_id;
+ size_t n_sz;
+ struct edge_neighbourhood* neighbourhood;
+ struct neighbour_info* info;
+ const vrtx_id_t v0 = triangles_in[t].vertice_id[ee];
+ const vrtx_id_t v1 = triangles_in[t].vertice_id[(ee + 1) % 3];
+ /* Process only "my" edges! */
+ const int64_t h =
+ /* v0,v1 and v1,v0 must give the same hash!!! */
+ v0 + v1 + (int64_t)MMIN(v0, v1);
+ if(h % thread_count != rank) continue;
+ /* Create edge. */
+ set_edge(v0, v1, &edge, &triangles_tmp[t].reversed_edge[ee]);
+ /* Find edge id; create it if not already done. */
+ p_id = htable_edge_id_find(&edge_ids, &edge);
+ if(p_id) {
+ neighbourhood =
+ darray_neighbourhood_data_get(&neighbourhood_by_edge) + *p_id;
+ ASSERT(neighbourhood->edge.vrtx0 == edge.vrtx0
+ && neighbourhood->edge.vrtx1 == edge.vrtx1);
+ } else {
+ /* Create id */
+ edge_id_t id;
+ sz = htable_edge_id_size_get(&edge_ids);
+ ASSERT(sz <= EDGE_MAX__);
+ id = (edge_id_t)sz;
+ ASSERT(htable_edge_id_size_get(&edge_ids)
+ == darray_neighbourhood_size_get(&neighbourhood_by_edge));
+ OK2(htable_edge_id_set(&edge_ids, &edge, &id));
+ OK2(darray_neighbourhood_resize(&neighbourhood_by_edge, 1 + sz));
+ neighbourhood = darray_neighbourhood_data_get(&neighbourhood_by_edge) + sz;
+ /* Add neighbour info to a newly created edge's neighbour list */
+ neighbourhood->edge = edge;
+ ASSERT(darray_neighbour_size_get(&neighbourhood->neighbours) == 0);
+ /* Just a guess: few edges will have less than 2 neighbours */
+ OK2(darray_neighbour_reserve(&neighbourhood->neighbours, 2));
+ }
+ /* Add neighbour info to neighbourhood */
+ n_sz = darray_neighbour_size_get(&neighbourhood->neighbours);
+ OK2(darray_neighbour_resize(&neighbourhood->neighbours, 1 + n_sz));
+ info = darray_neighbour_data_get(&neighbourhood->neighbours) + n_sz;
+ info->trg_id = t;
+ info->common_edge_rank = ee;
+ }
+ } /* No barrier here. */
+
+ /* Loop on collected edges.
+ * For each edge sort triangle sides by rotation angle
+ * and connect neighbours. */
+ sz = darray_neighbourhood_size_get(&neighbourhood_by_edge);
+ ASSERT(sz <= EDGE_MAX__);
+ edge_count = (edge_id_t)sz;
+ FOR_EACH(e, 0, edge_count) {
+ double edge[3], common_edge[3], basis[9], norm, max_z, maxz_edge, a;
+ vrtx_id_t v0, v1, v2;
+ struct edge_neighbourhood* neighbourhood
+ = darray_neighbourhood_data_get(&neighbourhood_by_edge) + e;
+ struct darray_neighbour* neighbour_list = &neighbourhood->neighbours;
+ side_id_t i, neighbour_count;
+ sz = darray_neighbour_size_get(neighbour_list);
+ ASSERT(sz > 0 && sz <= SIDE_MAX__);
+ neighbour_count = (side_id_t)sz;
+ ASSERT(neighbour_count);
+ v0 = neighbourhood->edge.vrtx0;
+ v1 = neighbourhood->edge.vrtx1;
+ d3_sub(common_edge, vertices[v1].vec, vertices[v0].vec);
+ maxz_edge = MMAX(vertices[v0].pos.z, vertices[v1].pos.z);
+ norm = d3_normalize(common_edge, common_edge);
+ ASSERT(norm); (void)norm;
+ d33_basis(basis, common_edge);
+ d33_inverse(basis, basis);
+ FOR_EACH(i, 0, neighbour_count) {
+ struct neighbour_info* neighbour_info
+ = darray_neighbour_data_get(neighbour_list) + i;
+ const trg_id_t crt_id = neighbour_info->trg_id;
+ const uchar crt_edge = neighbour_info->common_edge_rank;
+ const struct triangle_in* trg_in = triangles_in + crt_id;
+ struct triangle_tmp* neighbour = triangles_tmp + crt_id;
+ union double3 n; /* Geometrical normal to neighbour triangle */
+ const int is_reversed = neighbour->reversed_edge[crt_edge];
+ v2 = trg_in->vertice_id[(crt_edge + 2) % 3];
+ max_z = MMAX(vertices[v2].pos.z, maxz_edge);
+ ASSERT(neighbour->max_z <= max_z);
+ neighbour->max_z = max_z;
+ /* Compute rotation angle around common edge */
+ d3_sub(edge, vertices[v2].vec, vertices[v0].vec);
+ d33_muld3(edge, basis, edge);
+ ASSERT(d3_len(edge) && (edge[0] || edge[1]));
+ neighbour_info->angle = atan2(edge[1], edge[0]);
+ if(is_reversed)
+ d3(n.vec, +edge[1], -edge[0], 0);
+ else
+ d3(n.vec, -edge[1], +edge[0], 0);
+ if(neighbour_info->angle < 0) neighbour_info->angle += 2 * PI;
+
+ /* Normal orientation calculation. */
+ if(neighbour_info->angle <= PI / 4) {
+ ASSERT(n.pos.y);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
+ } else if(neighbour_info->angle <= 3 * PI / 4) {
+ ASSERT(n.pos.x);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.x < 0);
+ } else if(neighbour_info->angle <= 5 * PI / 4) {
+ ASSERT(n.pos.y);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y < 0);
+ } else if(neighbour_info->angle <= 7 * PI / 4) {
+ ASSERT(n.pos.x);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.x > 0);
+ } else {
+ ASSERT(n.pos.y);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
+ }
+ }
+ /* Sort triangles by rotation angle */
+ qsort(darray_neighbour_data_get(neighbour_list), neighbour_count,
+ sizeof(struct neighbour_info), neighbour_cmp);
+ /* Link sides.
+ * Create cycles of sides by neighbourhood around common edge. */
+ a = -DBL_MAX;
+ FOR_EACH(i, 0, neighbour_count) {
+ /* Neighbourhood info for current pair of triangles */
+ const struct neighbour_info* current
+ = darray_neighbour_cdata_get(neighbour_list) + i;
+ const struct neighbour_info* ccw_neighbour
+ = darray_neighbour_cdata_get(neighbour_list) + (i + 1) % neighbour_count;
+ /* Rank of the edge of interest in triangles */
+ const uchar crt_edge = current->common_edge_rank;
+ /* Here ccw refers to the rotation around the common edge
+ * and has nothing to do with vertices order in triangle definition
+ * nor Front/Back side convention */
+ const uchar ccw_edge = ccw_neighbour->common_edge_rank;
+ /* User id of current triangles */
+ const trg_id_t crt_id = current->trg_id;
+ const trg_id_t ccw_id = ccw_neighbour->trg_id;
+ /* Facing sides of triangles */
+ const int front = ((scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0);
+ const enum senc3d_side crt_side
+ = current->normal_toward_next_neighbour == front ? SENC3D_FRONT : SENC3D_BACK;
+ const enum senc3d_side ccw_side
+ = ccw_neighbour->normal_toward_next_neighbour == front ?
+ SENC3D_BACK : SENC3D_FRONT;
+ /* Index of sides in trgsides */
+ const side_id_t crt_side_idx = TRGIDxSIDE_2_TRGSIDE(crt_id, crt_side);
+ const side_id_t ccw_side_idx = TRGIDxSIDE_2_TRGSIDE(ccw_id, ccw_side);
+ /* Side ptrs */
+ struct trgside* const p_crt_side = trgsides + crt_side_idx;
+ struct trgside* const p_ccw_side = trgsides + ccw_side_idx;
+ /* Check that angle is a discriminant property */
+ ASSERT(a <= current->angle); /* Is sorted */
+ if(a == current->angle) {
+ /* Two consecutive triangles with same angle! */
+ const struct neighbour_info* previous;
+ trg_id_t prev_id;
+ ASSERT(i > 0);
+ previous = darray_neighbour_cdata_get(neighbour_list) + i - 1;
+ prev_id = previous->trg_id;
+ log_err(scn->dev,
+ "%s: found 2 overlying triangles ("PRTF_TRG" & "PRTF_TRG").\n",
+ FUNC_NAME, crt_id, prev_id);
+ tmp_res = RES_BAD_OP;
+ goto tmp_error;
+ }
+ a = current->angle;
+ /* Link sides */
+ ASSERT(p_crt_side->facing_side_id[crt_edge] == SIDE_NULL__);
+ ASSERT(p_ccw_side->facing_side_id[ccw_edge] == SIDE_NULL__);
+ p_crt_side->facing_side_id[crt_edge] = ccw_side_idx;
+ p_ccw_side->facing_side_id[ccw_edge] = crt_side_idx;
+ /* Record media */
+ ASSERT(p_crt_side->medium == MEDIUM_NULL__
+ || p_crt_side->medium == triangles_in[crt_id].medium[crt_side]);
+ ASSERT(p_ccw_side->medium == MEDIUM_NULL__
+ || p_ccw_side->medium == triangles_in[ccw_id].medium[ccw_side]);
+ p_crt_side->medium = triangles_in[crt_id].medium[crt_side];
+ p_ccw_side->medium = triangles_in[ccw_id].medium[ccw_side];
+ ASSERT(p_crt_side->medium == SENC3D_UNSPECIFIED_MEDIUM
+ || p_crt_side->medium < scn->next_medium_idx);
+ ASSERT(p_ccw_side->medium == SENC3D_UNSPECIFIED_MEDIUM
+ || p_ccw_side->medium < scn->next_medium_idx);
+ /* Detect triangles that could surround a hole:
+ * - single triangle on (one of) its edge
+ * - different media on its sides */
+ if(neighbour_count == 1
+ && p_crt_side->medium != p_ccw_side->medium)
+#pragma omp critical
+ {
+ struct frontier_edge frontier_edge;
+ frontier_edge.trg = crt_id;
+ frontier_edge.vrtx0 = v0;
+ frontier_edge.vrtx1 = v1;
+ darray_frontier_edge_push_back(frontiers, &frontier_edge);
+ }
+ }
+ }
+tmp_error:
+ if(tmp_res != RES_OK) *res = tmp_res;
+ /* Threads are allowed to return whitout sync. */
+ htable_edge_id_release(&edge_ids);
+ darray_neighbourhood_release(&neighbourhood_by_edge);
+}
+
+static void
+build_result
+ (struct senc3d_scene* scn,
+ const struct darray_ptr_component_descriptor* connex_components,
+ const struct darray_triangle_comp* triangles_comp_array,
+ struct darray_frontier_edge* frontiers,
+ /* Shared error status.
+ * We accept to overwrite an error with a different error */
+ res_T* res)
+{
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ struct mem_allocator* alloc;
+ struct cc_descriptor* const* cc_descriptors;
+ struct enclosure_data* enclosures;
+ const struct triangle_in* triangles_in;
+ struct triangle_enc* triangles_enc;
+ const struct triangle_comp* triangles_comp;
+ struct htable_vrtx_id vtable;
+ int output_normal_in, normals_front, normals_back;
+ int64_t tt;
+ int64_t ee;
+
+ ASSERT(scn && connex_components && triangles_comp_array && frontiers && res);
+
+ alloc = scn->dev->allocator;
+ output_normal_in = (scn->convention & SENC3D_CONVENTION_NORMAL_INSIDE) != 0;
+ normals_front = (scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0;
+ normals_back = (scn->convention & SENC3D_CONVENTION_NORMAL_BACK) != 0;
+ ASSERT(normals_back != normals_front);
+ ASSERT(output_normal_in
+ != ((scn->convention & SENC3D_CONVENTION_NORMAL_OUTSIDE) != 0));
+ ASSERT(darray_ptr_component_descriptor_size_get(connex_components)
+ <= COMPONENT_MAX__);
+ cc_descriptors = darray_ptr_component_descriptor_cdata_get(connex_components);
+ enclosures = darray_enclosure_data_get(&scn->analyze.enclosures);
+ triangles_in = darray_triangle_in_cdata_get(&scn->triangles_in);
+ triangles_comp = darray_triangle_comp_cdata_get(triangles_comp_array);
+
+ #pragma omp single
+ {
+ res_T tmp_res =
+ darray_triangle_enc_resize(&scn->analyze.triangles_enc, scn->ntris);
+ if(tmp_res != RES_OK) *res = tmp_res;
+ }/* Implicit barrier here. */
+ if(*res != RES_OK) return;
+ triangles_enc = darray_triangle_enc_data_get(&scn->analyze.triangles_enc);
+
+ /* Build global enclosure information */
+ #pragma omp for
+ for(tt = 0; tt < (int64_t)scn->ntris; tt++) {
+ trg_id_t t = (trg_id_t)tt;
+ const component_id_t cf_id = triangles_comp[t].component[SENC3D_FRONT];
+ const component_id_t cb_id = triangles_comp[t].component[SENC3D_BACK];
+ const struct cc_descriptor* cf = cc_descriptors[cf_id];
+ const struct cc_descriptor* cb = cc_descriptors[cb_id];
+ const enclosure_id_t ef_id = cf->enclosure_id;
+ const enclosure_id_t eb_id = cb->enclosure_id;
+ ASSERT(triangles_enc[t].enclosure[SENC3D_FRONT] == ENCLOSURE_NULL__);
+ triangles_enc[t].enclosure[SENC3D_FRONT] = ef_id;
+ ASSERT(triangles_enc[t].enclosure[SENC3D_BACK] == ENCLOSURE_NULL__);
+ triangles_enc[t].enclosure[SENC3D_BACK] = eb_id;
+ }
+ /* Implicit barrier here */
+
+ /* Resize/push operations on enclosure's fields are valid in the
+ * openmp block as a given enclosure is processed by a single thread */
+ htable_vrtx_id_init(alloc, &vtable);
+
+ ASSERT(scn->analyze.enclosures_count <= ENCLOSURE_MAX__);
+ #pragma omp for schedule(dynamic) nowait
+ for(ee = 0; ee < (int64_t)scn->analyze.enclosures_count; ee++) {
+ const enclosure_id_t e = (enclosure_id_t)ee;
+ struct enclosure_data* enc = enclosures + e;
+ trg_id_t fst_idx = 0;
+ trg_id_t sgd_idx = enc->side_count;
+ trg_id_t t;
+ medium_id_t m;
+ res_T tmp_res = RES_OK;
+ ASSERT(enc->first_component
+ < darray_ptr_component_descriptor_size_get(connex_components));
+ ASSERT(cc_descriptors[enc->first_component]->cc_id
+ == enc->first_component);
+
+ if(*res != RES_OK) continue;
+ ASSERT(e <= ENCLOSURE_MAX__);
+ enc->header.enclosure_id = (enclosure_id_t)e; /* Back to API type */
+ ASSERT(cc_descriptors[enc->first_component]->enclosure_id
+ == enc->header.enclosure_id);
+ enc->header.is_infinite = (e == 0);
+
+ ASSERT(enc->header.enclosed_media_count < 1 + scn->next_medium_idx);
+ OK2(bool_array_of_media_to_darray_media
+ (&enc->enclosed_media, &enc->tmp_enclosed_media, scn->next_medium_idx));
+ ASSERT(darray_media_size_get(&enc->enclosed_media) <= MEDIUM_MAX__);
+ enc->header.enclosed_media_count
+ = (medium_id_t)darray_media_size_get(&enc->enclosed_media);
+ darray_uchar_purge(&enc->tmp_enclosed_media);
+
+ /* Add this enclosure in relevant by-medium lists */
+ FOR_EACH(m, 0, enc->header.enclosed_media_count) {
+ medium_id_t medium = darray_media_cdata_get(&enc->enclosed_media)[m];
+ size_t m_idx = medium_id_2_medium_idx(medium);
+ struct darray_enc_id* enc_ids_array_by_medium;
+ ASSERT(medium == SENC3D_UNSPECIFIED_MEDIUM || medium < scn->next_medium_idx);
+ ASSERT(darray_enc_ids_array_size_get(&scn->analyze.enc_ids_array_by_medium)
+ == 1 + scn->next_medium_idx);
+ enc_ids_array_by_medium =
+ darray_enc_ids_array_data_get(&scn->analyze.enc_ids_array_by_medium) + m_idx;
+ #pragma omp critical
+ {
+ tmp_res = darray_enc_id_push_back(enc_ids_array_by_medium, &e);
+ }
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
+ }
+ if(*res != RES_OK) continue;
+
+ /* Build side and vertex lists. */
+ OK2(darray_sides_enc_resize(&enc->sides, enc->side_count));
+ /* Size is just a int */
+ OK2(darray_vrtx_id_reserve(&enc->vertices,
+ (size_t)(enc->side_count * 0.6)));
+ /* New vertex numbering scheme local to the enclosure */
+ htable_vrtx_id_clear(&vtable);
+ ASSERT(scn->ntris == darray_triangle_in_size_get(&scn->triangles_in));
+ /* Put at the end the back-faces of triangles that also have their
+ * front-face in the list. */
+ for(t = TRGSIDE_2_TRG(enc->side_range.first);
+ t <= TRGSIDE_2_TRG(enc->side_range.last);
+ t++)
+ {
+ const struct triangle_in* trg_in = triangles_in + t;
+ struct side_enc* side_enc;
+ vrtx_id_t vertice_id[3];
+ int i;
+ if(triangles_enc[t].enclosure[SENC3D_FRONT] != e
+ && triangles_enc[t].enclosure[SENC3D_BACK] != e)
+ continue;
+ ++enc->header.unique_primitives_count;
+
+ FOR_EACH(i, 0, 3) {
+ vrtx_id_t* p_id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i);
+ if(p_id) {
+ vertice_id[i] = *p_id; /* Known vertex */
+ } else {
+ /* Create new association */
+ size_t tmp = htable_vrtx_id_size_get(&vtable);
+ ASSERT(tmp == darray_vrtx_id_size_get(&enc->vertices));
+ ASSERT(tmp < VRTX_MAX__);
+ vertice_id[i] = (vrtx_id_t)tmp;
+ OK2(htable_vrtx_id_set(&vtable, trg_in->vertice_id + i,
+ vertice_id + i));
+ OK2(darray_vrtx_id_push_back(&enc->vertices, trg_in->vertice_id + i));
+ ++enc->header.vertices_count;
+ }
+ }
+ ASSERT(triangles_enc[t].enclosure[SENC3D_FRONT] == e
+ || triangles_enc[t].enclosure[SENC3D_BACK] == e);
+ if(triangles_enc[t].enclosure[SENC3D_FRONT] == e) {
+ /* Front side of the original triangle is member of the enclosure */
+ int input_normal_in = normals_front;
+ int revert_triangle = (input_normal_in != output_normal_in);
+ ++enc->header.primitives_count;
+ side_enc = darray_sides_enc_data_get(&enc->sides) + fst_idx++;
+ FOR_EACH(i, 0, 3) {
+ int ii = revert_triangle ? 2 - i : i;
+ side_enc->vertice_id[i] = vertice_id[ii];
+ }
+ side_enc->side_id = TRGIDxSIDE_2_TRGSIDE(t, SENC3D_FRONT);
+ }
+ if(triangles_enc[t].enclosure[SENC3D_BACK] == e) {
+ /* Back side of the original triangle is member of the enclosure */
+ int input_normal_in = normals_back;
+ int revert_triangle = (input_normal_in != output_normal_in);
+ ++enc->header.primitives_count;
+ /* If both sides are in the enclosure, put the second side at the end */
+ side_enc = darray_sides_enc_data_get(&enc->sides) +
+ ((triangles_enc[t].enclosure[SENC3D_FRONT] == e) ? --sgd_idx : fst_idx++);
+ FOR_EACH(i, 0, 3) {
+ int ii = revert_triangle ? 2 - i : i;
+ side_enc->vertice_id[i] = vertice_id[ii];
+ }
+ side_enc->side_id = TRGIDxSIDE_2_TRGSIDE(t, SENC3D_BACK);
+ }
+ if(fst_idx == sgd_idx) break;
+ }
+ continue;
+ tmp_error:
+ ASSERT(tmp_res != RES_OK);
+ *res = tmp_res;
+ } /* No barrier here */
+ htable_vrtx_id_release(&vtable);
+ /* The first thread here copies frontiers into descriptor */
+#pragma omp single nowait
+ darray_frontier_edge_copy_and_clear(&scn->analyze.frontiers, frontiers);
+ /* No barrier here */
+}
+
+/******************************************************************************
+ * Exported functions
+ *****************************************************************************/
+res_T
+scene_analyze
+ (struct senc3d_scene* scn)
+{
+ /* By triangle tmp data */
+ struct darray_triangle_tmp triangles_tmp;
+ char triangles_tmp_initialized = 0;
+ /* Array of connex components.
+ * They are refered to by arrays of ids. */
+ struct darray_ptr_component_descriptor connex_components;
+ char connex_components_initialized = 0;
+ /* Array of frontiers edges */
+ struct darray_frontier_edge frontiers;
+ char frontiers_initialized = 0;
+ /* Store by-triangle components */
+ struct darray_triangle_comp triangles_comp;
+ char triangles_comp_initialized = 0;
+ /* Array of triangle sides. */
+ struct trgside* trgsides = NULL;
+ struct s3d_scene_view* s3d_view = NULL;
+ /* Atomic counters to share beetwen threads */
+ ATOMIC component_count = 0;
+ ATOMIC next_enclosure_id = 1;
+ res_T res = RES_OK;
+ res_T res2 = RES_OK;
+
+ if(!scn) return RES_BAD_ARG;
+
+ if(!scn->ntris) goto exit;
+
+ darray_triangle_tmp_init(scn->dev->allocator, &triangles_tmp);
+ triangles_tmp_initialized = 1;
+ darray_frontier_edge_init(scn->dev->allocator, &frontiers);
+ frontiers_initialized = 1;
+
+ OK(darray_triangle_tmp_resize(&triangles_tmp, scn->ntris));
+ trgsides
+ = MEM_CALLOC(scn->dev->allocator, 2 * scn->ntris, sizeof(struct trgside));
+ if(!trgsides) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+#ifndef NDEBUG
+ else {
+ /* Initialise trgsides to allow assert code */
+ size_t i;
+ FOR_EACH(i, 0, 2 * scn->ntris)
+ init_trgside(scn->dev->allocator, trgsides + i);
+ }
+#endif
+
+ /* The end of the analyze is multithreaded */
+ ASSERT(scn->dev->nthreads > 0);
+ #pragma omp parallel num_threads(scn->dev->nthreads)
+ {
+ /* Step 1: build neighbourhoods */
+ collect_and_link_neighbours(scn, trgsides, &triangles_tmp, &frontiers,
+ &res);
+ /* No barrier at the end of step 1: data used in step 1 cannot be
+ * released / data produced by step 1 cannot be used
+ * until next sync point */
+
+ /* The first thread here allocates some data.
+ * Barrier needed at the end to ensure data created before any use. */
+ #pragma omp single
+ {
+ res_T tmp_res = RES_OK;
+ darray_ptr_component_descriptor_init(scn->dev->allocator,
+ &connex_components);
+ connex_components_initialized = 1;
+ /* Just a hint; to limit contention */
+ OK2(darray_ptr_component_descriptor_reserve(&connex_components,
+ 2 + 2 * scn->next_medium_idx));
+ darray_triangle_comp_init(scn->dev->allocator, &triangles_comp);
+ triangles_comp_initialized = 1;
+ OK2(darray_triangle_comp_resize(&triangles_comp, scn->ntris));
+ tmp_error:
+ if(tmp_res != RES_OK) res2 = tmp_res;
+ }
+ /* Implicit barrier here: constraints on step 1 data are now met */
+
+ if(res != RES_OK || res2 != RES_OK) {
+ #pragma omp single nowait
+ {
+ if(res != RES_OK) {
+ log_err(scn->dev,
+ "%s: could not build neighbourhoods from scene.\n", FUNC_NAME);
+ } else {
+ res = res2;
+ }
+ }
+ goto error_;
+ }
+
+ /* Step 2: extract triangle connex components */
+ extract_connex_components(scn, trgsides, &connex_components,
+ &triangles_tmp, &triangles_comp, &s3d_view, &component_count, &res);
+ /* No barrier at the end of step 2: data used in step 2 cannot be
+ * released / data produced by step 2 cannot be used
+ * until next sync point */
+
+ #pragma omp barrier
+ /* Constraints on step 2 data are now met */
+
+ if(res != RES_OK) {
+ #pragma omp single nowait
+ {
+ log_err(scn->dev,
+ "%s: could not extract connex components from scene.\n", FUNC_NAME);
+ } /* No barrier here */
+ goto error_;
+ }
+
+ /* One thread releases some data before going to step 3,
+ * the others go to step 3 without sync */
+ #pragma omp single nowait
+ {
+ darray_triangle_tmp_release(&triangles_tmp);
+ triangles_tmp_initialized = 0;
+ } /* No barrier here */
+
+ /* Step 3: group components */
+ group_connex_components(scn, &triangles_comp, &connex_components, s3d_view,
+ &next_enclosure_id, &res);
+ /* Barrier at the end of step 3: data used in step 3 can be released /
+ * data produced by step 3 can be used */
+
+ if(res != RES_OK) {
+ #pragma omp single nowait
+ {
+ log_err(scn->dev,
+ "%s: could not group connex components from scene.\n", FUNC_NAME);
+ }
+ goto error_;
+ }
+
+ /* One thread releases some data before going to step 4,
+ * the others go to step 4 without sync */
+ #pragma omp single nowait
+ {
+ if(s3d_view) S3D(scene_view_ref_put(s3d_view));
+ s3d_view = NULL;
+ } /* No barrier here */
+
+ /* Step 4: Build result */
+ build_result(scn, &connex_components, &triangles_comp, &frontiers, &res);
+ /* No barrier at the end of step 4: data used in step 4 cannot be
+ * released / data produced by step 4 cannot be used
+ * until next sync point */
+
+ #pragma omp barrier
+ /* Constraints on step 4 data are now met */
+
+ if(res != RES_OK) {
+ #pragma omp single nowait
+ {
+ log_err(scn->dev, "%s: could not build result.\n", FUNC_NAME);
+ }
+ goto error_;
+ }
+
+ /* Some threads release data */
+ #pragma omp sections nowait
+ {
+ #pragma omp section
+ {
+ custom_darray_ptr_component_descriptor_release(&connex_components);
+ connex_components_initialized = 0;
+ }
+ #pragma omp section
+ {
+ darray_triangle_comp_release(&triangles_comp);
+ triangles_comp_initialized = 0;
+ }
+ } /* No barrier here */
+
+error_:
+ ;
+ } /* Implicit barrier here */
+
+ if(res != RES_OK) goto error;
+exit:
+ if(connex_components_initialized)
+ custom_darray_ptr_component_descriptor_release(&connex_components);
+ if(s3d_view) S3D(scene_view_ref_put(s3d_view));
+ if(triangles_tmp_initialized) darray_triangle_tmp_release(&triangles_tmp);
+ if(triangles_comp_initialized) darray_triangle_comp_release(&triangles_comp);
+ if(frontiers_initialized)
+ darray_frontier_edge_release(&frontiers);
+ if(trgsides) MEM_RM(scn->dev->allocator, trgsides);
+
+ return res;
+error:
+ goto exit;
+}
diff --git a/src/senc3d_scene_analyze_c.h b/src/senc3d_scene_analyze_c.h
@@ -0,0 +1,201 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC3D_SCNENE_ANALYZE_C_H
+#define SENC3D_SCNENE_ANALYZE_C_H
+
+#include "senc3d_internal_types.h"
+#include "senc3d.h"
+
+#include <rsys/mem_allocator.h>
+#include <rsys/hash_table.h>
+#include <rsys/double3.h>
+
+struct senc3d_scene;
+
+static FINLINE void
+init_trgside(struct mem_allocator* alloc, struct trgside* data)
+{
+ int i;
+ ASSERT(data); (void)alloc;
+ FOR_EACH(i, 0, 3) data->facing_side_id[i] = SIDE_NULL__;
+ data->medium = MEDIUM_NULL__;
+}
+
+#define DARRAY_NAME side_id
+#define DARRAY_DATA side_id_t
+#include <rsys/dynamic_array.h>
+
+/* Descriptors for connex component.
+ * Define lists of trg sides starting from a given head.
+ * Also keeps the maximum z info of the component
+ * and the list of media found */
+struct cc_descriptor {
+ /* Does this component is an outer border of an enclosure or an inner one? */
+ char is_outer_border;
+ vrtx_id_t max_z_vrtx_id; /* id of the vrtx with max z value */
+ side_id_t side_count;
+ /* Used when grouping components to form enclosures */
+ component_id_t cc_id;
+ component_id_t cc_group_root;
+ enclosure_id_t enclosure_id;
+ /* Range of sides member of this component */
+ struct side_range side_range;
+ /* Media used by this component */
+ uchar* media;
+};
+extern const struct cc_descriptor CC_DESCRIPTOR_NULL;
+
+static FINLINE void
+cc_descriptor_init
+ (struct mem_allocator* alloc,
+ struct cc_descriptor* data)
+{
+ ASSERT(data);
+ (void)alloc;
+ *data = CC_DESCRIPTOR_NULL;
+}
+
+static FINLINE void
+ptr_component_descriptor_init
+ (struct mem_allocator* alloc,
+ struct cc_descriptor** data)
+{
+ (void)alloc;
+ ASSERT(data);
+ *data = NULL;
+}
+
+#define DARRAY_NAME ptr_component_descriptor
+#define DARRAY_DATA struct cc_descriptor*
+#define DARRAY_FUNCTOR_INIT ptr_component_descriptor_init
+#include <rsys/dynamic_array.h>
+
+/* Need allocator to free array elts: cannot rely on standard
+ * darray release stuff */
+static FINLINE void
+custom_darray_ptr_component_descriptor_release
+ (struct darray_ptr_component_descriptor* array)
+{
+ size_t c, cc_count;
+ struct cc_descriptor** components;
+ if(!array) return;
+ cc_count = darray_ptr_component_descriptor_size_get(array);
+ components = darray_ptr_component_descriptor_data_get(array);
+ FOR_EACH(c, 0, cc_count) {
+ if(!components[c]) continue;
+ MEM_RM(array->allocator, components[c]->media);
+ MEM_RM(array->allocator, components[c]);
+ }
+ darray_ptr_component_descriptor_release(array);
+}
+
+/* Triangle information.
+ * Depending on lifespan, information is kept in different places:
+ * - triangle_in for user provided information (kept in scene)
+ * - triangle_tmp for tmp information (kept until triangle_comp is ready)
+ * - triangle_comp for information describing components (kept until
+ * triangle_enc is ready)
+ * - triangle_enc for information describing enclosures (kept in
+ * struct descriptor). */
+struct triangle_tmp {
+ /* Are the edges of the triangle defined in the same order than
+ * the edges they are linked to? */
+ uchar reversed_edge[3];
+ double max_z;
+};
+
+#ifndef NDEBUG
+static FINLINE void
+triangle_tmp_init(struct mem_allocator* alloc, struct triangle_tmp* trg) {
+ int i;
+ (void)alloc;
+ ASSERT(trg);
+ FOR_EACH(i, 0, 3) trg->reversed_edge[i] = UCHAR_MAX;
+ trg->max_z = -DBL_MAX;
+}
+#define DARRAY_FUNCTOR_INIT triangle_tmp_init
+#endif
+
+#define DARRAY_NAME triangle_tmp
+#define DARRAY_DATA struct triangle_tmp
+#include <rsys/dynamic_array.h>
+
+#define HTABLE_NAME edge_id
+#define HTABLE_KEY struct trg_edge
+#define HTABLE_DATA edge_id_t
+#define HTABLE_KEY_FUNCTOR_EQ edge_eq
+#include <rsys/hash_table.h>
+
+struct neighbour_info {
+ double angle;
+ trg_id_t trg_id;
+ /* Rank of the edge in the triangle (in [0 2]) */
+ uchar common_edge_rank;
+ /* Does the geometrical normal point towards the next neighbour
+ * (if not, it points towards the previous one)? */
+ uchar normal_toward_next_neighbour;
+};
+#define DARRAY_NAME neighbour
+#define DARRAY_DATA struct neighbour_info
+#include <rsys/dynamic_array.h>
+
+struct edge_neighbourhood {
+ struct trg_edge edge;
+ struct darray_neighbour neighbours;
+};
+static void
+neighbourhood_init
+ (struct mem_allocator* alloc,
+ struct edge_neighbourhood* n)
+{
+ ASSERT(n);
+ darray_neighbour_init(alloc, &n->neighbours);
+}
+static res_T
+neighbourhood_copy
+ (struct edge_neighbourhood* dst,
+ const struct edge_neighbourhood* src)
+{
+ ASSERT(src && dst);
+ dst->edge = src->edge;
+ return darray_neighbour_copy(&dst->neighbours, &src->neighbours);
+}
+static void
+neighbourhood_release(struct edge_neighbourhood* n) {
+ ASSERT(n);
+ darray_neighbour_release(&n->neighbours);
+}
+static res_T
+neighbourhood_copy_and_release
+ (struct edge_neighbourhood* dst,
+ struct edge_neighbourhood* src)
+{
+ ASSERT(src && dst);
+ dst->edge = src->edge;
+ return darray_neighbour_copy_and_release(&dst->neighbours, &src->neighbours);
+}
+#define DARRAY_NAME neighbourhood
+#define DARRAY_DATA struct edge_neighbourhood
+#define DARRAY_FUNCTOR_INIT neighbourhood_init
+#define DARRAY_FUNCTOR_COPY neighbourhood_copy
+#define DARRAY_FUNCTOR_RELEASE neighbourhood_release
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE neighbourhood_copy_and_release
+#include <rsys/dynamic_array.h>
+
+extern LOCAL_SYM res_T
+scene_analyze(struct senc3d_scene* scene);
+
+#endif /* SENC3D_SCNENE_ANALYZE_C_H */
diff --git a/src/senc3d_scene_c.h b/src/senc3d_scene_c.h
@@ -0,0 +1,308 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC3D_SCENE_C_H
+#define SENC3D_SCENE_C_H
+
+#include "senc3d_internal_types.h"
+#include "senc3d_enclosure_data.h"
+#include "senc3d_side_range.h"
+#include "senc3d.h"
+
+#include <rsys/ref_count.h>
+#include <rsys/dynamic_array.h>
+#include <rsys/hash_table.h>
+
+struct mem_allocator;
+struct senc3d_scene;
+
+struct triangle_comp {
+ /* The connex component in which each side is. */
+ component_id_t component[2];
+};
+
+static void
+triangle_comp_init(struct mem_allocator* alloc, struct triangle_comp* trg) {
+ int i;
+ (void)alloc;
+ ASSERT(trg);
+ FOR_EACH(i, 0, 2) trg->component[i] = COMPONENT_NULL__;
+}
+
+#define DARRAY_NAME triangle_comp
+#define DARRAY_DATA struct triangle_comp
+#define DARRAY_FUNCTOR_INIT triangle_comp_init
+#include <rsys/dynamic_array.h>
+
+struct triangle_enc {
+ /* The enclosure in which each side is. */
+ enclosure_id_t enclosure[2];
+};
+
+#ifndef NDEBUG
+static void
+triangle_enc_init(struct mem_allocator* alloc, struct triangle_enc* trg) {
+ int i;
+ (void)alloc;
+ ASSERT(trg);
+ FOR_EACH(i, 0, 2) trg->enclosure[i] = ENCLOSURE_NULL__;
+}
+#define DARRAY_FUNCTOR_INIT triangle_enc_init
+#endif
+
+#define DARRAY_NAME triangle_enc
+#define DARRAY_DATA struct triangle_enc
+#include <rsys/dynamic_array.h>
+
+/* Triangle edge struct and basic functions */
+struct trg_edge {
+ vrtx_id_t vrtx0, vrtx1;
+};
+
+static FINLINE int
+edge_ok(const struct trg_edge* edge) {
+ return(edge
+ && edge->vrtx0 <= VRTX_MAX__
+ && edge->vrtx1 <= VRTX_MAX__
+ && edge->vrtx0 < edge->vrtx1);
+}
+
+static FINLINE void
+set_edge
+ (const vrtx_id_t vrtx0,
+ const vrtx_id_t vrtx1,
+ struct trg_edge* edge,
+ uchar* reversed)
+{
+ ASSERT(edge && reversed && vrtx0 != vrtx1);
+ ASSERT(*reversed == UCHAR_MAX); /* Should not be already set. */
+ if(vrtx0 < vrtx1) {
+ edge->vrtx0 = vrtx0;
+ edge->vrtx1 = vrtx1;
+ *reversed = 0; /* Non reversed edge */
+ } else {
+ edge->vrtx0 = vrtx1;
+ edge->vrtx1 = vrtx0;
+ *reversed = 1; /* Reversed edge */
+ }
+ ASSERT(edge_ok(edge));
+}
+
+static FINLINE int
+edge_eq(const struct trg_edge* e1, const struct trg_edge* e2)
+{
+ ASSERT(edge_ok(e1) && edge_ok(e2));
+ return e1->vrtx0 == e2->vrtx0 && e1->vrtx1 == e2->vrtx1;
+}
+
+/* Information kept during the building of side groups. */
+struct trgside {
+ /* Rank of the trgside facing this trgside through its edges */
+ side_id_t facing_side_id[3];
+ /* Id of this trgside's medium */
+ medium_id_t medium;
+
+ /* Implicit information that we don't need to store:
+ * - triangle_id
+ * - side
+ * This is due to the memory layout of the elt darray:
+ * front(trg_0), back(trg_0), front(trg_1), back(trg_1), ... */
+};
+
+/* Frontier edge type */
+struct frontier_edge {
+ trg_id_t trg;
+ vrtx_id_t vrtx0, vrtx1;
+};
+
+#define DARRAY_NAME frontier_edge
+#define DARRAY_DATA struct frontier_edge
+#include <rsys/dynamic_array.h>
+
+union double3 {
+ struct {
+ double x, y, z;
+ } pos;
+ double vec[3];
+};
+#define DARRAY_NAME position
+#define DARRAY_DATA union double3
+#include <rsys/dynamic_array.h>
+/* Triangle information.
+ * Depending on lifespan, information is kept in different places:
+ * - triangle_in for user provided information (kept in scene)
+ * - triangle_comp for information describing components (kept in struct descriptor)
+ * - triangle_tmp for tmp information (kept until triangle_comp is ready) */
+struct triangle_in {
+ /* Ids of the triangle's vertices */
+ vrtx_id_t vertice_id[3];
+ /* Ids of this triangle's media */
+ medium_id_t medium[2];
+};
+
+static FINLINE void
+triangle_in_init(struct mem_allocator* alloc, struct triangle_in* trg) {
+ int i;
+ (void)alloc;
+ ASSERT(trg);
+ FOR_EACH(i, 0, 3) trg->vertice_id[i] = VRTX_NULL__;
+ FOR_EACH(i, 0, 2) trg->medium[i] = SENC3D_UNSPECIFIED_MEDIUM;
+}
+
+#define DARRAY_NAME triangle_in
+#define DARRAY_DATA struct triangle_in
+#define DARRAY_FUNCTOR_INIT triangle_in_init
+#include <rsys/dynamic_array.h>
+
+static FINLINE void
+triangle_in_flip(struct triangle_in* trg) {
+ vrtx_id_t v;
+ medium_id_t m;
+ ASSERT(trg);
+ v = trg->vertice_id[1];
+ trg->vertice_id[1] = trg->vertice_id[2];
+ trg->vertice_id[2] = v;
+ m = trg->medium[0];
+ trg->medium[0] = trg->medium[1];
+ trg->medium[1] = m;
+}
+
+static FINLINE int
+vrtx_eq(const union double3* v1, const union double3* v2)
+{
+ ASSERT(v1 && v2);
+ return (v1->pos.x == v2->pos.x
+ && v1->pos.y == v2->pos.y
+ && v1->pos.z == v2->pos.z);
+}
+
+#define HTABLE_NAME vrtx
+#define HTABLE_KEY union double3
+#define HTABLE_DATA vrtx_id_t
+#define HTABLE_KEY_FUNCTOR_EQ vrtx_eq
+#include <rsys/hash_table.h>
+
+union vrtx_id3 {
+ struct {
+ vrtx_id_t v0, v1, v2;
+ } pos;
+ vrtx_id_t vec[3];
+};
+
+static FINLINE char /* Return 1 if reversed */
+trg_make_key(union vrtx_id3* k, const vrtx_id_t t[3])
+{
+ ASSERT(t);
+ ASSERT(t[0] != t[1] && t[0] != t[2] && t[1] != t[2]);
+ if(t[0] < t[2]) {
+ if(t[0] < t[1]) {
+ k->vec[0] = t[0];
+ if(t[1] < t[2]) {
+ k->vec[1] = t[1];
+ k->vec[2] = t[2];
+ return 0;
+ } else {
+ k->vec[1] = t[2];
+ k->vec[2] = t[1];
+ return 1;
+ }
+ } else {
+ k->vec[0] = t[1];
+ if(t[0] < t[2]) {
+ k->vec[1] = t[0];
+ k->vec[2] = t[2];
+ return 1;
+ } else {
+ k->vec[1] = t[2];
+ k->vec[2] = t[0];
+ return 0;
+ }
+ }
+ } else if(t[2] < t[1]) {
+ k->vec[0] = t[2];
+ if(t[0] < t[1]) {
+ k->vec[1] = t[0];
+ k->vec[2] = t[1];
+ return 0;
+ } else {
+ k->vec[1] = t[1];
+ k->vec[2] = t[0];
+ return 1;
+ }
+ } else {
+ k->vec[0] = t[1];
+ if(t[0] < t[2]) {
+ k->vec[1] = t[0];
+ k->vec[2] = t[2];
+ return 1;
+ } else {
+ k->vec[1] = t[2];
+ k->vec[2] = t[0];
+ return 0;
+ }
+ }
+}
+
+static FINLINE int
+trg_key_eq(const union vrtx_id3* k1, const union vrtx_id3* k2)
+{
+ ASSERT(k1 && k2);
+ ASSERT(k1->vec[0] < k1->vec[1] && k1->vec[1] < k1->vec[2]);
+ ASSERT(k2->vec[0] < k2->vec[1] && k2->vec[1] < k2->vec[2]);
+ return (k1->vec[0] == k2->vec[0])
+ && (k1->vec[1] == k2->vec[1])
+ && (k1->vec[2] == k2->vec[2]);
+}
+
+#define HTABLE_NAME trg
+#define HTABLE_KEY union vrtx_id3
+#define HTABLE_DATA trg_id_t
+#define HTABLE_KEY_FUNCTOR_EQ trg_key_eq
+#include <rsys/hash_table.h>
+
+struct descriptor {
+ enclosure_id_t enclosures_count;
+ /* Store by-triangle enclosures */
+ struct darray_triangle_enc triangles_enc;
+ /* Store enclosures */
+ struct darray_enclosure enclosures;
+ struct darray_enc_ids_array enc_ids_array_by_medium;
+ /* Store frontiers */
+ struct darray_frontier_edge frontiers;
+};
+
+struct senc3d_scene {
+ /* Front / Back sides convention */
+ int convention;
+ /* Triangle information as given by user */
+ struct darray_triangle_in triangles_in;
+ /* Vertex information as given by user */
+ struct darray_position vertices;
+
+ /* Keep sizes */
+ trg_id_t ntris; /* Trg count */
+ vrtx_id_t nverts; /* Vrtx count */
+ medium_id_t next_medium_idx;
+ /* media_use 0 is for SENC3D_UNSPECIFIED_MEDIUM, n+1 is for n */
+ struct darray_side_range media_use;
+
+ /* The descriptor of the analyze */
+ struct descriptor analyze;
+
+ ref_T ref;
+ struct senc3d_device* dev;
+};
+
+#endif /* SENC3D_SCENE_C_H */
diff --git a/src/senc3d_side_range.h b/src/senc3d_side_range.h
@@ -0,0 +1,44 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC3D_SIDE_RANGE_H
+#define SENC3D_SIDE_RANGE_H
+
+#include "senc3d_internal_types.h"
+
+#include <rsys/dynamic_array.h>
+
+struct mem_allocator;
+
+struct side_range {
+ side_id_t first, last;
+};
+
+static FINLINE void
+side_range_init(struct mem_allocator* alloc, struct side_range* data)
+{
+ ASSERT(data);
+ (void)alloc;
+ data->first = SIDE_NULL__;
+ data->last = 0;
+}
+
+#define DARRAY_NAME side_range
+#define DARRAY_DATA struct side_range
+#define DARRAY_FUNCTOR_INIT side_range_init
+#include <rsys/dynamic_array.h>
+
+
+#endif /* SENC3D_SCENE_C_H */
diff --git a/src/sencX3d.h b/src/sencX3d.h
@@ -0,0 +1,44 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC_X_3D_H
+#define SENC_X_3D_H
+
+#if !defined(SENCXD_DIM) || (SENCXD_DIM != 2 && SENCXD_DIM != 3)
+#error "SENCXD_DIM must be defined; admissible values are 2 and 3"
+#endif
+
+#include <star/senc3d.h>
+
+/* Star-enclosures-XD macros generic to the SENCXD_DIM */
+#ifndef SENCXD
+#define SENCXD CONCAT(CONCAT(SENC, SENCXD_DIM), D)
+#endif
+#ifndef sencXd
+#define sencXd(Name) CONCAT(CONCAT(CONCAT(senc, SENCXD_DIM), d_), Name)
+#endif
+#ifndef SENCXD_
+#define SENCXD_(Name) CONCAT(CONCAT(CONCAT(SENC, SENCXD_DIM), D_), Name)
+#endif
+
+/* Function names that require additional dedicated macros */
+#define senc3d_scene_get_primitives_count senc3d_scene_get_triangles_count
+#define senc3d_scene_get_primitive senc3d_scene_get_triangle
+#define senc3d_scene_get_primitive_media senc3d_scene_get_triangle_media
+#define senc3d_scene_get_primitive_enclosures senc3d_scene_get_triangle_enclosures
+#define senc3d_enclosure_get_primitive senc3d_enclosure_get_triangle
+#define senc3d_enclosure_get_primitive_id senc3d_enclosure_get_triangle_id
+
+#endif /* SENC_X_3D_H */
diff --git a/src/sencX3d_undefs.h b/src/sencX3d_undefs.h
@@ -0,0 +1,33 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 SENC_X_3D_H
+#error "The sencX3d.h file must be included priorly to this file."
+#endif
+
+ /* Star-enclosures-XD macros generic to the SENCXD_DIM */
+#undef SENCXD
+#undef sencXd
+#undef SENCXD_
+
+/* Function names that require additional dedicated macros */
+#undef senc3d_scene_get_primitives_count
+#undef senc3d_scene_get_primitive
+#undef senc3d_scene_get_primitive_media
+#undef senc3d_scene_get_primitive_enclosures
+#undef senc3d_enclosure_get_primitive
+#undef senc3d_enclosure_get_primitive_id
+
+#undef SENC_X_3D_H
diff --git a/src/senc_descriptor.c b/src/senc_descriptor.c
@@ -1,333 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc_descriptor_c.h"
-#include "senc_device_c.h"
-#include "senc_enclosure_c.h"
-#include "senc_scene_c.h"
-#include "senc.h"
-
-#include <rsys/rsys.h>
-#include <rsys/double3.h>
-#include <rsys/mem_allocator.h>
-
- /*******************************************************************************
- * Helper function
- ******************************************************************************/
-static void
-descriptor_release(ref_T * ref)
-{
- struct senc_scene* scn = NULL;
- struct senc_descriptor* desc = NULL;
- ASSERT(ref);
- desc = CONTAINER_OF(ref, struct senc_descriptor, ref);
- scn = desc->scene;
- darray_triangle_enc_release(&desc->triangles_enc);
- darray_enclosure_release(&desc->enclosures);
- darray_enc_ids_array_release(&desc->enc_ids_array_by_medium);
- darray_frontier_edge_release(&desc->frontiers);
-
- MEM_RM(scn->dev->allocator, desc);
- SENC(scene_ref_put(scn));
-}
-
-/*******************************************************************************
- * Local functions
- ******************************************************************************/
-struct senc_descriptor*
-descriptor_create(struct senc_scene* scn)
-{
- struct senc_descriptor* desc;
- res_T res = RES_OK;
- ASSERT(scn);
- desc = MEM_CALLOC(scn->dev->allocator, 1, sizeof(struct senc_descriptor));
- if(desc) {
- desc->scene = scn;
- SENC(scene_ref_get(desc->scene));
- ref_init(&desc->ref);
- darray_triangle_enc_init(scn->dev->allocator, &desc->triangles_enc);
- darray_enclosure_init(scn->dev->allocator, &desc->enclosures);
- darray_enc_ids_array_init(scn->dev->allocator,
- &desc->enc_ids_array_by_medium);
- OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium,
- 1 + scn->next_medium_idx)); /* +1 is for undef */
- darray_frontier_edge_init(scn->dev->allocator, &desc->frontiers);
- /* Enclosure 0 is always defined for infinite */
- OK(darray_enclosure_resize(&desc->enclosures, 1));
- desc->enclosures_count = 1;
- desc->triangle_count = scn->nutris;
- desc->vertices_count = scn->nuverts;
- }
-end:
- return desc;
-error:
- if(desc) SENC(descriptor_ref_put(desc));
- goto end;
-}
-
-struct mem_allocator*
- descriptor_get_allocator(struct senc_descriptor* desc)
-{
- ASSERT(desc);
- return desc->scene->dev->allocator;
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-senc_descriptor_get_max_medium
- (const struct senc_descriptor* desc, unsigned* max_medium_id)
-{
- if(!desc || !max_medium_id) return RES_BAD_ARG;
- ASSERT(desc->scene->next_medium_idx < UINT_MAX); /* API type */
- *max_medium_id = (unsigned)desc->scene->next_medium_idx - 1;
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_enclosure_count
- (const struct senc_descriptor* desc, unsigned* count)
-{
- size_t tmp;
- if(!desc || !count) return RES_BAD_ARG;
- tmp = darray_enclosure_size_get(&desc->enclosures);
- ASSERT(tmp < UINT_MAX); /* API type */
- ASSERT(desc->enclosures_count == tmp);
- *count = (unsigned)tmp;
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_enclosure_count_by_medium
- (const struct senc_descriptor* desc,
- const unsigned imed,
- unsigned* count)
-{
- size_t tmp, m_idx;
- const struct darray_enc_id* enc_ids;
- if(!desc || !count
- || (imed != SENC_UNDEFINED_MEDIUM && imed >= desc->scene->next_medium_idx))
- return RES_BAD_ARG;
- ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
- == 1 + desc->scene->next_medium_idx);
- m_idx = (imed == SENC_UNDEFINED_MEDIUM) ? desc->scene->next_medium_idx : imed;
- enc_ids = darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium)
- + m_idx;
- tmp = darray_enc_id_size_get(enc_ids);
- ASSERT(tmp < UINT_MAX); /* API type */
- *count = (unsigned)tmp;
- return RES_OK;
-}
-
-FINLINE res_T
-senc_descriptor_get_enclosure
- (struct senc_descriptor* desc,
- const unsigned idx,
- struct senc_enclosure** out_enc)
-{
- struct senc_enclosure* enc;
- if(!desc || idx >= darray_enclosure_size_get(&desc->enclosures) || !out_enc)
- return RES_BAD_ARG;
- enc = enclosure_create(desc, idx);
- if(!enc) return RES_MEM_ERR;
- *out_enc = enc;
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_enclosure_by_medium
- (struct senc_descriptor* desc,
- const unsigned imed,
- const unsigned idx,
- struct senc_enclosure** out_enc)
-{
- size_t m_idx;
- const struct darray_enc_id* enc_ids;
- unsigned index;
- if(!desc || !out_enc
- || (imed != SENC_UNDEFINED_MEDIUM && imed >= desc->scene->next_medium_idx))
- return RES_BAD_ARG;
- ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
- == 1 + desc->scene->next_medium_idx);
- m_idx = (imed == SENC_UNDEFINED_MEDIUM) ? desc->scene->next_medium_idx : imed;
- enc_ids =
- darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + m_idx;
- if(idx >= darray_enc_id_size_get(enc_ids)) return RES_BAD_ARG;
- index = darray_enc_id_cdata_get(enc_ids)[idx];
- return senc_descriptor_get_enclosure(desc, index, out_enc);
-}
-
-res_T
-senc_descriptor_get_global_triangles_count
- (const struct senc_descriptor* desc,
- unsigned* count)
-{
- if(!desc || !count) return RES_BAD_ARG;
- ASSERT(desc->triangle_count < UINT_MAX);
- *count = (unsigned)desc->triangle_count; /* Back to API type */
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_global_vertices_count
- (const struct senc_descriptor* desc,
- unsigned* count)
-{
- if(!desc || !count) return RES_BAD_ARG;
- if(desc->vertices_count >= UINT_MAX)
- return RES_BAD_ARG;
- *count = (unsigned)desc->vertices_count; /* Back to API type */
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_global_triangle
- (const struct senc_descriptor* desc,
- const unsigned itri,
- unsigned indices[3])
-{
- const struct triangle_in* trg;
- int i;
- if(!indices || ! desc
- || itri >= darray_triangle_in_size_get(&desc->scene->triangles_in))
- return RES_BAD_ARG;
- trg = darray_triangle_in_cdata_get(&desc->scene->triangles_in) + itri;
-
- FOR_EACH(i, 0, 3) {
- ASSERT(trg->vertice_id[i] < UINT_MAX);
- indices[i] = (unsigned)trg->vertice_id[i]; /* Back to API type */
- }
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_global_vertex
- (const struct senc_descriptor* desc,
- const unsigned ivert,
- double vrtx[3])
-{
- const union double3* v;
- if(!vrtx || !desc
- || ivert >= darray_position_size_get(&desc->scene->vertices))
- return RES_BAD_ARG;
-
- v = darray_position_cdata_get(&desc->scene->vertices) + ivert;
- d3_set(vrtx, v->vec);
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_global_triangle_media
- (const struct senc_descriptor* desc,
- const unsigned itri,
- unsigned media[2])
-{
- const struct triangle_in* trg;
- int i;
- if(!media || !desc
- || itri >= darray_triangle_in_size_get(&desc->scene->triangles_in))
- return RES_BAD_ARG;
- trg = darray_triangle_in_cdata_get(&desc->scene->triangles_in) + itri;
- FOR_EACH(i, 0, 2) {
-#if (UINT_MAX < MEDIUM_MAX__)
- ASSERT(trg->medium[i] < UINT_MAX);
-#endif
- media[i] = (unsigned)trg->medium[i]; /* Back to API type */
- }
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_global_triangle_enclosures
- (const struct senc_descriptor* desc,
- const unsigned itri,
- unsigned enclosures[2])
-{
- const struct triangle_enc* trg;
- int i;
- if(!enclosures || !desc
- || itri >= darray_triangle_enc_size_get(&desc->triangles_enc))
- return RES_BAD_ARG;
- trg = darray_triangle_enc_cdata_get(&desc->triangles_enc) + itri;
- FOR_EACH(i, 0, 2) {
-#if (UINT_MAX < ENCLOSURE_MAX__)
- ASSERT(trg->enclosure[i] < UINT_MAX);
-#endif
- enclosures[i] = (unsigned)trg->enclosure[i]; /* Back to API type */
- }
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_global_triangle_global_id
- (const struct senc_descriptor* desc,
- const unsigned itri,
- unsigned* gid)
-{
- const struct triangle_in* trg;
- if(!gid || !desc
- || itri >= darray_triangle_in_size_get(&desc->scene->triangles_in))
- return RES_BAD_ARG;
- trg = darray_triangle_in_cdata_get(&desc->scene->triangles_in) + itri;
- *gid = trg->global_id;
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_frontier_segments_count
- (const struct senc_descriptor* desc,
- unsigned* count)
-{
- size_t tmp;
- if(!desc || !count)
- return RES_BAD_ARG;
- tmp = darray_frontier_edge_size_get(&desc->frontiers);
- ASSERT(tmp < UINT_MAX);
- *count = (unsigned)tmp;
- return RES_OK;
-}
-
-res_T
-senc_descriptor_get_frontier_segment
- (const struct senc_descriptor* desc,
- const unsigned iseg,
- unsigned vrtx_id[2])
-{
- const struct trg_edge* edge;
- if(!vrtx_id || !desc
- || iseg >= darray_frontier_edge_size_get(&desc->frontiers))
- return RES_BAD_ARG;
- edge = darray_frontier_edge_cdata_get(&desc->frontiers) + iseg;
- vrtx_id[0] = (unsigned)edge->vrtx0; /* Back to API type */
- vrtx_id[1] = (unsigned)edge->vrtx1; /* Back to API type */
- return RES_OK;
-}
-
-res_T
-senc_descriptor_ref_get(struct senc_descriptor* desc)
-{
- if(!desc) return RES_BAD_ARG;
- ref_get(&desc->ref);
- return RES_OK;
-}
-
-res_T
-senc_descriptor_ref_put(struct senc_descriptor* desc)
-{
- if(!desc) return RES_BAD_ARG;
- ref_put(&desc->ref, descriptor_release);
- return RES_OK;
-}
diff --git a/src/senc_descriptor_c.h b/src/senc_descriptor_c.h
@@ -1,168 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 SENC_DESCRIPTOR_C_H
-#define SENC_DESCRIPTOR_C_H
-
-#include <rsys/ref_count.h>
-#include <rsys/dynamic_array.h>
-
-#include "senc.h"
-#include "senc_enclosure_data.h"
-#include "senc_internal_types.h"
-
-struct senc_scene;
-struct mem_allocator;
-
-struct triangle_comp {
- /* The connex component in which each side is. */
- component_id_t component[2];
-};
-
-static void
-triangle_comp_init(struct mem_allocator* alloc, struct triangle_comp* trg) {
- int i;
- (void)alloc;
- ASSERT(trg);
- FOR_EACH(i, 0, 2) trg->component[i] = COMPONENT_NULL__;
-}
-
-#define DARRAY_NAME triangle_comp
-#define DARRAY_DATA struct triangle_comp
-#define DARRAY_FUNCTOR_INIT triangle_comp_init
-#include <rsys/dynamic_array.h>
-
-struct triangle_enc {
- /* The enclosure in which each side is. */
- enclosure_id_t enclosure[2];
-};
-
-#ifndef NDEBUG
-static void
-triangle_enc_init(struct mem_allocator* alloc, struct triangle_enc* trg) {
- int i;
- (void)alloc;
- ASSERT(trg);
- FOR_EACH(i, 0, 2) trg->enclosure[i] = ENCLOSURE_NULL__;
-}
-#define DARRAY_FUNCTOR_INIT triangle_enc_init
-#endif
-
-#define DARRAY_NAME triangle_enc
-#define DARRAY_DATA struct triangle_enc
-#include <rsys/dynamic_array.h>
-
-#define DARRAY_NAME enclosure
-#define DARRAY_DATA struct enclosure_data
-#define DARRAY_FUNCTOR_INIT enclosure_data_init
-#define DARRAY_FUNCTOR_COPY enclosure_data_copy
-#define DARRAY_FUNCTOR_RELEASE enclosure_data_release
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE enclosure_data_copy_and_release
-#include <rsys/dynamic_array.h>
-
-#define DARRAY_NAME enc_id
-#define DARRAY_DATA enclosure_id_t
-#include <rsys/dynamic_array.h>
-
-#define DARRAY_NAME enc_ids_array
-#define DARRAY_DATA struct darray_enc_id
-#define DARRAY_FUNCTOR_INIT darray_enc_id_init
-#define DARRAY_FUNCTOR_COPY darray_enc_id_copy
-#define DARRAY_FUNCTOR_RELEASE darray_enc_id_release
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_enc_id_copy_and_release
-#include <rsys/dynamic_array.h>
-
-/* Triangle edge struct and basic functions */
-struct trg_edge {
- vrtx_id_t vrtx0, vrtx1;
-};
-
-static FINLINE int
-edge_ok(const struct trg_edge* edge) {
- return(edge
- && edge->vrtx0 <= VRTX_MAX__
- && edge->vrtx1 <= VRTX_MAX__
- && edge->vrtx0 < edge->vrtx1);
-}
-
-static FINLINE void
-set_edge
-(const vrtx_id_t vrtx0,
- const vrtx_id_t vrtx1,
- struct trg_edge* edge,
- unsigned char* reversed)
-{
- ASSERT(edge && reversed && vrtx0 != vrtx1);
- ASSERT(*reversed == UCHAR_MAX); /* Should not be already set. */
- if(vrtx0 < vrtx1) {
- edge->vrtx0 = vrtx0;
- edge->vrtx1 = vrtx1;
- *reversed = 0; /* Non reversed edge */
- } else {
- edge->vrtx0 = vrtx1;
- edge->vrtx1 = vrtx0;
- *reversed = 1; /* Reversed edge */
- }
- ASSERT(edge_ok(edge));
-}
-
-static FINLINE int
-edge_eq(const struct trg_edge* e1, const struct trg_edge* e2)
-{
- ASSERT(edge_ok(e1) && edge_ok(e2));
- return e1->vrtx0 == e2->vrtx0 && e1->vrtx1 == e2->vrtx1;
-}
-
-/* Information kept during the building of side groups. */
-struct trgside {
- /* Rank of the trgside facing this trgside through its edges */
- side_id_t facing_side_id[3];
- /* Id of this trgside's medium */
- medium_id_t medium;
-
- /* Implicit information that we don't need to store:
- * - triangle_id
- * - side
- * This is due to the memory layout of the elt darray:
- * front(trg_0), back(trg_0), front(trg_1), back(trg_1), ... */
-};
-
-#define DARRAY_NAME frontier_edge
-#define DARRAY_DATA struct trg_edge
-#include <rsys/dynamic_array.h>
-
-struct senc_descriptor {
- struct senc_scene* scene;
- enclosure_id_t enclosures_count;
- /* Store by-triangle enclosures */
- struct darray_triangle_enc triangles_enc;
- /* Store enclosures */
- struct darray_enclosure enclosures;
- struct darray_enc_ids_array enc_ids_array_by_medium;
- trg_id_t triangle_count;
- vrtx_id_t vertices_count;
- /* Store frontiers */
- struct darray_frontier_edge frontiers;
-
- ref_T ref;
-};
-
-struct senc_descriptor*
-descriptor_create(struct senc_scene* scn);
-
-struct mem_allocator*
-descriptor_get_allocator(struct senc_descriptor* desc);
-
-#endif /* SENC_DESCRIPTOR_C_H */
diff --git a/src/senc_device.c b/src/senc_device.c
@@ -1,148 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "senc_device_c.h"
-
-#include <rsys/logger.h>
-#include <rsys/mem_allocator.h>
-
-#include <omp.h>
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static void
-log_msg
- (struct senc_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 senc_device* dev;
- ASSERT(ref);
- dev = CONTAINER_OF(ref, struct senc_device, ref);
- MEM_RM(dev->allocator, dev);
-}
-
-/*******************************************************************************
- * Local functions
- ******************************************************************************/
-void
-log_err(struct senc_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_warn(struct senc_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);
-}
-
-void
-log_info(struct senc_device* dev, const char* msg, ...)
-{
- va_list vargs_list;
- ASSERT(dev && msg);
-
- va_start(vargs_list, msg);
- log_msg(dev, LOG_OUTPUT, msg, vargs_list);
- va_end(vargs_list);
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-senc_device_create
- (struct logger* logger,
- struct mem_allocator* mem_allocator,
- const unsigned nthreads_hint,
- const int verbose,
- struct senc_device** out_dev)
-{
- struct logger* log = NULL;
- struct senc_device* dev = NULL;
- struct mem_allocator* allocator = NULL;
- res_T res = RES_OK;
- if(nthreads_hint == 0 || !out_dev) return RES_BAD_ARG;
-
- log = logger ? logger : LOGGER_DEFAULT;
- allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
- dev = MEM_CALLOC(allocator, 1, sizeof(struct senc_device));
- if(!dev) {
- if(verbose) {
- /* Do not use helper log functions since dev is not initialised */
- CHK(logger_print(log, LOG_ERROR,
- "%s: could not allocate the StarEnclosures device.\n", FUNC_NAME) == RES_OK);
- }
- res = RES_MEM_ERR;
- goto error;
- }
- dev->logger = log;
- dev->allocator = allocator;
- dev->verbose = verbose;
- /* Cannot use int args for MMIN here as default is -1 */
- dev->nthreads = (int)MMIN(nthreads_hint, (unsigned)omp_get_num_procs());
- ref_init(&dev->ref);
-
-exit:
- if(dev) *out_dev = dev;
- return res;
-error:
- if(dev) {
- SENC(device_ref_put(dev));
- dev = NULL;
- }
- goto exit;
-}
-
-res_T
-senc_device_ref_get(struct senc_device* dev)
-{
- if(!dev) return RES_BAD_ARG;
- ref_get(&dev->ref);
- return RES_OK;
-}
-
-res_T
-senc_device_ref_put(struct senc_device* dev)
-{
- if(!dev) return RES_BAD_ARG;
- ref_put(&dev->ref, device_release);
- return RES_OK;
-}
diff --git a/src/senc_device_c.h b/src/senc_device_c.h
@@ -1,71 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 SENC_DEVICE_C_H
-#define SENC_DEVICE_C_H
-
-#include <rsys/free_list.h>
-#include <rsys/ref_count.h>
-
-struct name { FITEM; };
-#define FITEM_TYPE name
-#include <rsys/free_list.h>
-
-struct senc_device {
- struct logger* logger;
- struct mem_allocator* allocator;
- int verbose;
- int nthreads;
-
- 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_err
- (struct senc_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_warn
- (struct senc_device* dev,
- const char* msg,
- ...)
-#ifdef COMPILER_GCC
- __attribute((format(printf, 2, 3)))
-#endif
-;
-
-/* Conditionally log a message on the LOG_OUTPUT stream of the device logger,
- * with respect to the device verbose flag */
-extern LOCAL_SYM void
-log_info
- (struct senc_device* dev,
- const char* msg,
- ...)
-#ifdef COMPILER_GCC
- __attribute((format(printf, 2, 3)))
-#endif
- ;
-
-#endif /* SENC_DEVICE_C_H */
diff --git a/src/senc_enclosure.c b/src/senc_enclosure.c
@@ -1,168 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc_enclosure_c.h"
-#include "senc_descriptor_c.h"
-#include "senc_scene_c.h"
-#include "senc.h"
-
-#include <rsys/rsys.h>
-#include <rsys/double3.h>
-#include <rsys/mem_allocator.h>
-
-
-/*******************************************************************************
- * Helper function
- ******************************************************************************/
-static void
-enclosure_release(ref_T * ref)
-{
- struct senc_enclosure* enclosure = NULL;
- struct senc_descriptor* desc = NULL;
- ASSERT(ref);
- enclosure = CONTAINER_OF(ref, struct senc_enclosure, ref);
- desc = enclosure->desc;
-
- MEM_RM(descriptor_get_allocator(desc), enclosure);
- SENC(descriptor_ref_put(desc));
-}
-
-/*******************************************************************************
- * Local functions
- ******************************************************************************/
-struct senc_enclosure*
-enclosure_create
- (struct senc_descriptor* desc,
- const unsigned idx)
-{
- struct senc_enclosure* enc;
- ASSERT(desc && idx < darray_enclosure_size_get(&desc->enclosures));
- enc = MEM_CALLOC(descriptor_get_allocator(desc),
- 1, sizeof(struct senc_enclosure));
- if(enc) {
- const struct enclosure_data* data
- = darray_enclosure_data_get(&desc->enclosures) + idx;
- SENC(descriptor_ref_get(desc));
- enc->desc = desc;
- enc->data = data;
- ref_init(&enc->ref);
- }
- return enc;
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-senc_enclosure_get_header
- (const struct senc_enclosure* enclosure,
- struct senc_enclosure_header* header)
-{
- if(!enclosure || !header) return RES_BAD_ARG;
- *header = enclosure->data->header;
- return RES_OK;
-}
-
-res_T
-senc_enclosure_get_triangle
- (const struct senc_enclosure* enclosure,
- const unsigned itri,
- unsigned indices[3])
-{
- const struct side_enc* side;
- int i;
- if(!enclosure || !indices
- || itri >= enclosure->data->header.triangle_count)
- return RES_BAD_ARG;
- ASSERT(darray_sides_enc_size_get(&enclosure->data->sides)
- == enclosure->data->header.triangle_count);
- side = darray_sides_enc_cdata_get(&enclosure->data->sides) + itri;
- FOR_EACH(i, 0, 3) {
- ASSERT(side->vertice_id[i] < UINT_MAX);
- indices[i] = (unsigned)side->vertice_id[i]; /* Back to API type */
- }
- return RES_OK;
-}
-
-res_T
-senc_enclosure_get_vertex
- (const struct senc_enclosure* enclosure,
- const unsigned ivert,
- double coord[3])
-{
- if(!enclosure || !coord
- || ivert >= enclosure->data->header.vertices_count) {
- return RES_BAD_ARG;
- } else {
- const vrtx_id_t idx
- = darray_vrtx_id_cdata_get(&enclosure->data->vertices)[ivert];
- const union double3* positions
- = darray_position_cdata_get(&enclosure->desc->scene->vertices);
- ASSERT(darray_vrtx_id_size_get(&enclosure->data->vertices)
- == enclosure->data->header.vertices_count);
- d3_set(coord, positions[idx].vec);
- return RES_OK;
- }
-}
-
-res_T
-senc_enclosure_get_triangle_global_id
- (const struct senc_enclosure* enclosure,
- const unsigned itri,
- unsigned* gid,
- enum senc_side* sde)
-{
- const struct side_enc* side;
- if(!enclosure || !gid || !sde
- || itri >= enclosure->data->header.triangle_count)
- return RES_BAD_ARG;
- ASSERT(darray_sides_enc_size_get(&enclosure->data->sides)
- == enclosure->data->header.triangle_count);
- side = darray_sides_enc_cdata_get(&enclosure->data->sides) + itri;
- *gid = (unsigned)TRGSIDE_2_TRG(side->side_id);
- *sde = TRGSIDE_2_SIDE(side->side_id);
- return RES_OK;
-}
-
-res_T
-senc_enclosure_get_medium
- (const struct senc_enclosure* enclosure,
- const unsigned imed,
- unsigned* medium)
-{
- if(!enclosure || !medium
- || imed >= enclosure->data->header.enclosed_media_count)
- return RES_BAD_ARG;
- ASSERT(enclosure->data->header.enclosed_media_count
- == darray_media_size_get(&enclosure->data->enclosed_media));
- *medium = darray_media_cdata_get(&enclosure->data->enclosed_media)[imed];
- return RES_OK;
-}
-
-res_T
-senc_enclosure_ref_get(struct senc_enclosure* enc)
-{
- if(!enc) return RES_BAD_ARG;
- ref_get(&enc->ref);
- return RES_OK;
-}
-
-res_T
-senc_enclosure_ref_put(struct senc_enclosure* enc)
-{
- if(!enc) return RES_BAD_ARG;
- ref_put(&enc->ref, enclosure_release);
- return RES_OK;
-}
diff --git a/src/senc_enclosure_c.h b/src/senc_enclosure_c.h
@@ -1,37 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 SENC_ENCLOSURE_C_H
-#define SENC_ENCLOSURE_C_H
-
-#include <rsys/ref_count.h>
-
-#include "senc.h"
-
-struct enclosure_data;
-struct senc_descriptor;
-
-struct senc_enclosure {
- const struct enclosure_data* data;
- struct senc_descriptor* desc;
- ref_T ref;
-};
-
-struct senc_enclosure*
-enclosure_create
- (struct senc_descriptor* desc,
- const unsigned idx);
-
-#endif /* SENC_ENCLOSURE_C_H */
diff --git a/src/senc_enclosure_data.h b/src/senc_enclosure_data.h
@@ -1,205 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 SENC_ENCLOSURE_DATA_H
-#define SENC_ENCLOSURE_DATA_H
-
-#include <rsys/rsys.h>
-#include <rsys/ref_count.h>
-#include <rsys/hash_table.h>
-#include <rsys/dynamic_array.h>
-
-#include "senc.h"
-#include "senc_scene_c.h"
-#include "senc_internal_types.h"
-
-#include <limits.h>
-
-struct side_enc {
- vrtx_id_t vertice_id[3];
- side_id_t side_id;
-};
-
-#define DARRAY_NAME sides_enc
-#define DARRAY_DATA struct side_enc
-#include <rsys/dynamic_array.h>
-
-/* unsigned char array with init to zero */
-static FINLINE void
-zero_init_uchar
- (struct mem_allocator* alloc, unsigned char* data)
-{
- ASSERT(data); (void) alloc;
- *data = 0;
-}
-#define DARRAY_FUNCTOR_INIT zero_init_uchar
-#include <rsys/dynamic_array_uchar.h>
-
-static void
-init_header(struct senc_enclosure_header* header)
-{
- ASSERT(header);
- header->enclosure_id = ENCLOSURE_NULL__;
- header->triangle_count = 0;
- header->unique_triangle_count = 0;
- header->vertices_count = 0;
- header->enclosed_media_count = 0;
- header->is_infinite = CHAR_MAX;
-}
-
-#define DARRAY_NAME media
-#define DARRAY_DATA medium_id_t
-#include <rsys/dynamic_array.h>
-
-static FINLINE res_T
-bool_array_of_media_merge
- (struct darray_uchar* dst,
- const unsigned char* src,
- const medium_id_t sz)
-{
- res_T res = RES_OK;
- medium_id_t i;
- unsigned char* data_dst;
-
- ASSERT(src && dst);
-
- OK(darray_uchar_resize(dst, sz));
- data_dst = darray_uchar_data_get(dst);
- ASSERT(sz <= MEDIUM_MAX__);
- if(res != RES_OK) goto error;
- FOR_EACH(i, 0, sz) {
- if(!src[i]) continue;
- data_dst[i] = 1;
- }
-end:
- return res;
-error:
- goto end;
-}
-
-static FINLINE res_T
-bool_array_of_media_to_darray_media
- (struct darray_media* dst,
- const struct darray_uchar* src,
- const medium_id_t undef_idx)
-{
- res_T res = RES_OK;
- medium_id_t i;
- const unsigned char* data;
-
- ASSERT(src && dst);
-
- data = darray_uchar_cdata_get(src);
- ASSERT(undef_idx + 1 == darray_uchar_size_get(src));
- ASSERT(undef_idx < MEDIUM_MAX__);
- darray_media_clear(dst);
- if(res != RES_OK) goto error;
- FOR_EACH(i, 0, undef_idx + 1) {
- medium_id_t v = (i == undef_idx) ? SENC_UNDEFINED_MEDIUM : i;
- if(!data[i]) continue;
- res = darray_media_push_back(dst, &v);
- if(res != RES_OK) goto error;
- }
-end:
- return res;
-error:
- goto end;
-}
-
-struct enclosure_data {
- struct senc_enclosure_header header;
- /* Same triangle can appear twice if both sides */
- struct darray_sides_enc sides;
- /* Index of vertices in scene's unique vertices */
- struct darray_vrtx_id vertices;
- /* List of the enclosed media */
- struct darray_uchar tmp_enclosed_media;
- struct darray_media enclosed_media;
- /* Number of components involved in this enclosure */
- component_id_t cc_count;
- /* Linked list of the components */
- component_id_t first_component;
- /* Range of triangles member of the enclosure */
- struct side_range side_range;
- /* Counts */
- side_id_t side_count;
-};
-
-static FINLINE void
-enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) {
- ASSERT(enc);
- init_header(&enc->header);
- enc->cc_count = 0;
- enc->first_component = COMPONENT_NULL__;
- enc->side_range.first = SIDE_NULL__;
- enc->side_range.last = 0;
- enc->side_count = 0;
- darray_sides_enc_init(alloc, &enc->sides);
- darray_vrtx_id_init(alloc, &enc->vertices);
- darray_uchar_init(alloc, &enc->tmp_enclosed_media);
- darray_media_init(alloc, &enc->enclosed_media);
-}
-
-static FINLINE res_T
-enclosure_data_copy
- (struct enclosure_data* dst,
- const struct enclosure_data* src)
-{
- res_T res = RES_OK;
- ASSERT(src && dst);
- dst->header = src->header;
- dst->cc_count = src->cc_count;
- dst->first_component = src->first_component;
- dst->side_range = src->side_range;
- dst->side_count = src->side_count;
- OK(darray_sides_enc_copy(&dst->sides, &src->sides));
- OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices));
- OK(darray_uchar_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media));
- OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media));
-error:
- return res;
-}
-
-static FINLINE void
-enclosure_data_release(struct enclosure_data* n) {
- ASSERT(n);
- darray_sides_enc_release(&n->sides);
- darray_vrtx_id_release(&n->vertices);
- darray_uchar_release(&n->tmp_enclosed_media);
- darray_media_release(&n->enclosed_media);
-}
-
-static FINLINE res_T
-enclosure_data_copy_and_release
- (struct enclosure_data* dst,
- struct enclosure_data* src)
-{
- res_T res = RES_OK;
- ASSERT(src && dst);
- dst->header = src->header;
- dst->cc_count = src->cc_count;
- dst->first_component = src->first_component;
- dst->side_range = src->side_range;
- dst->side_count = src->side_count;
- OK(darray_sides_enc_copy_and_release(&dst->sides, &src->sides));
- OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices));
- OK(darray_uchar_copy_and_release(&dst->tmp_enclosed_media,
- &src->tmp_enclosed_media));
- OK(darray_media_copy_and_release(&dst->enclosed_media, &src->enclosed_media));
-error:
- return res;
-}
-
-#endif /* SENC_ENCLOSURE_DATA_H */
diff --git a/src/senc_internal_types.h b/src/senc_internal_types.h
@@ -1,139 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 SENC_INTERNAL_TYPES_H
-#define SENC_INTERNAL_TYPES_H
-
-#include <rsys/math.h>
-
-#include <stdint.h>
-
-/* Utility macros */
-#ifdef NDEBUG
-#define OK2(Expr)\
- if((tmp_res = (Expr)) != RES_OK) goto tmp_error;
-
-#define OK(Expr)\
- if((res = (Expr)) != RES_OK) goto error;
-#else
-#define OK2(Expr)\
- if((tmp_res = (Expr)) != RES_OK) {\
- fprintf(stderr, "%s: error code set to %d at line %d\n", FUNC_NAME,\
- tmp_res, __LINE__);\
- goto tmp_error;\
- }
-
-#define OK(Expr)\
- if((res = (Expr)) != RES_OK) {\
- fprintf(stderr, "%s: error code set to %d at line %d\n", FUNC_NAME,\
- res, __LINE__);\
- goto error;\
- }
-#endif
-
-/* Side IDs are uint32_t */
-typedef uint32_t side_id_t;
-#define SIDE_MAX__ (UINT32_MAX-1)
-#define SIDE_NULL__ UINT32_MAX
-
-/* Trg IDs use internally side_id_t */
-/* Cannot be larger than unsigned, as the API uses it. */
-typedef side_id_t trg_id_t;
-/* TRG_MAX__ is limited to allow to count sides */
-#define TRG_MAX__ (SIDE_MAX__ / 2)
-#define TRG_NULL__ UINT32_MAX
-
-/* Vertex IDs are internally uint32_t */
-/* Cannot be larger than unsigned, as the API uses it. */
-typedef uint32_t vrtx_id_t;
-#define VRTX_MAX__ (UINT32_MAX-1)
-#define VRTX_NULL__ UINT32_MAX
-
-/* Edge IDs use the same type than vertex IDs */
-/* Cannot be larger than unsigned, as the API uses it. */
-typedef vrtx_id_t edge_id_t;
-#define EDGE_MAX__ VRTX_MAX__
-#define EDGE_NULL__ VRTX_NULL__
-
-/* Medium IDs are internally uint32_t */
-/* Should nnot be larger than unsigned, as the API uses it. */
-typedef uint32_t medium_id_t;
-#define MEDIUM_MAX__ INT32_MAX
-#define MEDIUM_NULL__ UINT32_MAX
-
-/* Enclosure IDs are internally uint32_t */
-/* Cannot be larger than unsigned, as the API uses it. */
-typedef uint32_t enclosure_id_t;
-#define ENCLOSURE_MAX__ UINT32_MAX
-#define ENCLOSURE_NULL__ UINT32_MAX
-
-/* Component IDs use the same type than enclosure IDs */
-typedef enclosure_id_t component_id_t;
-#define COMPONENT_MAX__ (UINT32_MAX - 2) /* To allow special values */
-#define COMPONENT_NULL__ UINT32_MAX
-/* Special values */
-#define CC_GROUP_ROOT_NONE UINT32_MAX
-#define CC_GROUP_ROOT_INFINITE (UINT32_MAX - 1)
-#define CC_GROUP_ID_NONE UINT32_MAX
-#define CC_ID_NONE UINT32_MAX
-
-/* This one is used as flag */
-enum side_flag {
- FLAG_FRONT = BIT(0),
- FLAG_BACK = BIT(1)
-};
-
-/* Utility macros */
-static FINLINE trg_id_t
-TRGSIDE_2_TRG(side_id_t s) {
- ASSERT(((size_t)s >> 1) <= TRG_MAX__);
- return s >> 1;
-}
-
-static FINLINE int
-TRGSIDE_IS_FRONT(side_id_t s) {
- return (s & 1) == 0;
-}
-
-static FINLINE enum senc_side
-TRGSIDE_2_SIDE(side_id_t s) {
- return (s & 1) ? SENC_BACK : SENC_FRONT;
-}
-
-static FINLINE enum side_flag
-TRGSIDE_2_SIDEFLAG(side_id_t s) {
- return (s & 1) ? FLAG_BACK : FLAG_FRONT;
-}
-
-static FINLINE unsigned char
-SIDE_CANCELED_FLAG(enum side_flag f) {
- ASSERT((f << 4) <= UCHAR_MAX);
- return (unsigned char)(f << 4);
-}
-
-static FINLINE side_id_t
-TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum senc_side i) {
- ASSERT((((size_t)t << 1) | (i == SENC_BACK)) < SIDE_MAX__);
- ASSERT(i == SENC_FRONT || i == SENC_BACK);
- return (side_id_t)((t << 1) | (i == SENC_BACK));
-}
-
-static FINLINE side_id_t
-TRGSIDE_OPPOSITE(side_id_t s) {
- return TRGIDxSIDE_2_TRGSIDE(TRGSIDE_2_TRG(s),
- TRGSIDE_IS_FRONT(s) ? SENC_BACK : SENC_FRONT);
-}
-
-#endif /* SENC_INTERNAL_TYPES_H */
diff --git a/src/senc_s3d_wrapper.h b/src/senc_s3d_wrapper.h
@@ -1,80 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 SENC_S3D_WRAPPER_H
-#define SENC_S3D_WRAPPER_H
-
-#include "senc.h"
-
-#include <rsys/rsys.h>
-#include <rsys/float3.h>
-
-static FINLINE void
-senc_descriptor_get_global_indices__
- (const unsigned itri,
- unsigned indices[3],
- void* ctx)
-{
- const struct senc_descriptor* descriptor = ctx;
- res_T r;
- ASSERT(indices && ctx);
- r = senc_descriptor_get_global_triangle(descriptor, itri, indices);
- ASSERT(r == RES_OK); (void)r;
-}
-
-static FINLINE void
-senc_descriptor_get_global_vertices__
- (const unsigned ivert,
- float coord[3],
- void* ctx)
-{
- const struct senc_descriptor* descriptor = ctx;
- double tmp[3];
- res_T r;
- ASSERT(coord && ctx);
- r = senc_descriptor_get_global_vertex(descriptor, ivert, tmp);
- ASSERT(r == RES_OK); (void)r;
- f3_set_d3(coord, tmp);
-}
-
-static FINLINE void
-senc_enclosure_get_triangle__
- (const unsigned itri,
- unsigned indices[3],
- void* ctx)
-{
- const struct senc_enclosure* enclosure = ctx;
- res_T r;
- ASSERT(indices && ctx);
- r = senc_enclosure_get_triangle(enclosure, itri, indices);
- ASSERT(r == RES_OK); (void)r;
-}
-
-static FINLINE void
-senc_enclosure_get_vertex__
- (const unsigned ivert,
- float coord[3],
- void* ctx)
-{
- const struct senc_enclosure* enclosure = ctx;
- double tmp[3];
- res_T r;
- ASSERT(coord && ctx);
- r = senc_enclosure_get_vertex(enclosure, ivert, tmp);
- ASSERT(r == RES_OK); (void)r;
- f3_set_d3(coord, tmp);
-}
-
-#endif /* SENC_S3D_WRAPPER_H */
diff --git a/src/senc_scene.c b/src/senc_scene.c
@@ -1,456 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "senc_device_c.h"
-#include "senc_scene_c.h"
-
-#include <rsys/rsys.h>
-#include <rsys/double3.h>
-#include <rsys/mem_allocator.h>
-
-#include <limits.h>
-
-/*******************************************************************************
- * Helper function
- ******************************************************************************/
-static void
-scene_release(ref_T * ref)
-{
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- ASSERT(ref);
- scn = CONTAINER_OF(ref, struct senc_scene, ref);
- dev = scn->dev;
- darray_triangle_in_release(&scn->triangles_in);
- darray_position_release(&scn->vertices);
- htable_vrtx_release(&scn->unique_vertices);
- htable_trg_release(&scn->unique_triangles);
- darray_side_range_release(&scn->media_use);
- MEM_RM(dev->allocator, scn);
- SENC(device_ref_put(dev));
-}
-
-static INLINE int
-compatible_medium
- (const medium_id_t m1,
- const medium_id_t m2)
-{
- if(m1 == SENC_UNDEFINED_MEDIUM || m2 == SENC_UNDEFINED_MEDIUM) return 1;
- return (m1 == m2);
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-senc_scene_create
- (struct senc_device* dev,
- const int conv,
- struct senc_scene** out_scn)
-{
- struct senc_scene* scn = NULL;
- res_T res = RES_OK;
-
- if(!dev || !out_scn
- /* Convention must be set both regarding FRONT/BACK and INSIDE/OUTSIDE */
- || !(conv & (SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_BACK))
- || !(conv & (SENC_CONVENTION_NORMAL_INSIDE | SENC_CONVENTION_NORMAL_OUTSIDE)))
- return RES_BAD_ARG;
-
- scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct senc_scene));
- if(!scn) {
- log_err(dev, "%s: could not allocate the StarEnclosures scene.\n", FUNC_NAME);
- res = RES_MEM_ERR;
- goto error;
- }
- ref_init(&scn->ref);
- SENC(device_ref_get(dev));
- scn->dev = dev;
- scn->convention = conv;
- scn->ntris = 0;
- scn->nutris = 0;
- scn->next_medium_idx = 0;
- scn->nverts = 0;
- scn->nuverts = 0;
- scn->sides_with_defined_medium_count = 0;
- darray_triangle_in_init(dev->allocator, &scn->triangles_in);
- darray_position_init(dev->allocator, &scn->vertices);
- htable_vrtx_init(dev->allocator, &scn->unique_vertices);
- htable_trg_init(dev->allocator, &scn->unique_triangles);
- darray_side_range_init(dev->allocator, &scn->media_use);
-
-exit:
- if(scn) *out_scn = scn;
- return res;
-error:
- if(scn) {
- SENC(scene_ref_put(scn));
- scn = NULL;
- }
- goto exit;
-}
-
-res_T
-senc_scene_reserve
- (struct senc_scene* scn,
- const unsigned vertices_count,
- const unsigned triangles_count,
- const unsigned media_count)
-{
- res_T res = RES_OK;
- if(!scn) return RES_BAD_ARG;
-
- OK(darray_position_reserve(&scn->vertices, vertices_count));
- OK(darray_triangle_in_reserve(&scn->triangles_in, triangles_count));
- OK(htable_vrtx_reserve(&scn->unique_vertices, vertices_count));
- OK(htable_trg_reserve(&scn->unique_triangles, triangles_count));
- OK(darray_side_range_reserve(&scn->media_use, media_count));
-
-end:
- return res;
-error:
- goto end;
-}
-
-res_T
-senc_scene_add_geometry
- (struct senc_scene* scn,
- const unsigned ntris,
- void(*indices)(const unsigned, unsigned*, void*),
- void(*media)(const unsigned, unsigned*, void*),
- const unsigned nverts,
- void(*position)(const unsigned, double*, void* ctx),
- res_T(*add_triangle)(const unsigned, const unsigned, void*),
- res_T(*merge_triangle)(const unsigned, const unsigned, const int,
- const unsigned*, const unsigned*, void*),
- void* ctx)
-{
- struct darray_vrtx_id unique_vertice_ids;
- unsigned i;
- vrtx_id_t actual_nverts = 0;
- vrtx_id_t actual_nuverts = 0;
- trg_id_t actual_ntris = 0;
- trg_id_t actual_nutris = 0;
- const struct triangle_in* trg;
- res_T res = RES_OK;
-
- if(!scn
- || !indices || !position
- || !nverts || ((size_t)scn->nverts + (size_t)nverts) > VRTX_MAX__
- || !ntris || ((size_t)scn->ntris + (size_t)ntris) > TRG_MAX__)
- return RES_BAD_ARG;
-
- /* Make room for new geometry; suppose no more duplicates. */
- darray_vrtx_id_init(scn->dev->allocator, &unique_vertice_ids);
- OK(darray_vrtx_id_reserve(&unique_vertice_ids, nverts));
- OK(darray_position_reserve(&scn->vertices, scn->nuverts + nverts));
- OK(darray_triangle_in_reserve(&scn->triangles_in, scn->nutris + ntris));
- OK(htable_vrtx_reserve(&scn->unique_vertices, scn->nuverts + nverts));
- OK(htable_trg_reserve(&scn->unique_triangles, scn->nutris + ntris));
-
- trg = darray_triangle_in_cdata_get(&scn->triangles_in);
-
- /* Get geometry */
- FOR_EACH(i, 0, nverts) {
- vrtx_id_t* p_vrtx;
- union double3 tmp;
- vrtx_id_t unique_v;
- /* API: position needs an unsigned */
- position(i, tmp.vec, ctx);
- p_vrtx = htable_vrtx_find(&scn->unique_vertices, &tmp);
- if(p_vrtx) {
- /* Duplicate vertex */
- unique_v = *p_vrtx;
- } else {
- /* New vertex */
- unique_v = scn->nuverts + actual_nuverts;
- ASSERT(unique_v == htable_vrtx_size_get(&scn->unique_vertices));
- OK(darray_position_push_back(&scn->vertices, &tmp));
- OK(htable_vrtx_set(&scn->unique_vertices, &tmp, &unique_v));
- ++actual_nuverts;
- }
- /* The unique ID for vertex i is unique_v */
- ASSERT(i == darray_vrtx_id_size_get(&unique_vertice_ids));
- OK(darray_vrtx_id_push_back(&unique_vertice_ids, &unique_v));
- ++actual_nverts;
- }
-
- FOR_EACH(i, 0, ntris) {
- int j;
- unsigned med[2] = { SENC_UNDEFINED_MEDIUM, SENC_UNDEFINED_MEDIUM };
- unsigned ind[3];
- union vrtx_id3 trg_key;
- struct triangle_in tmp, *range_adjust_ptr = NULL;
- trg_id_t* p_trg;
- char reversed;
- /* Triangle index in user world regardless of deduplication. */
- tmp.global_id = (unsigned)(scn->ntris + i);
- indices(i, ind, ctx); /* API: indices need unsigneds */
- FOR_EACH(j, 0, 3) {
- if(ind[j] >= nverts) {
- res = RES_BAD_ARG;
- goto error;
- }
- ASSERT(ind[j] < darray_vrtx_id_size_get(&unique_vertice_ids));
- /* Find the unique ID for this vertex */
- tmp.vertice_id[j] = darray_vrtx_id_cdata_get(&unique_vertice_ids)[ind[j]];
- }
- if(tmp.vertice_id[0] == tmp.vertice_id[1]
- || tmp.vertice_id[0] == tmp.vertice_id[2]
- || tmp.vertice_id[1] == tmp.vertice_id[2]) {
- const union double3* positions
- = darray_position_cdata_get(&scn->vertices);
- log_err(scn->dev, "%s: triangle %lu is degenerate.\n",
- FUNC_NAME, (unsigned long)tmp.global_id);
- log_err(scn->dev, " (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
- SPLIT3(positions[trg[i].vertice_id[0]].vec),
- SPLIT3(positions[trg[i].vertice_id[1]].vec),
- SPLIT3(positions[trg[i].vertice_id[2]].vec));
- res = RES_BAD_ARG;
- goto error;
- }
- /* Get media */
- if(media) media(i, med, ctx); /* API: media needs an unsigned */
- FOR_EACH(j, 0, 2) {
- if(med[j] != SENC_UNDEFINED_MEDIUM && med[j] >= scn->next_medium_idx) {
- ASSERT(med[j] < MEDIUM_MAX__);
- scn->next_medium_idx = med[j] + 1;
- darray_side_range_resize(&scn->media_use, scn->next_medium_idx);
- }
- tmp.medium[j] = (medium_id_t)med[j];
- }
- /* Find duplicate triangles */
- reversed = trg_make_key(&trg_key, tmp.vertice_id);
- p_trg = htable_trg_find(&scn->unique_triangles, &trg_key);
- if(p_trg) {
- /* Duplicate triangle. Need to check duplicate validity */
- union vrtx_id3 utrg_key;
- char ureversed = trg_make_key(&utrg_key, trg[*p_trg].vertice_id);
- int same = (reversed == ureversed);
- const medium_id_t* umed;
- ASSERT(trg_key_eq(&trg_key, &utrg_key));
- if(!same) SWAP(unsigned, tmp.medium[0], tmp.medium[1]);
- umed = trg[*p_trg].medium;
- if(merge_triangle) {
- /* Let the client app rule. */
- unsigned smed[2], mmed[2];
- FOR_EACH(j, 0, 2) {
- smed[j] = (unsigned)umed[j];
- mmed[j] = (unsigned)tmp.medium[j];
- }
- OK(merge_triangle(trg[*p_trg].global_id, i, same, smed, mmed, ctx));
- /* If merge_triangle returns OK its OK even if media are incompatible. */
- } else {
- if(!compatible_medium(umed[0], tmp.medium[0])
- || !compatible_medium(umed[1], tmp.medium[1]))
- {
- res = RES_BAD_ARG;
- goto error;
- }
- }
- /* Legit duplicate (or accepted by merge_triangle): replace undef media. */
- range_adjust_ptr = darray_triangle_in_data_get(&scn->triangles_in) + *p_trg;
- /* Replace possible undefined media */
- FOR_EACH(j, 0, 2) {
- if(range_adjust_ptr->medium[j] == SENC_UNDEFINED_MEDIUM
- && tmp.medium[j] != SENC_UNDEFINED_MEDIUM) {
- range_adjust_ptr->medium[j] = tmp.medium[j];
- scn->sides_with_defined_medium_count++;
- }
- }
- } else {
- /* New triangle */
- trg_id_t u = scn->nutris + actual_nutris;
- if (add_triangle)
- OK(add_triangle(tmp.global_id, i, ctx));
- OK(darray_triangle_in_push_back(&scn->triangles_in, &tmp));
- range_adjust_ptr = darray_triangle_in_data_get(&scn->triangles_in) + u;
- FOR_EACH(j, 0, 2) {
- if(tmp.medium[j] != SENC_UNDEFINED_MEDIUM)
- scn->sides_with_defined_medium_count++;
- }
- ASSERT(u == htable_trg_size_get(&scn->unique_triangles));
- OK(htable_trg_set(&scn->unique_triangles, &trg_key, &u));
- ++actual_nutris;
- }
- if(range_adjust_ptr) {
- ptrdiff_t u = range_adjust_ptr - trg;
- ASSERT(u < scn->nutris + actual_nutris && u < TRG_MAX__);
- FOR_EACH(j, 0, 2) {
- struct side_range* media_use;
- if(tmp.medium[j] == SENC_UNDEFINED_MEDIUM) continue;
- ASSERT(tmp.medium[j] < scn->next_medium_idx);
- media_use = darray_side_range_data_get(&scn->media_use) + tmp.medium[j];
- media_use->first =
- MMIN(media_use->first, TRGIDxSIDE_2_TRGSIDE((trg_id_t)u, j));
- ASSERT(media_use->first < 2 * (scn->nutris + actual_nutris + 1));
- media_use->last =
- MMAX(media_use->last, TRGIDxSIDE_2_TRGSIDE((trg_id_t)u, j));
- ASSERT(media_use->last < 2 * (scn->nutris + actual_nutris + 1));
- ASSERT(media_use->first <= media_use->last);
- }
- }
- ++actual_ntris;
- }
-
-exit:
- darray_vrtx_id_release(&unique_vertice_ids);
- /* Update sizes */
- scn->nuverts += actual_nuverts;
- scn->nverts += actual_nverts;
- scn->nutris += actual_nutris;
- scn->ntris += actual_ntris;
- ASSERT(scn->nuverts == htable_vrtx_size_get(&scn->unique_vertices));
- ASSERT(scn->nutris == htable_trg_size_get(&scn->unique_triangles));
- return res;
-error:
- goto exit;
-}
-
-res_T
-senc_scene_get_convention
- (const struct senc_scene* scn,
- int* convention)
-{
- if(!scn || !convention) return RES_BAD_ARG;
- *convention = scn->convention;
- return RES_OK;
-
-}
-
-res_T
-senc_scene_get_triangles_count
- (const struct senc_scene* scn,
- unsigned* count)
-{
- if(!scn || !count) return RES_BAD_ARG;
- *count = scn->ntris;
- return RES_OK;
-}
-
-res_T
-senc_scene_get_unique_triangles_count
- (const struct senc_scene* scn,
- unsigned* count)
-{
- if(!scn || !count) return RES_BAD_ARG;
- *count = scn->nutris;
- return RES_OK;
-}
-
-res_T
-senc_scene_get_unique_sides_without_medium_count
- (const struct senc_scene* scn,
- unsigned* count)
-{
- if(!scn || !count) return RES_BAD_ARG;
- ASSERT(2 * scn->nutris >= scn->sides_with_defined_medium_count);
- *count = 2 * scn->nutris - scn->sides_with_defined_medium_count;
- return RES_OK;
-}
-
-res_T
-senc_scene_get_unique_triangle
- (const struct senc_scene* scn,
- const unsigned itri,
- unsigned indices[3])
-{
- const struct triangle_in* trg;
- int i;
- if(!scn || !indices
- || itri >= darray_triangle_in_size_get(&scn->triangles_in))
- return RES_BAD_ARG;
- trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri;
-
- FOR_EACH(i, 0, 3) {
- ASSERT(trg->vertice_id[i] < UINT_MAX);
- indices[i] = (unsigned)trg->vertice_id[i]; /* Back to API type */
- }
- return RES_OK;
-}
-
-res_T
-senc_scene_get_unique_triangle_media
- (const struct senc_scene* scn,
- const unsigned itri,
- unsigned media[2])
-{
- const struct triangle_in* trg;
- int i;
- if(!scn || !media
- || itri >= darray_triangle_in_size_get(&scn->triangles_in))
- return RES_BAD_ARG;
- trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri;
-
- FOR_EACH(i, 0, 2) {
- ASSERT(trg->vertice_id[i] < UINT_MAX);
- media[i] = (unsigned)trg->medium[i]; /* Back to API type */
- }
- return RES_OK;
-}
-
-res_T
-senc_scene_get_vertices_count
- (const struct senc_scene* scn,
- unsigned* count)
-{
- if(!scn || !count) return RES_BAD_ARG;
- *count = scn->nverts;
- return RES_OK;
-}
-
-res_T
-senc_scene_get_unique_vertices_count
- (const struct senc_scene* scn,
- unsigned* count)
-{
- if(!scn || !count) return RES_BAD_ARG;
- *count = scn->nuverts;
- return RES_OK;
-}
-
-res_T
-senc_scene_get_unique_vertex
- (const struct senc_scene* scn,
- const unsigned ivert,
- double coord[3])
-{
-
- const union double3* v;
- if(!scn || !coord
- || ivert >= darray_position_size_get(&scn->vertices))
- return RES_BAD_ARG;
-
- v = darray_position_cdata_get(&scn->vertices) + ivert;
- d3_set(coord, v->vec);
- return RES_OK;
-}
-
-res_T
-senc_scene_ref_get(struct senc_scene* scn)
-{
- if(!scn) return RES_BAD_ARG;
- ref_get(&scn->ref);
- return RES_OK;
-}
-
-res_T
-senc_scene_ref_put(struct senc_scene* scn)
-{
- if(!scn) return RES_BAD_ARG;
- ref_put(&scn->ref, scene_release);
- return RES_OK;
-}
diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c
@@ -1,1374 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "senc_device_c.h"
-#include "senc_scene_c.h"
-#include "senc_scene_analyze_c.h"
-#include "senc_internal_types.h"
-
-#include <rsys/rsys.h>
-#include <rsys/float3.h>
-#include <rsys/double33.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/hash_table.h>
-#include <rsys/dynamic_array.h>
-#include <rsys/dynamic_array_uchar.h>
-#include <rsys/clock_time.h>
-
-#include <star/s3d.h>
-
-#include <omp.h>
-#include <limits.h>
-#include <stdlib.h>
-
-#define CC_DESCRIPTOR_NULL__ {\
- CHAR_MAX, VRTX_NULL__, 0,\
- CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\
- { TRG_NULL__, 0},\
- NULL\
-}
-#ifdef COMPILER_GCC
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
-#endif
-const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
-#ifdef COMPILER_GCC
- #pragma GCC diagnostic pop
-#endif
-
-#define DARRAY_NAME component_id
-#define DARRAY_DATA component_id_t
-#include <rsys/dynamic_array.h>
-
-/*******************************************************************************
- * Helper function
- ******************************************************************************/
-static INLINE int
-neighbour_cmp(const void* w1, const void* w2)
-{
- const double a1 = ((struct neighbour_info*)w1)->angle;
- const double a2 = ((struct neighbour_info*)w2)->angle;
- return (a1 > a2) - (a1 < a2);
-}
-
-static side_id_t
-get_side_not_in_connex_component
- (const side_id_t last_side,
- const struct trgside* trgsides,
- const unsigned char* processed,
- side_id_t* first_side_not_in_component,
- const medium_id_t medium)
-{
- ASSERT(trgsides && processed && first_side_not_in_component);
- {
- side_id_t i = *first_side_not_in_component;
- while (i <= last_side
- && (trgsides[i].medium != medium
- || (processed[TRGSIDE_2_TRG(i)] & TRGSIDE_2_SIDEFLAG(i))))
- ++i;
-
- *first_side_not_in_component = i + 1;
- if(i > last_side) return SIDE_NULL__;
- return i;
- }
-}
-
-static void
-get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) {
- int i;
- const struct senc_scene* scene = ctx;
- const struct triangle_in* trg =
- darray_triangle_in_cdata_get(&scene->triangles_in) + itri;
- FOR_EACH(i, 0, 3) {
- ASSERT(trg->vertice_id[i] < scene->nverts);
- ids[i] = (unsigned)trg->vertice_id[i]; /* Back to API type */
- }
-}
-
-static void
-get_scn_position(const unsigned ivert, float pos[3], void* ctx) {
- const struct senc_scene* scene = ctx;
- const union double3* pt =
- darray_position_cdata_get(&scene->vertices) + ivert;
- f3_set_d3(pos, pt->vec);
-}
-
-static int
-self_hit_filter
- (const struct s3d_hit* hit,
- const float ray_org[3],
- const float ray_dir[3],
- void* ray_data,
- void* filter_data)
-{
- const struct darray_triangle_comp* triangles_comp = filter_data;
- const component_id_t* origin_component = ray_data;
- const struct triangle_comp* hit_trg_comp;
-
- (void)ray_org; (void)ray_dir;
- ASSERT(hit && triangles_comp && origin_component);
- ASSERT(hit->prim.prim_id < darray_triangle_comp_size_get(triangles_comp));
- hit_trg_comp = darray_triangle_comp_cdata_get(triangles_comp)
- + hit->prim.prim_id;
- return (hit_trg_comp->component[SENC_FRONT] == *origin_component
- || hit_trg_comp->component[SENC_BACK] == *origin_component);
-
-}
-
-static void
-extract_connex_components
- (struct senc_descriptor* desc,
- struct trgside* trgsides,
- struct darray_ptr_component_descriptor* connex_components,
- const struct darray_triangle_tmp* triangles_tmp_array,
- struct darray_triangle_comp* triangles_comp_array,
- struct s3d_scene_view** s3d_view,
- ATOMIC* component_count,
- /* Shared error status.
- * We accept to overwrite an error with a different error */
- res_T* p_res)
-{
- /* This function is called from an omp parallel block and executed
- * concurrently. */
- struct senc_scene* scn;
- struct mem_allocator* alloc;
- int64_t mm, undefs;
- struct darray_side_id stack;
- struct darray_side_id ids_of_sides_around_max_z_vertex;
- const union double3* positions;
- const struct triangle_tmp* triangles_tmp;
- struct triangle_comp* triangles_comp;
- /* An array to flag sides when processed */
- unsigned char* processed;
- /* An array to store the component being processed */
- struct darray_side_id current_component;
- /* A bool array to store media of the component being processed */
- unsigned char* current_media = NULL;
- size_t sz, ii;
-
- ASSERT(trgsides && desc && connex_components && triangles_tmp_array
- && triangles_comp_array && s3d_view && component_count && p_res);
- alloc = descriptor_get_allocator(desc);
- scn = desc->scene;
- positions = darray_position_cdata_get(&scn->vertices);
- triangles_tmp = darray_triangle_tmp_cdata_get(triangles_tmp_array);
- triangles_comp = darray_triangle_comp_data_get(triangles_comp_array);
- darray_side_id_init(alloc, &stack);
- darray_side_id_init(alloc, &ids_of_sides_around_max_z_vertex);
- darray_side_id_init(alloc, ¤t_component);
- processed = MEM_CALLOC(alloc, scn->nutris, sizeof(unsigned char));
- if(!processed) {
- *p_res = RES_MEM_ERR;
- return;
- }
-
- /* If there are sides with undefined medium, its like another medium */
- undefs = (scn->sides_with_defined_medium_count < 2 * scn->nutris) ? 1 : 0;
- #pragma omp single
- {
- if(undefs) {
- /* Range is unknown, process each side */
- struct side_range und;
- und.first = 0;
- und.last = 2 * scn->nutris - 1;
- darray_side_range_push_back(&scn->media_use, &und);
- }
- } /* Implicit barrier here */
-
-#ifndef NDEBUG
- #pragma omp single
- {
- trg_id_t t_;
- ASSERT(darray_ptr_component_descriptor_size_get(connex_components) == 0);
- FOR_EACH(t_, 0, scn->nutris) {
- const struct triangle_in* trg_in =
- darray_triangle_in_cdata_get(&scn->triangles_in) + t_;
- const struct side_range* media_use
- = darray_side_range_cdata_get(&scn->media_use);
- FOR_EACH(mm, 0, 2) {
- const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t_, mm);
- medium_id_t medium = trg_in->medium[mm];
- if(medium == SENC_UNDEFINED_MEDIUM) medium = scn->next_medium_idx;
- ASSERT(media_use[medium].first <= side && side
- <= media_use[medium].last);
- }
- }
- } /* Implicit barrier here */
-#endif
-
- /* We loop on sides to build connex components. */
- #pragma omp for schedule(dynamic) nowait
- /* Process all media, including undef */
- for(mm = 0; mm < undefs + (int64_t)scn->next_medium_idx; mm++) {
- const medium_id_t m_idx = (medium_id_t)mm;
- const medium_id_t m = (mm == scn->next_medium_idx)
- ? SENC_UNDEFINED_MEDIUM : (medium_id_t)mm;
- /* Any not-already-used side is used as a starting point */
- const struct side_range* media_use =
- darray_side_range_cdata_get(&scn->media_use) + m_idx;
- side_id_t first_side_not_in_component = media_use->first;
- double max_nz;
- side_id_t max_nz_side_id = SIDE_NULL__;
- const side_id_t last_side = media_use->last;
- int component_canceled = 0;
- res_T tmp_res = RES_OK;
- ATOMIC id;
-
- if(*p_res != RES_OK) continue;
- if(first_side_not_in_component == SIDE_NULL__)
- continue; /* Unused medium */
- ASSERT(first_side_not_in_component < 2 * scn->nutris);
- ASSERT(darray_side_id_size_get(&stack) == 0);
- ASSERT(darray_side_id_size_get(¤t_component) == 0);
- for(;;) { /* Process all components for this medium */
- const side_id_t start_side_id = get_side_not_in_connex_component
- (last_side, trgsides, processed, &first_side_not_in_component, m);
- side_id_t crt_side_id = start_side_id;
- side_id_t last_side_id = start_side_id;
- vrtx_id_t max_z_vrtx_id = VRTX_NULL__;
- struct cc_descriptor *cc;
- double max_z = -DBL_MAX;
- component_canceled = 0;
- ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nutris);
- darray_side_id_clear(¤t_component);
-
- if(*p_res != RES_OK) break;
- if(start_side_id == SIDE_NULL__)
- break; /* start_side_id=SIDE_NULL__ => component done! */
-
-#ifndef NDEBUG
- {
- trg_id_t tid = TRGSIDE_2_TRG(start_side_id);
- enum senc_side s = TRGSIDE_2_SIDE(start_side_id);
- medium_id_t side_med
- = darray_triangle_in_data_get(&desc->scene->triangles_in)[tid].medium[s];
- ASSERT(side_med == m);
- }
-#endif
-
- /* Reuse array if possible, or create a new one */
- if(current_media) {
- memset(current_media, 0, 1 + scn->next_medium_idx); /* +1 for possible undef */
- } else {
- current_media = MEM_CALLOC(alloc, 1 + scn->next_medium_idx, sizeof(unsigned char));
- if(!current_media) {
- *p_res = RES_MEM_ERR;
- continue;
- }
- }
- current_media[m_idx] = 1;
- for(;;) { /* Process all sides of this component */
- int i;
- enum side_flag crt_side_flag = TRGSIDE_2_SIDEFLAG(crt_side_id);
- struct trgside* crt_side = trgsides + crt_side_id;
- const trg_id_t crt_trg_id = TRGSIDE_2_TRG(crt_side_id);
- const struct triangle_in* trg_in =
- darray_triangle_in_cdata_get(&scn->triangles_in) + crt_trg_id;
- unsigned char* trg_used = processed + crt_trg_id;
- const struct triangle_tmp* const trg_tmp = triangles_tmp + crt_trg_id;
- ASSERT(crt_trg_id < scn->nutris);
-
- if(*p_res != RES_OK) break;
-
- /* Record Zmax information
- * Keep track of the appropriate vertex of the component in order
- * to cast a ray at the component grouping step of the algorithm.
- * The most appropriate vertex is (the) one with the greater Z
- * coordinate. */
- if(max_z < trg_tmp->max_z) {
- /* New best vertex */
- max_z = trg_tmp->max_z;
- /* New vertex: reset list of sides */
- darray_side_id_clear(&ids_of_sides_around_max_z_vertex);
-
- /* Select a vertex with z == max_z */
- FOR_EACH(i, 0, 3) {
- if(max_z == positions[trg_in->vertice_id[i]].pos.z) {
- max_z_vrtx_id = trg_in->vertice_id[i];
- break;
- }
- }
- ASSERT(i < 3); /* Found one */
- /* List of sides using the vertex */
- OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex,
- &crt_side_id));
- } else if(max_z == trg_tmp->max_z) {
- /* Does this triangle use the currently selected max_z vertex? */
- FOR_EACH(i, 0, 3) {
- if(max_z_vrtx_id == trg_in->vertice_id[i]) {
- /* List of sides using the vertex */
- OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex,
- &crt_side_id));
- break;
- }
- }
- }
-
- /* Record crt_side both as component and triangle level */
- if((*trg_used & crt_side_flag) == 0) {
- OK2(darray_side_id_push_back(¤t_component, &crt_side_id));
- *trg_used = *trg_used | (unsigned char)crt_side_flag;
- }
-
- /* Store neighbour's sides in a waiting stack */
- FOR_EACH(i, 0, 3) {
- side_id_t neighbour_id = crt_side->facing_side_id[i];
- trg_id_t nbour_trg_id = TRGSIDE_2_TRG(neighbour_id);
- enum side_flag nbour_side_id = TRGSIDE_2_SIDEFLAG(neighbour_id);
- unsigned char* nbour_used = processed + nbour_trg_id;
- const struct trgside* neighbour = trgsides + neighbour_id;
- medium_id_t nbour_med_idx = (neighbour->medium == SENC_UNDEFINED_MEDIUM)
- ? scn->next_medium_idx : neighbour->medium;
- if(neighbour->medium < m
- || (*nbour_used & SIDE_CANCELED_FLAG(nbour_side_id)))
- {
- /* 1) Not the same medium.
- * Neighbour's medium id is less than current medium: the whole
- * component is to be processed by another thread (possibly the one
- * associated with neighbour's medium).
- * 2) Neighbour was canceled: no need to replay the component
- * again as it will eventually rediscover the side with low medium
- * id and recancel all the work in progress */
- component_canceled = 1;
- darray_side_id_clear(&stack);
- /* Don't cancel used flags as all these sides will get us back to
- * (at least) the neighbour side we have just discovered, that will
- * cancel them again and again */
- sz = darray_side_id_size_get(¤t_component);
- FOR_EACH(ii, 0, sz) {
- side_id_t used_side
- = darray_side_id_cdata_get(¤t_component)[ii];
- trg_id_t used_trg_id = TRGSIDE_2_TRG(used_side);
- enum side_flag used_side_flag
- = TRGSIDE_2_SIDEFLAG(used_side);
- unsigned char* used = processed + used_trg_id;
- ASSERT(*used & (unsigned char)used_side_flag);
- /* Set the used flag for sides in cancelled component as leading
- * to further cancellations */
- *used |= SIDE_CANCELED_FLAG(used_side_flag);
- }
-
- goto canceled;
- }
- if(*nbour_used & nbour_side_id) continue; /* Already processed */
- /* Mark neighbour as processed and stack it */
- *nbour_used |= (unsigned char)nbour_side_id;
- OK2(darray_side_id_push_back(&stack, &neighbour_id));
- OK2(darray_side_id_push_back(¤t_component, &neighbour_id));
- current_media[nbour_med_idx] = 1;
- }
- sz = darray_side_id_size_get(&stack);
- if(sz == 0) break; /* Empty stack => component is done! */
- crt_side_id = darray_side_id_cdata_get(&stack)[sz - 1];
- darray_side_id_pop_back(&stack);
- last_side_id = MMAX(last_side_id, crt_side_id);
- }
- canceled:
- if(component_canceled) continue;
-
- /* Register the new component and get it initialized */
- cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor));
- if(!cc) *p_res = RES_MEM_ERR;
- if(*p_res != RES_OK) break;
-
- ASSERT(m == trgsides[start_side_id].medium);
- ASSERT(max_z_vrtx_id != VRTX_NULL__);
- cc_descriptor_init(alloc, cc);
- id = ATOMIC_INCR(component_count) - 1;
- ASSERT(id <= COMPONENT_MAX__);
- cc->cc_id = (component_id_t)id;
- sz = darray_side_id_size_get(¤t_component);
- ASSERT(sz <= SIDE_MAX__);
- cc->side_count = (side_id_t)sz;
- cc->side_range.first = start_side_id;
- cc->side_range.last = last_side_id;
- cc->max_z_vrtx_id = max_z_vrtx_id;
- /* Tranfer ownership of the array to component */
- ASSERT(!cc->media && current_media);
- cc->media = current_media;
- current_media = NULL;
-
- /* Write component membership in the global structure
- * No need for sync here as an unique thread writes a given side */
- {STATIC_ASSERT(sizeof(cc->cc_id) >= 4, Cannot_write_IDs_sync_free);}
- ASSERT(IS_ALIGNED(triangles_comp->component, sizeof(cc->cc_id)));
- FOR_EACH(ii, 0, sz) {
- const side_id_t s = darray_side_id_cdata_get(¤t_component)[ii];
- trg_id_t tid = TRGSIDE_2_TRG(s);
- enum senc_side sid = TRGSIDE_2_SIDE(s);
- component_id_t* cmp = triangles_comp[tid].component;
- ASSERT(cmp[sid] == COMPONENT_NULL__);
- ASSERT(trgsides[s].medium >= m);
- cmp[sid] = cc->cc_id;
- }
-
- /* Compute the normal at the max_z vertex. */
- max_nz = 0;
- sz = darray_side_id_size_get(&ids_of_sides_around_max_z_vertex);
- ASSERT(sz > 0);
- FOR_EACH(ii, 0, sz) {
- const side_id_t side_id =
- darray_side_id_cdata_get(&ids_of_sides_around_max_z_vertex)[ii];
- const trg_id_t trg_id = TRGSIDE_2_TRG(side_id);
- enum senc_side s = TRGSIDE_2_SIDE(side_id);
- const struct triangle_in* trg_in =
- darray_triangle_in_cdata_get(&scn->triangles_in) + trg_id;
- const struct triangle_comp* trg_comp = triangles_comp + trg_id;
- const union double3* vertices =
- darray_position_cdata_get(&scn->vertices);
- double edge0[3], edge1[3], normal[3], norm;
-
- /* To ensure that triangles with 2 sides in the component total to 0
- * regardless of numeric accuracy, we need to prevent them to
- * contribute (remember than x + y - y == x can be false). */
- ASSERT(trg_comp->component[s] == cc->cc_id); (void)s;
- if(trg_comp->component[SENC_FRONT] == trg_comp->component[SENC_BACK])
- continue;
-
- d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec,
- vertices[trg_in->vertice_id[0]].vec);
- d3_sub(edge1, vertices[trg_in->vertice_id[2]].vec,
- vertices[trg_in->vertice_id[0]].vec);
- d3_cross(normal, edge0, edge1);
- norm = d3_normalize(normal, normal);
- ASSERT(norm); (void)norm;
-
- if(fabs(max_nz) < fabs(normal[2])) {
- max_nz_side_id = side_id;
- max_nz = normal[2];
- }
- }
- if(max_nz == 0) cc->is_outer_border = 0;
- else {
- if(TRGSIDE_IS_FRONT(max_nz_side_id)
- == ((scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0)) {
- /* Geom normal points towards the component */
- cc->is_outer_border = (max_nz < 0);
- } else {
- /* Geom normal points away from the component */
- cc->is_outer_border = (max_nz > 0);
- }
- }
-
- /* Need to synchronize connex_components growth as this global structure
- * is accessed by multipe threads */
- #pragma omp critical
- {
- struct cc_descriptor** components;
- sz = darray_ptr_component_descriptor_size_get(connex_components);
- if(sz <= cc->cc_id) {
- tmp_res = darray_ptr_component_descriptor_resize(connex_components,
- 1 + cc->cc_id);
- if(tmp_res != RES_OK) *p_res = tmp_res;
- }
- if(*p_res == RES_OK) {
- /* Don't set the pointer before resize as this can lead to move data */
- components =
- darray_ptr_component_descriptor_data_get(connex_components);
- ASSERT(components[cc->cc_id] == NULL);
- components[cc->cc_id] = cc;
- }
- }
- }
- tmp_error:
- if(tmp_res != RES_OK) *p_res = tmp_res;
- } /* No barrier here */
-
- MEM_RM(alloc, processed);
- MEM_RM(alloc, current_media);
- darray_side_id_release(¤t_component);
- darray_side_id_release(&stack);
- darray_side_id_release(&ids_of_sides_around_max_z_vertex);
-
- /* The first thread here creates the s3d view */
- #pragma omp single nowait
- if(*p_res == RES_OK) {
- res_T res = RES_OK;
- struct s3d_device* s3d = NULL;
- struct s3d_scene* s3d_scn = NULL;
- struct s3d_shape* s3d_shp = NULL;
- struct s3d_vertex_data attribs;
-
- attribs.type = S3D_FLOAT3;
- attribs.usage = S3D_POSITION;
- attribs.get = get_scn_position;
-
- /* Put geometry in a 3D view */
- OK(s3d_device_create(desc->scene->dev->logger, alloc, 0, &s3d));
- OK(s3d_scene_create(s3d, &s3d_scn));
- OK(s3d_shape_create_mesh(s3d, &s3d_shp));
-
- /* Back to API type for ntris and nverts */
- ASSERT(desc->scene->nutris < UINT_MAX);
- ASSERT(desc->scene->nuverts < UINT_MAX);
- OK(s3d_mesh_setup_indexed_vertices(s3d_shp,
- (unsigned)desc->scene->nutris, get_scn_indices,
- (unsigned)desc->scene->nuverts, &attribs, 1, scn));
- s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter,
- triangles_comp_array);
- OK(s3d_scene_attach_shape(s3d_scn, s3d_shp));
- OK(s3d_scene_view_create(s3d_scn, S3D_TRACE, s3d_view));
- error:
- if(res != RES_OK) *p_res = res;
- if(s3d) S3D(device_ref_put(s3d));
- if(s3d_scn) S3D(scene_ref_put(s3d_scn));
- if(s3d_shp) S3D(shape_ref_put(s3d_shp));
- }
-
-#ifndef NDEBUG
- /* Need to wait for all threads done to be able to check stuff */
- #pragma omp barrier
- if(*p_res != RES_OK) return;
- #pragma omp single
- {
- trg_id_t t_;
- component_id_t c;
- ASSERT(ATOMIC_GET(component_count) ==
- (int)darray_ptr_component_descriptor_size_get(connex_components));
- FOR_EACH(t_, 0, scn->nutris) {
- struct triangle_comp* trg_comp =
- darray_triangle_comp_data_get(triangles_comp_array) + t_;
- ASSERT(trg_comp->component[SENC_FRONT] != COMPONENT_NULL__);
- ASSERT(trg_comp->component[SENC_BACK] != COMPONENT_NULL__);
- }
- FOR_EACH(c, 0, ATOMIC_GET(component_count)) {
- struct cc_descriptor** components =
- darray_ptr_component_descriptor_data_get(connex_components);
- ASSERT(components[c] != NULL && components[c]->cc_id == c);
- }
- ASSERT(desc->triangle_count == scn->nutris);
- } /* Implicit barrier here */
-#endif
-}
-
-static void
-group_connex_components
- (struct senc_descriptor* desc,
- struct trgside* trgsides,
- struct darray_triangle_comp* triangles_comp,
- struct darray_ptr_component_descriptor* connex_components,
- struct s3d_scene_view* s3d_view,
- ATOMIC* next_enclosure_id,
- /* Shared error status.
- * We accept to overwrite an error with a different error */
- res_T* res)
-{
- /* This function is called from an omp parallel block and executed
- * concurrently. */
- struct cc_descriptor** descriptors;
- const union double3* positions;
- size_t tmp;
- component_id_t cc_count;
- int64_t ccc;
-
- (void)trgsides;
- ASSERT(desc && trgsides && triangles_comp && connex_components
- && s3d_view && next_enclosure_id && res);
- ASSERT(desc->enclosures_count == 1);
-
- descriptors = darray_ptr_component_descriptor_data_get(connex_components);
- tmp = darray_ptr_component_descriptor_size_get(connex_components);
- ASSERT(tmp <= COMPONENT_MAX__);
- cc_count = (component_id_t)tmp;
- positions = darray_position_cdata_get(&desc->scene->vertices);
-
- /* Cast rays to find links between connex components */
- #pragma omp for
- for(ccc = 0; ccc < (int64_t)cc_count; ccc++) {
- res_T tmp_res = RES_OK;
- component_id_t c = (component_id_t)ccc;
- struct s3d_hit hit = S3D_HIT_NULL;
- float origin[3];
- const float dir[3] = { 0, 0, 1 };
- const float range[2] = { 0, FLT_MAX };
- struct cc_descriptor* const cc = descriptors[c];
- component_id_t self_hit_component = cc->cc_id;
- const double* max_vrtx;
-
- if(*res != RES_OK) continue;
- ASSERT(cc->cc_id == c);
- ASSERT(cc->cc_group_root == CC_GROUP_ID_NONE);
- ASSERT(cc->max_z_vrtx_id < desc->scene->nverts);
-
- max_vrtx = positions[cc->max_z_vrtx_id].vec;
- if(cc->is_outer_border) {
- ATOMIC id;
- /* Don't need to cast a ray */
- cc->cc_group_root = cc->cc_id; /* New group with self as root */
- id = ATOMIC_INCR(next_enclosure_id) - 1;
- ASSERT(id <= ENCLOSURE_MAX__);
- cc->enclosure_id = (enclosure_id_t)id;
- continue;
- }
-
- f3_set_d3(origin, max_vrtx);
- /* Self-hit data: self hit if hit this component "on the other side" */
- tmp_res = s3d_scene_view_trace_ray(s3d_view, origin, dir, range,
- &self_hit_component, &hit);
- if(tmp_res != RES_OK) {
- *res = tmp_res;
- continue;
- }
- /* If no hit, the component is facing an infinite medium */
- if(S3D_HIT_NONE(&hit)) {
- cc->cc_group_root = CC_GROUP_ROOT_INFINITE;
- cc->enclosure_id = 0;
- } else {
- /* If hit, group this component */
- const trg_id_t hit_trg_id = (trg_id_t)hit.prim.prim_id;
- const struct triangle_comp* hit_trg_comp =
- darray_triangle_comp_cdata_get(triangles_comp) + hit_trg_id;
- enum senc_side hit_side =
- ((hit.normal[2] < 0) /* Facing geometrical normal of hit */
- == ((desc->scene->convention & SENC_CONVENTION_NORMAL_FRONT) != 0))
- /* Warning: following Embree 2 convention for geometrical normals,
- * the Star3D hit normal is left-handed while star-enclosure uses
- * right-handed convention */
- ? SENC_BACK : SENC_FRONT;
- ASSERT(hit.normal[2] != 0);
- ASSERT(hit_trg_id < desc->scene->nutris);
-
- /* Not really the root until following links */
- cc->cc_group_root = hit_trg_comp->component[hit_side];
- ASSERT(cc->cc_group_root < cc_count);
- }
- }
- /* Implicit barrier here */
- ASSERT(ATOMIC_GET(next_enclosure_id) < ENCLOSURE_MAX__);
- if(*res != RES_OK) return;
-
- /* One thread post-processes links to group connex components */
- #pragma omp single
- {
- res_T tmp_res = RES_OK;
- desc->enclosures_count = (enclosure_id_t)ATOMIC_GET(next_enclosure_id);
- tmp_res = darray_enclosure_resize(&desc->enclosures, desc->enclosures_count);
- if(tmp_res != RES_OK) {
- *res = tmp_res;
- } else {
- struct enclosure_data* enclosures
- = darray_enclosure_data_get(&desc->enclosures);
- FOR_EACH(ccc, 0, cc_count) {
- component_id_t c = (component_id_t)ccc;
- struct cc_descriptor* const cc = descriptors[c];
- const struct cc_descriptor* other_desc = cc;
- struct enclosure_data* enc;
-#ifndef NDEBUG
- component_id_t cc_cpt = 0;
-#endif
-
- while(other_desc->enclosure_id == CC_GROUP_ID_NONE) {
- ASSERT(other_desc->cc_group_root < cc_count);
- other_desc = descriptors[other_desc->cc_group_root];
- /* Cannot have more components in cc than cc_count! */
- ASSERT(++cc_cpt <= cc_count);
- }
- ASSERT(other_desc->cc_group_root != CC_GROUP_ROOT_NONE);
- ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE);
- cc->cc_group_root = other_desc->cc_group_root;
- cc->enclosure_id = other_desc->enclosure_id;
- enc = enclosures + cc->enclosure_id;
- ++enc->cc_count;
- /* Linked list of componnents */
- enc->first_component = cc->cc_id;
- enc->side_range.first = MMIN(enc->side_range.first, cc->side_range.first);
- enc->side_range.last = MMAX(enc->side_range.last, cc->side_range.last);
- enc->side_count += cc->side_count;
- tmp_res = bool_array_of_media_merge(&enc->tmp_enclosed_media, cc->media,
- desc->scene->next_medium_idx + 1);
- if(tmp_res != RES_OK) {
- *res = tmp_res;
- break;
- }
- }
- }
- }
- /* Implicit barrier here */
-}
-
-static void
-collect_and_link_neighbours
- (struct senc_scene* scn,
- struct trgside* trgsides,
- struct darray_triangle_tmp* triangles_tmp_array,
- struct darray_frontier_edge* frontiers,
- /* Shared error status.
- * We accept to overwrite an error with a different error */
- res_T* res)
-{
- /* This function is called from an omp parallel block and executed
- * concurrently. */
- const struct triangle_in* triangles_in;
- struct triangle_tmp* triangles_tmp;
- const union double3* vertices;
- const int thread_count = omp_get_num_threads();
- const int rank = omp_get_thread_num();
- /* Htable used to give an id to edges */
- struct htable_edge_id edge_ids;
- /* Array to keep neighbourhood of edges
- * Resize/Push operations on neighbourhood_by_edge are valid in the
- * openmp block because a given neighbourhood is only processed
- * by a single thread */
- struct darray_neighbourhood neighbourhood_by_edge;
- edge_id_t edge_count;
- edge_id_t nbedges_guess;
- edge_id_t e;
- trg_id_t t;
- size_t sz;
- res_T tmp_res;
-
- ASSERT(scn && trgsides && triangles_tmp_array && frontiers && res);
- ASSERT((size_t)scn->nuverts + (size_t)scn->nutris + 2 <= EDGE_MAX__);
-
- htable_edge_id_init(scn->dev->allocator, &edge_ids);
- darray_neighbourhood_init(scn->dev->allocator, &neighbourhood_by_edge);
-
- triangles_in = darray_triangle_in_cdata_get(&scn->triangles_in);
- triangles_tmp = darray_triangle_tmp_data_get(triangles_tmp_array);
- vertices = darray_position_cdata_get(&scn->vertices);
-
- ASSERT(scn->nutris == darray_triangle_tmp_size_get(triangles_tmp_array));
-
- /* Make some room for edges. */
- nbedges_guess = 4 + (thread_count == 1
- ? (edge_id_t)(scn->nuverts + scn->nutris)
- : (edge_id_t)((scn->nuverts + scn->nutris) / (0.75 * thread_count)));
- OK2(darray_neighbourhood_reserve(&neighbourhood_by_edge, nbedges_guess));
- OK2(htable_edge_id_reserve(&edge_ids, nbedges_guess));
-
- /* Loop on triangles to register edges.
- * All threads considering all the edges and processing some */
- FOR_EACH(t, 0, scn->nutris) {
- struct trg_edge edge;
- unsigned char ee;
- FOR_EACH(ee, 0, 3) {
- edge_id_t* p_id;
- size_t n_sz;
- struct edge_neighbourhood* neighbourhood;
- struct neighbour_info* info;
- const vrtx_id_t v0 = triangles_in[t].vertice_id[ee];
- const vrtx_id_t v1 = triangles_in[t].vertice_id[(ee + 1) % 3];
- /* Process only "my" edges! */
- const int64_t h =
- /* v0,v1 and v1,v0 must give the same hash!!! */
- v0 + v1 + (int64_t)MMIN(v0, v1);
- if(h % thread_count != rank) continue;
- /* Create edge. */
- set_edge(v0, v1, &edge, &triangles_tmp[t].reversed_edge[ee]);
- /* Find edge id; create it if not already done. */
- p_id = htable_edge_id_find(&edge_ids, &edge);
- if(p_id) {
- neighbourhood =
- darray_neighbourhood_data_get(&neighbourhood_by_edge) + *p_id;
- ASSERT(neighbourhood->edge.vrtx0 == edge.vrtx0
- && neighbourhood->edge.vrtx1 == edge.vrtx1);
- } else {
- /* Create id */
- edge_id_t id;
- sz = htable_edge_id_size_get(&edge_ids);
- ASSERT(sz <= EDGE_MAX__);
- id = (edge_id_t)sz;
- ASSERT(htable_edge_id_size_get(&edge_ids)
- == darray_neighbourhood_size_get(&neighbourhood_by_edge));
- OK2(htable_edge_id_set(&edge_ids, &edge, &id));
- OK2(darray_neighbourhood_resize(&neighbourhood_by_edge, 1 + sz));
- neighbourhood = darray_neighbourhood_data_get(&neighbourhood_by_edge) + sz;
- /* Add neighbour info to a newly created edge's neighbour list */
- neighbourhood->edge = edge;
- ASSERT(darray_neighbour_size_get(&neighbourhood->neighbours) == 0);
- /* Just a guess: few edges will have less than 2 neighbours */
- OK2(darray_neighbour_reserve(&neighbourhood->neighbours, 2));
- }
- /* Add neighbour info to neighbourhood */
- n_sz = darray_neighbour_size_get(&neighbourhood->neighbours);
- OK2(darray_neighbour_resize(&neighbourhood->neighbours, 1 + n_sz));
- info = darray_neighbour_data_get(&neighbourhood->neighbours) + n_sz;
- info->trg_id = t;
- info->common_edge_rank = ee;
- }
- } /* No barrier here. */
-
- /* Loop on collected edges.
- * For each edge sort triangle sides by rotation angle
- * and connect neighbours. */
- sz = darray_neighbourhood_size_get(&neighbourhood_by_edge);
- ASSERT(sz <= EDGE_MAX__);
- edge_count = (edge_id_t)sz;
- FOR_EACH(e, 0, edge_count) {
- double edge[3], common_edge[3], basis[9], norm, max_z, maxz_edge, a;
- vrtx_id_t v0, v1, v2;
- struct edge_neighbourhood* neighbourhood
- = darray_neighbourhood_data_get(&neighbourhood_by_edge) + e;
- struct darray_neighbour* neighbour_list = &neighbourhood->neighbours;
- side_id_t i, neighbour_count;
- sz = darray_neighbour_size_get(neighbour_list);
- ASSERT(sz > 0 && sz <= SIDE_MAX__);
- neighbour_count = (side_id_t)sz;
- ASSERT(neighbour_count);
- v0 = neighbourhood->edge.vrtx0;
- v1 = neighbourhood->edge.vrtx1;
- d3_sub(common_edge, vertices[v1].vec, vertices[v0].vec);
- maxz_edge = MMAX(vertices[v0].pos.z, vertices[v1].pos.z);
- norm = d3_normalize(common_edge, common_edge);
- ASSERT(norm); (void)norm;
- d33_basis(basis, common_edge);
- d33_inverse(basis, basis);
- FOR_EACH(i, 0, neighbour_count) {
- struct neighbour_info* neighbour_info
- = darray_neighbour_data_get(neighbour_list) + i;
- const trg_id_t crt_id = neighbour_info->trg_id;
- const unsigned char crt_edge = neighbour_info->common_edge_rank;
- const struct triangle_in* trg_in = triangles_in + crt_id;
- struct triangle_tmp* neighbour = triangles_tmp + crt_id;
- union double3 n; /* Geometrical normal to neighbour triangle */
- const int is_reversed = neighbour->reversed_edge[crt_edge];
- v2 = trg_in->vertice_id[(crt_edge + 2) % 3];
- max_z = MMAX(vertices[v2].pos.z, maxz_edge);
- ASSERT(neighbour->max_z <= max_z);
- neighbour->max_z = max_z;
- /* Compute rotation angle around common edge */
- d3_sub(edge, vertices[v2].vec, vertices[v0].vec);
- d33_muld3(edge, basis, edge);
- ASSERT(d3_len(edge) && (edge[0] || edge[1]));
- neighbour_info->angle = atan2(edge[1], edge[0]);
- if(is_reversed)
- d3(n.vec, +edge[1], -edge[0], 0);
- else
- d3(n.vec, -edge[1], +edge[0], 0);
- if(neighbour_info->angle < 0) neighbour_info->angle += 2 * PI;
-
- /* Normal orientation calculation. */
- if(neighbour_info->angle <= PI / 4) {
- ASSERT(n.pos.y);
- neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
- } else if(neighbour_info->angle <= 3 * PI / 4) {
- ASSERT(n.pos.x);
- neighbour_info->normal_toward_next_neighbour = (n.pos.x < 0);
- } else if(neighbour_info->angle <= 5 * PI / 4) {
- ASSERT(n.pos.y);
- neighbour_info->normal_toward_next_neighbour = (n.pos.y < 0);
- } else if(neighbour_info->angle <= 7 * PI / 4) {
- ASSERT(n.pos.x);
- neighbour_info->normal_toward_next_neighbour = (n.pos.x > 0);
- } else {
- ASSERT(n.pos.y);
- neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
- }
- }
- /* Sort triangles by rotation angle */
- qsort(darray_neighbour_data_get(neighbour_list), neighbour_count,
- sizeof(struct neighbour_info), neighbour_cmp);
- /* Link sides.
- * Create cycles of sides by neighbourhood around common edge. */
- a = -DBL_MAX;
- FOR_EACH(i, 0, neighbour_count) {
- /* Neighbourhood info for current pair of triangles */
- const struct neighbour_info* current
- = darray_neighbour_cdata_get(neighbour_list) + i;
- const struct neighbour_info* ccw_neighbour
- = darray_neighbour_cdata_get(neighbour_list) + (i + 1) % neighbour_count;
- /* Rank of the edge of interest in triangles */
- const unsigned char crt_edge = current->common_edge_rank;
- /* Here ccw refers to the rotation around the common edge
- * and has nothing to do with vertices order in triangle definition
- * nor Front/Back side convention */
- const unsigned char ccw_edge = ccw_neighbour->common_edge_rank;
- /* User id of current triangles */
- const trg_id_t crt_id = current->trg_id;
- const trg_id_t ccw_id = ccw_neighbour->trg_id;
- /* Facing sides of triangles */
- const int front = ((scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0);
- const enum senc_side crt_side
- = current->normal_toward_next_neighbour == front ? SENC_FRONT : SENC_BACK;
- const enum senc_side ccw_side
- = ccw_neighbour->normal_toward_next_neighbour == front ?
- SENC_BACK : SENC_FRONT;
- /* Index of sides in trgsides */
- const side_id_t crt_side_idx = TRGIDxSIDE_2_TRGSIDE(crt_id, crt_side);
- const side_id_t ccw_side_idx = TRGIDxSIDE_2_TRGSIDE(ccw_id, ccw_side);
- /* Side ptrs */
- struct trgside* const p_crt_side = trgsides + crt_side_idx;
- struct trgside* const p_ccw_side = trgsides + ccw_side_idx;
- /* Check that angle is a discriminant property */
- ASSERT(a <= current->angle); /* Is sorted */
- if(a == current->angle) {
- /* Two consecutive triangles with same angle! */
- const struct neighbour_info* previous;
- trg_id_t prev_id;
- ASSERT(i > 0);
- previous = darray_neighbour_cdata_get(neighbour_list) + i - 1;
- prev_id = previous->trg_id;
- log_err(scn->dev,
- "%s: found 2 overlying triangles (%lu & %lu).\n", FUNC_NAME,
- (unsigned long)triangles_in[crt_id].global_id,
- (unsigned long)triangles_in[prev_id].global_id);
- tmp_res = RES_BAD_OP;
- goto tmp_error;
- }
- a = current->angle;
- /* Link sides */
- ASSERT(p_crt_side->facing_side_id[crt_edge] == SIDE_NULL__);
- ASSERT(p_ccw_side->facing_side_id[ccw_edge] == SIDE_NULL__);
- p_crt_side->facing_side_id[crt_edge] = ccw_side_idx;
- p_ccw_side->facing_side_id[ccw_edge] = crt_side_idx;
- /* Record media */
- ASSERT(p_crt_side->medium == MEDIUM_NULL__
- || p_crt_side->medium == triangles_in[crt_id].medium[crt_side]);
- ASSERT(p_ccw_side->medium == MEDIUM_NULL__
- || p_ccw_side->medium == triangles_in[ccw_id].medium[ccw_side]);
- p_crt_side->medium = triangles_in[crt_id].medium[crt_side];
- p_ccw_side->medium = triangles_in[ccw_id].medium[ccw_side];
- ASSERT(p_crt_side->medium == SENC_UNDEFINED_MEDIUM
- || p_crt_side->medium < scn->next_medium_idx);
- ASSERT(p_ccw_side->medium == SENC_UNDEFINED_MEDIUM
- || p_ccw_side->medium < scn->next_medium_idx);
- /* Detect triangles that could surround a hole:
- * - single triangle on (one of) its edge
- * - different media on its sides */
- if(neighbour_count == 1
- && p_crt_side->medium != p_ccw_side->medium)
-#pragma omp critical
- {
- struct trg_edge disc;
- log_warn(scn->dev,
- "%s: found frontier involving triangle %lu.\n",
- FUNC_NAME, (unsigned long)triangles_in[crt_id].global_id);
- disc.vrtx0 = v0;
- disc.vrtx1 = v1;
- darray_frontier_edge_push_back(frontiers, &disc);
- }
- }
- }
-tmp_error:
- if(tmp_res != RES_OK) *res = tmp_res;
- /* Threads are allowed to return whitout sync. */
- htable_edge_id_release(&edge_ids);
- darray_neighbourhood_release(&neighbourhood_by_edge);
-}
-
-static void
-build_result
- (struct senc_descriptor* desc,
- const struct darray_ptr_component_descriptor* connex_components,
- const struct darray_triangle_comp* triangles_comp_array,
- struct darray_frontier_edge* frontiers,
- /* Shared error status.
- * We accept to overwrite an error with a different error */
- res_T* res)
-{
- /* This function is called from an omp parallel block and executed
- * concurrently. */
- struct mem_allocator* alloc;
- struct cc_descriptor* const* cc_descriptors;
- struct enclosure_data* enclosures;
- const struct triangle_in* triangles_in;
- struct triangle_enc* triangles_enc;
- const struct triangle_comp* triangles_comp;
- struct htable_vrtx_id vtable;
- struct senc_scene* scn;
- int output_normal_in, normals_front, normals_back;
- int64_t tt;
- int64_t ee;
-
- ASSERT(desc && connex_components && triangles_comp_array && frontiers && res);
-
- alloc = descriptor_get_allocator(desc);
- scn = desc->scene;
- output_normal_in = (scn->convention & SENC_CONVENTION_NORMAL_INSIDE) != 0;
- normals_front = (scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0;
- normals_back = (scn->convention & SENC_CONVENTION_NORMAL_BACK) != 0;
- ASSERT(normals_back != normals_front);
- ASSERT(output_normal_in
- != ((scn->convention & SENC_CONVENTION_NORMAL_OUTSIDE) != 0));
- ASSERT(darray_ptr_component_descriptor_size_get(connex_components)
- <= COMPONENT_MAX__);
- cc_descriptors = darray_ptr_component_descriptor_cdata_get(connex_components);
- enclosures = darray_enclosure_data_get(&desc->enclosures);
- triangles_in = darray_triangle_in_cdata_get(&scn->triangles_in);
- triangles_comp = darray_triangle_comp_cdata_get(triangles_comp_array);
-
- #pragma omp single
- {
- res_T tmp_res =
- darray_triangle_enc_resize(&desc->triangles_enc, scn->nutris);
- if(tmp_res != RES_OK) *res = tmp_res;
- }/* Implicit barrier here. */
- if(*res != RES_OK) return;
- triangles_enc = darray_triangle_enc_data_get(&desc->triangles_enc);
-
- /* Build global enclosure information */
- #pragma omp for
- for(tt = 0; tt < (int64_t)scn->nutris; tt++) {
- trg_id_t t = (trg_id_t)tt;
- const component_id_t cf_id = triangles_comp[t].component[SENC_FRONT];
- const component_id_t cb_id = triangles_comp[t].component[SENC_BACK];
- const struct cc_descriptor* cf = cc_descriptors[cf_id];
- const struct cc_descriptor* cb = cc_descriptors[cb_id];
- const enclosure_id_t ef_id = cf->enclosure_id;
- const enclosure_id_t eb_id = cb->enclosure_id;
- ASSERT(triangles_enc[t].enclosure[SENC_FRONT] == ENCLOSURE_NULL__);
- triangles_enc[t].enclosure[SENC_FRONT] = ef_id;
- ASSERT(triangles_enc[t].enclosure[SENC_BACK] == ENCLOSURE_NULL__);
- triangles_enc[t].enclosure[SENC_BACK] = eb_id;
- }
- /* Implicit barrier here */
-
- /* Resize/push operations on enclosure's fields are valid in the
- * openmp block as a given enclosure is processed by a single thread */
- htable_vrtx_id_init(alloc, &vtable);
-
- ASSERT(desc->enclosures_count <= ENCLOSURE_MAX__);
- #pragma omp for schedule(dynamic) nowait
- for(ee = 0; ee < (int64_t)desc->enclosures_count; ee++) {
- const enclosure_id_t e = (enclosure_id_t)ee;
- struct enclosure_data* enc = enclosures + e;
- trg_id_t fst_idx = 0;
- trg_id_t sgd_idx = enc->side_count;
- trg_id_t t;
- medium_id_t m;
- res_T tmp_res = RES_OK;
- ASSERT(enc->first_component
- < darray_ptr_component_descriptor_size_get(connex_components));
- ASSERT(cc_descriptors[enc->first_component]->cc_id
- == enc->first_component);
-
- if(*res != RES_OK) continue;
- ASSERT(e <= UINT_MAX);
- enc->header.enclosure_id = (unsigned)e; /* Back to API type */
- ASSERT(cc_descriptors[enc->first_component]->enclosure_id
- == enc->header.enclosure_id);
- enc->header.is_infinite = (e == 0);
-
- ASSERT(darray_uchar_size_get(&enc->tmp_enclosed_media) <= UINT_MAX);
- ASSERT(enc->header.enclosed_media_count < 1 + scn->next_medium_idx);
- OK2(bool_array_of_media_to_darray_media
- (&enc->enclosed_media, &enc->tmp_enclosed_media, scn->next_medium_idx));
- enc->header.enclosed_media_count
- = (unsigned)darray_media_size_get(&enc->enclosed_media);
- darray_uchar_purge(&enc->tmp_enclosed_media);
-
- /* Add this enclosure in relevant by-medium lists */
- FOR_EACH(m, 0, enc->header.enclosed_media_count) {
- medium_id_t medium = darray_media_data_get(&enc->enclosed_media)[m];
- size_t m_idx = (medium == SENC_UNDEFINED_MEDIUM)
- ? scn->next_medium_idx : medium;
- struct darray_enc_id* enc_ids_by_medium;
- ASSERT(medium == SENC_UNDEFINED_MEDIUM || medium < scn->next_medium_idx);
- ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
- == 1 + scn->next_medium_idx);
- enc_ids_by_medium =
- darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + m_idx;
- #pragma omp critical
- {
- tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e);
- }
- if(tmp_res != RES_OK) {
- *res = tmp_res;
- break;
- }
- }
- if(*res != RES_OK) continue;
-
- /* Build side and vertex lists. */
- OK2(darray_sides_enc_resize(&enc->sides, enc->side_count));
- /* Size is just a int */
- OK2(darray_vrtx_id_reserve(&enc->vertices,
- (size_t)(enc->side_count * 0.6)));
- /* New vertex numbering scheme local to the enclosure */
- htable_vrtx_id_clear(&vtable);
- ASSERT(scn->nutris == darray_triangle_in_size_get(&scn->triangles_in));
- /* Put at the end the back-faces of triangles that also have their
- * front-face in the list. */
- for(t = TRGSIDE_2_TRG(enc->side_range.first);
- t <= TRGSIDE_2_TRG(enc->side_range.last);
- t++)
- {
- const struct triangle_in* trg_in = triangles_in + t;
- struct side_enc* side_enc;
- unsigned vertice_id[3];
- int i;
- if(triangles_enc[t].enclosure[SENC_FRONT] != e
- && triangles_enc[t].enclosure[SENC_BACK] != e)
- continue;
- ++enc->header.unique_triangle_count;
-
- FOR_EACH(i, 0, 3) {
- vrtx_id_t* p_id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i);
- if(p_id) {
- vertice_id[i] = *p_id; /* Known vertex */
- } else {
- /* Create new association */
- size_t tmp = htable_vrtx_id_size_get(&vtable);
- ASSERT(tmp == darray_vrtx_id_size_get(&enc->vertices));
- ASSERT(tmp < VRTX_MAX__);
- vertice_id[i] = (vrtx_id_t)tmp;
- OK2(htable_vrtx_id_set(&vtable, trg_in->vertice_id + i,
- vertice_id + i));
- OK2(darray_vrtx_id_push_back(&enc->vertices, trg_in->vertice_id + i));
- ++enc->header.vertices_count;
- }
- }
- ASSERT(triangles_enc[t].enclosure[SENC_FRONT] == e
- || triangles_enc[t].enclosure[SENC_BACK] == e);
- if(triangles_enc[t].enclosure[SENC_FRONT] == e) {
- /* Front side of the original triangle is member of the enclosure */
- int input_normal_in = normals_front;
- int revert_triangle = (input_normal_in != output_normal_in);
- ++enc->header.triangle_count;
- side_enc = darray_sides_enc_data_get(&enc->sides) + fst_idx++;
- FOR_EACH(i, 0, 3) {
- int ii = revert_triangle ? 2 - i : i;
- side_enc->vertice_id[i] = vertice_id[ii];
- }
- side_enc->side_id = TRGIDxSIDE_2_TRGSIDE(trg_in->global_id, SENC_FRONT);
- }
- if(triangles_enc[t].enclosure[SENC_BACK] == e) {
- /* Back side of the original triangle is member of the enclosure */
- int input_normal_in = normals_back;
- int revert_triangle = (input_normal_in != output_normal_in);
- ++enc->header.triangle_count;
- /* If both sides are in the enclosure, put the second side at the end */
- side_enc = darray_sides_enc_data_get(&enc->sides) +
- ((triangles_enc[t].enclosure[SENC_FRONT] == e) ? --sgd_idx : fst_idx++);
- FOR_EACH(i, 0, 3) {
- int ii = revert_triangle ? 2 - i : i;
- side_enc->vertice_id[i] = vertice_id[ii];
- }
- side_enc->side_id = TRGIDxSIDE_2_TRGSIDE(trg_in->global_id, SENC_BACK);
- }
- if(fst_idx == sgd_idx) break;
- }
- continue;
- tmp_error:
- ASSERT(tmp_res != RES_OK);
- *res = tmp_res;
- } /* No barrier here */
- htable_vrtx_id_release(&vtable);
- /* The first thread here copies frontiers into descriptor */
-#pragma omp single nowait
- darray_frontier_edge_copy_and_clear(&desc->frontiers, frontiers);
- /* No barrier here */
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-senc_scene_analyze
- (struct senc_scene* scn,
- struct senc_descriptor** out_desc)
-{
- struct senc_descriptor* desc = NULL;
- /* By triangle tmp data */
- struct darray_triangle_tmp triangles_tmp;
- char triangles_tmp_initialized = 0;
- /* Array of connex components.
- * They are refered to by arrays of ids. */
- struct darray_ptr_component_descriptor connex_components;
- char connex_components_initialized = 0;
- /* Array of frontiers edges */
- struct darray_frontier_edge frontiers;
- char frontiers_initialized = 0;
- /* Store by-triangle components */
- struct darray_triangle_comp triangles_comp;
- char triangles_comp_initialized = 0;
- /* Array of triangle sides. */
- struct trgside* trgsides = NULL;
- struct s3d_scene_view* s3d_view = NULL;
- /* Atomic counters to share beetwen threads */
- ATOMIC component_count = 0;
- ATOMIC next_enclosure_id = 1;
- res_T res = RES_OK;
- res_T res2 = RES_OK;
-
- if(!scn || !out_desc) return RES_BAD_ARG;
-
- desc = descriptor_create(scn);
- if(!desc) {
- res = RES_MEM_ERR;
- goto error;
- }
-
- if(!scn->nutris) goto exit;
-
- darray_triangle_tmp_init(scn->dev->allocator, &triangles_tmp);
- triangles_tmp_initialized = 1;
- darray_frontier_edge_init(scn->dev->allocator, &frontiers);
- frontiers_initialized = 1;
-
- OK(darray_triangle_tmp_resize(&triangles_tmp, scn->nutris));
- trgsides
- = MEM_CALLOC(scn->dev->allocator, 2 * scn->nutris, sizeof(struct trgside));
- if(!trgsides) {
- res = RES_MEM_ERR;
- goto error;
- }
-#ifndef NDEBUG
- else {
- /* Initialise trgsides to allow assert code */
- size_t i;
- FOR_EACH(i, 0, 2 * scn->nutris)
- init_trgside(scn->dev->allocator, trgsides + i);
- }
-#endif
-
- /* The end of the analyze is multithreaded */
- ASSERT(scn->dev->nthreads > 0);
- #pragma omp parallel num_threads(scn->dev->nthreads)
- {
- /* Step 1: build neighbourhoods */
- collect_and_link_neighbours(scn, trgsides, &triangles_tmp, &frontiers,
- &res);
- /* No barrier at the end of step 1: data used in step 1 cannot be
- * released / data produced by step 1 cannot be used
- * until next sync point */
-
- /* The first thread here allocates some data.
- * Barrier needed at the end to ensure data created before any use. */
- #pragma omp single
- {
- res_T tmp_res = RES_OK;
- darray_ptr_component_descriptor_init(scn->dev->allocator,
- &connex_components);
- connex_components_initialized = 1;
- /* Just a hint; to limit contention */
- OK2(darray_ptr_component_descriptor_reserve(&connex_components,
- 2 + 2 * scn->next_medium_idx));
- darray_triangle_comp_init(scn->dev->allocator, &triangles_comp);
- triangles_comp_initialized = 1;
- OK2(darray_triangle_comp_resize(&triangles_comp, scn->nutris));
- tmp_error:
- if(tmp_res != RES_OK) res2 = tmp_res;
- }
- /* Implicit barrier here: constraints on step 1 data are now met */
-
- if(res != RES_OK || res2 != RES_OK) {
- #pragma omp single nowait
- {
- if(res != RES_OK) {
- log_err(scn->dev,
- "%s: could not build neighbourhoods from scene.\n", FUNC_NAME);
- } else {
- res = res2;
- }
- }
- goto error_;
- }
-
- /* Step 2: extract triangle connex components */
- extract_connex_components(desc, trgsides, &connex_components,
- &triangles_tmp, &triangles_comp, &s3d_view, &component_count, &res);
- /* No barrier at the end of step 2: data used in step 2 cannot be
- * released / data produced by step 2 cannot be used
- * until next sync point */
-
- #pragma omp barrier
- /* Constraints on step 2 data are now met */
-
- if(res != RES_OK) {
- #pragma omp single nowait
- {
- log_err(scn->dev,
- "%s: could not extract connex components from scene.\n", FUNC_NAME);
- } /* No barrier here */
- goto error_;
- }
-
- /* One thread releases some data before going to step 3,
- * the others go to step 3 without sync */
- #pragma omp single nowait
- {
- darray_triangle_tmp_release(&triangles_tmp);
- triangles_tmp_initialized = 0;
- } /* No barrier here */
-
- /* Step 3: group components */
- group_connex_components(desc, trgsides, &triangles_comp,
- &connex_components, s3d_view, &next_enclosure_id, &res);
- /* Barrier at the end of step 3: data used in step 3 can be released /
- * data produced by step 3 can be used */
-
- if(res != RES_OK) {
- #pragma omp single nowait
- {
- log_err(scn->dev,
- "%s: could not group connex components from scene.\n", FUNC_NAME);
- }
- goto error_;
- }
-
- /* One thread releases some data before going to step 4,
- * the others go to step 4 without sync */
- #pragma omp single nowait
- {
- if(s3d_view) S3D(scene_view_ref_put(s3d_view));
- s3d_view = NULL;
- } /* No barrier here */
-
- /* Step 4: Build result */
- build_result(desc, &connex_components, &triangles_comp, &frontiers, &res);
- /* No barrier at the end of step 4: data used in step 4 cannot be
- * released / data produced by step 4 cannot be used
- * until next sync point */
-
- #pragma omp barrier
- /* Constraints on step 4 data are now met */
-
- if(res != RES_OK) {
- #pragma omp single nowait
- {
- log_err(scn->dev, "%s: could not build result.\n", FUNC_NAME);
- }
- goto error_;
- }
-
- /* Some threads release data */
- #pragma omp sections nowait
- {
- #pragma omp section
- {
- custom_darray_ptr_component_descriptor_release(&connex_components);
- connex_components_initialized = 0;
- }
- #pragma omp section
- {
- darray_triangle_comp_release(&triangles_comp);
- triangles_comp_initialized = 0;
- }
- } /* No barrier here */
-
-error_:
- ;
- } /* Implicit barrier here */
-
- if(res != RES_OK) goto error;
-exit:
- if(connex_components_initialized)
- custom_darray_ptr_component_descriptor_release(&connex_components);
- if(s3d_view) S3D(scene_view_ref_put(s3d_view));
- if(triangles_tmp_initialized) darray_triangle_tmp_release(&triangles_tmp);
- if(triangles_comp_initialized) darray_triangle_comp_release(&triangles_comp);
- if(frontiers_initialized)
- darray_frontier_edge_release(&frontiers);
- if(trgsides) MEM_RM(scn->dev->allocator, trgsides);
- if(desc) *out_desc = desc;
-
- return res;
-error:
- if(desc) SENC(descriptor_ref_put(desc));
- desc = NULL;
- goto exit;
-}
diff --git a/src/senc_scene_analyze_c.h b/src/senc_scene_analyze_c.h
@@ -1,197 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 SENC_SCNENE_ANALYZE_C_H
-#define SENC_SCNENE_ANALYZE_C_H
-
-#include "senc_scene_c.h"
-#include "senc_internal_types.h"
-#include "senc_descriptor_c.h"
-
-#include <rsys/mem_allocator.h>
-#include <rsys/hash_table.h>
-#include <rsys/double3.h>
-
-static FINLINE void
-init_trgside(struct mem_allocator* alloc, struct trgside* data)
-{
- int i;
- ASSERT(data); (void)alloc;
- FOR_EACH(i, 0, 3) data->facing_side_id[i] = SIDE_NULL__;
- data->medium = MEDIUM_NULL__;
-}
-
-#define DARRAY_NAME side_id
-#define DARRAY_DATA side_id_t
-#include <rsys/dynamic_array.h>
-
-/* Descriptors for connex component.
- * Define lists of trg sides starting from a given head.
- * Also keeps the maximum z info of the component
- * and the list of media found */
-struct cc_descriptor {
- /* Does this component is an outer border of an enclosure or an inner one? */
- char is_outer_border;
- vrtx_id_t max_z_vrtx_id; /* id of the vrtx with max z value */
- side_id_t side_count;
- /* Used when grouping components to form enclosures */
- component_id_t cc_id;
- component_id_t cc_group_root;
- enclosure_id_t enclosure_id;
- /* Range of sides member of this component */
- struct side_range side_range;
- /* Media used by this component */
- unsigned char* media;
-};
-extern const struct cc_descriptor CC_DESCRIPTOR_NULL;
-
-static FINLINE void
-cc_descriptor_init
- (struct mem_allocator* alloc,
- struct cc_descriptor* data)
-{
- ASSERT(data);
- (void)alloc;
- *data = CC_DESCRIPTOR_NULL;
-}
-
-static FINLINE void
-ptr_component_descriptor_init
- (struct mem_allocator* alloc,
- struct cc_descriptor** data)
-{
- (void)alloc;
- ASSERT(data);
- *data = NULL;
-}
-
-#define DARRAY_NAME ptr_component_descriptor
-#define DARRAY_DATA struct cc_descriptor*
-#define DARRAY_FUNCTOR_INIT ptr_component_descriptor_init
-#include <rsys/dynamic_array.h>
-
-/* Need allocator to free array elts: cannot rely on standard
- * darray release stuff */
-static FINLINE void
-custom_darray_ptr_component_descriptor_release
- (struct darray_ptr_component_descriptor* array)
-{
- size_t c, cc_count;
- struct cc_descriptor** components;
- if(!array) return;
- cc_count = darray_ptr_component_descriptor_size_get(array);
- components = darray_ptr_component_descriptor_data_get(array);
- FOR_EACH(c, 0, cc_count) {
- if(!components[c]) continue;
- MEM_RM(array->allocator, components[c]->media);
- MEM_RM(array->allocator, components[c]);
- }
- darray_ptr_component_descriptor_release(array);
-}
-
-/* Triangle information.
- * Depending on lifespan, information is kept in different places:
- * - triangle_in for user provided information (kept in scene)
- * - triangle_tmp for tmp information (kept until triangle_comp is ready)
- * - triangle_comp for information describing components (kept until
- * triangle_enc is ready)
- * - triangle_enc for information describing enclosures (kept in
- * senc_descriptor). */
-struct triangle_tmp {
- /* Are the edges of the triangle defined in the same order than
- * the edges they are linked to? */
- unsigned char reversed_edge[3];
- double max_z;
-};
-
-#ifndef NDEBUG
-static FINLINE void
-triangle_tmp_init(struct mem_allocator* alloc, struct triangle_tmp* trg) {
- int i;
- (void)alloc;
- ASSERT(trg);
- FOR_EACH(i, 0, 3) trg->reversed_edge[i] = UCHAR_MAX;
- trg->max_z = -DBL_MAX;
-}
-#define DARRAY_FUNCTOR_INIT triangle_tmp_init
-#endif
-
-#define DARRAY_NAME triangle_tmp
-#define DARRAY_DATA struct triangle_tmp
-#include <rsys/dynamic_array.h>
-
-#define HTABLE_NAME edge_id
-#define HTABLE_KEY struct trg_edge
-#define HTABLE_DATA edge_id_t
-#define HTABLE_KEY_FUNCTOR_EQ edge_eq
-#include <rsys/hash_table.h>
-
-struct neighbour_info {
- double angle;
- trg_id_t trg_id;
- /* Rank of the edge in the triangle (in [0 2]) */
- unsigned char common_edge_rank;
- /* Does the geometrical normal point towards the next neighbour
- * (if not, it points towards the previous one)? */
- unsigned char normal_toward_next_neighbour;
-};
-#define DARRAY_NAME neighbour
-#define DARRAY_DATA struct neighbour_info
-#include <rsys/dynamic_array.h>
-
-struct edge_neighbourhood {
- struct trg_edge edge;
- struct darray_neighbour neighbours;
-};
-static void
-neighbourhood_init
- (struct mem_allocator* alloc,
- struct edge_neighbourhood* n)
-{
- ASSERT(n);
- darray_neighbour_init(alloc, &n->neighbours);
-}
-static res_T
-neighbourhood_copy
- (struct edge_neighbourhood* dst,
- const struct edge_neighbourhood* src)
-{
- ASSERT(src && dst);
- dst->edge = src->edge;
- return darray_neighbour_copy(&dst->neighbours, &src->neighbours);
-}
-static void
-neighbourhood_release(struct edge_neighbourhood* n) {
- ASSERT(n);
- darray_neighbour_release(&n->neighbours);
-}
-static res_T
-neighbourhood_copy_and_release
- (struct edge_neighbourhood* dst,
- struct edge_neighbourhood* src)
-{
- ASSERT(src && dst);
- dst->edge = src->edge;
- return darray_neighbour_copy_and_release(&dst->neighbours, &src->neighbours);
-}
-#define DARRAY_NAME neighbourhood
-#define DARRAY_DATA struct edge_neighbourhood
-#define DARRAY_FUNCTOR_INIT neighbourhood_init
-#define DARRAY_FUNCTOR_COPY neighbourhood_copy
-#define DARRAY_FUNCTOR_RELEASE neighbourhood_release
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE neighbourhood_copy_and_release
-#include <rsys/dynamic_array.h>
-
-#endif /* SENC_SCNENE_ANALYZE_C_H */
diff --git a/src/senc_scene_c.h b/src/senc_scene_c.h
@@ -1,227 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 SENC_SCNENE_C_H
-#define SENC_SCNENE_C_H
-
-#include "senc_internal_types.h"
-
-#include <rsys/ref_count.h>
-#include <rsys/dynamic_array.h>
-#include <rsys/hash_table.h>
-
-struct mem_allocator;
-
-#define HTABLE_NAME vrtx_id
-#define HTABLE_KEY vrtx_id_t
-#define HTABLE_DATA vrtx_id_t
-#include <rsys/hash_table.h>
-
-union double3 {
- struct {
- double x, y, z;
- } pos;
- double vec[3];
-};
-#define DARRAY_NAME position
-#define DARRAY_DATA union double3
-#include <rsys/dynamic_array.h>
-/* Triangle information.
- * Depending on lifespan, information is kept in different places:
- * - triangle_in for user provided information (kept in scene)
- * - triangle_comp for information describing components (kept in senc_descriptor)
- * - triangle_tmp for tmp information (kept until triangle_comp is ready) */
-struct triangle_in {
- /* Ids of the triangle's vertices */
- vrtx_id_t vertice_id[3];
- /* Ids of this triangle's media */
- medium_id_t medium[2];
- /* Triangle index in user world regardless of deduplication. */
- unsigned global_id;
-};
-
-static FINLINE void
-triangle_in_init(struct mem_allocator* alloc, struct triangle_in* trg) {
- int i;
- (void)alloc;
- ASSERT(trg);
- FOR_EACH(i, 0, 3) trg->vertice_id[i] = VRTX_NULL__;
- FOR_EACH(i, 0, 2) trg->medium[i] = SENC_UNDEFINED_MEDIUM;
- trg->global_id = 0;
-}
-
-#define DARRAY_NAME triangle_in
-#define DARRAY_DATA struct triangle_in
-#define DARRAY_FUNCTOR_INIT triangle_in_init
-#include <rsys/dynamic_array.h>
-
-static FINLINE void
-triangle_in_flip(struct triangle_in* trg) {
- vrtx_id_t v;
- medium_id_t m;
- ASSERT(trg);
- v = trg->vertice_id[1];
- trg->vertice_id[1] = trg->vertice_id[2];
- trg->vertice_id[2] = v;
- m = trg->medium[0];
- trg->medium[0] = trg->medium[1];
- trg->medium[1] = m;
-}
-
-static FINLINE int
-vrtx_eq(const union double3* v1, const union double3* v2)
-{
- ASSERT(v1 && v2);
- return (v1->pos.x == v2->pos.x
- && v1->pos.y == v2->pos.y
- && v1->pos.z == v2->pos.z);
-}
-
-#define HTABLE_NAME vrtx
-#define HTABLE_KEY union double3
-#define HTABLE_DATA vrtx_id_t
-#define HTABLE_KEY_FUNCTOR_EQ vrtx_eq
-#include <rsys/hash_table.h>
-
-#define DARRAY_NAME vrtx_id
-#define DARRAY_DATA vrtx_id_t
-#include <rsys/dynamic_array.h>
-
-union vrtx_id3 {
- struct {
- vrtx_id_t v0, v1, v2;
- } pos;
- vrtx_id_t vec[3];
-};
-
-static FINLINE char /* Return 1 if reversed */
-trg_make_key(union vrtx_id3* k, const vrtx_id_t t[3])
-{
- ASSERT(t);
- ASSERT(t[0] != t[1] && t[0] != t[2] && t[1] != t[2]);
- if(t[0] < t[2]) {
- if(t[0] < t[1]) {
- k->vec[0] = t[0];
- if(t[1] < t[2]) {
- k->vec[1] = t[1];
- k->vec[2] = t[2];
- return 0;
- } else {
- k->vec[1] = t[2];
- k->vec[2] = t[1];
- return 1;
- }
- } else {
- k->vec[0] = t[1];
- if(t[0] < t[2]) {
- k->vec[1] = t[0];
- k->vec[2] = t[2];
- return 1;
- } else {
- k->vec[1] = t[2];
- k->vec[2] = t[0];
- return 0;
- }
- }
- } else if(t[2] < t[1]) {
- k->vec[0] = t[2];
- if(t[0] < t[1]) {
- k->vec[1] = t[0];
- k->vec[2] = t[1];
- return 0;
- } else {
- k->vec[1] = t[1];
- k->vec[2] = t[0];
- return 1;
- }
- } else {
- k->vec[0] = t[1];
- if(t[0] < t[2]) {
- k->vec[1] = t[0];
- k->vec[2] = t[2];
- return 1;
- } else {
- k->vec[1] = t[2];
- k->vec[2] = t[0];
- return 0;
- }
- }
-}
-
-static FINLINE int
-trg_key_eq(const union vrtx_id3* k1, const union vrtx_id3* k2)
-{
- ASSERT(k1 && k2);
- ASSERT(k1->vec[0] < k1->vec[1] && k1->vec[1] < k1->vec[2]);
- ASSERT(k2->vec[0] < k2->vec[1] && k2->vec[1] < k2->vec[2]);
- return (k1->vec[0] == k2->vec[0])
- && (k1->vec[1] == k2->vec[1])
- && (k1->vec[2] == k2->vec[2]);
-}
-
-#define HTABLE_NAME trg
-#define HTABLE_KEY union vrtx_id3
-#define HTABLE_DATA trg_id_t
-#define HTABLE_KEY_FUNCTOR_EQ trg_key_eq
-#include <rsys/hash_table.h>
-
-struct side_range {
- side_id_t first, last;
-};
-static FINLINE void
-side_range_init(struct mem_allocator* alloc, struct side_range* data)
-{
- ASSERT(data);
- (void)alloc;
- data->first = SIDE_NULL__;
- data->last = 0;
-}
-#define DARRAY_NAME side_range
-#define DARRAY_DATA struct side_range
-#define DARRAY_FUNCTOR_INIT side_range_init
-#include <rsys/dynamic_array.h>
-
-struct senc_scene {
- /* Front / Back sides convention */
- int convention;
-
- /* Triangle information as given by user; no duplicates here */
- struct darray_triangle_in triangles_in;
-
- /* Vertex information as given by user; no duplicates here */
- struct darray_position vertices;
-
- /* Htables used to detect duplicate vertices.
- * As we rely on edges (i.e. vertice IDs) to build
- * neighbourhoods, we need vertice unicity. */
- /* Keep each unique vertex; no duplicates here. */
- struct htable_vrtx unique_vertices;
-
- /* Htables used to detect duplicate triangles. */
- /* Keep each unique triangle; no duplicates here. */
- struct htable_trg unique_triangles;
-
- /* Keep sizes */
- trg_id_t ntris, nutris; /* Trg count, unique trg count */
- vrtx_id_t nverts, nuverts; /* Vrtx count, unique vrtx count */
- medium_id_t next_medium_idx;
- struct darray_side_range media_use;
- side_id_t sides_with_defined_medium_count;
-
- ref_T ref;
- struct senc_device* dev;
-};
-
-#endif /* SENC_SCNENE_C_H */
diff --git a/src/test_senc3d_cube_behind_cube.c b/src/test_senc3d_cube_behind_cube.c
@@ -0,0 +1,311 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_cube_behind_cube. */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+/* Dump of star-geometry 'cube_behind_cube_2'. */
+static const unsigned cube_behind_cube_2_vertices_count = 16;
+static const double cube_behind_cube_2_vertices[48] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1,
+ -1.5, -2, 20,
+ 3, -2, 20,
+ -2, 3, 20,
+ 3, 3, 20,
+ -2, -2, 25.5,
+ 3, -2, 25,
+ -2, 3, 25,
+ 3, 3.5, 25
+};
+static const unsigned cube_behind_cube_2_triangles_count = 24;
+static const unsigned cube_behind_cube_2_triangles[72] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5,
+ 8, 10, 9,
+ 9, 10, 11,
+ 8, 12, 10,
+ 10, 12, 14,
+ 12, 13, 14,
+ 14, 13, 15,
+ 11, 15, 9,
+ 9, 15, 13,
+ 10, 14, 11,
+ 11, 14, 15,
+ 8, 9, 12,
+ 12, 9, 13
+};
+static const unsigned cube_behind_cube_2_properties[72] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0
+};
+/* Dump of star-geometry 'cube_behind_cube_3'. */
+static const unsigned cube_behind_cube_3_vertices_count = 24;
+static const double cube_behind_cube_3_vertices[72] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1,
+ -1.5, -2, 20,
+ 3, -2, 20,
+ -2, 3, 20,
+ 3, 3, 20,
+ -2, -2, 25.5,
+ 3, -2, 25,
+ -2, 3, 25,
+ 3, 3.5, 25,
+ -2.3, -3, 30,
+ 4, -3, 30,
+ -3, 4, 30,
+ 4, 4, 30,
+ -3, -3, 37.7,
+ 4, -3, 37,
+ -3, 4, 37,
+ 4, 4.7, 37
+};
+static const unsigned cube_behind_cube_3_triangles_count = 36;
+static const unsigned cube_behind_cube_3_triangles[108] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5,
+ 8, 10, 9,
+ 9, 10, 11,
+ 8, 12, 10,
+ 10, 12, 14,
+ 12, 13, 14,
+ 14, 13, 15,
+ 11, 15, 9,
+ 9, 15, 13,
+ 10, 14, 11,
+ 11, 14, 15,
+ 8, 9, 12,
+ 12, 9, 13,
+ 16, 18, 17,
+ 17, 18, 19,
+ 16, 20, 18,
+ 18, 20, 22,
+ 20, 21, 22,
+ 22, 21, 23,
+ 19, 23, 17,
+ 17, 23, 21,
+ 18, 22, 19,
+ 19, 22, 23,
+ 16, 17, 20,
+ 20, 17, 21
+};
+static const unsigned cube_behind_cube_3_properties[108] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0
+};
+
+/*
+ cube_2 cube_3
+
+ +-----------------------+
+ | 3
+ | |
+ m1 | m0 |
+ | |
+ | |
+ | |
+ | |--> N
+ | |
+ | |
+ +-----------------------+
+ +------------+ +------------+
+ | 2 | 2
+ m0 | m1 | m0 | m1 |
+ | | | |
+ | |--> N | |--> N
+ | | | |
+ +------------+ +------------+
+ +-----+ +-----+
+ m0 | m1 1 m0 | m1 1
+ | |--> N | |--> N
+ +-----+ +-----+
+ */
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned i, ecount, maxm;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Create a scene with the first and second cubes.
+ * Both cubes have medium 1 inside and medium 0 outside,
+ * the second cube is +Z from the first cube and is big enough
+ * to prevent rays from the first cube to miss it. */
+ ctx.positions = cube_behind_cube_2_vertices;
+ ctx.indices = cube_behind_cube_2_triangles;
+ ctx.properties = cube_behind_cube_2_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ cube_behind_cube_2_triangles_count, get_indices, get_media_from_properties,
+ cube_behind_cube_2_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 3);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ OK(senc3d_scene_get_enclosure(scn, i, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ ASSERT(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_get_max_medium(scn, &maxm));
+ CHK(maxm == 1);
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Create a scene with the 3 cubes, same 2 first cubes as above
+ * The third cube has medium 0 inside and medium 1 outside and is further
+ * in +Z and bigger */
+ ctx.positions = cube_behind_cube_3_vertices;
+ ctx.indices = cube_behind_cube_3_triangles;
+ ctx.properties = cube_behind_cube_3_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ cube_behind_cube_3_triangles_count, get_indices, get_media_from_properties,
+ cube_behind_cube_3_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 4);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ OK(senc3d_scene_get_enclosure(scn, i, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ /* Inside enclosures contain 1 single media */
+ ASSERT(header.enclosed_media_count == (header.is_infinite ? 2u : 1u));
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_get_max_medium(scn, &maxm));
+ CHK(maxm == 1);
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_cube_in_cube.c b/src/test_senc3d_cube_in_cube.c
@@ -0,0 +1,314 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_cube_in_cube. */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+/*
+ cube_2 cube_3
+
+ +-------------------------+
+ | B
+ +-------------+ | +-------------+ |
+ m1 | m0 M m1 | m1 | m0 M |
+ | +------+ | | m0 | +------+ | |
+ | | m1 S | | | | m1 S | |
+ | | N <--| | | | | N <--| | |
+ | +------+ | | | +------+ | |
+ | N <--| | | N <--| |
+ +-------------+ | +-------------+ |
+ | N <--|
+ +-------------------------+
+ */
+
+
+/* Dump of star-geometry 'cube_in_cube_2'. */
+static const unsigned cube_in_cube_2_vertices_count = 16;
+static const double cube_in_cube_2_vertices[48] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1,
+ -0.7, -1, -1,
+ 2, -1, -1,
+ -1, 2, -1,
+ 2, 2, -1,
+ -1, -1, 2.3,
+ 2, -1, 2,
+ -1, 2, 2,
+ 2, 2.3, 2
+};
+static const unsigned cube_in_cube_2_triangles_count = 24;
+static const unsigned cube_in_cube_2_triangles[72] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5,
+ 8, 9, 10,
+ 9, 11, 10,
+ 8, 10, 12,
+ 10, 14, 12,
+ 12, 14, 13,
+ 14, 15, 13,
+ 11, 9, 15,
+ 9, 13, 15,
+ 10, 11, 14,
+ 11, 15, 14,
+ 8, 12, 9,
+ 12, 13, 9
+};
+static const unsigned cube_in_cube_2_properties[72] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0
+};
+/* Dump of star-geometry 'cube_in_cube_3'. */
+static const unsigned cube_in_cube_3_vertices_count = 24;
+static const double cube_in_cube_3_vertices[72] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1,
+ -0.7, -1, -1,
+ 2, -1, -1,
+ -1, 2, -1,
+ 2, 2, -1,
+ -1, -1, 2.3,
+ 2, -1, 2,
+ -1, 2, 2,
+ 2, 2.3, 2,
+ -3, -4, -4,
+ 6, -4, -4,
+ -4, 6, -4,
+ 6, 6, -4,
+ -4, -4, 7,
+ 6, -4, 6,
+ -4, 6, 6,
+ 6, 7, 6
+};
+static const unsigned cube_in_cube_3_triangles_count = 36;
+static const unsigned cube_in_cube_3_triangles[108] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5,
+ 8, 9, 10,
+ 9, 11, 10,
+ 8, 10, 12,
+ 10, 14, 12,
+ 12, 14, 13,
+ 14, 15, 13,
+ 11, 9, 15,
+ 9, 13, 15,
+ 10, 11, 14,
+ 11, 15, 14,
+ 8, 12, 9,
+ 12, 13, 9,
+ 16, 17, 18,
+ 17, 19, 18,
+ 16, 18, 20,
+ 18, 22, 20,
+ 20, 22, 21,
+ 22, 23, 21,
+ 19, 17, 23,
+ 17, 21, 23,
+ 18, 19, 22,
+ 19, 23, 22,
+ 16, 20, 17,
+ 20, 21, 17
+};
+static const unsigned cube_in_cube_3_properties[108] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0
+};
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned e, ecount, maxm, e2;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Create a scene with the first and second cubes.
+ * The enclosure in the small contains medium 1, the external enclosure
+ * contains medium 1, the enclosure between the small and medium cubes
+ * contains medium 0. */
+ ctx.positions = cube_in_cube_2_vertices;
+ ctx.indices = cube_in_cube_2_triangles;
+ ctx.properties = cube_in_cube_2_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ cube_in_cube_2_triangles_count, get_indices, get_media_from_properties,
+ cube_in_cube_2_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 3);
+
+ FOR_EACH(e, 0, ecount) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ unsigned m;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ ASSERT(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &m));
+ ASSERT(m <= 1);
+ ASSERT((m == 0) == (header.primitives_count == cube_in_cube_2_triangles_count));
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_get_max_medium(scn, &maxm));
+ CHK(maxm == 1);
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Create a scene with the 3 cubes, same 2 first cubes as above.
+ * The enclosure in the small cube contains medium 1, the external enclosure
+ * contains medium 1, the enclosure between the small and medium cubes
+ * contains medium 0 and the enclosure between the medium and big cubes
+ * contains both media 0 and 1. */
+ ctx.positions = cube_in_cube_3_vertices;
+ ctx.indices = cube_in_cube_3_triangles;
+ ctx.properties = cube_in_cube_3_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ cube_in_cube_3_triangles_count, get_indices, get_media_from_properties,
+ cube_in_cube_3_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 4);
+
+ e2 = ecount;
+ FOR_EACH(e, 0, ecount) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ ASSERT(header.enclosed_media_count <= 2);
+ if(header.enclosed_media_count == 2) {
+ /* A single internal enclosure has 2 media */
+ ASSERT(!header.is_infinite);
+ ASSERT(e2 == ecount); (void)e2;
+ e2 = e;
+ }
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_get_max_medium(scn, &maxm));
+ CHK(maxm == 1);
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_cube_on_cube.c b/src/test_senc3d_cube_on_cube.c
@@ -0,0 +1,205 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_cube_on_cube. */
+
+#define _POSIX_C_SOURCE 200112L /* snprintf */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+#include <stdio.h>
+
+/*
+ +-----------------------+
+ | 3
+ | +------+ |
+ m2 | m1 | m0 2 |
+ | | |--> N |
+ | +------+ |
+ | | m0 1 |
+ | | |--> N |
+ | +------+ |
+ |--> N |
+ +-----------------------+
+ */
+
+/* Dump of star-geometry 'cube_on_cube'. */
+static const unsigned cube_on_cube_vertices_count = 20;
+static const double cube_on_cube_vertices[60] =
+{
+ 1, 1, 2,
+ 2, 1, 2,
+ 1, 2, 2,
+ 2, 2, 2,
+ 1, 1, 3,
+ 2, 1, 3,
+ 1, 2, 3,
+ 2, 2, 3,
+ 1, 1, 1,
+ 2, 1, 1,
+ 1, 2, 1,
+ 2, 2, 1,
+ 0.4, 0, 0,
+ 4, 0, 0,
+ 0, 4, 0,
+ 4, 4, 0,
+ 0, 0, 4.4,
+ 4, 0, 4,
+ 0, 4, 4,
+ 4, 4.4, 4
+};
+static const unsigned cube_on_cube_triangles_count = 34;
+static const unsigned cube_on_cube_triangles[102] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5,
+ 8, 10, 9,
+ 9, 10, 11,
+ 8, 0, 10,
+ 10, 0, 2,
+ 11, 3, 9,
+ 9, 3, 1,
+ 10, 2, 11,
+ 11, 2, 3,
+ 8, 9, 0,
+ 0, 9, 1,
+ 12, 13, 14,
+ 13, 15, 14,
+ 12, 14, 16,
+ 14, 18, 16,
+ 16, 18, 17,
+ 18, 19, 17,
+ 15, 13, 19,
+ 13, 17, 19,
+ 14, 15, 18,
+ 15, 19, 18,
+ 12, 16, 13,
+ 16, 17, 13
+};
+static const unsigned cube_on_cube_properties[102] =
+{
+ 0, 0, 0,
+ 0, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0
+};
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned count, e;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Create a scene with the cubes.
+ * The enclosures in the small cubes contain medium 0, the external enclosure
+ * contains medium 2, the enclosure between the small and big cubes
+ * contains medium 1. */
+ ctx.positions = cube_on_cube_vertices;
+ ctx.indices = cube_on_cube_triangles;
+ ctx.properties = cube_on_cube_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ cube_on_cube_triangles_count, get_indices, get_media_from_properties,
+ cube_on_cube_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 4);
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == cube_on_cube_vertices_count);
+
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == cube_on_cube_triangles_count);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 4);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ unsigned m;
+ char name[128]; (void)name;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ CHK(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &m));
+ if(header.is_infinite) ASSERT(m == 2); /* External */
+ else if(header.primitives_count == 12) ASSERT(m == 0); /* Internal */
+ else ASSERT(m == 1); /* In between */
+ OK(senc3d_enclosure_ref_put(enclosure));
+#ifdef DUMP_ENCLOSURES
+ snprintf(name, sizeof(name), "test_cube_on_cube_%u.obj", e);
+ dump_enclosure(scn, e, name);
+#endif
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_device.c b/src/test_senc3d_device.c
@@ -0,0 +1,77 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/logger.h>
+
+#include <stdio.h>
+
+static INLINE void
+log_stream(const char* msg, void* ctx)
+{
+ ASSERT(msg);
+ (void)msg, (void)ctx;
+ printf("%s\n", msg);
+}
+
+int
+main(int argc, char** argv)
+{
+ struct logger logger;
+ struct mem_allocator allocator;
+ struct senc3d_device* dev;
+ (void)argc, (void)argv;
+
+ BA(senc3d_device_create(NULL, NULL, 0, 0, NULL));
+ BA(senc3d_device_create(NULL, NULL, 0, 0, &dev));
+ OK(senc3d_device_create(NULL, NULL, 1, 0, &dev));
+ BA(senc3d_device_ref_get(NULL));
+ OK(senc3d_device_ref_get(dev));
+ BA(senc3d_device_ref_put(NULL));
+ OK(senc3d_device_ref_put(dev));
+ OK(senc3d_device_ref_put(dev));
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+
+ CHK(MEM_ALLOCATED_SIZE(&allocator) == 0);
+ BA(senc3d_device_create(NULL, &allocator, 1, 0, NULL));
+ OK(senc3d_device_create(NULL, &allocator, 1, 0, &dev));
+ OK(senc3d_device_ref_put(dev));
+ CHK(MEM_ALLOCATED_SIZE(&allocator) == 0);
+
+ OK(logger_init(&allocator, &logger));
+ 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);
+
+ BA(senc3d_device_create(&logger, NULL, 1, 0, NULL));
+ OK(senc3d_device_create(&logger, NULL, 1, 0, &dev));
+ OK(senc3d_device_ref_put(dev));
+
+ BA(senc3d_device_create(&logger, &allocator, 1, 0, NULL));
+ OK(senc3d_device_create(&logger, &allocator, 1, 0, &dev));
+ OK(senc3d_device_ref_put(dev));
+
+ OK(senc3d_device_create(&logger, &allocator, SENC3D_NTHREADS_DEFAULT, 0, &dev));
+ OK(senc3d_device_ref_put(dev));
+
+ logger_release(&logger);
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_enclosure.c b/src/test_senc3d_enclosure.c
@@ -0,0 +1,248 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 "senc3d.h"
+#include "senc3d_sXd_helper.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+#include <star/s3d.h>
+
+static void
+test(const int convention)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct senc3d_enclosure* enclosures[2] = { NULL, NULL };
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ struct s3d_device* s3d = NULL;
+ struct s3d_scene* s3d_scn = NULL;
+ struct s3d_shape* s3d_shp = NULL;
+ struct s3d_vertex_data s3d_attribs;
+ unsigned indices[2][3];
+ unsigned medium;
+ unsigned gid;
+ enum senc3d_side side;
+ double vrtx[3];
+ struct context ctx = CONTEXT_NULL__;
+ unsigned i, n, t, count;
+ int conv;
+ const int conv_front = (convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0;
+ const int conv_in = (convention & SENC3D_CONVENTION_NORMAL_INSIDE) != 0;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* A 3D cube.
+ * 2 enclosures (inside, outside) sharing the same triangles,
+ * but opposite sides */
+ ctx.positions = box_vertices;
+ ctx.indices = box_indices;
+ ctx.front_media = medium0;
+ ctx.back_media = medium1;
+
+ OK(senc3d_scene_create(dev, convention, ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_convention(scn, &conv));
+ CHK(conv == convention);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 2);
+
+ OK(senc3d_scene_get_enclosure(scn, 0, &enclosure));
+ BA(senc3d_enclosure_ref_get(NULL));
+ OK(senc3d_enclosure_ref_get(enclosure));
+ BA(senc3d_enclosure_ref_put(NULL));
+ OK(senc3d_enclosure_ref_put(enclosure));
+
+ BA(senc3d_enclosure_get_triangle(NULL, 0, indices[0]));
+ BA(senc3d_enclosure_get_triangle(enclosure, ntriangles, indices[0]));
+ BA(senc3d_enclosure_get_triangle(enclosure, 0, NULL));
+ BA(senc3d_enclosure_get_triangle(NULL, ntriangles, indices[0]));
+ BA(senc3d_enclosure_get_triangle(NULL, 0, NULL));
+ BA(senc3d_enclosure_get_triangle(enclosure, ntriangles, NULL));
+ BA(senc3d_enclosure_get_triangle(NULL, ntriangles, NULL));
+ OK(senc3d_enclosure_get_triangle(enclosure, 0, indices[0]));
+
+ BA(senc3d_enclosure_get_vertex(NULL, 0, vrtx));
+ BA(senc3d_enclosure_get_vertex(enclosure, nvertices, vrtx));
+ BA(senc3d_enclosure_get_vertex(enclosure, 0, NULL));
+ BA(senc3d_enclosure_get_vertex(NULL, nvertices, vrtx));
+ BA(senc3d_enclosure_get_vertex(NULL, 0, NULL));
+ BA(senc3d_enclosure_get_vertex(enclosure, nvertices, NULL));
+ BA(senc3d_enclosure_get_vertex(NULL, nvertices, NULL));
+ OK(senc3d_enclosure_get_vertex(enclosure, 0, vrtx));
+
+ BA(senc3d_enclosure_get_triangle_id(NULL, 0, &gid, NULL));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, &gid, NULL));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, 0, NULL, NULL));
+ BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, &gid, NULL));
+ BA(senc3d_enclosure_get_triangle_id(NULL, 0, NULL, NULL));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, NULL, NULL));
+ BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, NULL, NULL));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, 0, &gid, NULL));
+ BA(senc3d_enclosure_get_triangle_id(NULL, 0, &gid, &side));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, &gid, &side));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, 0, NULL, &side));
+ BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, &gid, &side));
+ BA(senc3d_enclosure_get_triangle_id(NULL, 0, NULL, &side));
+ BA(senc3d_enclosure_get_triangle_id(enclosure, ntriangles, NULL, &side));
+ BA(senc3d_enclosure_get_triangle_id(NULL, ntriangles, NULL, &side));
+ OK(senc3d_enclosure_get_triangle_id(enclosure, 0, &gid, &side));
+
+ BA(senc3d_enclosure_get_medium(NULL, 0, &medium));
+ BA(senc3d_enclosure_get_medium(enclosure, 2, &medium));
+ BA(senc3d_enclosure_get_medium(enclosure, 0, NULL));
+ BA(senc3d_enclosure_get_medium(NULL, 2, &medium));
+ BA(senc3d_enclosure_get_medium(NULL, 0, NULL));
+ BA(senc3d_enclosure_get_medium(enclosure, 2, NULL));
+ BA(senc3d_enclosure_get_medium(NULL, 2, NULL));
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &medium));
+
+ OK(senc3d_enclosure_ref_put(enclosure));
+
+ FOR_EACH(i, 0, count) {
+ OK(senc3d_scene_get_enclosure(scn, i, &enclosure));
+
+ BA(senc3d_enclosure_get_header(NULL, &header));
+ BA(senc3d_enclosure_get_header(enclosure, NULL));
+ BA(senc3d_enclosure_get_header(NULL, NULL));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == i);
+ CHK(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &medium));
+ /* Geometrical normals point outside the cube in input triangles:
+ * if convention is front, front medium (0) is outside,
+ * that is medium 0's enclosure is infinite */
+ CHK(conv_front == ((medium == 0) == header.is_infinite));
+ CHK(header.primitives_count == ntriangles);
+ CHK(header.unique_primitives_count == ntriangles);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == (i == 0));
+
+ FOR_EACH(t, 0, header.primitives_count) {
+ OK(senc3d_enclosure_get_triangle_id(enclosure, t, &gid, &side));
+ CHK(gid == t);
+ CHK(side == (medium == 0) ? SENC3D_FRONT : SENC3D_BACK);
+ }
+
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ FOR_EACH(i, 0, 2)
+ OK(senc3d_scene_get_enclosure(scn, i, enclosures + i));
+ FOR_EACH(n, 0, ntriangles) {
+ int same, reversed;
+ /* Read same triangles in both enclosures */
+ FOR_EACH(i, 0, 2)
+ OK(senc3d_enclosure_get_triangle(enclosures[i], n, indices[i]));
+ /* Same triangles and opposite sides for the 2 enclosures */
+ FOR_EACH(i, 0, 3) CHK(indices[0][i] == indices[1][2 - i]);
+ /* Enclosure 0 is outside (and contains medium 0 if convention is front).
+ * Geometrical normals in output data point in the same direction that those
+ * of input triangles for enclosure 0 iff convention is inside.
+ * The opposite holds for enclosure 1. */
+ cmp_trg(n, enclosures[0], box_indices + 3 * n, box_vertices, &same, &reversed);
+ CHK((same && !reversed) == conv_in);
+ cmp_trg(n, enclosures[1], box_indices + 3 * n, box_vertices, &same, &reversed);
+ CHK(same && reversed == conv_in);
+ }
+ FOR_EACH(i, 0, 2)
+ OK(senc3d_enclosure_ref_put(enclosures[i]));
+
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Same 3D cube, but with a hole (incomplete).
+ * 1 single enclosure including both sides of triangles */
+
+ ctx.positions = box_vertices;
+ ctx.indices = box_indices;
+ ctx.front_media = medium0;
+ ctx.back_media = medium1;
+
+ OK(senc3d_scene_create(dev, convention, ntriangles - 1, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_frontier_segments_count(scn, &count));
+ CHK(count == 3);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 1);
+
+#ifdef DUMP_ENCLOSURES
+ dump_enclosure(scn, 0, "test_enclosure_hole.obj");
+#endif
+
+ OK(senc3d_scene_get_enclosure(scn, 0, &enclosure));
+
+ BA(senc3d_enclosure_get_header(NULL, &header));
+ BA(senc3d_enclosure_get_header(enclosure, NULL));
+ BA(senc3d_enclosure_get_header(NULL, NULL));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == 0);
+ CHK(header.enclosed_media_count == 2);
+ CHK(header.primitives_count == 2 * header.unique_primitives_count);
+ CHK(header.unique_primitives_count == ntriangles - 1);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == 1);
+
+ FOR_EACH(t, 0, header.primitives_count) {
+ OK(senc3d_enclosure_get_triangle_id(enclosure, t, &gid, &side));
+ /* The first unique_triangle_count triangles of an enclosure
+ * are unique triangles */
+ if(t < header.unique_primitives_count) CHK(gid == t);
+ CHK(side == (t < header.unique_primitives_count) ? SENC3D_FRONT : SENC3D_BACK);
+ }
+
+ /* Put geometry in a 3D view using helper functions */
+ s3d_attribs.type = S3D_FLOAT3;
+ s3d_attribs.usage = S3D_POSITION;
+ s3d_attribs.get = senc3d_sXd_enclosure_get_position;
+ OK(s3d_device_create(NULL, &allocator, 0, &s3d));
+ OK(s3d_scene_create(s3d, &s3d_scn));
+ OK(s3d_shape_create_mesh(s3d, &s3d_shp));
+ OK(s3d_mesh_setup_indexed_vertices(s3d_shp, header.primitives_count,
+ senc3d_sXd_enclosure_get_indices, header.vertices_count, &s3d_attribs,
+ 1, enclosure));
+ OK(s3d_scene_attach_shape(s3d_scn, s3d_shp));
+ S3D(shape_ref_put(s3d_shp));
+ S3D(device_ref_put(s3d));
+ S3D(scene_ref_put(s3d_scn));
+
+ SENC3D(scene_ref_put(scn));
+ SENC3D(device_ref_put(dev));
+ SENC3D(enclosure_ref_put(enclosure));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+}
+
+int
+main(int argc, char** argv)
+{
+ (void) argc, (void) argv;
+ test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE);
+ test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE);
+ test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_OUTSIDE);
+ test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE);
+ return 0;
+}
diff --git a/src/test_senc3d_inconsistant_cube.c b/src/test_senc3d_inconsistant_cube.c
@@ -0,0 +1,145 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+/* The following array lists the indices toward the 3D vertices of each
+* triangle.
+* ,6---,7 ,6----7
+* ,' | ,'/| ,' | \ | Y Z
+* 2----3' / | 2', | \ | | ,'
+* |', | / ,5 | ',4---,5 0----X
+* | ',|/,' | ,' | ,'
+* 0----1' 0----1'
+* Front, right Back, left and
+* and Top faces bottom faces */
+/* Triangle #1 rotation order is not consistant with other triangles */
+static unsigned
+inconsistant_box_indices[12/*#triangles*/ * 3/*#indices per triangle*/] = {
+ 0, 1, 2, 1, 2, 3, /* Front face */
+ 0, 4, 2, 2, 4, 6, /* Left face*/
+ 4, 5, 6, 6, 5, 7, /* Back face */
+ 3, 7, 1, 1, 7, 5, /* Right face */
+ 2, 6, 3, 3, 6, 7, /* Top face */
+ 0, 1, 4, 4, 1, 5 /* Bottom face */
+};
+static const unsigned inconsistant_box_ntriangles
+= sizeof(inconsistant_box_indices) / (3 * sizeof(*inconsistant_box_indices));
+
+/* Media definitions reflect triangle #1 inconsistancy */
+static const unsigned
+inconsistant_medium_front[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static const unsigned
+inconsistant_medium_back[12] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static void
+test(const int convention)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ int conv;
+ int conv_front, conv_in;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned i, e, ecount;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* A 3D cube.
+ * 2 enclosures (inside, outside) sharing the same triangles,
+ * but opposite sides.
+ * What differs in this test is that triangle #0 vertices are given
+ * in the opposite rotation order. */
+ ctx.positions = box_vertices;
+ ctx.indices = inconsistant_box_indices;
+ ctx.front_media = inconsistant_medium_front;
+ ctx.back_media = inconsistant_medium_back;
+
+ OK(senc3d_scene_create(dev, convention, inconsistant_box_ntriangles,
+ get_indices, get_media, nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 2);
+
+ OK(senc3d_scene_get_convention(scn, &conv));
+ CHK(conv == convention);
+ conv_front = (conv & SENC3D_CONVENTION_NORMAL_FRONT) != 0;
+ conv_in = (conv & SENC3D_CONVENTION_NORMAL_INSIDE) != 0;
+
+ FOR_EACH(e, 0, ecount) {
+ unsigned medium, expected_external_medium, expected_medium;
+ char name[128];
+ enum senc3d_side side, expected_side;
+ unsigned gid;
+ (void)name;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ CHK(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &medium));
+ /* If NORMAL_FRONT the external enclosure's medium should be 0,
+ * 1 if NORMAL_BACK */
+ expected_external_medium = conv_front ? 0 : 1;
+ expected_medium = (header.is_infinite ?
+ expected_external_medium : !expected_external_medium);
+ CHK(medium == expected_medium);
+
+#ifdef DUMP_ENCLOSURES
+ sprintf(name, "test_inconsistant_cube_%s_%s_%u.obj",
+ conv_front ? "front" : "back", conv_in ? "in" : "out", e);
+ dump_enclosure(scn, e, name);
+#endif
+
+ FOR_EACH(i, 0, header.primitives_count) {
+ int same, reversed, fst_reversed;
+ fst_reversed = ((e == 0) == conv_in);
+ expected_side = (inconsistant_medium_front[i] == expected_medium)
+ ? SENC3D_FRONT : SENC3D_BACK;
+ cmp_trg(i, enclosure,
+ inconsistant_box_indices + (3 * i), box_vertices,
+ &same, &reversed);
+ /* Should be made of the same triangles */
+ CHK(same);
+ CHK(i ? reversed != fst_reversed : reversed == fst_reversed);
+ OK(senc3d_enclosure_get_triangle_id(enclosure, i, &gid, &side));
+ CHK(side == expected_side);
+ }
+ SENC3D(enclosure_ref_put(enclosure));
+ }
+
+ SENC3D(scene_ref_put(scn));
+ SENC3D(device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+}
+
+int main(int argc, char** argv)
+{
+ (void) argc, (void) argv;
+
+ test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE);
+ test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE);
+ test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_OUTSIDE);
+ test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE);
+
+ return 0;
+}
diff --git a/src/test_senc3d_many_enclosures.c b/src/test_senc3d_many_enclosures.c
@@ -0,0 +1,107 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test is similar to test_senc3d_some_enclosures, but involves 64*64*64
+ * cylinders instead of 4*4*4, thus making it impossible to define the geometry
+ * through static arrays. */
+
+#define NB_CYL_X 32
+#define NB_CYL_Y 32
+#define NB_CYL_Z 16
+#define NB_CYL (NB_CYL_X * NB_CYL_Y * NB_CYL_Z)
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+#include "test_senc3d_utils2.h"
+
+#include <star/s3dut.h>
+#include <rsys/clock_time.h>
+#include <rsys/double3.h>
+
+#include <stdio.h>
+#include <limits.h>
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct s3dut_mesh* cyl = NULL;
+ struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ };
+ unsigned count;
+ unsigned cyl_trg_count, cyl_vrtx_count, e;
+ char dump[64];
+ struct time t0, t1;
+ (void)argc, (void)argv;
+
+ OK(mem_init_regular_allocator(&allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* A 20 triangles 12 vertices cylinder template */
+ S3DUT(create_cylinder(&allocator, 1, 1, 3, 1, &cyl));
+ S3DUT(mesh_get_data(cyl, &ctx.data));
+ ASSERT(ctx.data.nprimitives < UINT_MAX);
+ ASSERT(ctx.data.nvertices < UINT_MAX);
+ cyl_trg_count = (unsigned)ctx.data.nprimitives;
+ cyl_vrtx_count = (unsigned)ctx.data.nvertices;
+
+ /* Create the scene with N_CYL cylinders.
+ * There are NB_CYL_X * NB_CYL_Y imbrications of NB_CYL_Z cylinders each.
+ * Each imbrication is located on a grid.
+ * The get_s3du_xxx getters have to retrieve the cylinder from the
+ * primitive and vertice indexes. */
+ time_current(&t0);
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ NB_CYL * cyl_trg_count, get_s3dut_indices, get_s3dut_media,
+ NB_CYL * cyl_vrtx_count, get_s3dut_position, &ctx, &scn));
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump));
+ printf("Scene created in: %s\n", dump);
+ S3DUT(mesh_ref_put(cyl));
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == NB_CYL * cyl_vrtx_count);
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == NB_CYL * cyl_trg_count);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 1 + NB_CYL);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ unsigned m;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ CHK(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &m));
+ CHK(header.primitives_count ==
+ (header.is_infinite /* Outermost enclosure: NB_CYL_X*NB_CYL_Y cylinders */
+ ? NB_CYL_X * NB_CYL_Y * cyl_trg_count
+ : (m == 0
+ ? cyl_trg_count /* Innermost enclosures: 1 cylinder */
+ : 2 * cyl_trg_count))); /* Other enclosures: 2 cylinders */
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_regular_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_many_triangles.c b/src/test_senc3d_many_triangles.c
@@ -0,0 +1,101 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test is similar to test_senc3d_some_triangles, but involves 4*2562560
+ * triangles instead of 4*1054, thus making it impossible to define the geometry
+ * through static arrays. */
+
+#define NB_CYL_X 2
+#define NB_CYL_Y 1
+#define NB_CYL_Z 1
+ /* 4 cylinders */
+#define NB_CYL (NB_CYL_X * NB_CYL_Y * NB_CYL_Z)
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+#include "test_senc3d_utils2.h"
+
+#include <star/s3dut.h>
+#include <rsys/clock_time.h>
+#include <rsys/double3.h>
+
+#include <stdio.h>
+#include <limits.h>
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct s3dut_mesh* cyl = NULL;
+ struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ };
+ unsigned m0 = 0;
+ unsigned count;
+ unsigned cyl_trg_count, cyl_vrtx_count, e;
+ char dump[64];
+ struct time t0, t1;
+ (void)argc, (void)argv;
+
+ OK(mem_init_regular_allocator(&allocator));
+ OK(senc3d_device_create (NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* A 2,562,560 triangles 1,281,282 vertices cylinder template */
+ S3DUT(create_cylinder(&allocator, 1, 2, 1280, 1000, &cyl));
+ S3DUT(mesh_get_data(cyl, &ctx.data));
+ ASSERT(ctx.data.nprimitives < UINT_MAX);
+ ASSERT(ctx.data.nvertices < UINT_MAX);
+ cyl_trg_count = (unsigned)ctx.data.nprimitives;
+ cyl_vrtx_count = (unsigned)ctx.data.nvertices;
+
+ /* Create the scene with 4 cylinders.
+ * The get_s3du_xxx getters have to retrieve the cylinder from the
+ * primitive and vertice indexes. */
+ ctx.ctx.back_media = &m0;
+ time_current(&t0);
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ NB_CYL* cyl_trg_count, get_s3dut_indices, get_s3dut_media,
+ NB_CYL* cyl_vrtx_count, get_s3dut_position, &ctx, &scn));
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump));
+ printf("Scene created in: %s\n", dump);
+ S3DUT(mesh_ref_put(cyl));
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == NB_CYL * cyl_vrtx_count);
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == NB_CYL * cyl_trg_count);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 1 + NB_CYL);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ CHK(header.primitives_count ==
+ e ? cyl_trg_count : NB_CYL * cyl_trg_count);
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_regular_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_sample_enclosure.c b/src/test_senc3d_sample_enclosure.c
@@ -0,0 +1,124 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* 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 "senc3d.h"
+#include "senc3d_sXd_helper.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/float3.h>
+#include <rsys/double3.h>
+
+#include <star/s3d.h>
+#include <star/ssp.h>
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct senc3d_enclosure* enclosure = NULL;
+ struct senc3d_enclosure_header header;
+ struct s3d_device* s3d = NULL;
+ struct s3d_scene* s3d_scn = NULL;
+ struct s3d_scene_view* s3d_view = NULL;
+ struct s3d_shape* s3d_shp = NULL;
+ struct s3d_primitive prim;
+ struct s3d_vertex_data vrtx_get;
+ struct ssp_rng* rng;
+ struct context ctx = CONTEXT_NULL__;
+ int i;
+ float st[2];
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* A 3D cube, but with a hole (incomplete).
+ * 1 single enclosure including both sides of triangles */
+ ctx.positions = cube_vertices;
+ ctx.indices = box_indices;
+ ctx.front_media = medium0;
+ ctx.back_media = medium0;
+
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles - 1, get_indices, get_media, nvertices, get_position, &ctx,
+ &scn));
+
+ OK(senc3d_scene_get_enclosure(scn, 0, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ /* Put enclosure in a 3D view... */
+ vrtx_get.type = S3D_FLOAT3;
+ vrtx_get.usage = S3D_POSITION;
+ vrtx_get.get = senc3d_sXd_enclosure_get_position;
+ S3D(device_create(NULL, &allocator, 0, &s3d));
+ S3D(scene_create(s3d, &s3d_scn));
+ S3D(shape_create_mesh(s3d, &s3d_shp));
+ S3D(mesh_setup_indexed_vertices(s3d_shp, header.primitives_count,
+ senc3d_sXd_enclosure_get_indices, header.vertices_count,
+ &vrtx_get, 1, enclosure));
+ S3D(scene_attach_shape(s3d_scn, s3d_shp));
+ S3D(scene_view_create(s3d_scn, S3D_SAMPLE, &s3d_view));
+
+ /* ... and sample it. */
+ OK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng));
+ FOR_EACH(i, 0, 10000) {
+ struct s3d_attrib attrib;
+ int n, c;
+ S3D(scene_view_sample(s3d_view,
+ ssp_rng_canonical_float(rng),
+ ssp_rng_canonical_float(rng),
+ ssp_rng_canonical_float(rng),
+ &prim, st));
+ S3D(primitive_get_attrib(&prim, S3D_POSITION, st, &attrib));
+ c = 0;
+ FOR_EACH(n, 0, 3)
+ if(eq_eps(attrib.value[n], 0, FLT_EPSILON)
+ || eq_eps(attrib.value[n], 1, FLT_EPSILON))
+ c++;
+ CHK(c == 1);
+ S3D(primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, st, &attrib));
+ c = 0;
+ FOR_EACH(n, 0, 3)
+ if(eq_eps(attrib.value[n], -1, FLT_EPSILON)
+ || eq_eps(attrib.value[n], 1, FLT_EPSILON))
+ c++;
+ CHK(c == 1);
+ c = 0;
+ FOR_EACH(n, 0, 3)
+ if(eq_eps(attrib.value[n], 0, FLT_EPSILON))
+ c++;
+ CHK(c == 2);
+ }
+
+ SENC3D(enclosure_ref_put(enclosure));
+ SENC3D(scene_ref_put(scn));
+ SENC3D(device_ref_put(dev));
+
+ SSP(rng_ref_put(rng));
+
+ S3D(shape_ref_put(s3d_shp));
+ S3D(scene_view_ref_put(s3d_view));
+ S3D(device_ref_put(s3d));
+ S3D(scene_ref_put(s3d_scn));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+
+ return 0;
+}
diff --git a/src/test_senc3d_scene.c b/src/test_senc3d_scene.c
@@ -0,0 +1,304 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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 "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/float3.h>
+#include <rsys/double3.h>
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct senc3d_enclosure* enc = NULL;
+ struct senc3d_enclosure_header header;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned medfront[2], medback[2], ind[3], ids[2], trg;
+ double vrtx[3];
+ unsigned count, i, maxm;
+ int convention;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* A 3D cube.
+ * With this geometry front is inside with NORMAL_BACK convention,
+ * outside with NORMAL_FRONT convention */
+ ctx.positions = box_vertices;
+ ctx.indices = box_indices;
+ ctx.front_media = medium0;
+ ctx.back_media = medium1;
+
+ BA(senc3d_scene_create(NULL,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+ BA(senc3d_scene_create(dev,
+ 0,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+ BA(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ 0, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+ BA(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, NULL, get_media,
+ nvertices, get_position, &ctx, &scn));
+ BA(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ 0, get_position, &ctx, &scn));
+ BA(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, NULL, &ctx, &scn));
+ BA(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, NULL));
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+
+ BA(senc3d_scene_get_convention(NULL, &convention));
+ BA(senc3d_scene_get_convention(scn, NULL));
+ BA(senc3d_scene_get_convention(NULL, NULL));
+ OK(senc3d_scene_get_convention(scn, &convention));
+ CHK(convention
+ == (SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE));
+
+ BA(senc3d_scene_get_triangles_count(NULL, &count));
+ BA(senc3d_scene_get_triangles_count(scn, NULL));
+ BA(senc3d_scene_get_triangles_count(NULL, NULL));
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == ntriangles);
+
+ BA(senc3d_scene_get_vertices_count(NULL, &count));
+ BA(senc3d_scene_get_vertices_count(scn, NULL));
+ BA(senc3d_scene_get_vertices_count(NULL, NULL));
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == nvertices);
+
+ BA(senc3d_scene_get_triangle(NULL, 0, ind));
+ BA(senc3d_scene_get_triangle(scn, UINT_MAX, ind));
+ BA(senc3d_scene_get_triangle(scn, 0, NULL));
+ BA(senc3d_scene_get_triangle(NULL, UINT_MAX, ind));
+ BA(senc3d_scene_get_triangle(NULL, 0, NULL));
+ BA(senc3d_scene_get_triangle(scn, UINT_MAX, NULL));
+ BA(senc3d_scene_get_triangle(NULL, UINT_MAX, NULL));
+ OK(senc3d_scene_get_triangle(scn, 0, ind));
+
+ BA(senc3d_scene_get_triangle_media(NULL, 0, ind));
+ BA(senc3d_scene_get_triangle_media(scn, UINT_MAX, ind));
+ BA(senc3d_scene_get_triangle_media(scn, 0, NULL));
+ BA(senc3d_scene_get_triangle_media(NULL, UINT_MAX, ind));
+ BA(senc3d_scene_get_triangle_media(NULL, 0, NULL));
+ BA(senc3d_scene_get_triangle_media(scn, UINT_MAX, NULL));
+ BA(senc3d_scene_get_triangle_media(NULL, UINT_MAX, NULL));
+ OK(senc3d_scene_get_triangle_media(scn, 0, ind));
+
+ BA(senc3d_scene_get_vertex(NULL, 0, vrtx));
+ BA(senc3d_scene_get_vertex(scn, UINT_MAX, vrtx));
+ BA(senc3d_scene_get_vertex(scn, 0, NULL));
+ BA(senc3d_scene_get_vertex(NULL, UINT_MAX, vrtx));
+ BA(senc3d_scene_get_vertex(NULL, 0, NULL));
+ BA(senc3d_scene_get_vertex(scn, UINT_MAX, NULL));
+ BA(senc3d_scene_get_vertex(NULL, UINT_MAX, NULL));
+ OK(senc3d_scene_get_vertex(scn, 0, vrtx));
+
+ BA(senc3d_scene_get_max_medium(NULL, &maxm));
+ BA(senc3d_scene_get_max_medium(scn, NULL));
+ BA(senc3d_scene_get_max_medium(NULL, NULL));
+ OK(senc3d_scene_get_max_medium(scn, &maxm));
+ CHK(maxm == 1);
+
+ BA(senc3d_scene_get_enclosure_count(NULL, &count));
+ BA(senc3d_scene_get_enclosure_count(scn, NULL));
+ BA(senc3d_scene_get_enclosure_count(NULL, NULL));
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 2);
+
+ BA(senc3d_scene_get_enclosure_count_by_medium(NULL, 0, &count));
+ BA(senc3d_scene_get_enclosure_count_by_medium(scn, 100, &count));
+ BA(senc3d_scene_get_enclosure_count_by_medium(scn, 0, NULL));
+ BA(senc3d_scene_get_enclosure_count_by_medium(NULL, 100, &count));
+ BA(senc3d_scene_get_enclosure_count_by_medium(NULL, 0, NULL));
+ BA(senc3d_scene_get_enclosure_count_by_medium(scn, 100, NULL));
+ BA(senc3d_scene_get_enclosure_count_by_medium(NULL, 100, NULL));
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, 0, &count));
+ CHK(count == 1);
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, SENC3D_UNSPECIFIED_MEDIUM,
+ &count));
+ CHK(count == 0);
+
+ BA(senc3d_scene_get_enclosure(NULL, 0, &enc));
+ BA(senc3d_scene_get_enclosure(scn, UINT_MAX, &enc));
+ BA(senc3d_scene_get_enclosure(scn, 0, NULL));
+ BA(senc3d_scene_get_enclosure(NULL, UINT_MAX, &enc));
+ BA(senc3d_scene_get_enclosure(NULL, 0, NULL));
+ BA(senc3d_scene_get_enclosure(scn, UINT_MAX, NULL));
+ BA(senc3d_scene_get_enclosure(NULL, UINT_MAX, NULL));
+ OK(senc3d_scene_get_enclosure(scn, 0, &enc));
+ OK(senc3d_enclosure_ref_put(enc));
+
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 0, 0, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 100, 0, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 0, UINT_MAX, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 0, 0, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 100, 0, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 0, UINT_MAX, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 0, 0, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 100, UINT_MAX, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 100, 0, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 0, UINT_MAX, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, 100, UINT_MAX, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 0, UINT_MAX, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 100, 0, NULL));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 100, UINT_MAX, &enc));
+ BA(senc3d_scene_get_enclosure_by_medium(NULL, 100, UINT_MAX, NULL));
+ OK(senc3d_scene_get_enclosure_by_medium(scn, 0, 0, &enc));
+ OK(senc3d_enclosure_ref_put(enc));
+ /* Index 0 is out of range for SENC3D_UNSPECIFIED_MEDIUM. */
+ BA(senc3d_scene_get_enclosure_by_medium(scn, SENC3D_UNSPECIFIED_MEDIUM, 0, &enc));
+
+ BA(senc3d_scene_get_triangle_enclosures(NULL, 0, ids));
+ BA(senc3d_scene_get_triangle_enclosures(scn, UINT_MAX, ids));
+ BA(senc3d_scene_get_triangle_enclosures(scn, 0, NULL));
+ BA(senc3d_scene_get_triangle_enclosures(NULL, UINT_MAX, ids));
+ BA(senc3d_scene_get_triangle_enclosures(NULL, 0, NULL));
+ BA(senc3d_scene_get_triangle_enclosures(scn, UINT_MAX, NULL));
+ BA(senc3d_scene_get_triangle_enclosures(NULL, UINT_MAX, NULL));
+ OK(senc3d_scene_get_triangle_enclosures(scn, 0, ids));
+
+ BA(senc3d_scene_get_frontier_segments_count(NULL, &count));
+ BA(senc3d_scene_get_frontier_segments_count(scn, NULL));
+ BA(senc3d_scene_get_frontier_segments_count(NULL, NULL));
+ OK(senc3d_scene_get_frontier_segments_count(scn, &count));
+ CHK(count == 0);
+
+ BA(senc3d_scene_get_frontier_segment(NULL, 0, ids, &trg));
+ BA(senc3d_scene_get_frontier_segment(scn, UINT_MAX, ids, &trg));
+ BA(senc3d_scene_get_frontier_segment(scn, 0, NULL, &trg));
+ BA(senc3d_scene_get_frontier_segment(scn, 0, ids, NULL));
+ BA(senc3d_scene_get_frontier_segment(NULL, UINT_MAX, ids, &trg));
+ BA(senc3d_scene_get_frontier_segment(NULL, 0, NULL, &trg));
+ BA(senc3d_scene_get_frontier_segment(NULL, 0, ids, NULL));
+ BA(senc3d_scene_get_frontier_segment(scn, UINT_MAX, NULL, &trg));
+ BA(senc3d_scene_get_frontier_segment(scn, UINT_MAX, ids, NULL));
+ BA(senc3d_scene_get_frontier_segment(scn, 0, NULL, NULL));
+ BA(senc3d_scene_get_frontier_segment(NULL, UINT_MAX, NULL, &trg));
+ BA(senc3d_scene_get_frontier_segment(NULL, UINT_MAX, ids, NULL));
+ BA(senc3d_scene_get_frontier_segment(NULL, 0, NULL, NULL));
+ BA(senc3d_scene_get_frontier_segment(scn, UINT_MAX, NULL, NULL));
+ BA(senc3d_scene_get_frontier_segment(NULL, UINT_MAX, NULL, NULL));
+
+ BA(senc3d_scene_ref_get(NULL));
+ OK(senc3d_scene_ref_get(scn));
+ BA(senc3d_scene_ref_put(NULL));
+ OK(senc3d_scene_ref_put(scn));
+
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Same geometry with SENC3D_UNSPECIFIED_MEDIUM */
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, NULL,
+ nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_by_medium(scn, SENC3D_UNSPECIFIED_MEDIUM, 0, &enc));
+ OK(senc3d_enclosure_ref_put(enc));
+ BA(senc3d_scene_get_enclosure_by_medium(scn, SENC3D_UNSPECIFIED_MEDIUM, 100, &enc));
+
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Same geometry with a hole (1 missing triangle) */
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles - 1, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_frontier_segments_count(scn, &count));
+ CHK(count == 3);
+ OK(senc3d_scene_get_frontier_segment(scn, 0, ids, &trg));
+ BA(senc3d_scene_get_frontier_segment(scn, 3, ids, &trg));
+
+ OK(senc3d_scene_ref_put(scn));
+
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_convention(scn, &convention));
+ CHK(convention
+ == (SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE));
+ /* Check that medium 0 is inside */
+ OK(senc3d_scene_get_enclosure_by_medium(scn, 0, 0, &enc));
+ OK(senc3d_enclosure_get_header(enc, &header));
+ CHK(!header.is_infinite);
+ OK(senc3d_enclosure_ref_put(enc));
+
+ OK(senc3d_scene_get_triangle_media(scn, 0, medback));
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Medium mismatch between neighbour segments, but OK */
+ ctx.front_media = medium1_3;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_max_medium(scn, &maxm));
+ CHK(maxm == 3);
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, 0, &count));
+ CHK(count == 0); /* Medium 0 unused */
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, 1, &count));
+ CHK(count == 2); /* Medium 1 used twice */
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, 2, &count));
+ CHK(count == 0); /* Medium 2 unused */
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, 3, &count));
+ CHK(count == 1); /* Medium 3 used */
+
+ OK(senc3d_scene_ref_put(scn));
+
+ ctx.front_media = medium0;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ ntriangles, get_indices, get_media,
+ nvertices, get_position, &ctx, &scn));
+ /* Check that medium 0 is outside */
+ OK(senc3d_scene_get_enclosure_by_medium(scn, 0, 0, &enc));
+ OK(senc3d_enclosure_get_header(enc, &header));
+ CHK(header.is_infinite);
+ OK(senc3d_enclosure_ref_put(enc));
+
+ OK(senc3d_scene_get_triangle_media(scn, 0, medfront));
+ FOR_EACH(i, 0, 2) CHK(medback[i] == medfront[i]);
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+
+ return 0;
+}
diff --git a/src/test_senc3d_some_enclosures.c b/src/test_senc3d_some_enclosures.c
@@ -0,0 +1,3427 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_some_enclosures.
+ * This test is similar to test_senc3d_many_enclosures that creates a huge
+ * geometry by program. */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+/* Dump of star-geometry 'some_enclosures'. */
+static const unsigned some_enclosures_vertices_count = 768;
+static const double some_enclosures_vertices[2304] =
+{
+ -19, -20, -0.5,
+ -19, -20, 0.5,
+ -19.691, -19.0489, -0.5,
+ -19.691, -19.0489, 0.5,
+ -20.809, -19.4122, -0.5,
+ -20.809, -19.4122, 0.5,
+ -20.809, -20.5878, -0.5,
+ -20.809, -20.5878, 0.5,
+ -19.691, -20.9511, -0.5,
+ -19.691, -20.9511, 0.5,
+ -20, -20, -0.5,
+ -20, -20, 0.5,
+ -18, -20, -1,
+ -18, -20, 1,
+ -19.382, -18.0979, -1,
+ -19.382, -18.0979, 1,
+ -21.618, -18.8244, -1,
+ -21.618, -18.8244, 1,
+ -21.618, -21.1756, -1,
+ -21.618, -21.1756, 1,
+ -19.382, -21.9021, -1,
+ -19.382, -21.9021, 1,
+ -20, -20, -1,
+ -20, -20, 1,
+ -17, -20, -1.5,
+ -17, -20, 1.5,
+ -19.0729, -17.1468, -1.5,
+ -19.0729, -17.1468, 1.5,
+ -22.4271, -18.2366, -1.5,
+ -22.4271, -18.2366, 1.5,
+ -22.4271, -21.7634, -1.5,
+ -22.4271, -21.7634, 1.5,
+ -19.0729, -22.8532, -1.5,
+ -19.0729, -22.8532, 1.5,
+ -20, -20, -1.5,
+ -20, -20, 1.5,
+ -16, -20, -2,
+ -16, -20, 2,
+ -18.7639, -16.1958, -2,
+ -18.7639, -16.1958, 2,
+ -23.2361, -17.6489, -2,
+ -23.2361, -17.6489, 2,
+ -23.2361, -22.3511, -2,
+ -23.2361, -22.3511, 2,
+ -18.7639, -23.8042, -2,
+ -18.7639, -23.8042, 2,
+ -20, -20, -2,
+ -20, -20, 2,
+ -19, -10, -0.5,
+ -19, -10, 0.5,
+ -19.691, -9.04894, -0.5,
+ -19.691, -9.04894, 0.5,
+ -20.809, -9.41221, -0.5,
+ -20.809, -9.41221, 0.5,
+ -20.809, -10.5878, -0.5,
+ -20.809, -10.5878, 0.5,
+ -19.691, -10.9511, -0.5,
+ -19.691, -10.9511, 0.5,
+ -20, -10, -0.5,
+ -20, -10, 0.5,
+ -18, -10, -1,
+ -18, -10, 1,
+ -19.382, -8.09789, -1,
+ -19.382, -8.09789, 1,
+ -21.618, -8.82443, -1,
+ -21.618, -8.82443, 1,
+ -21.618, -11.1756, -1,
+ -21.618, -11.1756, 1,
+ -19.382, -11.9021, -1,
+ -19.382, -11.9021, 1,
+ -20, -10, -1,
+ -20, -10, 1,
+ -17, -10, -1.5,
+ -17, -10, 1.5,
+ -19.0729, -7.14683, -1.5,
+ -19.0729, -7.14683, 1.5,
+ -22.4271, -8.23664, -1.5,
+ -22.4271, -8.23664, 1.5,
+ -22.4271, -11.7634, -1.5,
+ -22.4271, -11.7634, 1.5,
+ -19.0729, -12.8532, -1.5,
+ -19.0729, -12.8532, 1.5,
+ -20, -10, -1.5,
+ -20, -10, 1.5,
+ -16, -10, -2,
+ -16, -10, 2,
+ -18.7639, -6.19577, -2,
+ -18.7639, -6.19577, 2,
+ -23.2361, -7.64886, -2,
+ -23.2361, -7.64886, 2,
+ -23.2361, -12.3511, -2,
+ -23.2361, -12.3511, 2,
+ -18.7639, -13.8042, -2,
+ -18.7639, -13.8042, 2,
+ -20, -10, -2,
+ -20, -10, 2,
+ -19, 0, -0.5,
+ -19, 0, 0.5,
+ -19.691, 0.951057, -0.5,
+ -19.691, 0.951057, 0.5,
+ -20.809, 0.587785, -0.5,
+ -20.809, 0.587785, 0.5,
+ -20.809, -0.587785, -0.5,
+ -20.809, -0.587785, 0.5,
+ -19.691, -0.951057, -0.5,
+ -19.691, -0.951057, 0.5,
+ -20, 0, -0.5,
+ -20, 0, 0.5,
+ -18, 0, -1,
+ -18, 0, 1,
+ -19.382, 1.90211, -1,
+ -19.382, 1.90211, 1,
+ -21.618, 1.17557, -1,
+ -21.618, 1.17557, 1,
+ -21.618, -1.17557, -1,
+ -21.618, -1.17557, 1,
+ -19.382, -1.90211, -1,
+ -19.382, -1.90211, 1,
+ -20, 0, -1,
+ -20, 0, 1,
+ -17, 0, -1.5,
+ -17, 0, 1.5,
+ -19.0729, 2.85317, -1.5,
+ -19.0729, 2.85317, 1.5,
+ -22.4271, 1.76336, -1.5,
+ -22.4271, 1.76336, 1.5,
+ -22.4271, -1.76336, -1.5,
+ -22.4271, -1.76336, 1.5,
+ -19.0729, -2.85317, -1.5,
+ -19.0729, -2.85317, 1.5,
+ -20, 0, -1.5,
+ -20, 0, 1.5,
+ -16, 0, -2,
+ -16, 0, 2,
+ -18.7639, 3.80423, -2,
+ -18.7639, 3.80423, 2,
+ -23.2361, 2.35114, -2,
+ -23.2361, 2.35114, 2,
+ -23.2361, -2.35114, -2,
+ -23.2361, -2.35114, 2,
+ -18.7639, -3.80423, -2,
+ -18.7639, -3.80423, 2,
+ -20, 0, -2,
+ -20, 0, 2,
+ -19, 10, -0.5,
+ -19, 10, 0.5,
+ -19.691, 10.9511, -0.5,
+ -19.691, 10.9511, 0.5,
+ -20.809, 10.5878, -0.5,
+ -20.809, 10.5878, 0.5,
+ -20.809, 9.41221, -0.5,
+ -20.809, 9.41221, 0.5,
+ -19.691, 9.04894, -0.5,
+ -19.691, 9.04894, 0.5,
+ -20, 10, -0.5,
+ -20, 10, 0.5,
+ -18, 10, -1,
+ -18, 10, 1,
+ -19.382, 11.9021, -1,
+ -19.382, 11.9021, 1,
+ -21.618, 11.1756, -1,
+ -21.618, 11.1756, 1,
+ -21.618, 8.82443, -1,
+ -21.618, 8.82443, 1,
+ -19.382, 8.09789, -1,
+ -19.382, 8.09789, 1,
+ -20, 10, -1,
+ -20, 10, 1,
+ -17, 10, -1.5,
+ -17, 10, 1.5,
+ -19.0729, 12.8532, -1.5,
+ -19.0729, 12.8532, 1.5,
+ -22.4271, 11.7634, -1.5,
+ -22.4271, 11.7634, 1.5,
+ -22.4271, 8.23664, -1.5,
+ -22.4271, 8.23664, 1.5,
+ -19.0729, 7.14683, -1.5,
+ -19.0729, 7.14683, 1.5,
+ -20, 10, -1.5,
+ -20, 10, 1.5,
+ -16, 10, -2,
+ -16, 10, 2,
+ -18.7639, 13.8042, -2,
+ -18.7639, 13.8042, 2,
+ -23.2361, 12.3511, -2,
+ -23.2361, 12.3511, 2,
+ -23.2361, 7.64886, -2,
+ -23.2361, 7.64886, 2,
+ -18.7639, 6.19577, -2,
+ -18.7639, 6.19577, 2,
+ -20, 10, -2,
+ -20, 10, 2,
+ -9, -20, -0.5,
+ -9, -20, 0.5,
+ -9.69098, -19.0489, -0.5,
+ -9.69098, -19.0489, 0.5,
+ -10.809, -19.4122, -0.5,
+ -10.809, -19.4122, 0.5,
+ -10.809, -20.5878, -0.5,
+ -10.809, -20.5878, 0.5,
+ -9.69098, -20.9511, -0.5,
+ -9.69098, -20.9511, 0.5,
+ -10, -20, -0.5,
+ -10, -20, 0.5,
+ -8, -20, -1,
+ -8, -20, 1,
+ -9.38197, -18.0979, -1,
+ -9.38197, -18.0979, 1,
+ -11.618, -18.8244, -1,
+ -11.618, -18.8244, 1,
+ -11.618, -21.1756, -1,
+ -11.618, -21.1756, 1,
+ -9.38197, -21.9021, -1,
+ -9.38197, -21.9021, 1,
+ -10, -20, -1,
+ -10, -20, 1,
+ -7, -20, -1.5,
+ -7, -20, 1.5,
+ -9.07295, -17.1468, -1.5,
+ -9.07295, -17.1468, 1.5,
+ -12.4271, -18.2366, -1.5,
+ -12.4271, -18.2366, 1.5,
+ -12.4271, -21.7634, -1.5,
+ -12.4271, -21.7634, 1.5,
+ -9.07295, -22.8532, -1.5,
+ -9.07295, -22.8532, 1.5,
+ -10, -20, -1.5,
+ -10, -20, 1.5,
+ -6, -20, -2,
+ -6, -20, 2,
+ -8.76393, -16.1958, -2,
+ -8.76393, -16.1958, 2,
+ -13.2361, -17.6489, -2,
+ -13.2361, -17.6489, 2,
+ -13.2361, -22.3511, -2,
+ -13.2361, -22.3511, 2,
+ -8.76393, -23.8042, -2,
+ -8.76393, -23.8042, 2,
+ -10, -20, -2,
+ -10, -20, 2,
+ -9, -10, -0.5,
+ -9, -10, 0.5,
+ -9.69098, -9.04894, -0.5,
+ -9.69098, -9.04894, 0.5,
+ -10.809, -9.41221, -0.5,
+ -10.809, -9.41221, 0.5,
+ -10.809, -10.5878, -0.5,
+ -10.809, -10.5878, 0.5,
+ -9.69098, -10.9511, -0.5,
+ -9.69098, -10.9511, 0.5,
+ -10, -10, -0.5,
+ -10, -10, 0.5,
+ -8, -10, -1,
+ -8, -10, 1,
+ -9.38197, -8.09789, -1,
+ -9.38197, -8.09789, 1,
+ -11.618, -8.82443, -1,
+ -11.618, -8.82443, 1,
+ -11.618, -11.1756, -1,
+ -11.618, -11.1756, 1,
+ -9.38197, -11.9021, -1,
+ -9.38197, -11.9021, 1,
+ -10, -10, -1,
+ -10, -10, 1,
+ -7, -10, -1.5,
+ -7, -10, 1.5,
+ -9.07295, -7.14683, -1.5,
+ -9.07295, -7.14683, 1.5,
+ -12.4271, -8.23664, -1.5,
+ -12.4271, -8.23664, 1.5,
+ -12.4271, -11.7634, -1.5,
+ -12.4271, -11.7634, 1.5,
+ -9.07295, -12.8532, -1.5,
+ -9.07295, -12.8532, 1.5,
+ -10, -10, -1.5,
+ -10, -10, 1.5,
+ -6, -10, -2,
+ -6, -10, 2,
+ -8.76393, -6.19577, -2,
+ -8.76393, -6.19577, 2,
+ -13.2361, -7.64886, -2,
+ -13.2361, -7.64886, 2,
+ -13.2361, -12.3511, -2,
+ -13.2361, -12.3511, 2,
+ -8.76393, -13.8042, -2,
+ -8.76393, -13.8042, 2,
+ -10, -10, -2,
+ -10, -10, 2,
+ -9, 0, -0.5,
+ -9, 0, 0.5,
+ -9.69098, 0.951057, -0.5,
+ -9.69098, 0.951057, 0.5,
+ -10.809, 0.587785, -0.5,
+ -10.809, 0.587785, 0.5,
+ -10.809, -0.587785, -0.5,
+ -10.809, -0.587785, 0.5,
+ -9.69098, -0.951057, -0.5,
+ -9.69098, -0.951057, 0.5,
+ -10, 0, -0.5,
+ -10, 0, 0.5,
+ -8, 0, -1,
+ -8, 0, 1,
+ -9.38197, 1.90211, -1,
+ -9.38197, 1.90211, 1,
+ -11.618, 1.17557, -1,
+ -11.618, 1.17557, 1,
+ -11.618, -1.17557, -1,
+ -11.618, -1.17557, 1,
+ -9.38197, -1.90211, -1,
+ -9.38197, -1.90211, 1,
+ -10, 0, -1,
+ -10, 0, 1,
+ -7, 0, -1.5,
+ -7, 0, 1.5,
+ -9.07295, 2.85317, -1.5,
+ -9.07295, 2.85317, 1.5,
+ -12.4271, 1.76336, -1.5,
+ -12.4271, 1.76336, 1.5,
+ -12.4271, -1.76336, -1.5,
+ -12.4271, -1.76336, 1.5,
+ -9.07295, -2.85317, -1.5,
+ -9.07295, -2.85317, 1.5,
+ -10, 0, -1.5,
+ -10, 0, 1.5,
+ -6, 0, -2,
+ -6, 0, 2,
+ -8.76393, 3.80423, -2,
+ -8.76393, 3.80423, 2,
+ -13.2361, 2.35114, -2,
+ -13.2361, 2.35114, 2,
+ -13.2361, -2.35114, -2,
+ -13.2361, -2.35114, 2,
+ -8.76393, -3.80423, -2,
+ -8.76393, -3.80423, 2,
+ -10, 0, -2,
+ -10, 0, 2,
+ -9, 10, -0.5,
+ -9, 10, 0.5,
+ -9.69098, 10.9511, -0.5,
+ -9.69098, 10.9511, 0.5,
+ -10.809, 10.5878, -0.5,
+ -10.809, 10.5878, 0.5,
+ -10.809, 9.41221, -0.5,
+ -10.809, 9.41221, 0.5,
+ -9.69098, 9.04894, -0.5,
+ -9.69098, 9.04894, 0.5,
+ -10, 10, -0.5,
+ -10, 10, 0.5,
+ -8, 10, -1,
+ -8, 10, 1,
+ -9.38197, 11.9021, -1,
+ -9.38197, 11.9021, 1,
+ -11.618, 11.1756, -1,
+ -11.618, 11.1756, 1,
+ -11.618, 8.82443, -1,
+ -11.618, 8.82443, 1,
+ -9.38197, 8.09789, -1,
+ -9.38197, 8.09789, 1,
+ -10, 10, -1,
+ -10, 10, 1,
+ -7, 10, -1.5,
+ -7, 10, 1.5,
+ -9.07295, 12.8532, -1.5,
+ -9.07295, 12.8532, 1.5,
+ -12.4271, 11.7634, -1.5,
+ -12.4271, 11.7634, 1.5,
+ -12.4271, 8.23664, -1.5,
+ -12.4271, 8.23664, 1.5,
+ -9.07295, 7.14683, -1.5,
+ -9.07295, 7.14683, 1.5,
+ -10, 10, -1.5,
+ -10, 10, 1.5,
+ -6, 10, -2,
+ -6, 10, 2,
+ -8.76393, 13.8042, -2,
+ -8.76393, 13.8042, 2,
+ -13.2361, 12.3511, -2,
+ -13.2361, 12.3511, 2,
+ -13.2361, 7.64886, -2,
+ -13.2361, 7.64886, 2,
+ -8.76393, 6.19577, -2,
+ -8.76393, 6.19577, 2,
+ -10, 10, -2,
+ -10, 10, 2,
+ 1, -20, -0.5,
+ 1, -20, 0.5,
+ 0.309017, -19.0489, -0.5,
+ 0.309017, -19.0489, 0.5,
+ -0.809017, -19.4122, -0.5,
+ -0.809017, -19.4122, 0.5,
+ -0.809017, -20.5878, -0.5,
+ -0.809017, -20.5878, 0.5,
+ 0.309017, -20.9511, -0.5,
+ 0.309017, -20.9511, 0.5,
+ 0, -20, -0.5,
+ 0, -20, 0.5,
+ 2, -20, -1,
+ 2, -20, 1,
+ 0.618034, -18.0979, -1,
+ 0.618034, -18.0979, 1,
+ -1.61803, -18.8244, -1,
+ -1.61803, -18.8244, 1,
+ -1.61803, -21.1756, -1,
+ -1.61803, -21.1756, 1,
+ 0.618034, -21.9021, -1,
+ 0.618034, -21.9021, 1,
+ 0, -20, -1,
+ 0, -20, 1,
+ 3, -20, -1.5,
+ 3, -20, 1.5,
+ 0.927051, -17.1468, -1.5,
+ 0.927051, -17.1468, 1.5,
+ -2.42705, -18.2366, -1.5,
+ -2.42705, -18.2366, 1.5,
+ -2.42705, -21.7634, -1.5,
+ -2.42705, -21.7634, 1.5,
+ 0.927051, -22.8532, -1.5,
+ 0.927051, -22.8532, 1.5,
+ 0, -20, -1.5,
+ 0, -20, 1.5,
+ 4, -20, -2,
+ 4, -20, 2,
+ 1.23607, -16.1958, -2,
+ 1.23607, -16.1958, 2,
+ -3.23607, -17.6489, -2,
+ -3.23607, -17.6489, 2,
+ -3.23607, -22.3511, -2,
+ -3.23607, -22.3511, 2,
+ 1.23607, -23.8042, -2,
+ 1.23607, -23.8042, 2,
+ 0, -20, -2,
+ 0, -20, 2,
+ 1, -10, -0.5,
+ 1, -10, 0.5,
+ 0.309017, -9.04894, -0.5,
+ 0.309017, -9.04894, 0.5,
+ -0.809017, -9.41221, -0.5,
+ -0.809017, -9.41221, 0.5,
+ -0.809017, -10.5878, -0.5,
+ -0.809017, -10.5878, 0.5,
+ 0.309017, -10.9511, -0.5,
+ 0.309017, -10.9511, 0.5,
+ 0, -10, -0.5,
+ 0, -10, 0.5,
+ 2, -10, -1,
+ 2, -10, 1,
+ 0.618034, -8.09789, -1,
+ 0.618034, -8.09789, 1,
+ -1.61803, -8.82443, -1,
+ -1.61803, -8.82443, 1,
+ -1.61803, -11.1756, -1,
+ -1.61803, -11.1756, 1,
+ 0.618034, -11.9021, -1,
+ 0.618034, -11.9021, 1,
+ 0, -10, -1,
+ 0, -10, 1,
+ 3, -10, -1.5,
+ 3, -10, 1.5,
+ 0.927051, -7.14683, -1.5,
+ 0.927051, -7.14683, 1.5,
+ -2.42705, -8.23664, -1.5,
+ -2.42705, -8.23664, 1.5,
+ -2.42705, -11.7634, -1.5,
+ -2.42705, -11.7634, 1.5,
+ 0.927051, -12.8532, -1.5,
+ 0.927051, -12.8532, 1.5,
+ 0, -10, -1.5,
+ 0, -10, 1.5,
+ 4, -10, -2,
+ 4, -10, 2,
+ 1.23607, -6.19577, -2,
+ 1.23607, -6.19577, 2,
+ -3.23607, -7.64886, -2,
+ -3.23607, -7.64886, 2,
+ -3.23607, -12.3511, -2,
+ -3.23607, -12.3511, 2,
+ 1.23607, -13.8042, -2,
+ 1.23607, -13.8042, 2,
+ 0, -10, -2,
+ 0, -10, 2,
+ 1, 0, -0.5,
+ 1, 0, 0.5,
+ 0.309017, 0.951057, -0.5,
+ 0.309017, 0.951057, 0.5,
+ -0.809017, 0.587785, -0.5,
+ -0.809017, 0.587785, 0.5,
+ -0.809017, -0.587785, -0.5,
+ -0.809017, -0.587785, 0.5,
+ 0.309017, -0.951057, -0.5,
+ 0.309017, -0.951057, 0.5,
+ 0, 0, -0.5,
+ 0, 0, 0.5,
+ 2, 0, -1,
+ 2, 0, 1,
+ 0.618034, 1.90211, -1,
+ 0.618034, 1.90211, 1,
+ -1.61803, 1.17557, -1,
+ -1.61803, 1.17557, 1,
+ -1.61803, -1.17557, -1,
+ -1.61803, -1.17557, 1,
+ 0.618034, -1.90211, -1,
+ 0.618034, -1.90211, 1,
+ 0, 0, -1,
+ 0, 0, 1,
+ 3, 0, -1.5,
+ 3, 0, 1.5,
+ 0.927051, 2.85317, -1.5,
+ 0.927051, 2.85317, 1.5,
+ -2.42705, 1.76336, -1.5,
+ -2.42705, 1.76336, 1.5,
+ -2.42705, -1.76336, -1.5,
+ -2.42705, -1.76336, 1.5,
+ 0.927051, -2.85317, -1.5,
+ 0.927051, -2.85317, 1.5,
+ 0, 0, -1.5,
+ 0, 0, 1.5,
+ 4, 0, -2,
+ 4, 0, 2,
+ 1.23607, 3.80423, -2,
+ 1.23607, 3.80423, 2,
+ -3.23607, 2.35114, -2,
+ -3.23607, 2.35114, 2,
+ -3.23607, -2.35114, -2,
+ -3.23607, -2.35114, 2,
+ 1.23607, -3.80423, -2,
+ 1.23607, -3.80423, 2,
+ 0, 0, -2,
+ 0, 0, 2,
+ 1, 10, -0.5,
+ 1, 10, 0.5,
+ 0.309017, 10.9511, -0.5,
+ 0.309017, 10.9511, 0.5,
+ -0.809017, 10.5878, -0.5,
+ -0.809017, 10.5878, 0.5,
+ -0.809017, 9.41221, -0.5,
+ -0.809017, 9.41221, 0.5,
+ 0.309017, 9.04894, -0.5,
+ 0.309017, 9.04894, 0.5,
+ 0, 10, -0.5,
+ 0, 10, 0.5,
+ 2, 10, -1,
+ 2, 10, 1,
+ 0.618034, 11.9021, -1,
+ 0.618034, 11.9021, 1,
+ -1.61803, 11.1756, -1,
+ -1.61803, 11.1756, 1,
+ -1.61803, 8.82443, -1,
+ -1.61803, 8.82443, 1,
+ 0.618034, 8.09789, -1,
+ 0.618034, 8.09789, 1,
+ 0, 10, -1,
+ 0, 10, 1,
+ 3, 10, -1.5,
+ 3, 10, 1.5,
+ 0.927051, 12.8532, -1.5,
+ 0.927051, 12.8532, 1.5,
+ -2.42705, 11.7634, -1.5,
+ -2.42705, 11.7634, 1.5,
+ -2.42705, 8.23664, -1.5,
+ -2.42705, 8.23664, 1.5,
+ 0.927051, 7.14683, -1.5,
+ 0.927051, 7.14683, 1.5,
+ 0, 10, -1.5,
+ 0, 10, 1.5,
+ 4, 10, -2,
+ 4, 10, 2,
+ 1.23607, 13.8042, -2,
+ 1.23607, 13.8042, 2,
+ -3.23607, 12.3511, -2,
+ -3.23607, 12.3511, 2,
+ -3.23607, 7.64886, -2,
+ -3.23607, 7.64886, 2,
+ 1.23607, 6.19577, -2,
+ 1.23607, 6.19577, 2,
+ 0, 10, -2,
+ 0, 10, 2,
+ 11, -20, -0.5,
+ 11, -20, 0.5,
+ 10.309, -19.0489, -0.5,
+ 10.309, -19.0489, 0.5,
+ 9.19098, -19.4122, -0.5,
+ 9.19098, -19.4122, 0.5,
+ 9.19098, -20.5878, -0.5,
+ 9.19098, -20.5878, 0.5,
+ 10.309, -20.9511, -0.5,
+ 10.309, -20.9511, 0.5,
+ 10, -20, -0.5,
+ 10, -20, 0.5,
+ 12, -20, -1,
+ 12, -20, 1,
+ 10.618, -18.0979, -1,
+ 10.618, -18.0979, 1,
+ 8.38197, -18.8244, -1,
+ 8.38197, -18.8244, 1,
+ 8.38197, -21.1756, -1,
+ 8.38197, -21.1756, 1,
+ 10.618, -21.9021, -1,
+ 10.618, -21.9021, 1,
+ 10, -20, -1,
+ 10, -20, 1,
+ 13, -20, -1.5,
+ 13, -20, 1.5,
+ 10.9271, -17.1468, -1.5,
+ 10.9271, -17.1468, 1.5,
+ 7.57295, -18.2366, -1.5,
+ 7.57295, -18.2366, 1.5,
+ 7.57295, -21.7634, -1.5,
+ 7.57295, -21.7634, 1.5,
+ 10.9271, -22.8532, -1.5,
+ 10.9271, -22.8532, 1.5,
+ 10, -20, -1.5,
+ 10, -20, 1.5,
+ 14, -20, -2,
+ 14, -20, 2,
+ 11.2361, -16.1958, -2,
+ 11.2361, -16.1958, 2,
+ 6.76393, -17.6489, -2,
+ 6.76393, -17.6489, 2,
+ 6.76393, -22.3511, -2,
+ 6.76393, -22.3511, 2,
+ 11.2361, -23.8042, -2,
+ 11.2361, -23.8042, 2,
+ 10, -20, -2,
+ 10, -20, 2,
+ 11, -10, -0.5,
+ 11, -10, 0.5,
+ 10.309, -9.04894, -0.5,
+ 10.309, -9.04894, 0.5,
+ 9.19098, -9.41221, -0.5,
+ 9.19098, -9.41221, 0.5,
+ 9.19098, -10.5878, -0.5,
+ 9.19098, -10.5878, 0.5,
+ 10.309, -10.9511, -0.5,
+ 10.309, -10.9511, 0.5,
+ 10, -10, -0.5,
+ 10, -10, 0.5,
+ 12, -10, -1,
+ 12, -10, 1,
+ 10.618, -8.09789, -1,
+ 10.618, -8.09789, 1,
+ 8.38197, -8.82443, -1,
+ 8.38197, -8.82443, 1,
+ 8.38197, -11.1756, -1,
+ 8.38197, -11.1756, 1,
+ 10.618, -11.9021, -1,
+ 10.618, -11.9021, 1,
+ 10, -10, -1,
+ 10, -10, 1,
+ 13, -10, -1.5,
+ 13, -10, 1.5,
+ 10.9271, -7.14683, -1.5,
+ 10.9271, -7.14683, 1.5,
+ 7.57295, -8.23664, -1.5,
+ 7.57295, -8.23664, 1.5,
+ 7.57295, -11.7634, -1.5,
+ 7.57295, -11.7634, 1.5,
+ 10.9271, -12.8532, -1.5,
+ 10.9271, -12.8532, 1.5,
+ 10, -10, -1.5,
+ 10, -10, 1.5,
+ 14, -10, -2,
+ 14, -10, 2,
+ 11.2361, -6.19577, -2,
+ 11.2361, -6.19577, 2,
+ 6.76393, -7.64886, -2,
+ 6.76393, -7.64886, 2,
+ 6.76393, -12.3511, -2,
+ 6.76393, -12.3511, 2,
+ 11.2361, -13.8042, -2,
+ 11.2361, -13.8042, 2,
+ 10, -10, -2,
+ 10, -10, 2,
+ 11, 0, -0.5,
+ 11, 0, 0.5,
+ 10.309, 0.951057, -0.5,
+ 10.309, 0.951057, 0.5,
+ 9.19098, 0.587785, -0.5,
+ 9.19098, 0.587785, 0.5,
+ 9.19098, -0.587785, -0.5,
+ 9.19098, -0.587785, 0.5,
+ 10.309, -0.951057, -0.5,
+ 10.309, -0.951057, 0.5,
+ 10, 0, -0.5,
+ 10, 0, 0.5,
+ 12, 0, -1,
+ 12, 0, 1,
+ 10.618, 1.90211, -1,
+ 10.618, 1.90211, 1,
+ 8.38197, 1.17557, -1,
+ 8.38197, 1.17557, 1,
+ 8.38197, -1.17557, -1,
+ 8.38197, -1.17557, 1,
+ 10.618, -1.90211, -1,
+ 10.618, -1.90211, 1,
+ 10, 0, -1,
+ 10, 0, 1,
+ 13, 0, -1.5,
+ 13, 0, 1.5,
+ 10.9271, 2.85317, -1.5,
+ 10.9271, 2.85317, 1.5,
+ 7.57295, 1.76336, -1.5,
+ 7.57295, 1.76336, 1.5,
+ 7.57295, -1.76336, -1.5,
+ 7.57295, -1.76336, 1.5,
+ 10.9271, -2.85317, -1.5,
+ 10.9271, -2.85317, 1.5,
+ 10, 0, -1.5,
+ 10, 0, 1.5,
+ 14, 0, -2,
+ 14, 0, 2,
+ 11.2361, 3.80423, -2,
+ 11.2361, 3.80423, 2,
+ 6.76393, 2.35114, -2,
+ 6.76393, 2.35114, 2,
+ 6.76393, -2.35114, -2,
+ 6.76393, -2.35114, 2,
+ 11.2361, -3.80423, -2,
+ 11.2361, -3.80423, 2,
+ 10, 0, -2,
+ 10, 0, 2,
+ 11, 10, -0.5,
+ 11, 10, 0.5,
+ 10.309, 10.9511, -0.5,
+ 10.309, 10.9511, 0.5,
+ 9.19098, 10.5878, -0.5,
+ 9.19098, 10.5878, 0.5,
+ 9.19098, 9.41221, -0.5,
+ 9.19098, 9.41221, 0.5,
+ 10.309, 9.04894, -0.5,
+ 10.309, 9.04894, 0.5,
+ 10, 10, -0.5,
+ 10, 10, 0.5,
+ 12, 10, -1,
+ 12, 10, 1,
+ 10.618, 11.9021, -1,
+ 10.618, 11.9021, 1,
+ 8.38197, 11.1756, -1,
+ 8.38197, 11.1756, 1,
+ 8.38197, 8.82443, -1,
+ 8.38197, 8.82443, 1,
+ 10.618, 8.09789, -1,
+ 10.618, 8.09789, 1,
+ 10, 10, -1,
+ 10, 10, 1,
+ 13, 10, -1.5,
+ 13, 10, 1.5,
+ 10.9271, 12.8532, -1.5,
+ 10.9271, 12.8532, 1.5,
+ 7.57295, 11.7634, -1.5,
+ 7.57295, 11.7634, 1.5,
+ 7.57295, 8.23664, -1.5,
+ 7.57295, 8.23664, 1.5,
+ 10.9271, 7.14683, -1.5,
+ 10.9271, 7.14683, 1.5,
+ 10, 10, -1.5,
+ 10, 10, 1.5,
+ 14, 10, -2,
+ 14, 10, 2,
+ 11.2361, 13.8042, -2,
+ 11.2361, 13.8042, 2,
+ 6.76393, 12.3511, -2,
+ 6.76393, 12.3511, 2,
+ 6.76393, 7.64886, -2,
+ 6.76393, 7.64886, 2,
+ 11.2361, 6.19577, -2,
+ 11.2361, 6.19577, 2,
+ 10, 10, -2,
+ 10, 10, 2
+};
+static const unsigned some_enclosures_triangles_count = 1280;
+static const unsigned some_enclosures_triangles[3840] =
+{
+ 0, 1, 2,
+ 2, 1, 3,
+ 2, 3, 4,
+ 4, 3, 5,
+ 4, 5, 6,
+ 6, 5, 7,
+ 6, 7, 8,
+ 8, 7, 9,
+ 8, 9, 0,
+ 0, 9, 1,
+ 10, 0, 2,
+ 10, 2, 4,
+ 10, 4, 6,
+ 10, 6, 8,
+ 10, 8, 0,
+ 11, 3, 1,
+ 11, 5, 3,
+ 11, 7, 5,
+ 11, 9, 7,
+ 11, 1, 9,
+ 12, 13, 14,
+ 14, 13, 15,
+ 14, 15, 16,
+ 16, 15, 17,
+ 16, 17, 18,
+ 18, 17, 19,
+ 18, 19, 20,
+ 20, 19, 21,
+ 20, 21, 12,
+ 12, 21, 13,
+ 22, 12, 14,
+ 22, 14, 16,
+ 22, 16, 18,
+ 22, 18, 20,
+ 22, 20, 12,
+ 23, 15, 13,
+ 23, 17, 15,
+ 23, 19, 17,
+ 23, 21, 19,
+ 23, 13, 21,
+ 24, 25, 26,
+ 26, 25, 27,
+ 26, 27, 28,
+ 28, 27, 29,
+ 28, 29, 30,
+ 30, 29, 31,
+ 30, 31, 32,
+ 32, 31, 33,
+ 32, 33, 24,
+ 24, 33, 25,
+ 34, 24, 26,
+ 34, 26, 28,
+ 34, 28, 30,
+ 34, 30, 32,
+ 34, 32, 24,
+ 35, 27, 25,
+ 35, 29, 27,
+ 35, 31, 29,
+ 35, 33, 31,
+ 35, 25, 33,
+ 36, 37, 38,
+ 38, 37, 39,
+ 38, 39, 40,
+ 40, 39, 41,
+ 40, 41, 42,
+ 42, 41, 43,
+ 42, 43, 44,
+ 44, 43, 45,
+ 44, 45, 36,
+ 36, 45, 37,
+ 46, 36, 38,
+ 46, 38, 40,
+ 46, 40, 42,
+ 46, 42, 44,
+ 46, 44, 36,
+ 47, 39, 37,
+ 47, 41, 39,
+ 47, 43, 41,
+ 47, 45, 43,
+ 47, 37, 45,
+ 48, 49, 50,
+ 50, 49, 51,
+ 50, 51, 52,
+ 52, 51, 53,
+ 52, 53, 54,
+ 54, 53, 55,
+ 54, 55, 56,
+ 56, 55, 57,
+ 56, 57, 48,
+ 48, 57, 49,
+ 58, 48, 50,
+ 58, 50, 52,
+ 58, 52, 54,
+ 58, 54, 56,
+ 58, 56, 48,
+ 59, 51, 49,
+ 59, 53, 51,
+ 59, 55, 53,
+ 59, 57, 55,
+ 59, 49, 57,
+ 60, 61, 62,
+ 62, 61, 63,
+ 62, 63, 64,
+ 64, 63, 65,
+ 64, 65, 66,
+ 66, 65, 67,
+ 66, 67, 68,
+ 68, 67, 69,
+ 68, 69, 60,
+ 60, 69, 61,
+ 70, 60, 62,
+ 70, 62, 64,
+ 70, 64, 66,
+ 70, 66, 68,
+ 70, 68, 60,
+ 71, 63, 61,
+ 71, 65, 63,
+ 71, 67, 65,
+ 71, 69, 67,
+ 71, 61, 69,
+ 72, 73, 74,
+ 74, 73, 75,
+ 74, 75, 76,
+ 76, 75, 77,
+ 76, 77, 78,
+ 78, 77, 79,
+ 78, 79, 80,
+ 80, 79, 81,
+ 80, 81, 72,
+ 72, 81, 73,
+ 82, 72, 74,
+ 82, 74, 76,
+ 82, 76, 78,
+ 82, 78, 80,
+ 82, 80, 72,
+ 83, 75, 73,
+ 83, 77, 75,
+ 83, 79, 77,
+ 83, 81, 79,
+ 83, 73, 81,
+ 84, 85, 86,
+ 86, 85, 87,
+ 86, 87, 88,
+ 88, 87, 89,
+ 88, 89, 90,
+ 90, 89, 91,
+ 90, 91, 92,
+ 92, 91, 93,
+ 92, 93, 84,
+ 84, 93, 85,
+ 94, 84, 86,
+ 94, 86, 88,
+ 94, 88, 90,
+ 94, 90, 92,
+ 94, 92, 84,
+ 95, 87, 85,
+ 95, 89, 87,
+ 95, 91, 89,
+ 95, 93, 91,
+ 95, 85, 93,
+ 96, 97, 98,
+ 98, 97, 99,
+ 98, 99, 100,
+ 100, 99, 101,
+ 100, 101, 102,
+ 102, 101, 103,
+ 102, 103, 104,
+ 104, 103, 105,
+ 104, 105, 96,
+ 96, 105, 97,
+ 106, 96, 98,
+ 106, 98, 100,
+ 106, 100, 102,
+ 106, 102, 104,
+ 106, 104, 96,
+ 107, 99, 97,
+ 107, 101, 99,
+ 107, 103, 101,
+ 107, 105, 103,
+ 107, 97, 105,
+ 108, 109, 110,
+ 110, 109, 111,
+ 110, 111, 112,
+ 112, 111, 113,
+ 112, 113, 114,
+ 114, 113, 115,
+ 114, 115, 116,
+ 116, 115, 117,
+ 116, 117, 108,
+ 108, 117, 109,
+ 118, 108, 110,
+ 118, 110, 112,
+ 118, 112, 114,
+ 118, 114, 116,
+ 118, 116, 108,
+ 119, 111, 109,
+ 119, 113, 111,
+ 119, 115, 113,
+ 119, 117, 115,
+ 119, 109, 117,
+ 120, 121, 122,
+ 122, 121, 123,
+ 122, 123, 124,
+ 124, 123, 125,
+ 124, 125, 126,
+ 126, 125, 127,
+ 126, 127, 128,
+ 128, 127, 129,
+ 128, 129, 120,
+ 120, 129, 121,
+ 130, 120, 122,
+ 130, 122, 124,
+ 130, 124, 126,
+ 130, 126, 128,
+ 130, 128, 120,
+ 131, 123, 121,
+ 131, 125, 123,
+ 131, 127, 125,
+ 131, 129, 127,
+ 131, 121, 129,
+ 132, 133, 134,
+ 134, 133, 135,
+ 134, 135, 136,
+ 136, 135, 137,
+ 136, 137, 138,
+ 138, 137, 139,
+ 138, 139, 140,
+ 140, 139, 141,
+ 140, 141, 132,
+ 132, 141, 133,
+ 142, 132, 134,
+ 142, 134, 136,
+ 142, 136, 138,
+ 142, 138, 140,
+ 142, 140, 132,
+ 143, 135, 133,
+ 143, 137, 135,
+ 143, 139, 137,
+ 143, 141, 139,
+ 143, 133, 141,
+ 144, 145, 146,
+ 146, 145, 147,
+ 146, 147, 148,
+ 148, 147, 149,
+ 148, 149, 150,
+ 150, 149, 151,
+ 150, 151, 152,
+ 152, 151, 153,
+ 152, 153, 144,
+ 144, 153, 145,
+ 154, 144, 146,
+ 154, 146, 148,
+ 154, 148, 150,
+ 154, 150, 152,
+ 154, 152, 144,
+ 155, 147, 145,
+ 155, 149, 147,
+ 155, 151, 149,
+ 155, 153, 151,
+ 155, 145, 153,
+ 156, 157, 158,
+ 158, 157, 159,
+ 158, 159, 160,
+ 160, 159, 161,
+ 160, 161, 162,
+ 162, 161, 163,
+ 162, 163, 164,
+ 164, 163, 165,
+ 164, 165, 156,
+ 156, 165, 157,
+ 166, 156, 158,
+ 166, 158, 160,
+ 166, 160, 162,
+ 166, 162, 164,
+ 166, 164, 156,
+ 167, 159, 157,
+ 167, 161, 159,
+ 167, 163, 161,
+ 167, 165, 163,
+ 167, 157, 165,
+ 168, 169, 170,
+ 170, 169, 171,
+ 170, 171, 172,
+ 172, 171, 173,
+ 172, 173, 174,
+ 174, 173, 175,
+ 174, 175, 176,
+ 176, 175, 177,
+ 176, 177, 168,
+ 168, 177, 169,
+ 178, 168, 170,
+ 178, 170, 172,
+ 178, 172, 174,
+ 178, 174, 176,
+ 178, 176, 168,
+ 179, 171, 169,
+ 179, 173, 171,
+ 179, 175, 173,
+ 179, 177, 175,
+ 179, 169, 177,
+ 180, 181, 182,
+ 182, 181, 183,
+ 182, 183, 184,
+ 184, 183, 185,
+ 184, 185, 186,
+ 186, 185, 187,
+ 186, 187, 188,
+ 188, 187, 189,
+ 188, 189, 180,
+ 180, 189, 181,
+ 190, 180, 182,
+ 190, 182, 184,
+ 190, 184, 186,
+ 190, 186, 188,
+ 190, 188, 180,
+ 191, 183, 181,
+ 191, 185, 183,
+ 191, 187, 185,
+ 191, 189, 187,
+ 191, 181, 189,
+ 192, 193, 194,
+ 194, 193, 195,
+ 194, 195, 196,
+ 196, 195, 197,
+ 196, 197, 198,
+ 198, 197, 199,
+ 198, 199, 200,
+ 200, 199, 201,
+ 200, 201, 192,
+ 192, 201, 193,
+ 202, 192, 194,
+ 202, 194, 196,
+ 202, 196, 198,
+ 202, 198, 200,
+ 202, 200, 192,
+ 203, 195, 193,
+ 203, 197, 195,
+ 203, 199, 197,
+ 203, 201, 199,
+ 203, 193, 201,
+ 204, 205, 206,
+ 206, 205, 207,
+ 206, 207, 208,
+ 208, 207, 209,
+ 208, 209, 210,
+ 210, 209, 211,
+ 210, 211, 212,
+ 212, 211, 213,
+ 212, 213, 204,
+ 204, 213, 205,
+ 214, 204, 206,
+ 214, 206, 208,
+ 214, 208, 210,
+ 214, 210, 212,
+ 214, 212, 204,
+ 215, 207, 205,
+ 215, 209, 207,
+ 215, 211, 209,
+ 215, 213, 211,
+ 215, 205, 213,
+ 216, 217, 218,
+ 218, 217, 219,
+ 218, 219, 220,
+ 220, 219, 221,
+ 220, 221, 222,
+ 222, 221, 223,
+ 222, 223, 224,
+ 224, 223, 225,
+ 224, 225, 216,
+ 216, 225, 217,
+ 226, 216, 218,
+ 226, 218, 220,
+ 226, 220, 222,
+ 226, 222, 224,
+ 226, 224, 216,
+ 227, 219, 217,
+ 227, 221, 219,
+ 227, 223, 221,
+ 227, 225, 223,
+ 227, 217, 225,
+ 228, 229, 230,
+ 230, 229, 231,
+ 230, 231, 232,
+ 232, 231, 233,
+ 232, 233, 234,
+ 234, 233, 235,
+ 234, 235, 236,
+ 236, 235, 237,
+ 236, 237, 228,
+ 228, 237, 229,
+ 238, 228, 230,
+ 238, 230, 232,
+ 238, 232, 234,
+ 238, 234, 236,
+ 238, 236, 228,
+ 239, 231, 229,
+ 239, 233, 231,
+ 239, 235, 233,
+ 239, 237, 235,
+ 239, 229, 237,
+ 240, 241, 242,
+ 242, 241, 243,
+ 242, 243, 244,
+ 244, 243, 245,
+ 244, 245, 246,
+ 246, 245, 247,
+ 246, 247, 248,
+ 248, 247, 249,
+ 248, 249, 240,
+ 240, 249, 241,
+ 250, 240, 242,
+ 250, 242, 244,
+ 250, 244, 246,
+ 250, 246, 248,
+ 250, 248, 240,
+ 251, 243, 241,
+ 251, 245, 243,
+ 251, 247, 245,
+ 251, 249, 247,
+ 251, 241, 249,
+ 252, 253, 254,
+ 254, 253, 255,
+ 254, 255, 256,
+ 256, 255, 257,
+ 256, 257, 258,
+ 258, 257, 259,
+ 258, 259, 260,
+ 260, 259, 261,
+ 260, 261, 252,
+ 252, 261, 253,
+ 262, 252, 254,
+ 262, 254, 256,
+ 262, 256, 258,
+ 262, 258, 260,
+ 262, 260, 252,
+ 263, 255, 253,
+ 263, 257, 255,
+ 263, 259, 257,
+ 263, 261, 259,
+ 263, 253, 261,
+ 264, 265, 266,
+ 266, 265, 267,
+ 266, 267, 268,
+ 268, 267, 269,
+ 268, 269, 270,
+ 270, 269, 271,
+ 270, 271, 272,
+ 272, 271, 273,
+ 272, 273, 264,
+ 264, 273, 265,
+ 274, 264, 266,
+ 274, 266, 268,
+ 274, 268, 270,
+ 274, 270, 272,
+ 274, 272, 264,
+ 275, 267, 265,
+ 275, 269, 267,
+ 275, 271, 269,
+ 275, 273, 271,
+ 275, 265, 273,
+ 276, 277, 278,
+ 278, 277, 279,
+ 278, 279, 280,
+ 280, 279, 281,
+ 280, 281, 282,
+ 282, 281, 283,
+ 282, 283, 284,
+ 284, 283, 285,
+ 284, 285, 276,
+ 276, 285, 277,
+ 286, 276, 278,
+ 286, 278, 280,
+ 286, 280, 282,
+ 286, 282, 284,
+ 286, 284, 276,
+ 287, 279, 277,
+ 287, 281, 279,
+ 287, 283, 281,
+ 287, 285, 283,
+ 287, 277, 285,
+ 288, 289, 290,
+ 290, 289, 291,
+ 290, 291, 292,
+ 292, 291, 293,
+ 292, 293, 294,
+ 294, 293, 295,
+ 294, 295, 296,
+ 296, 295, 297,
+ 296, 297, 288,
+ 288, 297, 289,
+ 298, 288, 290,
+ 298, 290, 292,
+ 298, 292, 294,
+ 298, 294, 296,
+ 298, 296, 288,
+ 299, 291, 289,
+ 299, 293, 291,
+ 299, 295, 293,
+ 299, 297, 295,
+ 299, 289, 297,
+ 300, 301, 302,
+ 302, 301, 303,
+ 302, 303, 304,
+ 304, 303, 305,
+ 304, 305, 306,
+ 306, 305, 307,
+ 306, 307, 308,
+ 308, 307, 309,
+ 308, 309, 300,
+ 300, 309, 301,
+ 310, 300, 302,
+ 310, 302, 304,
+ 310, 304, 306,
+ 310, 306, 308,
+ 310, 308, 300,
+ 311, 303, 301,
+ 311, 305, 303,
+ 311, 307, 305,
+ 311, 309, 307,
+ 311, 301, 309,
+ 312, 313, 314,
+ 314, 313, 315,
+ 314, 315, 316,
+ 316, 315, 317,
+ 316, 317, 318,
+ 318, 317, 319,
+ 318, 319, 320,
+ 320, 319, 321,
+ 320, 321, 312,
+ 312, 321, 313,
+ 322, 312, 314,
+ 322, 314, 316,
+ 322, 316, 318,
+ 322, 318, 320,
+ 322, 320, 312,
+ 323, 315, 313,
+ 323, 317, 315,
+ 323, 319, 317,
+ 323, 321, 319,
+ 323, 313, 321,
+ 324, 325, 326,
+ 326, 325, 327,
+ 326, 327, 328,
+ 328, 327, 329,
+ 328, 329, 330,
+ 330, 329, 331,
+ 330, 331, 332,
+ 332, 331, 333,
+ 332, 333, 324,
+ 324, 333, 325,
+ 334, 324, 326,
+ 334, 326, 328,
+ 334, 328, 330,
+ 334, 330, 332,
+ 334, 332, 324,
+ 335, 327, 325,
+ 335, 329, 327,
+ 335, 331, 329,
+ 335, 333, 331,
+ 335, 325, 333,
+ 336, 337, 338,
+ 338, 337, 339,
+ 338, 339, 340,
+ 340, 339, 341,
+ 340, 341, 342,
+ 342, 341, 343,
+ 342, 343, 344,
+ 344, 343, 345,
+ 344, 345, 336,
+ 336, 345, 337,
+ 346, 336, 338,
+ 346, 338, 340,
+ 346, 340, 342,
+ 346, 342, 344,
+ 346, 344, 336,
+ 347, 339, 337,
+ 347, 341, 339,
+ 347, 343, 341,
+ 347, 345, 343,
+ 347, 337, 345,
+ 348, 349, 350,
+ 350, 349, 351,
+ 350, 351, 352,
+ 352, 351, 353,
+ 352, 353, 354,
+ 354, 353, 355,
+ 354, 355, 356,
+ 356, 355, 357,
+ 356, 357, 348,
+ 348, 357, 349,
+ 358, 348, 350,
+ 358, 350, 352,
+ 358, 352, 354,
+ 358, 354, 356,
+ 358, 356, 348,
+ 359, 351, 349,
+ 359, 353, 351,
+ 359, 355, 353,
+ 359, 357, 355,
+ 359, 349, 357,
+ 360, 361, 362,
+ 362, 361, 363,
+ 362, 363, 364,
+ 364, 363, 365,
+ 364, 365, 366,
+ 366, 365, 367,
+ 366, 367, 368,
+ 368, 367, 369,
+ 368, 369, 360,
+ 360, 369, 361,
+ 370, 360, 362,
+ 370, 362, 364,
+ 370, 364, 366,
+ 370, 366, 368,
+ 370, 368, 360,
+ 371, 363, 361,
+ 371, 365, 363,
+ 371, 367, 365,
+ 371, 369, 367,
+ 371, 361, 369,
+ 372, 373, 374,
+ 374, 373, 375,
+ 374, 375, 376,
+ 376, 375, 377,
+ 376, 377, 378,
+ 378, 377, 379,
+ 378, 379, 380,
+ 380, 379, 381,
+ 380, 381, 372,
+ 372, 381, 373,
+ 382, 372, 374,
+ 382, 374, 376,
+ 382, 376, 378,
+ 382, 378, 380,
+ 382, 380, 372,
+ 383, 375, 373,
+ 383, 377, 375,
+ 383, 379, 377,
+ 383, 381, 379,
+ 383, 373, 381,
+ 384, 385, 386,
+ 386, 385, 387,
+ 386, 387, 388,
+ 388, 387, 389,
+ 388, 389, 390,
+ 390, 389, 391,
+ 390, 391, 392,
+ 392, 391, 393,
+ 392, 393, 384,
+ 384, 393, 385,
+ 394, 384, 386,
+ 394, 386, 388,
+ 394, 388, 390,
+ 394, 390, 392,
+ 394, 392, 384,
+ 395, 387, 385,
+ 395, 389, 387,
+ 395, 391, 389,
+ 395, 393, 391,
+ 395, 385, 393,
+ 396, 397, 398,
+ 398, 397, 399,
+ 398, 399, 400,
+ 400, 399, 401,
+ 400, 401, 402,
+ 402, 401, 403,
+ 402, 403, 404,
+ 404, 403, 405,
+ 404, 405, 396,
+ 396, 405, 397,
+ 406, 396, 398,
+ 406, 398, 400,
+ 406, 400, 402,
+ 406, 402, 404,
+ 406, 404, 396,
+ 407, 399, 397,
+ 407, 401, 399,
+ 407, 403, 401,
+ 407, 405, 403,
+ 407, 397, 405,
+ 408, 409, 410,
+ 410, 409, 411,
+ 410, 411, 412,
+ 412, 411, 413,
+ 412, 413, 414,
+ 414, 413, 415,
+ 414, 415, 416,
+ 416, 415, 417,
+ 416, 417, 408,
+ 408, 417, 409,
+ 418, 408, 410,
+ 418, 410, 412,
+ 418, 412, 414,
+ 418, 414, 416,
+ 418, 416, 408,
+ 419, 411, 409,
+ 419, 413, 411,
+ 419, 415, 413,
+ 419, 417, 415,
+ 419, 409, 417,
+ 420, 421, 422,
+ 422, 421, 423,
+ 422, 423, 424,
+ 424, 423, 425,
+ 424, 425, 426,
+ 426, 425, 427,
+ 426, 427, 428,
+ 428, 427, 429,
+ 428, 429, 420,
+ 420, 429, 421,
+ 430, 420, 422,
+ 430, 422, 424,
+ 430, 424, 426,
+ 430, 426, 428,
+ 430, 428, 420,
+ 431, 423, 421,
+ 431, 425, 423,
+ 431, 427, 425,
+ 431, 429, 427,
+ 431, 421, 429,
+ 432, 433, 434,
+ 434, 433, 435,
+ 434, 435, 436,
+ 436, 435, 437,
+ 436, 437, 438,
+ 438, 437, 439,
+ 438, 439, 440,
+ 440, 439, 441,
+ 440, 441, 432,
+ 432, 441, 433,
+ 442, 432, 434,
+ 442, 434, 436,
+ 442, 436, 438,
+ 442, 438, 440,
+ 442, 440, 432,
+ 443, 435, 433,
+ 443, 437, 435,
+ 443, 439, 437,
+ 443, 441, 439,
+ 443, 433, 441,
+ 444, 445, 446,
+ 446, 445, 447,
+ 446, 447, 448,
+ 448, 447, 449,
+ 448, 449, 450,
+ 450, 449, 451,
+ 450, 451, 452,
+ 452, 451, 453,
+ 452, 453, 444,
+ 444, 453, 445,
+ 454, 444, 446,
+ 454, 446, 448,
+ 454, 448, 450,
+ 454, 450, 452,
+ 454, 452, 444,
+ 455, 447, 445,
+ 455, 449, 447,
+ 455, 451, 449,
+ 455, 453, 451,
+ 455, 445, 453,
+ 456, 457, 458,
+ 458, 457, 459,
+ 458, 459, 460,
+ 460, 459, 461,
+ 460, 461, 462,
+ 462, 461, 463,
+ 462, 463, 464,
+ 464, 463, 465,
+ 464, 465, 456,
+ 456, 465, 457,
+ 466, 456, 458,
+ 466, 458, 460,
+ 466, 460, 462,
+ 466, 462, 464,
+ 466, 464, 456,
+ 467, 459, 457,
+ 467, 461, 459,
+ 467, 463, 461,
+ 467, 465, 463,
+ 467, 457, 465,
+ 468, 469, 470,
+ 470, 469, 471,
+ 470, 471, 472,
+ 472, 471, 473,
+ 472, 473, 474,
+ 474, 473, 475,
+ 474, 475, 476,
+ 476, 475, 477,
+ 476, 477, 468,
+ 468, 477, 469,
+ 478, 468, 470,
+ 478, 470, 472,
+ 478, 472, 474,
+ 478, 474, 476,
+ 478, 476, 468,
+ 479, 471, 469,
+ 479, 473, 471,
+ 479, 475, 473,
+ 479, 477, 475,
+ 479, 469, 477,
+ 480, 481, 482,
+ 482, 481, 483,
+ 482, 483, 484,
+ 484, 483, 485,
+ 484, 485, 486,
+ 486, 485, 487,
+ 486, 487, 488,
+ 488, 487, 489,
+ 488, 489, 480,
+ 480, 489, 481,
+ 490, 480, 482,
+ 490, 482, 484,
+ 490, 484, 486,
+ 490, 486, 488,
+ 490, 488, 480,
+ 491, 483, 481,
+ 491, 485, 483,
+ 491, 487, 485,
+ 491, 489, 487,
+ 491, 481, 489,
+ 492, 493, 494,
+ 494, 493, 495,
+ 494, 495, 496,
+ 496, 495, 497,
+ 496, 497, 498,
+ 498, 497, 499,
+ 498, 499, 500,
+ 500, 499, 501,
+ 500, 501, 492,
+ 492, 501, 493,
+ 502, 492, 494,
+ 502, 494, 496,
+ 502, 496, 498,
+ 502, 498, 500,
+ 502, 500, 492,
+ 503, 495, 493,
+ 503, 497, 495,
+ 503, 499, 497,
+ 503, 501, 499,
+ 503, 493, 501,
+ 504, 505, 506,
+ 506, 505, 507,
+ 506, 507, 508,
+ 508, 507, 509,
+ 508, 509, 510,
+ 510, 509, 511,
+ 510, 511, 512,
+ 512, 511, 513,
+ 512, 513, 504,
+ 504, 513, 505,
+ 514, 504, 506,
+ 514, 506, 508,
+ 514, 508, 510,
+ 514, 510, 512,
+ 514, 512, 504,
+ 515, 507, 505,
+ 515, 509, 507,
+ 515, 511, 509,
+ 515, 513, 511,
+ 515, 505, 513,
+ 516, 517, 518,
+ 518, 517, 519,
+ 518, 519, 520,
+ 520, 519, 521,
+ 520, 521, 522,
+ 522, 521, 523,
+ 522, 523, 524,
+ 524, 523, 525,
+ 524, 525, 516,
+ 516, 525, 517,
+ 526, 516, 518,
+ 526, 518, 520,
+ 526, 520, 522,
+ 526, 522, 524,
+ 526, 524, 516,
+ 527, 519, 517,
+ 527, 521, 519,
+ 527, 523, 521,
+ 527, 525, 523,
+ 527, 517, 525,
+ 528, 529, 530,
+ 530, 529, 531,
+ 530, 531, 532,
+ 532, 531, 533,
+ 532, 533, 534,
+ 534, 533, 535,
+ 534, 535, 536,
+ 536, 535, 537,
+ 536, 537, 528,
+ 528, 537, 529,
+ 538, 528, 530,
+ 538, 530, 532,
+ 538, 532, 534,
+ 538, 534, 536,
+ 538, 536, 528,
+ 539, 531, 529,
+ 539, 533, 531,
+ 539, 535, 533,
+ 539, 537, 535,
+ 539, 529, 537,
+ 540, 541, 542,
+ 542, 541, 543,
+ 542, 543, 544,
+ 544, 543, 545,
+ 544, 545, 546,
+ 546, 545, 547,
+ 546, 547, 548,
+ 548, 547, 549,
+ 548, 549, 540,
+ 540, 549, 541,
+ 550, 540, 542,
+ 550, 542, 544,
+ 550, 544, 546,
+ 550, 546, 548,
+ 550, 548, 540,
+ 551, 543, 541,
+ 551, 545, 543,
+ 551, 547, 545,
+ 551, 549, 547,
+ 551, 541, 549,
+ 552, 553, 554,
+ 554, 553, 555,
+ 554, 555, 556,
+ 556, 555, 557,
+ 556, 557, 558,
+ 558, 557, 559,
+ 558, 559, 560,
+ 560, 559, 561,
+ 560, 561, 552,
+ 552, 561, 553,
+ 562, 552, 554,
+ 562, 554, 556,
+ 562, 556, 558,
+ 562, 558, 560,
+ 562, 560, 552,
+ 563, 555, 553,
+ 563, 557, 555,
+ 563, 559, 557,
+ 563, 561, 559,
+ 563, 553, 561,
+ 564, 565, 566,
+ 566, 565, 567,
+ 566, 567, 568,
+ 568, 567, 569,
+ 568, 569, 570,
+ 570, 569, 571,
+ 570, 571, 572,
+ 572, 571, 573,
+ 572, 573, 564,
+ 564, 573, 565,
+ 574, 564, 566,
+ 574, 566, 568,
+ 574, 568, 570,
+ 574, 570, 572,
+ 574, 572, 564,
+ 575, 567, 565,
+ 575, 569, 567,
+ 575, 571, 569,
+ 575, 573, 571,
+ 575, 565, 573,
+ 576, 577, 578,
+ 578, 577, 579,
+ 578, 579, 580,
+ 580, 579, 581,
+ 580, 581, 582,
+ 582, 581, 583,
+ 582, 583, 584,
+ 584, 583, 585,
+ 584, 585, 576,
+ 576, 585, 577,
+ 586, 576, 578,
+ 586, 578, 580,
+ 586, 580, 582,
+ 586, 582, 584,
+ 586, 584, 576,
+ 587, 579, 577,
+ 587, 581, 579,
+ 587, 583, 581,
+ 587, 585, 583,
+ 587, 577, 585,
+ 588, 589, 590,
+ 590, 589, 591,
+ 590, 591, 592,
+ 592, 591, 593,
+ 592, 593, 594,
+ 594, 593, 595,
+ 594, 595, 596,
+ 596, 595, 597,
+ 596, 597, 588,
+ 588, 597, 589,
+ 598, 588, 590,
+ 598, 590, 592,
+ 598, 592, 594,
+ 598, 594, 596,
+ 598, 596, 588,
+ 599, 591, 589,
+ 599, 593, 591,
+ 599, 595, 593,
+ 599, 597, 595,
+ 599, 589, 597,
+ 600, 601, 602,
+ 602, 601, 603,
+ 602, 603, 604,
+ 604, 603, 605,
+ 604, 605, 606,
+ 606, 605, 607,
+ 606, 607, 608,
+ 608, 607, 609,
+ 608, 609, 600,
+ 600, 609, 601,
+ 610, 600, 602,
+ 610, 602, 604,
+ 610, 604, 606,
+ 610, 606, 608,
+ 610, 608, 600,
+ 611, 603, 601,
+ 611, 605, 603,
+ 611, 607, 605,
+ 611, 609, 607,
+ 611, 601, 609,
+ 612, 613, 614,
+ 614, 613, 615,
+ 614, 615, 616,
+ 616, 615, 617,
+ 616, 617, 618,
+ 618, 617, 619,
+ 618, 619, 620,
+ 620, 619, 621,
+ 620, 621, 612,
+ 612, 621, 613,
+ 622, 612, 614,
+ 622, 614, 616,
+ 622, 616, 618,
+ 622, 618, 620,
+ 622, 620, 612,
+ 623, 615, 613,
+ 623, 617, 615,
+ 623, 619, 617,
+ 623, 621, 619,
+ 623, 613, 621,
+ 624, 625, 626,
+ 626, 625, 627,
+ 626, 627, 628,
+ 628, 627, 629,
+ 628, 629, 630,
+ 630, 629, 631,
+ 630, 631, 632,
+ 632, 631, 633,
+ 632, 633, 624,
+ 624, 633, 625,
+ 634, 624, 626,
+ 634, 626, 628,
+ 634, 628, 630,
+ 634, 630, 632,
+ 634, 632, 624,
+ 635, 627, 625,
+ 635, 629, 627,
+ 635, 631, 629,
+ 635, 633, 631,
+ 635, 625, 633,
+ 636, 637, 638,
+ 638, 637, 639,
+ 638, 639, 640,
+ 640, 639, 641,
+ 640, 641, 642,
+ 642, 641, 643,
+ 642, 643, 644,
+ 644, 643, 645,
+ 644, 645, 636,
+ 636, 645, 637,
+ 646, 636, 638,
+ 646, 638, 640,
+ 646, 640, 642,
+ 646, 642, 644,
+ 646, 644, 636,
+ 647, 639, 637,
+ 647, 641, 639,
+ 647, 643, 641,
+ 647, 645, 643,
+ 647, 637, 645,
+ 648, 649, 650,
+ 650, 649, 651,
+ 650, 651, 652,
+ 652, 651, 653,
+ 652, 653, 654,
+ 654, 653, 655,
+ 654, 655, 656,
+ 656, 655, 657,
+ 656, 657, 648,
+ 648, 657, 649,
+ 658, 648, 650,
+ 658, 650, 652,
+ 658, 652, 654,
+ 658, 654, 656,
+ 658, 656, 648,
+ 659, 651, 649,
+ 659, 653, 651,
+ 659, 655, 653,
+ 659, 657, 655,
+ 659, 649, 657,
+ 660, 661, 662,
+ 662, 661, 663,
+ 662, 663, 664,
+ 664, 663, 665,
+ 664, 665, 666,
+ 666, 665, 667,
+ 666, 667, 668,
+ 668, 667, 669,
+ 668, 669, 660,
+ 660, 669, 661,
+ 670, 660, 662,
+ 670, 662, 664,
+ 670, 664, 666,
+ 670, 666, 668,
+ 670, 668, 660,
+ 671, 663, 661,
+ 671, 665, 663,
+ 671, 667, 665,
+ 671, 669, 667,
+ 671, 661, 669,
+ 672, 673, 674,
+ 674, 673, 675,
+ 674, 675, 676,
+ 676, 675, 677,
+ 676, 677, 678,
+ 678, 677, 679,
+ 678, 679, 680,
+ 680, 679, 681,
+ 680, 681, 672,
+ 672, 681, 673,
+ 682, 672, 674,
+ 682, 674, 676,
+ 682, 676, 678,
+ 682, 678, 680,
+ 682, 680, 672,
+ 683, 675, 673,
+ 683, 677, 675,
+ 683, 679, 677,
+ 683, 681, 679,
+ 683, 673, 681,
+ 684, 685, 686,
+ 686, 685, 687,
+ 686, 687, 688,
+ 688, 687, 689,
+ 688, 689, 690,
+ 690, 689, 691,
+ 690, 691, 692,
+ 692, 691, 693,
+ 692, 693, 684,
+ 684, 693, 685,
+ 694, 684, 686,
+ 694, 686, 688,
+ 694, 688, 690,
+ 694, 690, 692,
+ 694, 692, 684,
+ 695, 687, 685,
+ 695, 689, 687,
+ 695, 691, 689,
+ 695, 693, 691,
+ 695, 685, 693,
+ 696, 697, 698,
+ 698, 697, 699,
+ 698, 699, 700,
+ 700, 699, 701,
+ 700, 701, 702,
+ 702, 701, 703,
+ 702, 703, 704,
+ 704, 703, 705,
+ 704, 705, 696,
+ 696, 705, 697,
+ 706, 696, 698,
+ 706, 698, 700,
+ 706, 700, 702,
+ 706, 702, 704,
+ 706, 704, 696,
+ 707, 699, 697,
+ 707, 701, 699,
+ 707, 703, 701,
+ 707, 705, 703,
+ 707, 697, 705,
+ 708, 709, 710,
+ 710, 709, 711,
+ 710, 711, 712,
+ 712, 711, 713,
+ 712, 713, 714,
+ 714, 713, 715,
+ 714, 715, 716,
+ 716, 715, 717,
+ 716, 717, 708,
+ 708, 717, 709,
+ 718, 708, 710,
+ 718, 710, 712,
+ 718, 712, 714,
+ 718, 714, 716,
+ 718, 716, 708,
+ 719, 711, 709,
+ 719, 713, 711,
+ 719, 715, 713,
+ 719, 717, 715,
+ 719, 709, 717,
+ 720, 721, 722,
+ 722, 721, 723,
+ 722, 723, 724,
+ 724, 723, 725,
+ 724, 725, 726,
+ 726, 725, 727,
+ 726, 727, 728,
+ 728, 727, 729,
+ 728, 729, 720,
+ 720, 729, 721,
+ 730, 720, 722,
+ 730, 722, 724,
+ 730, 724, 726,
+ 730, 726, 728,
+ 730, 728, 720,
+ 731, 723, 721,
+ 731, 725, 723,
+ 731, 727, 725,
+ 731, 729, 727,
+ 731, 721, 729,
+ 732, 733, 734,
+ 734, 733, 735,
+ 734, 735, 736,
+ 736, 735, 737,
+ 736, 737, 738,
+ 738, 737, 739,
+ 738, 739, 740,
+ 740, 739, 741,
+ 740, 741, 732,
+ 732, 741, 733,
+ 742, 732, 734,
+ 742, 734, 736,
+ 742, 736, 738,
+ 742, 738, 740,
+ 742, 740, 732,
+ 743, 735, 733,
+ 743, 737, 735,
+ 743, 739, 737,
+ 743, 741, 739,
+ 743, 733, 741,
+ 744, 745, 746,
+ 746, 745, 747,
+ 746, 747, 748,
+ 748, 747, 749,
+ 748, 749, 750,
+ 750, 749, 751,
+ 750, 751, 752,
+ 752, 751, 753,
+ 752, 753, 744,
+ 744, 753, 745,
+ 754, 744, 746,
+ 754, 746, 748,
+ 754, 748, 750,
+ 754, 750, 752,
+ 754, 752, 744,
+ 755, 747, 745,
+ 755, 749, 747,
+ 755, 751, 749,
+ 755, 753, 751,
+ 755, 745, 753,
+ 756, 757, 758,
+ 758, 757, 759,
+ 758, 759, 760,
+ 760, 759, 761,
+ 760, 761, 762,
+ 762, 761, 763,
+ 762, 763, 764,
+ 764, 763, 765,
+ 764, 765, 756,
+ 756, 765, 757,
+ 766, 756, 758,
+ 766, 758, 760,
+ 766, 760, 762,
+ 766, 762, 764,
+ 766, 764, 756,
+ 767, 759, 757,
+ 767, 761, 759,
+ 767, 763, 761,
+ 767, 765, 763,
+ 767, 757, 765
+};
+static const unsigned some_enclosures_properties[3840] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 1, 2, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 2, 3, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0,
+ 3, 4, 0
+};
+
+#define NB_CYL_X 4
+#define NB_CYL_Y 4
+#define NB_CYL_Z 4
+#define NB_CYL (NB_CYL_X * NB_CYL_Y * NB_CYL_Z)
+#define CYL_VRTX_COUNT 12u
+#define CYL_TRG_COUNT 20u
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned e, count;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Create a scene */
+ ctx.positions = some_enclosures_vertices;
+ ctx.indices = some_enclosures_triangles;
+ ctx.properties = some_enclosures_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ some_enclosures_triangles_count, get_indices, get_media_from_properties,
+ some_enclosures_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == NB_CYL * CYL_VRTX_COUNT);
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == NB_CYL * CYL_TRG_COUNT);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 1 + NB_CYL);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ unsigned m;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ CHK(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &m));
+ CHK(header.primitives_count ==
+ (header.is_infinite /* Outermost enclosure: NB_CYL_X*NB_CYL_Y cylinders */
+ ? NB_CYL_X * NB_CYL_Y * CYL_TRG_COUNT
+ : (m == 0
+ ? CYL_TRG_COUNT /* Innermost enclosures: 1 cylinder */
+ : 2 * CYL_TRG_COUNT))); /* Other enclosures: 2 cylinders */
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_some_triangles.c b/src/test_senc3d_some_triangles.c
@@ -0,0 +1,2737 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_some_triangles.
+ * This test is similar to test_senc3d_many_triangles that creates a huge
+ * geometry by program. */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+/* Dump of star-geometry 'some_triangles'. */
+static const unsigned some_triangles_vertices_count = 536;
+static const double some_triangles_vertices[1608] =
+{
+ 1, 0, -1,
+ 1, 0, -0.8,
+ 1, 0, -0.6,
+ 1, 0, -0.4,
+ 1, 0, -0.2,
+ 1, 0, -5.55112e-17,
+ 1, 0, 0.2,
+ 1, 0, 0.4,
+ 1, 0, 0.6,
+ 1, 0, 0.8,
+ 1, 0, 1,
+ 0.866025, 0.5, -1,
+ 0.866025, 0.5, -0.8,
+ 0.866025, 0.5, -0.6,
+ 0.866025, 0.5, -0.4,
+ 0.866025, 0.5, -0.2,
+ 0.866025, 0.5, -5.55112e-17,
+ 0.866025, 0.5, 0.2,
+ 0.866025, 0.5, 0.4,
+ 0.866025, 0.5, 0.6,
+ 0.866025, 0.5, 0.8,
+ 0.866025, 0.5, 1,
+ 0.5, 0.866025, -1,
+ 0.5, 0.866025, -0.8,
+ 0.5, 0.866025, -0.6,
+ 0.5, 0.866025, -0.4,
+ 0.5, 0.866025, -0.2,
+ 0.5, 0.866025, -5.55112e-17,
+ 0.5, 0.866025, 0.2,
+ 0.5, 0.866025, 0.4,
+ 0.5, 0.866025, 0.6,
+ 0.5, 0.866025, 0.8,
+ 0.5, 0.866025, 1,
+ 6.12323e-17, 1, -1,
+ 6.12323e-17, 1, -0.8,
+ 6.12323e-17, 1, -0.6,
+ 6.12323e-17, 1, -0.4,
+ 6.12323e-17, 1, -0.2,
+ 6.12323e-17, 1, -5.55112e-17,
+ 6.12323e-17, 1, 0.2,
+ 6.12323e-17, 1, 0.4,
+ 6.12323e-17, 1, 0.6,
+ 6.12323e-17, 1, 0.8,
+ 6.12323e-17, 1, 1,
+ -0.5, 0.866025, -1,
+ -0.5, 0.866025, -0.8,
+ -0.5, 0.866025, -0.6,
+ -0.5, 0.866025, -0.4,
+ -0.5, 0.866025, -0.2,
+ -0.5, 0.866025, -5.55112e-17,
+ -0.5, 0.866025, 0.2,
+ -0.5, 0.866025, 0.4,
+ -0.5, 0.866025, 0.6,
+ -0.5, 0.866025, 0.8,
+ -0.5, 0.866025, 1,
+ -0.866025, 0.5, -1,
+ -0.866025, 0.5, -0.8,
+ -0.866025, 0.5, -0.6,
+ -0.866025, 0.5, -0.4,
+ -0.866025, 0.5, -0.2,
+ -0.866025, 0.5, -5.55112e-17,
+ -0.866025, 0.5, 0.2,
+ -0.866025, 0.5, 0.4,
+ -0.866025, 0.5, 0.6,
+ -0.866025, 0.5, 0.8,
+ -0.866025, 0.5, 1,
+ -1, 1.22465e-16, -1,
+ -1, 1.22465e-16, -0.8,
+ -1, 1.22465e-16, -0.6,
+ -1, 1.22465e-16, -0.4,
+ -1, 1.22465e-16, -0.2,
+ -1, 1.22465e-16, -5.55112e-17,
+ -1, 1.22465e-16, 0.2,
+ -1, 1.22465e-16, 0.4,
+ -1, 1.22465e-16, 0.6,
+ -1, 1.22465e-16, 0.8,
+ -1, 1.22465e-16, 1,
+ -0.866025, -0.5, -1,
+ -0.866025, -0.5, -0.8,
+ -0.866025, -0.5, -0.6,
+ -0.866025, -0.5, -0.4,
+ -0.866025, -0.5, -0.2,
+ -0.866025, -0.5, -5.55112e-17,
+ -0.866025, -0.5, 0.2,
+ -0.866025, -0.5, 0.4,
+ -0.866025, -0.5, 0.6,
+ -0.866025, -0.5, 0.8,
+ -0.866025, -0.5, 1,
+ -0.5, -0.866025, -1,
+ -0.5, -0.866025, -0.8,
+ -0.5, -0.866025, -0.6,
+ -0.5, -0.866025, -0.4,
+ -0.5, -0.866025, -0.2,
+ -0.5, -0.866025, -5.55112e-17,
+ -0.5, -0.866025, 0.2,
+ -0.5, -0.866025, 0.4,
+ -0.5, -0.866025, 0.6,
+ -0.5, -0.866025, 0.8,
+ -0.5, -0.866025, 1,
+ -1.83697e-16, -1, -1,
+ -1.83697e-16, -1, -0.8,
+ -1.83697e-16, -1, -0.6,
+ -1.83697e-16, -1, -0.4,
+ -1.83697e-16, -1, -0.2,
+ -1.83697e-16, -1, -5.55112e-17,
+ -1.83697e-16, -1, 0.2,
+ -1.83697e-16, -1, 0.4,
+ -1.83697e-16, -1, 0.6,
+ -1.83697e-16, -1, 0.8,
+ -1.83697e-16, -1, 1,
+ 0.5, -0.866025, -1,
+ 0.5, -0.866025, -0.8,
+ 0.5, -0.866025, -0.6,
+ 0.5, -0.866025, -0.4,
+ 0.5, -0.866025, -0.2,
+ 0.5, -0.866025, -5.55112e-17,
+ 0.5, -0.866025, 0.2,
+ 0.5, -0.866025, 0.4,
+ 0.5, -0.866025, 0.6,
+ 0.5, -0.866025, 0.8,
+ 0.5, -0.866025, 1,
+ 0.866025, -0.5, -1,
+ 0.866025, -0.5, -0.8,
+ 0.866025, -0.5, -0.6,
+ 0.866025, -0.5, -0.4,
+ 0.866025, -0.5, -0.2,
+ 0.866025, -0.5, -5.55112e-17,
+ 0.866025, -0.5, 0.2,
+ 0.866025, -0.5, 0.4,
+ 0.866025, -0.5, 0.6,
+ 0.866025, -0.5, 0.8,
+ 0.866025, -0.5, 1,
+ 0, 0, -1,
+ 0, 0, 1,
+ 1, 0, 9,
+ 1, 0, 9.2,
+ 1, 0, 9.4,
+ 1, 0, 9.6,
+ 1, 0, 9.8,
+ 1, 0, 10,
+ 1, 0, 10.2,
+ 1, 0, 10.4,
+ 1, 0, 10.6,
+ 1, 0, 10.8,
+ 1, 0, 11,
+ 0.866025, 0.5, 9,
+ 0.866025, 0.5, 9.2,
+ 0.866025, 0.5, 9.4,
+ 0.866025, 0.5, 9.6,
+ 0.866025, 0.5, 9.8,
+ 0.866025, 0.5, 10,
+ 0.866025, 0.5, 10.2,
+ 0.866025, 0.5, 10.4,
+ 0.866025, 0.5, 10.6,
+ 0.866025, 0.5, 10.8,
+ 0.866025, 0.5, 11,
+ 0.5, 0.866025, 9,
+ 0.5, 0.866025, 9.2,
+ 0.5, 0.866025, 9.4,
+ 0.5, 0.866025, 9.6,
+ 0.5, 0.866025, 9.8,
+ 0.5, 0.866025, 10,
+ 0.5, 0.866025, 10.2,
+ 0.5, 0.866025, 10.4,
+ 0.5, 0.866025, 10.6,
+ 0.5, 0.866025, 10.8,
+ 0.5, 0.866025, 11,
+ 6.12323e-17, 1, 9,
+ 6.12323e-17, 1, 9.2,
+ 6.12323e-17, 1, 9.4,
+ 6.12323e-17, 1, 9.6,
+ 6.12323e-17, 1, 9.8,
+ 6.12323e-17, 1, 10,
+ 6.12323e-17, 1, 10.2,
+ 6.12323e-17, 1, 10.4,
+ 6.12323e-17, 1, 10.6,
+ 6.12323e-17, 1, 10.8,
+ 6.12323e-17, 1, 11,
+ -0.5, 0.866025, 9,
+ -0.5, 0.866025, 9.2,
+ -0.5, 0.866025, 9.4,
+ -0.5, 0.866025, 9.6,
+ -0.5, 0.866025, 9.8,
+ -0.5, 0.866025, 10,
+ -0.5, 0.866025, 10.2,
+ -0.5, 0.866025, 10.4,
+ -0.5, 0.866025, 10.6,
+ -0.5, 0.866025, 10.8,
+ -0.5, 0.866025, 11,
+ -0.866025, 0.5, 9,
+ -0.866025, 0.5, 9.2,
+ -0.866025, 0.5, 9.4,
+ -0.866025, 0.5, 9.6,
+ -0.866025, 0.5, 9.8,
+ -0.866025, 0.5, 10,
+ -0.866025, 0.5, 10.2,
+ -0.866025, 0.5, 10.4,
+ -0.866025, 0.5, 10.6,
+ -0.866025, 0.5, 10.8,
+ -0.866025, 0.5, 11,
+ -1, 1.22465e-16, 9,
+ -1, 1.22465e-16, 9.2,
+ -1, 1.22465e-16, 9.4,
+ -1, 1.22465e-16, 9.6,
+ -1, 1.22465e-16, 9.8,
+ -1, 1.22465e-16, 10,
+ -1, 1.22465e-16, 10.2,
+ -1, 1.22465e-16, 10.4,
+ -1, 1.22465e-16, 10.6,
+ -1, 1.22465e-16, 10.8,
+ -1, 1.22465e-16, 11,
+ -0.866025, -0.5, 9,
+ -0.866025, -0.5, 9.2,
+ -0.866025, -0.5, 9.4,
+ -0.866025, -0.5, 9.6,
+ -0.866025, -0.5, 9.8,
+ -0.866025, -0.5, 10,
+ -0.866025, -0.5, 10.2,
+ -0.866025, -0.5, 10.4,
+ -0.866025, -0.5, 10.6,
+ -0.866025, -0.5, 10.8,
+ -0.866025, -0.5, 11,
+ -0.5, -0.866025, 9,
+ -0.5, -0.866025, 9.2,
+ -0.5, -0.866025, 9.4,
+ -0.5, -0.866025, 9.6,
+ -0.5, -0.866025, 9.8,
+ -0.5, -0.866025, 10,
+ -0.5, -0.866025, 10.2,
+ -0.5, -0.866025, 10.4,
+ -0.5, -0.866025, 10.6,
+ -0.5, -0.866025, 10.8,
+ -0.5, -0.866025, 11,
+ -1.83697e-16, -1, 9,
+ -1.83697e-16, -1, 9.2,
+ -1.83697e-16, -1, 9.4,
+ -1.83697e-16, -1, 9.6,
+ -1.83697e-16, -1, 9.8,
+ -1.83697e-16, -1, 10,
+ -1.83697e-16, -1, 10.2,
+ -1.83697e-16, -1, 10.4,
+ -1.83697e-16, -1, 10.6,
+ -1.83697e-16, -1, 10.8,
+ -1.83697e-16, -1, 11,
+ 0.5, -0.866025, 9,
+ 0.5, -0.866025, 9.2,
+ 0.5, -0.866025, 9.4,
+ 0.5, -0.866025, 9.6,
+ 0.5, -0.866025, 9.8,
+ 0.5, -0.866025, 10,
+ 0.5, -0.866025, 10.2,
+ 0.5, -0.866025, 10.4,
+ 0.5, -0.866025, 10.6,
+ 0.5, -0.866025, 10.8,
+ 0.5, -0.866025, 11,
+ 0.866025, -0.5, 9,
+ 0.866025, -0.5, 9.2,
+ 0.866025, -0.5, 9.4,
+ 0.866025, -0.5, 9.6,
+ 0.866025, -0.5, 9.8,
+ 0.866025, -0.5, 10,
+ 0.866025, -0.5, 10.2,
+ 0.866025, -0.5, 10.4,
+ 0.866025, -0.5, 10.6,
+ 0.866025, -0.5, 10.8,
+ 0.866025, -0.5, 11,
+ 0, 0, 9,
+ 0, 0, 11,
+ 1, 0, 19,
+ 1, 0, 19.2,
+ 1, 0, 19.4,
+ 1, 0, 19.6,
+ 1, 0, 19.8,
+ 1, 0, 20,
+ 1, 0, 20.2,
+ 1, 0, 20.4,
+ 1, 0, 20.6,
+ 1, 0, 20.8,
+ 1, 0, 21,
+ 0.866025, 0.5, 19,
+ 0.866025, 0.5, 19.2,
+ 0.866025, 0.5, 19.4,
+ 0.866025, 0.5, 19.6,
+ 0.866025, 0.5, 19.8,
+ 0.866025, 0.5, 20,
+ 0.866025, 0.5, 20.2,
+ 0.866025, 0.5, 20.4,
+ 0.866025, 0.5, 20.6,
+ 0.866025, 0.5, 20.8,
+ 0.866025, 0.5, 21,
+ 0.5, 0.866025, 19,
+ 0.5, 0.866025, 19.2,
+ 0.5, 0.866025, 19.4,
+ 0.5, 0.866025, 19.6,
+ 0.5, 0.866025, 19.8,
+ 0.5, 0.866025, 20,
+ 0.5, 0.866025, 20.2,
+ 0.5, 0.866025, 20.4,
+ 0.5, 0.866025, 20.6,
+ 0.5, 0.866025, 20.8,
+ 0.5, 0.866025, 21,
+ 6.12323e-17, 1, 19,
+ 6.12323e-17, 1, 19.2,
+ 6.12323e-17, 1, 19.4,
+ 6.12323e-17, 1, 19.6,
+ 6.12323e-17, 1, 19.8,
+ 6.12323e-17, 1, 20,
+ 6.12323e-17, 1, 20.2,
+ 6.12323e-17, 1, 20.4,
+ 6.12323e-17, 1, 20.6,
+ 6.12323e-17, 1, 20.8,
+ 6.12323e-17, 1, 21,
+ -0.5, 0.866025, 19,
+ -0.5, 0.866025, 19.2,
+ -0.5, 0.866025, 19.4,
+ -0.5, 0.866025, 19.6,
+ -0.5, 0.866025, 19.8,
+ -0.5, 0.866025, 20,
+ -0.5, 0.866025, 20.2,
+ -0.5, 0.866025, 20.4,
+ -0.5, 0.866025, 20.6,
+ -0.5, 0.866025, 20.8,
+ -0.5, 0.866025, 21,
+ -0.866025, 0.5, 19,
+ -0.866025, 0.5, 19.2,
+ -0.866025, 0.5, 19.4,
+ -0.866025, 0.5, 19.6,
+ -0.866025, 0.5, 19.8,
+ -0.866025, 0.5, 20,
+ -0.866025, 0.5, 20.2,
+ -0.866025, 0.5, 20.4,
+ -0.866025, 0.5, 20.6,
+ -0.866025, 0.5, 20.8,
+ -0.866025, 0.5, 21,
+ -1, 1.22465e-16, 19,
+ -1, 1.22465e-16, 19.2,
+ -1, 1.22465e-16, 19.4,
+ -1, 1.22465e-16, 19.6,
+ -1, 1.22465e-16, 19.8,
+ -1, 1.22465e-16, 20,
+ -1, 1.22465e-16, 20.2,
+ -1, 1.22465e-16, 20.4,
+ -1, 1.22465e-16, 20.6,
+ -1, 1.22465e-16, 20.8,
+ -1, 1.22465e-16, 21,
+ -0.866025, -0.5, 19,
+ -0.866025, -0.5, 19.2,
+ -0.866025, -0.5, 19.4,
+ -0.866025, -0.5, 19.6,
+ -0.866025, -0.5, 19.8,
+ -0.866025, -0.5, 20,
+ -0.866025, -0.5, 20.2,
+ -0.866025, -0.5, 20.4,
+ -0.866025, -0.5, 20.6,
+ -0.866025, -0.5, 20.8,
+ -0.866025, -0.5, 21,
+ -0.5, -0.866025, 19,
+ -0.5, -0.866025, 19.2,
+ -0.5, -0.866025, 19.4,
+ -0.5, -0.866025, 19.6,
+ -0.5, -0.866025, 19.8,
+ -0.5, -0.866025, 20,
+ -0.5, -0.866025, 20.2,
+ -0.5, -0.866025, 20.4,
+ -0.5, -0.866025, 20.6,
+ -0.5, -0.866025, 20.8,
+ -0.5, -0.866025, 21,
+ -1.83697e-16, -1, 19,
+ -1.83697e-16, -1, 19.2,
+ -1.83697e-16, -1, 19.4,
+ -1.83697e-16, -1, 19.6,
+ -1.83697e-16, -1, 19.8,
+ -1.83697e-16, -1, 20,
+ -1.83697e-16, -1, 20.2,
+ -1.83697e-16, -1, 20.4,
+ -1.83697e-16, -1, 20.6,
+ -1.83697e-16, -1, 20.8,
+ -1.83697e-16, -1, 21,
+ 0.5, -0.866025, 19,
+ 0.5, -0.866025, 19.2,
+ 0.5, -0.866025, 19.4,
+ 0.5, -0.866025, 19.6,
+ 0.5, -0.866025, 19.8,
+ 0.5, -0.866025, 20,
+ 0.5, -0.866025, 20.2,
+ 0.5, -0.866025, 20.4,
+ 0.5, -0.866025, 20.6,
+ 0.5, -0.866025, 20.8,
+ 0.5, -0.866025, 21,
+ 0.866025, -0.5, 19,
+ 0.866025, -0.5, 19.2,
+ 0.866025, -0.5, 19.4,
+ 0.866025, -0.5, 19.6,
+ 0.866025, -0.5, 19.8,
+ 0.866025, -0.5, 20,
+ 0.866025, -0.5, 20.2,
+ 0.866025, -0.5, 20.4,
+ 0.866025, -0.5, 20.6,
+ 0.866025, -0.5, 20.8,
+ 0.866025, -0.5, 21,
+ 0, 0, 19,
+ 0, 0, 21,
+ 1, 0, 29,
+ 1, 0, 29.2,
+ 1, 0, 29.4,
+ 1, 0, 29.6,
+ 1, 0, 29.8,
+ 1, 0, 30,
+ 1, 0, 30.2,
+ 1, 0, 30.4,
+ 1, 0, 30.6,
+ 1, 0, 30.8,
+ 1, 0, 31,
+ 0.866025, 0.5, 29,
+ 0.866025, 0.5, 29.2,
+ 0.866025, 0.5, 29.4,
+ 0.866025, 0.5, 29.6,
+ 0.866025, 0.5, 29.8,
+ 0.866025, 0.5, 30,
+ 0.866025, 0.5, 30.2,
+ 0.866025, 0.5, 30.4,
+ 0.866025, 0.5, 30.6,
+ 0.866025, 0.5, 30.8,
+ 0.866025, 0.5, 31,
+ 0.5, 0.866025, 29,
+ 0.5, 0.866025, 29.2,
+ 0.5, 0.866025, 29.4,
+ 0.5, 0.866025, 29.6,
+ 0.5, 0.866025, 29.8,
+ 0.5, 0.866025, 30,
+ 0.5, 0.866025, 30.2,
+ 0.5, 0.866025, 30.4,
+ 0.5, 0.866025, 30.6,
+ 0.5, 0.866025, 30.8,
+ 0.5, 0.866025, 31,
+ 6.12323e-17, 1, 29,
+ 6.12323e-17, 1, 29.2,
+ 6.12323e-17, 1, 29.4,
+ 6.12323e-17, 1, 29.6,
+ 6.12323e-17, 1, 29.8,
+ 6.12323e-17, 1, 30,
+ 6.12323e-17, 1, 30.2,
+ 6.12323e-17, 1, 30.4,
+ 6.12323e-17, 1, 30.6,
+ 6.12323e-17, 1, 30.8,
+ 6.12323e-17, 1, 31,
+ -0.5, 0.866025, 29,
+ -0.5, 0.866025, 29.2,
+ -0.5, 0.866025, 29.4,
+ -0.5, 0.866025, 29.6,
+ -0.5, 0.866025, 29.8,
+ -0.5, 0.866025, 30,
+ -0.5, 0.866025, 30.2,
+ -0.5, 0.866025, 30.4,
+ -0.5, 0.866025, 30.6,
+ -0.5, 0.866025, 30.8,
+ -0.5, 0.866025, 31,
+ -0.866025, 0.5, 29,
+ -0.866025, 0.5, 29.2,
+ -0.866025, 0.5, 29.4,
+ -0.866025, 0.5, 29.6,
+ -0.866025, 0.5, 29.8,
+ -0.866025, 0.5, 30,
+ -0.866025, 0.5, 30.2,
+ -0.866025, 0.5, 30.4,
+ -0.866025, 0.5, 30.6,
+ -0.866025, 0.5, 30.8,
+ -0.866025, 0.5, 31,
+ -1, 1.22465e-16, 29,
+ -1, 1.22465e-16, 29.2,
+ -1, 1.22465e-16, 29.4,
+ -1, 1.22465e-16, 29.6,
+ -1, 1.22465e-16, 29.8,
+ -1, 1.22465e-16, 30,
+ -1, 1.22465e-16, 30.2,
+ -1, 1.22465e-16, 30.4,
+ -1, 1.22465e-16, 30.6,
+ -1, 1.22465e-16, 30.8,
+ -1, 1.22465e-16, 31,
+ -0.866025, -0.5, 29,
+ -0.866025, -0.5, 29.2,
+ -0.866025, -0.5, 29.4,
+ -0.866025, -0.5, 29.6,
+ -0.866025, -0.5, 29.8,
+ -0.866025, -0.5, 30,
+ -0.866025, -0.5, 30.2,
+ -0.866025, -0.5, 30.4,
+ -0.866025, -0.5, 30.6,
+ -0.866025, -0.5, 30.8,
+ -0.866025, -0.5, 31,
+ -0.5, -0.866025, 29,
+ -0.5, -0.866025, 29.2,
+ -0.5, -0.866025, 29.4,
+ -0.5, -0.866025, 29.6,
+ -0.5, -0.866025, 29.8,
+ -0.5, -0.866025, 30,
+ -0.5, -0.866025, 30.2,
+ -0.5, -0.866025, 30.4,
+ -0.5, -0.866025, 30.6,
+ -0.5, -0.866025, 30.8,
+ -0.5, -0.866025, 31,
+ -1.83697e-16, -1, 29,
+ -1.83697e-16, -1, 29.2,
+ -1.83697e-16, -1, 29.4,
+ -1.83697e-16, -1, 29.6,
+ -1.83697e-16, -1, 29.8,
+ -1.83697e-16, -1, 30,
+ -1.83697e-16, -1, 30.2,
+ -1.83697e-16, -1, 30.4,
+ -1.83697e-16, -1, 30.6,
+ -1.83697e-16, -1, 30.8,
+ -1.83697e-16, -1, 31,
+ 0.5, -0.866025, 29,
+ 0.5, -0.866025, 29.2,
+ 0.5, -0.866025, 29.4,
+ 0.5, -0.866025, 29.6,
+ 0.5, -0.866025, 29.8,
+ 0.5, -0.866025, 30,
+ 0.5, -0.866025, 30.2,
+ 0.5, -0.866025, 30.4,
+ 0.5, -0.866025, 30.6,
+ 0.5, -0.866025, 30.8,
+ 0.5, -0.866025, 31,
+ 0.866025, -0.5, 29,
+ 0.866025, -0.5, 29.2,
+ 0.866025, -0.5, 29.4,
+ 0.866025, -0.5, 29.6,
+ 0.866025, -0.5, 29.8,
+ 0.866025, -0.5, 30,
+ 0.866025, -0.5, 30.2,
+ 0.866025, -0.5, 30.4,
+ 0.866025, -0.5, 30.6,
+ 0.866025, -0.5, 30.8,
+ 0.866025, -0.5, 31,
+ 0, 0, 29,
+ 0, 0, 31
+};
+static const unsigned some_triangles_triangles_count = 1056;
+static const unsigned some_triangles_triangles[3168] =
+{
+ 0, 1, 11,
+ 11, 1, 12,
+ 1, 2, 12,
+ 12, 2, 13,
+ 2, 3, 13,
+ 13, 3, 14,
+ 3, 4, 14,
+ 14, 4, 15,
+ 4, 5, 15,
+ 15, 5, 16,
+ 5, 6, 16,
+ 16, 6, 17,
+ 6, 7, 17,
+ 17, 7, 18,
+ 7, 8, 18,
+ 18, 8, 19,
+ 8, 9, 19,
+ 19, 9, 20,
+ 9, 10, 20,
+ 20, 10, 21,
+ 11, 12, 22,
+ 22, 12, 23,
+ 12, 13, 23,
+ 23, 13, 24,
+ 13, 14, 24,
+ 24, 14, 25,
+ 14, 15, 25,
+ 25, 15, 26,
+ 15, 16, 26,
+ 26, 16, 27,
+ 16, 17, 27,
+ 27, 17, 28,
+ 17, 18, 28,
+ 28, 18, 29,
+ 18, 19, 29,
+ 29, 19, 30,
+ 19, 20, 30,
+ 30, 20, 31,
+ 20, 21, 31,
+ 31, 21, 32,
+ 22, 23, 33,
+ 33, 23, 34,
+ 23, 24, 34,
+ 34, 24, 35,
+ 24, 25, 35,
+ 35, 25, 36,
+ 25, 26, 36,
+ 36, 26, 37,
+ 26, 27, 37,
+ 37, 27, 38,
+ 27, 28, 38,
+ 38, 28, 39,
+ 28, 29, 39,
+ 39, 29, 40,
+ 29, 30, 40,
+ 40, 30, 41,
+ 30, 31, 41,
+ 41, 31, 42,
+ 31, 32, 42,
+ 42, 32, 43,
+ 33, 34, 44,
+ 44, 34, 45,
+ 34, 35, 45,
+ 45, 35, 46,
+ 35, 36, 46,
+ 46, 36, 47,
+ 36, 37, 47,
+ 47, 37, 48,
+ 37, 38, 48,
+ 48, 38, 49,
+ 38, 39, 49,
+ 49, 39, 50,
+ 39, 40, 50,
+ 50, 40, 51,
+ 40, 41, 51,
+ 51, 41, 52,
+ 41, 42, 52,
+ 52, 42, 53,
+ 42, 43, 53,
+ 53, 43, 54,
+ 44, 45, 55,
+ 55, 45, 56,
+ 45, 46, 56,
+ 56, 46, 57,
+ 46, 47, 57,
+ 57, 47, 58,
+ 47, 48, 58,
+ 58, 48, 59,
+ 48, 49, 59,
+ 59, 49, 60,
+ 49, 50, 60,
+ 60, 50, 61,
+ 50, 51, 61,
+ 61, 51, 62,
+ 51, 52, 62,
+ 62, 52, 63,
+ 52, 53, 63,
+ 63, 53, 64,
+ 53, 54, 64,
+ 64, 54, 65,
+ 55, 56, 66,
+ 66, 56, 67,
+ 56, 57, 67,
+ 67, 57, 68,
+ 57, 58, 68,
+ 68, 58, 69,
+ 58, 59, 69,
+ 69, 59, 70,
+ 59, 60, 70,
+ 70, 60, 71,
+ 60, 61, 71,
+ 71, 61, 72,
+ 61, 62, 72,
+ 72, 62, 73,
+ 62, 63, 73,
+ 73, 63, 74,
+ 63, 64, 74,
+ 74, 64, 75,
+ 64, 65, 75,
+ 75, 65, 76,
+ 66, 67, 77,
+ 77, 67, 78,
+ 67, 68, 78,
+ 78, 68, 79,
+ 68, 69, 79,
+ 79, 69, 80,
+ 69, 70, 80,
+ 80, 70, 81,
+ 70, 71, 81,
+ 81, 71, 82,
+ 71, 72, 82,
+ 82, 72, 83,
+ 72, 73, 83,
+ 83, 73, 84,
+ 73, 74, 84,
+ 84, 74, 85,
+ 74, 75, 85,
+ 85, 75, 86,
+ 75, 76, 86,
+ 86, 76, 87,
+ 77, 78, 88,
+ 88, 78, 89,
+ 78, 79, 89,
+ 89, 79, 90,
+ 79, 80, 90,
+ 90, 80, 91,
+ 80, 81, 91,
+ 91, 81, 92,
+ 81, 82, 92,
+ 92, 82, 93,
+ 82, 83, 93,
+ 93, 83, 94,
+ 83, 84, 94,
+ 94, 84, 95,
+ 84, 85, 95,
+ 95, 85, 96,
+ 85, 86, 96,
+ 96, 86, 97,
+ 86, 87, 97,
+ 97, 87, 98,
+ 88, 89, 99,
+ 99, 89, 100,
+ 89, 90, 100,
+ 100, 90, 101,
+ 90, 91, 101,
+ 101, 91, 102,
+ 91, 92, 102,
+ 102, 92, 103,
+ 92, 93, 103,
+ 103, 93, 104,
+ 93, 94, 104,
+ 104, 94, 105,
+ 94, 95, 105,
+ 105, 95, 106,
+ 95, 96, 106,
+ 106, 96, 107,
+ 96, 97, 107,
+ 107, 97, 108,
+ 97, 98, 108,
+ 108, 98, 109,
+ 99, 100, 110,
+ 110, 100, 111,
+ 100, 101, 111,
+ 111, 101, 112,
+ 101, 102, 112,
+ 112, 102, 113,
+ 102, 103, 113,
+ 113, 103, 114,
+ 103, 104, 114,
+ 114, 104, 115,
+ 104, 105, 115,
+ 115, 105, 116,
+ 105, 106, 116,
+ 116, 106, 117,
+ 106, 107, 117,
+ 117, 107, 118,
+ 107, 108, 118,
+ 118, 108, 119,
+ 108, 109, 119,
+ 119, 109, 120,
+ 110, 111, 121,
+ 121, 111, 122,
+ 111, 112, 122,
+ 122, 112, 123,
+ 112, 113, 123,
+ 123, 113, 124,
+ 113, 114, 124,
+ 124, 114, 125,
+ 114, 115, 125,
+ 125, 115, 126,
+ 115, 116, 126,
+ 126, 116, 127,
+ 116, 117, 127,
+ 127, 117, 128,
+ 117, 118, 128,
+ 128, 118, 129,
+ 118, 119, 129,
+ 129, 119, 130,
+ 119, 120, 130,
+ 130, 120, 131,
+ 121, 122, 0,
+ 0, 122, 1,
+ 122, 123, 1,
+ 1, 123, 2,
+ 123, 124, 2,
+ 2, 124, 3,
+ 124, 125, 3,
+ 3, 125, 4,
+ 125, 126, 4,
+ 4, 126, 5,
+ 126, 127, 5,
+ 5, 127, 6,
+ 127, 128, 6,
+ 6, 128, 7,
+ 128, 129, 7,
+ 7, 129, 8,
+ 129, 130, 8,
+ 8, 130, 9,
+ 130, 131, 9,
+ 9, 131, 10,
+ 132, 0, 11,
+ 132, 11, 22,
+ 132, 22, 33,
+ 132, 33, 44,
+ 132, 44, 55,
+ 132, 55, 66,
+ 132, 66, 77,
+ 132, 77, 88,
+ 132, 88, 99,
+ 132, 99, 110,
+ 132, 110, 121,
+ 132, 121, 0,
+ 133, 21, 10,
+ 133, 32, 21,
+ 133, 43, 32,
+ 133, 54, 43,
+ 133, 65, 54,
+ 133, 76, 65,
+ 133, 87, 76,
+ 133, 98, 87,
+ 133, 109, 98,
+ 133, 120, 109,
+ 133, 131, 120,
+ 133, 10, 131,
+ 134, 135, 145,
+ 145, 135, 146,
+ 135, 136, 146,
+ 146, 136, 147,
+ 136, 137, 147,
+ 147, 137, 148,
+ 137, 138, 148,
+ 148, 138, 149,
+ 138, 139, 149,
+ 149, 139, 150,
+ 139, 140, 150,
+ 150, 140, 151,
+ 140, 141, 151,
+ 151, 141, 152,
+ 141, 142, 152,
+ 152, 142, 153,
+ 142, 143, 153,
+ 153, 143, 154,
+ 143, 144, 154,
+ 154, 144, 155,
+ 145, 146, 156,
+ 156, 146, 157,
+ 146, 147, 157,
+ 157, 147, 158,
+ 147, 148, 158,
+ 158, 148, 159,
+ 148, 149, 159,
+ 159, 149, 160,
+ 149, 150, 160,
+ 160, 150, 161,
+ 150, 151, 161,
+ 161, 151, 162,
+ 151, 152, 162,
+ 162, 152, 163,
+ 152, 153, 163,
+ 163, 153, 164,
+ 153, 154, 164,
+ 164, 154, 165,
+ 154, 155, 165,
+ 165, 155, 166,
+ 156, 157, 167,
+ 167, 157, 168,
+ 157, 158, 168,
+ 168, 158, 169,
+ 158, 159, 169,
+ 169, 159, 170,
+ 159, 160, 170,
+ 170, 160, 171,
+ 160, 161, 171,
+ 171, 161, 172,
+ 161, 162, 172,
+ 172, 162, 173,
+ 162, 163, 173,
+ 173, 163, 174,
+ 163, 164, 174,
+ 174, 164, 175,
+ 164, 165, 175,
+ 175, 165, 176,
+ 165, 166, 176,
+ 176, 166, 177,
+ 167, 168, 178,
+ 178, 168, 179,
+ 168, 169, 179,
+ 179, 169, 180,
+ 169, 170, 180,
+ 180, 170, 181,
+ 170, 171, 181,
+ 181, 171, 182,
+ 171, 172, 182,
+ 182, 172, 183,
+ 172, 173, 183,
+ 183, 173, 184,
+ 173, 174, 184,
+ 184, 174, 185,
+ 174, 175, 185,
+ 185, 175, 186,
+ 175, 176, 186,
+ 186, 176, 187,
+ 176, 177, 187,
+ 187, 177, 188,
+ 178, 179, 189,
+ 189, 179, 190,
+ 179, 180, 190,
+ 190, 180, 191,
+ 180, 181, 191,
+ 191, 181, 192,
+ 181, 182, 192,
+ 192, 182, 193,
+ 182, 183, 193,
+ 193, 183, 194,
+ 183, 184, 194,
+ 194, 184, 195,
+ 184, 185, 195,
+ 195, 185, 196,
+ 185, 186, 196,
+ 196, 186, 197,
+ 186, 187, 197,
+ 197, 187, 198,
+ 187, 188, 198,
+ 198, 188, 199,
+ 189, 190, 200,
+ 200, 190, 201,
+ 190, 191, 201,
+ 201, 191, 202,
+ 191, 192, 202,
+ 202, 192, 203,
+ 192, 193, 203,
+ 203, 193, 204,
+ 193, 194, 204,
+ 204, 194, 205,
+ 194, 195, 205,
+ 205, 195, 206,
+ 195, 196, 206,
+ 206, 196, 207,
+ 196, 197, 207,
+ 207, 197, 208,
+ 197, 198, 208,
+ 208, 198, 209,
+ 198, 199, 209,
+ 209, 199, 210,
+ 200, 201, 211,
+ 211, 201, 212,
+ 201, 202, 212,
+ 212, 202, 213,
+ 202, 203, 213,
+ 213, 203, 214,
+ 203, 204, 214,
+ 214, 204, 215,
+ 204, 205, 215,
+ 215, 205, 216,
+ 205, 206, 216,
+ 216, 206, 217,
+ 206, 207, 217,
+ 217, 207, 218,
+ 207, 208, 218,
+ 218, 208, 219,
+ 208, 209, 219,
+ 219, 209, 220,
+ 209, 210, 220,
+ 220, 210, 221,
+ 211, 212, 222,
+ 222, 212, 223,
+ 212, 213, 223,
+ 223, 213, 224,
+ 213, 214, 224,
+ 224, 214, 225,
+ 214, 215, 225,
+ 225, 215, 226,
+ 215, 216, 226,
+ 226, 216, 227,
+ 216, 217, 227,
+ 227, 217, 228,
+ 217, 218, 228,
+ 228, 218, 229,
+ 218, 219, 229,
+ 229, 219, 230,
+ 219, 220, 230,
+ 230, 220, 231,
+ 220, 221, 231,
+ 231, 221, 232,
+ 222, 223, 233,
+ 233, 223, 234,
+ 223, 224, 234,
+ 234, 224, 235,
+ 224, 225, 235,
+ 235, 225, 236,
+ 225, 226, 236,
+ 236, 226, 237,
+ 226, 227, 237,
+ 237, 227, 238,
+ 227, 228, 238,
+ 238, 228, 239,
+ 228, 229, 239,
+ 239, 229, 240,
+ 229, 230, 240,
+ 240, 230, 241,
+ 230, 231, 241,
+ 241, 231, 242,
+ 231, 232, 242,
+ 242, 232, 243,
+ 233, 234, 244,
+ 244, 234, 245,
+ 234, 235, 245,
+ 245, 235, 246,
+ 235, 236, 246,
+ 246, 236, 247,
+ 236, 237, 247,
+ 247, 237, 248,
+ 237, 238, 248,
+ 248, 238, 249,
+ 238, 239, 249,
+ 249, 239, 250,
+ 239, 240, 250,
+ 250, 240, 251,
+ 240, 241, 251,
+ 251, 241, 252,
+ 241, 242, 252,
+ 252, 242, 253,
+ 242, 243, 253,
+ 253, 243, 254,
+ 244, 245, 255,
+ 255, 245, 256,
+ 245, 246, 256,
+ 256, 246, 257,
+ 246, 247, 257,
+ 257, 247, 258,
+ 247, 248, 258,
+ 258, 248, 259,
+ 248, 249, 259,
+ 259, 249, 260,
+ 249, 250, 260,
+ 260, 250, 261,
+ 250, 251, 261,
+ 261, 251, 262,
+ 251, 252, 262,
+ 262, 252, 263,
+ 252, 253, 263,
+ 263, 253, 264,
+ 253, 254, 264,
+ 264, 254, 265,
+ 255, 256, 134,
+ 134, 256, 135,
+ 256, 257, 135,
+ 135, 257, 136,
+ 257, 258, 136,
+ 136, 258, 137,
+ 258, 259, 137,
+ 137, 259, 138,
+ 259, 260, 138,
+ 138, 260, 139,
+ 260, 261, 139,
+ 139, 261, 140,
+ 261, 262, 140,
+ 140, 262, 141,
+ 262, 263, 141,
+ 141, 263, 142,
+ 263, 264, 142,
+ 142, 264, 143,
+ 264, 265, 143,
+ 143, 265, 144,
+ 266, 134, 145,
+ 266, 145, 156,
+ 266, 156, 167,
+ 266, 167, 178,
+ 266, 178, 189,
+ 266, 189, 200,
+ 266, 200, 211,
+ 266, 211, 222,
+ 266, 222, 233,
+ 266, 233, 244,
+ 266, 244, 255,
+ 266, 255, 134,
+ 267, 155, 144,
+ 267, 166, 155,
+ 267, 177, 166,
+ 267, 188, 177,
+ 267, 199, 188,
+ 267, 210, 199,
+ 267, 221, 210,
+ 267, 232, 221,
+ 267, 243, 232,
+ 267, 254, 243,
+ 267, 265, 254,
+ 267, 144, 265,
+ 268, 269, 279,
+ 279, 269, 280,
+ 269, 270, 280,
+ 280, 270, 281,
+ 270, 271, 281,
+ 281, 271, 282,
+ 271, 272, 282,
+ 282, 272, 283,
+ 272, 273, 283,
+ 283, 273, 284,
+ 273, 274, 284,
+ 284, 274, 285,
+ 274, 275, 285,
+ 285, 275, 286,
+ 275, 276, 286,
+ 286, 276, 287,
+ 276, 277, 287,
+ 287, 277, 288,
+ 277, 278, 288,
+ 288, 278, 289,
+ 279, 280, 290,
+ 290, 280, 291,
+ 280, 281, 291,
+ 291, 281, 292,
+ 281, 282, 292,
+ 292, 282, 293,
+ 282, 283, 293,
+ 293, 283, 294,
+ 283, 284, 294,
+ 294, 284, 295,
+ 284, 285, 295,
+ 295, 285, 296,
+ 285, 286, 296,
+ 296, 286, 297,
+ 286, 287, 297,
+ 297, 287, 298,
+ 287, 288, 298,
+ 298, 288, 299,
+ 288, 289, 299,
+ 299, 289, 300,
+ 290, 291, 301,
+ 301, 291, 302,
+ 291, 292, 302,
+ 302, 292, 303,
+ 292, 293, 303,
+ 303, 293, 304,
+ 293, 294, 304,
+ 304, 294, 305,
+ 294, 295, 305,
+ 305, 295, 306,
+ 295, 296, 306,
+ 306, 296, 307,
+ 296, 297, 307,
+ 307, 297, 308,
+ 297, 298, 308,
+ 308, 298, 309,
+ 298, 299, 309,
+ 309, 299, 310,
+ 299, 300, 310,
+ 310, 300, 311,
+ 301, 302, 312,
+ 312, 302, 313,
+ 302, 303, 313,
+ 313, 303, 314,
+ 303, 304, 314,
+ 314, 304, 315,
+ 304, 305, 315,
+ 315, 305, 316,
+ 305, 306, 316,
+ 316, 306, 317,
+ 306, 307, 317,
+ 317, 307, 318,
+ 307, 308, 318,
+ 318, 308, 319,
+ 308, 309, 319,
+ 319, 309, 320,
+ 309, 310, 320,
+ 320, 310, 321,
+ 310, 311, 321,
+ 321, 311, 322,
+ 312, 313, 323,
+ 323, 313, 324,
+ 313, 314, 324,
+ 324, 314, 325,
+ 314, 315, 325,
+ 325, 315, 326,
+ 315, 316, 326,
+ 326, 316, 327,
+ 316, 317, 327,
+ 327, 317, 328,
+ 317, 318, 328,
+ 328, 318, 329,
+ 318, 319, 329,
+ 329, 319, 330,
+ 319, 320, 330,
+ 330, 320, 331,
+ 320, 321, 331,
+ 331, 321, 332,
+ 321, 322, 332,
+ 332, 322, 333,
+ 323, 324, 334,
+ 334, 324, 335,
+ 324, 325, 335,
+ 335, 325, 336,
+ 325, 326, 336,
+ 336, 326, 337,
+ 326, 327, 337,
+ 337, 327, 338,
+ 327, 328, 338,
+ 338, 328, 339,
+ 328, 329, 339,
+ 339, 329, 340,
+ 329, 330, 340,
+ 340, 330, 341,
+ 330, 331, 341,
+ 341, 331, 342,
+ 331, 332, 342,
+ 342, 332, 343,
+ 332, 333, 343,
+ 343, 333, 344,
+ 334, 335, 345,
+ 345, 335, 346,
+ 335, 336, 346,
+ 346, 336, 347,
+ 336, 337, 347,
+ 347, 337, 348,
+ 337, 338, 348,
+ 348, 338, 349,
+ 338, 339, 349,
+ 349, 339, 350,
+ 339, 340, 350,
+ 350, 340, 351,
+ 340, 341, 351,
+ 351, 341, 352,
+ 341, 342, 352,
+ 352, 342, 353,
+ 342, 343, 353,
+ 353, 343, 354,
+ 343, 344, 354,
+ 354, 344, 355,
+ 345, 346, 356,
+ 356, 346, 357,
+ 346, 347, 357,
+ 357, 347, 358,
+ 347, 348, 358,
+ 358, 348, 359,
+ 348, 349, 359,
+ 359, 349, 360,
+ 349, 350, 360,
+ 360, 350, 361,
+ 350, 351, 361,
+ 361, 351, 362,
+ 351, 352, 362,
+ 362, 352, 363,
+ 352, 353, 363,
+ 363, 353, 364,
+ 353, 354, 364,
+ 364, 354, 365,
+ 354, 355, 365,
+ 365, 355, 366,
+ 356, 357, 367,
+ 367, 357, 368,
+ 357, 358, 368,
+ 368, 358, 369,
+ 358, 359, 369,
+ 369, 359, 370,
+ 359, 360, 370,
+ 370, 360, 371,
+ 360, 361, 371,
+ 371, 361, 372,
+ 361, 362, 372,
+ 372, 362, 373,
+ 362, 363, 373,
+ 373, 363, 374,
+ 363, 364, 374,
+ 374, 364, 375,
+ 364, 365, 375,
+ 375, 365, 376,
+ 365, 366, 376,
+ 376, 366, 377,
+ 367, 368, 378,
+ 378, 368, 379,
+ 368, 369, 379,
+ 379, 369, 380,
+ 369, 370, 380,
+ 380, 370, 381,
+ 370, 371, 381,
+ 381, 371, 382,
+ 371, 372, 382,
+ 382, 372, 383,
+ 372, 373, 383,
+ 383, 373, 384,
+ 373, 374, 384,
+ 384, 374, 385,
+ 374, 375, 385,
+ 385, 375, 386,
+ 375, 376, 386,
+ 386, 376, 387,
+ 376, 377, 387,
+ 387, 377, 388,
+ 378, 379, 389,
+ 389, 379, 390,
+ 379, 380, 390,
+ 390, 380, 391,
+ 380, 381, 391,
+ 391, 381, 392,
+ 381, 382, 392,
+ 392, 382, 393,
+ 382, 383, 393,
+ 393, 383, 394,
+ 383, 384, 394,
+ 394, 384, 395,
+ 384, 385, 395,
+ 395, 385, 396,
+ 385, 386, 396,
+ 396, 386, 397,
+ 386, 387, 397,
+ 397, 387, 398,
+ 387, 388, 398,
+ 398, 388, 399,
+ 389, 390, 268,
+ 268, 390, 269,
+ 390, 391, 269,
+ 269, 391, 270,
+ 391, 392, 270,
+ 270, 392, 271,
+ 392, 393, 271,
+ 271, 393, 272,
+ 393, 394, 272,
+ 272, 394, 273,
+ 394, 395, 273,
+ 273, 395, 274,
+ 395, 396, 274,
+ 274, 396, 275,
+ 396, 397, 275,
+ 275, 397, 276,
+ 397, 398, 276,
+ 276, 398, 277,
+ 398, 399, 277,
+ 277, 399, 278,
+ 400, 268, 279,
+ 400, 279, 290,
+ 400, 290, 301,
+ 400, 301, 312,
+ 400, 312, 323,
+ 400, 323, 334,
+ 400, 334, 345,
+ 400, 345, 356,
+ 400, 356, 367,
+ 400, 367, 378,
+ 400, 378, 389,
+ 400, 389, 268,
+ 401, 289, 278,
+ 401, 300, 289,
+ 401, 311, 300,
+ 401, 322, 311,
+ 401, 333, 322,
+ 401, 344, 333,
+ 401, 355, 344,
+ 401, 366, 355,
+ 401, 377, 366,
+ 401, 388, 377,
+ 401, 399, 388,
+ 401, 278, 399,
+ 402, 403, 413,
+ 413, 403, 414,
+ 403, 404, 414,
+ 414, 404, 415,
+ 404, 405, 415,
+ 415, 405, 416,
+ 405, 406, 416,
+ 416, 406, 417,
+ 406, 407, 417,
+ 417, 407, 418,
+ 407, 408, 418,
+ 418, 408, 419,
+ 408, 409, 419,
+ 419, 409, 420,
+ 409, 410, 420,
+ 420, 410, 421,
+ 410, 411, 421,
+ 421, 411, 422,
+ 411, 412, 422,
+ 422, 412, 423,
+ 413, 414, 424,
+ 424, 414, 425,
+ 414, 415, 425,
+ 425, 415, 426,
+ 415, 416, 426,
+ 426, 416, 427,
+ 416, 417, 427,
+ 427, 417, 428,
+ 417, 418, 428,
+ 428, 418, 429,
+ 418, 419, 429,
+ 429, 419, 430,
+ 419, 420, 430,
+ 430, 420, 431,
+ 420, 421, 431,
+ 431, 421, 432,
+ 421, 422, 432,
+ 432, 422, 433,
+ 422, 423, 433,
+ 433, 423, 434,
+ 424, 425, 435,
+ 435, 425, 436,
+ 425, 426, 436,
+ 436, 426, 437,
+ 426, 427, 437,
+ 437, 427, 438,
+ 427, 428, 438,
+ 438, 428, 439,
+ 428, 429, 439,
+ 439, 429, 440,
+ 429, 430, 440,
+ 440, 430, 441,
+ 430, 431, 441,
+ 441, 431, 442,
+ 431, 432, 442,
+ 442, 432, 443,
+ 432, 433, 443,
+ 443, 433, 444,
+ 433, 434, 444,
+ 444, 434, 445,
+ 435, 436, 446,
+ 446, 436, 447,
+ 436, 437, 447,
+ 447, 437, 448,
+ 437, 438, 448,
+ 448, 438, 449,
+ 438, 439, 449,
+ 449, 439, 450,
+ 439, 440, 450,
+ 450, 440, 451,
+ 440, 441, 451,
+ 451, 441, 452,
+ 441, 442, 452,
+ 452, 442, 453,
+ 442, 443, 453,
+ 453, 443, 454,
+ 443, 444, 454,
+ 454, 444, 455,
+ 444, 445, 455,
+ 455, 445, 456,
+ 446, 447, 457,
+ 457, 447, 458,
+ 447, 448, 458,
+ 458, 448, 459,
+ 448, 449, 459,
+ 459, 449, 460,
+ 449, 450, 460,
+ 460, 450, 461,
+ 450, 451, 461,
+ 461, 451, 462,
+ 451, 452, 462,
+ 462, 452, 463,
+ 452, 453, 463,
+ 463, 453, 464,
+ 453, 454, 464,
+ 464, 454, 465,
+ 454, 455, 465,
+ 465, 455, 466,
+ 455, 456, 466,
+ 466, 456, 467,
+ 457, 458, 468,
+ 468, 458, 469,
+ 458, 459, 469,
+ 469, 459, 470,
+ 459, 460, 470,
+ 470, 460, 471,
+ 460, 461, 471,
+ 471, 461, 472,
+ 461, 462, 472,
+ 472, 462, 473,
+ 462, 463, 473,
+ 473, 463, 474,
+ 463, 464, 474,
+ 474, 464, 475,
+ 464, 465, 475,
+ 475, 465, 476,
+ 465, 466, 476,
+ 476, 466, 477,
+ 466, 467, 477,
+ 477, 467, 478,
+ 468, 469, 479,
+ 479, 469, 480,
+ 469, 470, 480,
+ 480, 470, 481,
+ 470, 471, 481,
+ 481, 471, 482,
+ 471, 472, 482,
+ 482, 472, 483,
+ 472, 473, 483,
+ 483, 473, 484,
+ 473, 474, 484,
+ 484, 474, 485,
+ 474, 475, 485,
+ 485, 475, 486,
+ 475, 476, 486,
+ 486, 476, 487,
+ 476, 477, 487,
+ 487, 477, 488,
+ 477, 478, 488,
+ 488, 478, 489,
+ 479, 480, 490,
+ 490, 480, 491,
+ 480, 481, 491,
+ 491, 481, 492,
+ 481, 482, 492,
+ 492, 482, 493,
+ 482, 483, 493,
+ 493, 483, 494,
+ 483, 484, 494,
+ 494, 484, 495,
+ 484, 485, 495,
+ 495, 485, 496,
+ 485, 486, 496,
+ 496, 486, 497,
+ 486, 487, 497,
+ 497, 487, 498,
+ 487, 488, 498,
+ 498, 488, 499,
+ 488, 489, 499,
+ 499, 489, 500,
+ 490, 491, 501,
+ 501, 491, 502,
+ 491, 492, 502,
+ 502, 492, 503,
+ 492, 493, 503,
+ 503, 493, 504,
+ 493, 494, 504,
+ 504, 494, 505,
+ 494, 495, 505,
+ 505, 495, 506,
+ 495, 496, 506,
+ 506, 496, 507,
+ 496, 497, 507,
+ 507, 497, 508,
+ 497, 498, 508,
+ 508, 498, 509,
+ 498, 499, 509,
+ 509, 499, 510,
+ 499, 500, 510,
+ 510, 500, 511,
+ 501, 502, 512,
+ 512, 502, 513,
+ 502, 503, 513,
+ 513, 503, 514,
+ 503, 504, 514,
+ 514, 504, 515,
+ 504, 505, 515,
+ 515, 505, 516,
+ 505, 506, 516,
+ 516, 506, 517,
+ 506, 507, 517,
+ 517, 507, 518,
+ 507, 508, 518,
+ 518, 508, 519,
+ 508, 509, 519,
+ 519, 509, 520,
+ 509, 510, 520,
+ 520, 510, 521,
+ 510, 511, 521,
+ 521, 511, 522,
+ 512, 513, 523,
+ 523, 513, 524,
+ 513, 514, 524,
+ 524, 514, 525,
+ 514, 515, 525,
+ 525, 515, 526,
+ 515, 516, 526,
+ 526, 516, 527,
+ 516, 517, 527,
+ 527, 517, 528,
+ 517, 518, 528,
+ 528, 518, 529,
+ 518, 519, 529,
+ 529, 519, 530,
+ 519, 520, 530,
+ 530, 520, 531,
+ 520, 521, 531,
+ 531, 521, 532,
+ 521, 522, 532,
+ 532, 522, 533,
+ 523, 524, 402,
+ 402, 524, 403,
+ 524, 525, 403,
+ 403, 525, 404,
+ 525, 526, 404,
+ 404, 526, 405,
+ 526, 527, 405,
+ 405, 527, 406,
+ 527, 528, 406,
+ 406, 528, 407,
+ 528, 529, 407,
+ 407, 529, 408,
+ 529, 530, 408,
+ 408, 530, 409,
+ 530, 531, 409,
+ 409, 531, 410,
+ 531, 532, 410,
+ 410, 532, 411,
+ 532, 533, 411,
+ 411, 533, 412,
+ 534, 402, 413,
+ 534, 413, 424,
+ 534, 424, 435,
+ 534, 435, 446,
+ 534, 446, 457,
+ 534, 457, 468,
+ 534, 468, 479,
+ 534, 479, 490,
+ 534, 490, 501,
+ 534, 501, 512,
+ 534, 512, 523,
+ 534, 523, 402,
+ 535, 423, 412,
+ 535, 434, 423,
+ 535, 445, 434,
+ 535, 456, 445,
+ 535, 467, 456,
+ 535, 478, 467,
+ 535, 489, 478,
+ 535, 500, 489,
+ 535, 511, 500,
+ 535, 522, 511,
+ 535, 533, 522,
+ 535, 412, 533
+};
+static const unsigned some_triangles_properties[3168] =
+{
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 1, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 2, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0,
+ 3, 0, 0
+};
+
+#define NB_CYL 4
+#define CYL_VRTX_COUNT 134u
+#define CYL_TRG_COUNT 264u
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned e, count;
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Create a scene */
+ ctx.positions = some_triangles_vertices;
+ ctx.indices = some_triangles_triangles;
+ ctx.properties = some_triangles_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE,
+ some_triangles_triangles_count, get_indices, get_media_from_properties,
+ some_triangles_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == NB_CYL * CYL_VRTX_COUNT);
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == NB_CYL * CYL_TRG_COUNT);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 1 + NB_CYL);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ CHK(header.primitives_count ==
+ (e ? CYL_TRG_COUNT : NB_CYL * CYL_TRG_COUNT));
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_unspecified_medium.c b/src/test_senc3d_unspecified_medium.c
@@ -0,0 +1,327 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses output from test_sg3_unspecified_properties.
+ * This test is similar to test_senc3d_many_enclosures that creates a huge
+ * geometry by program. */
+
+#include "senc3d.h"
+#include "senc3d_sXd_helper.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+#define SG3_UNSPECIFED_PROPERTY UINT_MAX
+
+/* Dump of star-geometry 'front_unspecified'. */
+static const unsigned front_unspecified_vertices_count = 8;
+static const double front_unspecified_vertices[24] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1
+};
+static const unsigned front_unspecified_triangles_count = 12;
+static const unsigned front_unspecified_triangles[36] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5
+};
+static const unsigned front_unspecified_properties[36] =
+{
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY
+};
+/* Dump of star-geometry 'front_half_unspecified'. */
+static const unsigned front_half_unspecified_vertices_count = 8;
+static const double front_half_unspecified_vertices[24] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1
+};
+static const unsigned front_half_unspecified_triangles_count = 12;
+static const unsigned front_half_unspecified_triangles[36] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5
+};
+static const unsigned front_half_unspecified_properties[36] =
+{
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ 0, 1, 0,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ 0, 1, 0,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ 0, 1, 0,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ 0, 1, 0,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ 0, 1, 0,
+ SG3_UNSPECIFED_PROPERTY, 1, SG3_UNSPECIFED_PROPERTY,
+ 0, 1, 0
+};
+/* Dump of star-geometry 'all_defined'. */
+static const unsigned all_defined_vertices_count = 8;
+static const double all_defined_vertices[24] =
+{
+ 0.1, 0, 0,
+ 1, 0, 0,
+ 0, 1, 0,
+ 1, 1, 0,
+ 0, 0, 1.1,
+ 1, 0, 1,
+ 0, 1, 1,
+ 1, 1.1, 1
+};
+static const unsigned all_defined_triangles_count = 12;
+static const unsigned all_defined_triangles[36] =
+{
+ 0, 2, 1,
+ 1, 2, 3,
+ 0, 4, 2,
+ 2, 4, 6,
+ 4, 5, 6,
+ 6, 5, 7,
+ 3, 7, 1,
+ 1, 7, 5,
+ 2, 6, 3,
+ 3, 6, 7,
+ 0, 1, 4,
+ 4, 1, 5
+};
+static const unsigned all_defined_properties[36] =
+{
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0,
+ 0, 1, 0
+};
+
+static void
+test(const int convention)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ unsigned medium, expected_external_medium, expected_internal_medium;
+ unsigned gid;
+ enum senc3d_side side;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned i, t, ecount;
+ const int conv_front = (convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Geometry with no media information on both sides */
+ ctx.positions = front_unspecified_vertices;
+ ctx.indices = front_unspecified_triangles;
+ ctx.properties = front_unspecified_properties;
+ OK(senc3d_scene_create(dev, convention, front_unspecified_triangles_count,
+ get_indices, get_media_from_properties, front_unspecified_vertices_count,
+ get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 2);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc3d_enclosure* ee;
+ struct senc3d_enclosure_header hh;
+ unsigned cc;
+ OK(senc3d_scene_get_enclosure(scn, i, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == i);
+ CHK(header.enclosed_media_count == 1);
+
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &medium));
+ /* Geometrical normals point outside the cube in input triangles:
+ * if convention is front, front medium (unspecified) is outside,
+ * that is medium 0's enclosure is infinite */
+ expected_external_medium = conv_front ? SENC3D_UNSPECIFIED_MEDIUM : 1;
+ expected_internal_medium = conv_front ? 1 : SENC3D_UNSPECIFIED_MEDIUM;
+
+ CHK(medium == (header.is_infinite
+ ? expected_external_medium : expected_internal_medium));
+ CHK(header.primitives_count == ntriangles);
+ CHK(header.unique_primitives_count == ntriangles);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == (i == 0));
+
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, medium, &cc));
+ CHK(cc == 1);
+ OK(senc3d_scene_get_enclosure_by_medium(scn, medium, 0, &ee));
+ OK(senc3d_enclosure_get_header(ee, &hh));
+ CHK(header.enclosure_id == hh.enclosure_id);
+ OK(senc3d_enclosure_ref_put(ee));
+
+ FOR_EACH(t, 0, header.primitives_count) {
+ unsigned ind[3];
+ OK(senc3d_enclosure_get_triangle_id(enclosure, t, &gid, &side));
+ CHK(gid == t);
+ CHK(side == (medium == 1) ? SENC3D_BACK : SENC3D_FRONT);
+ OK(senc3d_enclosure_get_triangle(enclosure, t, ind));
+ }
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Same geometry, front media are defined for odd triangles */
+ ctx.positions = front_half_unspecified_vertices;
+ ctx.indices = front_half_unspecified_triangles;
+ ctx.properties = front_half_unspecified_properties;
+ OK(senc3d_scene_create(dev, convention, front_half_unspecified_triangles_count,
+ get_indices, get_media_from_properties, front_half_unspecified_vertices_count,
+ get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 2);
+
+ FOR_EACH(i, 0, ecount) {
+ unsigned expected_external_media_count, expected_internal_media_count,
+ expected_media_count;
+ OK(senc3d_scene_get_enclosure(scn, i, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == i);
+
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &medium));
+ /* Geometrical normals point outside the cube in input triangles:
+ * if convention is front, front medium is outside and the enclosure
+ * contains 2 media */
+ expected_external_media_count = conv_front ? 2 : 1;
+ expected_internal_media_count = conv_front ? 1 : 2;
+ expected_media_count = header.is_infinite
+ ? expected_external_media_count : expected_internal_media_count;
+ CHK(header.enclosed_media_count == expected_media_count);
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+ OK(senc3d_scene_ref_put(scn));
+
+ /* Same geometry, all media are defined */
+ ctx.positions = all_defined_vertices;
+ ctx.indices = all_defined_triangles;
+ ctx.properties = all_defined_properties;
+ OK(senc3d_scene_create(dev, convention, all_defined_triangles_count,
+ get_indices, get_media_from_properties, all_defined_vertices_count,
+ get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_enclosure_count(scn, &ecount));
+ CHK(ecount == 2);
+
+ FOR_EACH(i, 0, ecount) {
+ struct senc3d_enclosure* ee;
+ struct senc3d_enclosure_header hh;
+ unsigned cc;
+ OK(senc3d_scene_get_enclosure(scn, i, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ CHK(header.enclosure_id == i);
+ CHK(header.enclosed_media_count == 1);
+ OK(senc3d_enclosure_get_medium(enclosure, 0, &medium));
+ /* Geometrical normals point outside the cube in input triangles:
+ * if convention is front, front medium (0) is outside,
+ * that is medium 0's enclosure is infinite */
+ CHK(conv_front == ((medium == 0) == header.is_infinite));
+ CHK(header.primitives_count == ntriangles);
+ CHK(header.unique_primitives_count == ntriangles);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == (i == 0));
+
+ OK(senc3d_scene_get_enclosure_count_by_medium(scn, medium, &cc));
+ CHK(cc == 1);
+ OK(senc3d_scene_get_enclosure_by_medium(scn, medium, 0, &ee));
+ OK(senc3d_enclosure_get_header(ee, &hh));
+ CHK(header.enclosure_id == hh.enclosure_id);
+ OK(senc3d_enclosure_ref_put(ee));
+
+ FOR_EACH(t, 0, header.primitives_count) {
+ OK(senc3d_enclosure_get_triangle_id(enclosure, t, &gid, &side));
+ CHK(gid == t);
+ CHK(side == (medium == 1) ? SENC3D_BACK : SENC3D_FRONT);
+ }
+ OK(senc3d_enclosure_ref_put(enclosure));
+ }
+
+ SENC3D(scene_ref_put(scn));
+ SENC3D(device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+}
+
+int
+main(int argc, char** argv)
+{
+ (void) argc, (void) argv;
+ test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_INSIDE);
+ test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_INSIDE);
+ test(SENC3D_CONVENTION_NORMAL_FRONT | SENC3D_CONVENTION_NORMAL_OUTSIDE);
+ test(SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE);
+ return 0;
+}
diff --git a/src/test_senc3d_utils.h b/src/test_senc3d_utils.h
@@ -0,0 +1,271 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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_UTILS_H
+#define TEST_UTILS_H
+
+#include <rsys/rsys.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/double3.h>
+
+#include <stdio.h>
+
+#define OK(Expr) CHK((Expr) == RES_OK)
+#define BA(Expr) CHK((Expr) == RES_BAD_ARG)
+
+/******************************************************************************
+ * Geometry
+ *****************************************************************************/
+/* Distorded cube */
+static const double box_vertices[8/*#vertices*/*3/*#coords per vertex*/] = {
+ 0.1, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 1.0, 0.0,
+ 0.0, 0.0, 1.1,
+ 1.0, 0.0, 1.0,
+ 0.0, 1.0, 1.0,
+ 1.0, 1.1, 1.0
+};
+/* Need a true cube for some tests */
+static const double cube_vertices[8/*#vertices*/ * 3/*#coords per vertex*/] = {
+ 0.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0,
+ 1.0, 0.0, 1.0,
+ 0.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0
+};
+static const unsigned nvertices = sizeof(box_vertices) / sizeof(double[3]);
+STATIC_ASSERT(sizeof(box_vertices) == sizeof(cube_vertices),
+ The_2_geometries_must_have_the_same_number_of_vertices);
+
+/* The following array lists the indices toward the 3D vertices of each
+ * triangle.
+ * ,2---,3 ,2----3
+ * ,' | ,'/| ,'/| \ |
+ * 6----7' / | 6' / | \ | Y
+ * |', | / ,1 | / ,0---,1 |
+ * | ',|/,' |/,' | ,' o--X
+ * 4----5' 4----5' /
+ * Front, right Back, left and Z
+ * and Top faces bottom faces */
+static const unsigned
+box_indices[12/*#triangles*/*3/*#indices per triangle*/] = {
+ 0, 2, 1, 1, 2, 3, /* Front face */
+ 0, 4, 2, 2, 4, 6, /* Left face*/
+ 4, 5, 6, 6, 5, 7, /* Back face */
+ 3, 7, 1, 1, 7, 5, /* Right face */
+ 2, 6, 3, 3, 6, 7, /* Top face */
+ 0, 1, 4, 4, 1, 5 /* Bottom face */
+};
+static const unsigned
+ntriangles = sizeof(box_indices) / (3 * sizeof(*box_indices));
+
+struct context {
+ const double* positions;
+ const unsigned* indices;
+ const unsigned* front_media;
+ const unsigned* back_media;
+ const unsigned* properties;
+ void* custom;
+ double offset[3];
+ double scale;
+ char reverse_vrtx, reverse_med;
+};
+#define CONTEXT_NULL__ {\
+ NULL, NULL, NULL, NULL, NULL, NULL, {0,0,0}, 1, 0, 0\
+}
+
+static const unsigned medium0[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static const unsigned medium1[12] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static const unsigned medium2[12] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
+static const unsigned medium1_3[12] = { 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1 };
+static const unsigned medium1_back0[12] = { 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1 };
+static const unsigned medium1_front0[12] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static INLINE void
+get_indices(const unsigned itri, unsigned ids[3], void* context)
+{
+ const struct context* ctx = context;
+ ASSERT(ids && ctx);
+ ids[0] = ctx->indices[itri * 3 + 0];
+ ids[ctx->reverse_vrtx ? 2 : 1] = ctx->indices[itri * 3 + 1];
+ ids[ctx->reverse_vrtx ? 1 : 2] = ctx->indices[itri * 3 + 2];
+}
+
+static INLINE void
+get_position(const unsigned ivert, double pos[3], void* context)
+{
+ const struct context* ctx = context;
+ ASSERT(pos && ctx);
+ pos[0] = ctx->positions[ivert * 3 + 0] * ctx->scale + ctx->offset[0];
+ pos[1] = ctx->positions[ivert * 3 + 1] * ctx->scale + ctx->offset[1];
+ pos[2] = ctx->positions[ivert * 3 + 2] * ctx->scale + ctx->offset[2];
+}
+
+static INLINE void
+get_media(const unsigned itri, unsigned medium[2], void* context)
+{
+ const struct context* ctx = context;
+ ASSERT(medium && ctx);
+ medium[ctx->reverse_med ? 1 : 0] = ctx->front_media[itri];
+ medium[ctx->reverse_med ? 0 : 1] = ctx->back_media[itri];
+}
+
+static INLINE void
+get_media_from_properties(const unsigned itri, unsigned medium[2], void* context)
+{
+ const struct context* ctx = context;
+ ASSERT(medium && ctx);
+ medium[ctx->reverse_med ? 1 : 0] = ctx->properties[3 * itri + 0];
+ medium[ctx->reverse_med ? 0 : 1] = ctx->properties[3 * itri + 1];
+}
+
+/******************************************************************************
+ * Miscellaneous
+ *****************************************************************************/
+static INLINE void
+dump_global
+ (struct senc3d_scene* scn,
+ const char* name)
+{
+ FILE* stream;
+ unsigned triangles_count, vertices_count, i;
+
+ ASSERT(scn && name);
+
+ OK(senc3d_scene_get_vertices_count(scn, &vertices_count));
+ OK(senc3d_scene_get_triangles_count(scn, &triangles_count));
+
+ stream = fopen(name, "w");
+ CHK(stream);
+ FOR_EACH(i, 0, vertices_count) {
+ double tmp[3];
+ OK(senc3d_scene_get_vertex(scn, i, tmp));
+ fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
+ }
+ FOR_EACH(i, 0, triangles_count) {
+ unsigned indices[3];
+ OK(senc3d_scene_get_triangle(scn, i, indices));
+ fprintf(stream, "f %u %u %u\n",
+ 1 + indices[0], 1 + indices[1], 1 + indices[2]);
+ }
+ fclose(stream);
+}
+
+static INLINE void
+dump_enclosure
+ (struct senc3d_scene* scn,
+ const unsigned enc,
+ const char* name)
+{
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ FILE* stream;
+ unsigned count, i;
+
+ ASSERT(scn && name);
+
+ SENC3D(scene_get_enclosure_count(scn, &count));
+ ASSERT(enc < count);
+ OK(senc3d_scene_get_enclosure(scn, enc, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ stream = fopen(name, "w");
+ CHK(stream);
+ FOR_EACH(i, 0, header.vertices_count) {
+ double tmp[3];
+ OK(senc3d_enclosure_get_vertex(enclosure, i, tmp));
+ fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
+ }
+ FOR_EACH(i, 0, header.primitives_count) {
+ unsigned indices[3];
+ OK(senc3d_enclosure_get_triangle(enclosure, i, indices));
+ fprintf(stream, "f %u %u %u\n",
+ 1+indices[0], 1+indices[1], 1+indices[2]);
+ }
+ OK(senc3d_enclosure_ref_put(enclosure));
+ fclose(stream);
+}
+
+static INLINE void
+check_memory_allocator(struct mem_allocator* allocator)
+{
+ if(MEM_ALLOCATED_SIZE(allocator)) {
+ char dump[1024];
+ MEM_DUMP(allocator, dump, sizeof(dump));
+ fprintf(stderr, "%s\n", dump);
+ FATAL("Memory leaks.\n");
+ }
+}
+
+/******************************************************************************
+ * Check functions
+ *****************************************************************************/
+/* Compare the itri-th triangle of enclosure with a triangle described by trg2 & vertices2 */
+static INLINE void
+cmp_trg
+ (const unsigned itri,
+ const struct senc3d_enclosure* enclosure,
+ const unsigned trg2[3],
+ const double* vertices2,
+ int* trg_eq,
+ int* trg_reversed)
+{
+ unsigned trg1[3];
+ double t1[3][3];
+ double t2[3][3];
+ unsigned trg1_eq[3] = { 3, 3, 3 };
+ unsigned i, j, fst_vrtx = 3;
+
+ ASSERT(enclosure && trg2 && vertices2 && trg_eq && trg_reversed);
+
+ OK(senc3d_enclosure_get_triangle(enclosure, itri, trg1));
+ FOR_EACH(i, 0, 3) {
+ OK(senc3d_enclosure_get_vertex(enclosure, trg1[i], t1[i]));
+ d3_set(t2[i], vertices2 + (3 * trg2[i]));
+ }
+ FOR_EACH(i, 0, 3) {
+ FOR_EACH(j, 0, 3) {
+ if(d3_eq(t1[i], t2[j])) {
+ trg1_eq[i] = j;
+ if(i == 0) fst_vrtx = j;
+ break;
+ }
+ }
+ }
+ FOR_EACH(i, 0, 3) {
+ if(trg1_eq[i] == 3) {
+ *trg_eq = 0;
+ return;
+ }
+ if(trg1_eq[i] == trg1_eq[(i + 1) % 3]
+ || trg1_eq[i] == trg1_eq[(i + 2) % 3]) {
+ *trg_eq = 0;
+ return;
+ }
+ }
+ /* Same 3 vertices */
+ ASSERT(fst_vrtx != 3);
+ *trg_eq = 1;
+
+ *trg_reversed = (trg1_eq[1] != (fst_vrtx + 1) % 3);
+ ASSERT(*trg_reversed != (trg1_eq[1] != (fst_vrtx + 2) % 3));
+}
+
+#endif /* TEST_UTILS_H */
diff --git a/src/test_senc3d_utils2.h b/src/test_senc3d_utils2.h
@@ -0,0 +1,108 @@
+/* Copyright (C) |Meso|Star> 2016-2020 (contact@meso-star.com)
+ *
+ * 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_UTILS2_H
+#define TEST_UTILS2_H
+
+#if !defined(NB_CYL_X) || !defined(NB_CYL_Y) || !defined(NB_CYL_Z) | !defined(NB_CYL)
+#error "Macro definitions are missing"
+#endif
+
+#include "test_senc3d_utils.h"
+
+#include <star/s3dut.h>
+#include <rsys/double3.h>
+
+struct s3dut_context {
+ struct s3dut_mesh_data data;
+ struct context ctx;
+};
+
+static void
+get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context)
+{
+ struct s3dut_context* ctx = context;
+ unsigned s3dut_itri, cyl_idx, v_offset;
+ ASSERT(ids && ctx);
+ ASSERT(itri < NB_CYL * ctx->data.nprimitives);
+ /* Get cyl_idx along with the s3dut vertice index */
+ s3dut_itri = itri % (unsigned)ctx->data.nprimitives;
+ cyl_idx = itri / (unsigned)ctx->data.nprimitives;
+ ASSERT(ctx->data.indices[s3dut_itri * 3 + 0] <= UINT_MAX
+ && ctx->data.indices[s3dut_itri * 3 + 1] <= UINT_MAX
+ && ctx->data.indices[s3dut_itri * 3 + 2] <= UINT_MAX);
+ /* Compute the vertex index in the user numbering
+ * from cyl_idx and s3dut data; vertex related getters
+ * will have to get the s3dut index back */
+ v_offset = cyl_idx * (unsigned)ctx->data.nvertices;
+ ids[0] = v_offset + (unsigned)ctx->data.indices[s3dut_itri * 3 + 0];
+ ids[ctx->ctx.reverse_vrtx ? 2 : 1]
+ = v_offset + (unsigned)ctx->data.indices[s3dut_itri * 3 + 1];
+ ids[ctx->ctx.reverse_vrtx ? 1 : 2]
+ = v_offset + (unsigned)ctx->data.indices[s3dut_itri * 3 + 2];
+}
+
+static void
+get_s3dut_position(const unsigned ivert, double pos[3], void* context)
+{
+ struct s3dut_context* ctx = context;
+ unsigned s3dut_ivert, cyl_idx;
+ int i, j, k;
+ double offset[3], tmp[3];
+ double center_x, center_y, scale, misalignment = 0;
+ ASSERT(pos && ctx);
+ ASSERT(ivert < NB_CYL * ctx->data.nvertices);
+ /* Get cyl_idx and cylinder imbrication along with the s3dut vertice index */
+ s3dut_ivert = ivert % (unsigned)ctx->data.nvertices;
+ cyl_idx = ivert / (unsigned)ctx->data.nvertices;
+ /* k th cylinder of the imbrication at grid position i,j */
+ i = (int)cyl_idx / (NB_CYL_Y * NB_CYL_Z);
+ j = (cyl_idx / NB_CYL_Z) % NB_CYL_Y;
+ k = cyl_idx % NB_CYL_Z;
+ ASSERT(i < NB_CYL_X && j < NB_CYL_Y && k < NB_CYL_Z);
+ ASSERT((unsigned)(i * NB_CYL_Y * NB_CYL_Z + j * NB_CYL_Z + k)
+ * ctx->data.nvertices + s3dut_ivert == ivert);
+ center_x = 2 * (1 + NB_CYL_Z) * (i - NB_CYL_X / 2);
+ center_y = 2 * (1 + NB_CYL_Z) * (j - NB_CYL_Y / 2);
+ /* Compute scale and offset from imbrication */
+ scale = k + 1;
+#ifdef MITIGATE_EMBREE_181
+ /* Mitigate Embree issue #181
+ * We cannot keep perfect alignment of cylinders
+ * or some hits are missed */
+ misalignment = (k % 2) ? -0.01 : +0.01;
+#endif
+ d3(offset, center_x + misalignment, center_y + misalignment, 0);
+ d3_add(pos, d3_muld(tmp, ctx->data.positions + s3dut_ivert * 3, scale),
+ offset);
+}
+
+static void
+get_s3dut_media(const unsigned itri, unsigned medium[2], void* context)
+{
+ struct s3dut_context* ctx = context;
+ unsigned cyl_idx;
+ int k;
+ ASSERT(medium && ctx);
+ ASSERT(itri < NB_CYL * ctx->data.nprimitives);
+ /* Get cyl_idx */
+ cyl_idx = itri / (unsigned)ctx->data.nprimitives;
+ /* k th cylinder of the imbrication at some grid position */
+ k = cyl_idx % NB_CYL_Z;
+ medium[ctx->ctx.reverse_med ? SENC3D_BACK : SENC3D_FRONT] = (unsigned)k;
+ medium[ctx->ctx.reverse_med ? SENC3D_FRONT : SENC3D_BACK] = (unsigned)(k + 1);
+}
+
+#endif /* TEST_UTILS2_H */
diff --git a/src/test_senc_add_n_merge.c b/src/test_senc_add_n_merge.c
@@ -1,205 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "test_senc_utils.h"
-
-/* Manage add_geometry behaviour */
-struct add_geom_ctx {
- unsigned add_cpt, merge_cpt;
- res_T add_res, merge_res;
-};
-
-static res_T
-add_trg
- (const unsigned global_id,
- const unsigned iseg,
- void* context)
-{
- struct context* ctx = context;
- struct add_geom_ctx* add_geom_ctx;
- ASSERT(ctx); (void)global_id; (void)iseg;
- add_geom_ctx = ctx->custom;
- if(add_geom_ctx->add_res == RES_OK) ++add_geom_ctx->add_cpt;
- return add_geom_ctx->add_res;
-}
-
-static res_T
-merge_trg
- (const unsigned global_id,
- const unsigned iseg,
- const int reversed_segment,
- const unsigned triangle_media[2],
- const unsigned merge_media[2],
- void* context)
-{
- struct context* ctx = context;
- struct add_geom_ctx* add_geom_ctx;
- ASSERT(ctx && triangle_media && merge_media);
- (void)global_id; (void)iseg; (void)reversed_segment; (void)triangle_media; (void)merge_media;
- add_geom_ctx = ctx->custom;
- if(add_geom_ctx->merge_res == RES_OK) ++add_geom_ctx->merge_cpt;
- return add_geom_ctx->merge_res;
-}
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct context ctx;
- unsigned i;
- struct add_geom_ctx add_geom_ctx;
- unsigned media[12];
- const int conv = SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE;
- const unsigned media_count = sizeof(media) / sizeof(*media);
- (void)argc; (void)argv;
-
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev));
- OK(senc_scene_create(dev, conv, &scn));
-
- /* A 3D cube.
- * 2 enclosures (inside, outside) sharing the same triangles,
- * but opposite sides */
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = media;
- ctx.back_media = medium1;
- ctx.custom = &add_geom_ctx;
-
- add_geom_ctx.add_cpt = add_geom_ctx.merge_cpt = 0;
- add_geom_ctx.add_res = add_geom_ctx.merge_res = RES_OK;
-
- /* Geometry with no media information on both sides */
- for (i = 0; i < media_count; i++) media[i] = SENC_UNDEFINED_MEDIUM;
- ctx.front_media = media;
- ctx.back_media = media;
-
- /* If add fails, add geometry fails the same way */
- add_geom_ctx.add_res = RES_BAD_ARG;
- BA(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.add_cpt == 0);
- add_geom_ctx.add_res = RES_MEM_ERR;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx) == RES_MEM_ERR);
- CHK(add_geom_ctx.add_cpt == 0);
-
- /* Successful add geometry with add callback */
- add_geom_ctx.add_res = RES_OK;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.add_cpt == media_count);
- CHK(add_geom_ctx.merge_cpt == 0);
-
- /* Clear scene */
- SENC(scene_ref_put(scn));
- OK(senc_scene_create(dev, conv, &scn));
-
- /* Successful add geometry without add callback */
- add_geom_ctx.add_cpt = 0;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, NULL, merge_trg, &ctx));
- CHK(add_geom_ctx.add_cpt == 0);
- CHK(add_geom_ctx.merge_cpt == 0);
-
- /* If merge fails, add geometry fails the same way */
- add_geom_ctx.merge_res = RES_BAD_ARG;
- BA(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.merge_cpt == 0);
- add_geom_ctx.merge_res = RES_MEM_ERR;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx) == RES_MEM_ERR);
- CHK(add_geom_ctx.merge_cpt == 0);
-
- /* Successful add geometry without merge callback */
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, NULL, &ctx));
- CHK(add_geom_ctx.merge_cpt == 0);
-
- /* Successful add geometry with merge callback */
- add_geom_ctx.merge_res = RES_OK;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.merge_cpt == media_count);
- add_geom_ctx.merge_cpt = 0;
-
- /* Geometry with media information on both sides */
- ctx.front_media = medium0;
- ctx.back_media = medium1;
-
- /* Clear scene */
- SENC(scene_ref_put(scn));
- OK(senc_scene_create(dev, conv, &scn));
-
- /* Successful add geometry with add callback */
- add_geom_ctx.add_res = RES_OK;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.add_cpt == media_count);
- CHK(add_geom_ctx.merge_cpt == 0);
- add_geom_ctx.add_cpt = 0;
-
- /* Clear scene */
- SENC(scene_ref_put(scn));
- OK(senc_scene_create(dev, conv, &scn));
-
- /* Successful add geometry with add callback */
- add_geom_ctx.add_res = RES_OK;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.add_cpt == media_count);
- CHK(add_geom_ctx.merge_cpt == 0);
- add_geom_ctx.add_cpt = 0;
-
- /* Successful add geometry with merge callback */
- add_geom_ctx.merge_res = RES_OK;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.merge_cpt == media_count);
- add_geom_ctx.merge_cpt = 0;
-
- /* Geometry with incompatible media information on both sides */
- ctx.front_media = medium1;
- ctx.back_media = medium0;
-
- /* Unsuccessful add geometry without merge callback */
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, NULL, &ctx));
- CHK(add_geom_ctx.merge_cpt == 0);
-
- /* Successful add geometry with merge callback */
- add_geom_ctx.merge_res = RES_OK;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- CHK(add_geom_ctx.merge_cpt == media_count);
- add_geom_ctx.merge_cpt = 0;
-
- SENC(scene_ref_put(scn));
- SENC(device_ref_put(dev));
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-
- return 0;
-}
diff --git a/src/test_senc_cube_behind_cube.c b/src/test_senc_cube_behind_cube.c
@@ -1,119 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct context ctx;
- unsigned i, ecount, maxm;
- (void)argc, (void)argv;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create
- (NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
-
- /* Create the scene */
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = medium0;
- ctx.back_media = medium1;
-
- /* First cube */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- /* +Z from the first cube,
- * big enough to prevent rays from the first cube to miss this one */
- d3(ctx.offset, -2, -2, 20);
- ctx.scale = 5;
-
- /* Second cube */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 3);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- ASSERT(header.enclosed_media_count == 1);
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- }
-
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(maxm == 1);
- check_desc(desc);
-
- /* Even further in +Z, even bigger */
- d3(ctx.offset, -3, -3, 30);
- ctx.scale = 7;
- /* Front/back media have been exchanged: external enclosure shows 2 media */
- ctx.front_media = medium1;
- ctx.back_media = medium0;
-
- /* Third cube */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
- desc = NULL;
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 4);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- ASSERT(header.enclosed_media_count == (header.is_infinite ? 2u : 1u));
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- }
-
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(maxm == 1);
- check_desc(desc);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
- return 0;
-}
diff --git a/src/test_senc_cube_in_cube.c b/src/test_senc_cube_in_cube.c
@@ -1,116 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct context ctx;
- unsigned i, ecount, maxm;
- (void)argc, (void)argv;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create
- (NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
-
- /* Create the scene */
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- /* Smallest cube exterior is medium 0 */
- ctx.front_media = medium0;
- /* Smallest cube interior is medium 1 */
- ctx.back_media = medium1;
-
- /* First cube */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- d3(ctx.offset, -1, -1, -1);
- ctx.scale = 3;
- /* Bigger cube exterior is medium 1 */
- /* Bigger cube interior is medium 0 */
- ctx.reverse_vrtx = 1;
-
- /* Second cube */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 3);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- ASSERT(header.enclosed_media_count == 1);
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- }
-
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(maxm == 1);
- check_desc(desc);
-
- d3(ctx.offset, -4, -4, -4);
- ctx.scale = 10;
- ctx.reverse_vrtx = 1;
- ctx.reverse_med = 1;
- /* Biggest cube exterior is medium 1 */
- ctx.front_media = medium1;
- /* Biggest cube interior is medium 0
- * interior/exterior media have been exchanged: external enclosure shows 2 media */
- ctx.back_media = medium0;
-
- /* Third cube */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
- desc = NULL;
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 4);
-
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(maxm == 1);
- check_desc(desc);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
- return 0;
-}
diff --git a/src/test_senc_cube_on_cube.c b/src/test_senc_cube_on_cube.c
@@ -1,131 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#define _POSIX_C_SOURCE 200112L /* snprintf */
-
-#include "senc.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-
-#include <stdio.h>
-
-/*
- Z
- ^
-4 | +-----------------------+
- | | 3
-3 | | +-----+ |
- | m2 | m1 | m0 2 |
- | | | | |
-2 | | +-----+ |
- | | | m0 1 |
- | | | | |
-1 | | +-----+ |
- | | |
-0 - +-----------------------+
-
- |--------------------------> X / Y
- 0 1 2 3 4
-*/
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct context ctx;
- unsigned count, i;
- (void)argc, (void)argv;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create
- (NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
-
- /* Create the scene */
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- ctx.positions = cube_vertices; /* Need true cubes for cubes #1 and #2 */
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 1, 1, 2);
- /* Small cube #1 exterior is medium 1,
- * except for the top face where it is 0 */
- ctx.front_media = medium1_front0;
- /* Smallest cube interior is medium 0 */
- ctx.back_media = medium0;
-
- /* Add cube #1 */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- d3(ctx.offset, 1, 1, 1);
- ctx.scale = 1;
- /* Small cube #2 exterior is medium 1,
- * except for the bottom face where it is 0 */
- ctx.front_media = medium1_back0;
- /* Smallest cube interior is medium 0 */
- ctx.back_media = medium0;
-
- /* Add cube #2 (has a duplicate face with cube #1) */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- ctx.positions = box_vertices; /* Can use distorded cube for cube #3 */
- d3(ctx.offset, 0, 0, 0);
- ctx.scale = 4;
- ctx.reverse_vrtx = 1;
- ctx.reverse_med = 1;
- /* Big cube #3 exterior is medium 2 */
- ctx.front_media = medium2;
- /* Big cube #3 interior is medium 1 */
- ctx.back_media = medium1;
-
- /* Add cube #3 */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
- CHK(count == 4);
-
- CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
- CHK(count == 20);
-
- CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
- CHK(count == 34);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
- FOR_EACH(i, 0, count) {
- char name[128];
- snprintf(name, sizeof(name), "test_cube_on_cube_%u.obj", i);
- dump_enclosure(desc, i, name);
- }
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
- return 0;
-}
diff --git a/src/test_senc_descriptor.c b/src/test_senc_descriptor.c
@@ -1,238 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <rsys/float3.h>
-#include <rsys/double3.h>
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_descriptor* desc = NULL;
- struct senc_enclosure* enc = NULL;
- struct context ctx;
- unsigned count, maxm;
- unsigned indices[3];
- double coord[3];
- unsigned media[2];
- unsigned enclosures[2];
- (void)argc, (void)argv;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- /* A 3D cube */
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = medium0;
- ctx.back_media = medium1;
-
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_ref_get(desc) == RES_OK);
- CHK(senc_descriptor_ref_get(NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_ref_put(NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- CHK(senc_descriptor_get_max_medium(NULL, &maxm) == RES_BAD_ARG);
- CHK(senc_descriptor_get_max_medium(desc, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_max_medium(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
-
- CHK(maxm == 1);
-
- CHK(senc_descriptor_get_enclosure_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count(desc, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
-
- CHK(count == 2);
-
- CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 0, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 9, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 9, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 0, &count) == RES_OK);
-
- CHK(count == 1);
-
- CHK(senc_descriptor_get_enclosure(NULL, 0, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(desc, 9, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(desc, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(NULL, 9, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(desc, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(NULL, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(desc, 0, &enc) == RES_OK);
-
- CHK(senc_enclosure_ref_put(enc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 9, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 0, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 9, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 0, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 9, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 0, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 9, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 9, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK);
-
- CHK(senc_descriptor_get_global_vertices_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_vertices_count(desc, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
- CHK(count == nvertices);
-
- CHK(senc_descriptor_get_global_triangles_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangles_count(desc, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
- CHK(count == ntriangles);
-
- CHK(senc_descriptor_get_global_triangle(NULL, 0, indices) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle(NULL, ntriangles, indices)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle(desc, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle(desc, 0, indices) == RES_OK);
- CHK(indices[0] == box_indices[0]
- && indices[1] == box_indices[1]
- && indices[2] == box_indices[2]);
-
- CHK(senc_descriptor_get_global_vertex(NULL, 0, coord) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_vertex(NULL, nvertices, coord)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_vertex(desc, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_vertex(desc, 0, coord) == RES_OK);
- CHK(coord[0] == box_vertices[0]
- && coord[1] == box_vertices[1]
- && coord[2] == box_vertices[2]);
-
- CHK(senc_descriptor_get_global_triangle_media(NULL, 0, media)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_media(NULL, nvertices, media)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_media(desc, 0, NULL)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_media(desc, 0, media) == RES_OK);
- CHK(media[0] == ctx.front_media[0]
- && media[1] == ctx.back_media[1]);
-
- CHK(senc_descriptor_get_global_triangle_enclosures(
- NULL, 0, enclosures) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_enclosures(
- NULL, nvertices, enclosures) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_enclosures(desc, 0, NULL)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_enclosures(desc, 0, enclosures)
- == RES_OK);
- CHK(enclosures[0] == 0 && enclosures[1] == 1);
-
- CHK(senc_descriptor_get_global_triangle_global_id(NULL, 0, indices)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_global_id(NULL, nvertices, indices)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_global_id(desc, 0, NULL)
- == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_global_id(desc, 0, indices)
- == RES_OK);
- /* No duplicates: user id is unique vertex id */
- CHK(indices[0] == 0);
-
- /* Add valid duplicate geometry */
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
- desc = NULL;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
- /* Duplicate vertices have been replaced */
- CHK(count == nvertices);
-
- CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
- /* Duplicate triangles have been replaced */
- CHK(count == ntriangles);
-
- /* Add invalid duplicate geometry */
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
- desc = NULL;
- ctx.front_media = medium1;
- ctx.back_media = medium0;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
- desc = NULL;
- CHK(senc_enclosure_ref_put(enc) == RES_OK);
-
- /* Same cube with a hole (last triangle is missing) */
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn)
- == RES_OK);
-
- CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_frontier_segments_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segments_count(desc, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segments_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segments_count(desc, &count) == RES_OK);
-
- CHK(senc_descriptor_get_frontier_segment(NULL, count, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(desc, count, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(NULL, count, indices) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(desc, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(desc, count, indices) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(NULL, 0, indices) == RES_BAD_ARG);
- CHK(senc_descriptor_get_frontier_segment(desc, 0, indices) == RES_OK);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-
- return 0;
-}
diff --git a/src/test_senc_device.c b/src/test_senc_device.c
@@ -1,77 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <rsys/logger.h>
-
-static INLINE void
-log_stream(const char* msg, void* ctx)
-{
- ASSERT(msg);
- (void)msg, (void)ctx;
- printf("%s\n", msg);
-}
-
-int
-main(int argc, char** argv)
-{
- struct logger logger;
- struct mem_allocator allocator;
- struct senc_device* dev;
- (void)argc, (void)argv;
-
- CHK(senc_device_create(NULL, NULL, 0, 0, NULL) == RES_BAD_ARG);
- CHK(senc_device_create(NULL, NULL, 0, 0, &dev) == RES_BAD_ARG);
- CHK(senc_device_create(NULL, NULL, 1, 0, &dev) == RES_OK);
- CHK(senc_device_ref_get(NULL) == RES_BAD_ARG);
- CHK(senc_device_ref_get(dev) == RES_OK);
- CHK(senc_device_ref_put(NULL) == RES_BAD_ARG);
- CHK(senc_device_ref_put(dev) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)
- == RES_OK);
-
- CHK(MEM_ALLOCATED_SIZE(&allocator) == 0);
- CHK(senc_device_create(NULL, &allocator, 1, 0, NULL) == RES_BAD_ARG);
- CHK(senc_device_create(NULL, &allocator, 1, 0, &dev) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- CHK(MEM_ALLOCATED_SIZE(&allocator) == 0);
-
- CHK(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);
-
- CHK(senc_device_create(&logger, NULL, 1, 0, NULL) == RES_BAD_ARG);
- CHK(senc_device_create(&logger, NULL, 1, 0, &dev) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
-
- CHK(senc_device_create(&logger, &allocator, 1, 0, NULL) == RES_BAD_ARG);
- CHK(senc_device_create(&logger, &allocator, 1, 0, &dev) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
-
- CHK(senc_device_create
- (&logger, &allocator, SENC_NTHREADS_DEFAULT, 0, &dev) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
-
- logger_release(&logger);
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
- return 0;
-}
diff --git a/src/test_senc_enclosure.c b/src/test_senc_enclosure.c
@@ -1,291 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "senc_s3d_wrapper.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-
-#include <star/s3d.h>
-
-static void
-test(const int convention)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_enclosure* enclosures[2] = { NULL, NULL };
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- struct s3d_device* s3d = NULL;
- struct s3d_scene* s3d_scn = NULL;
- struct s3d_shape* s3d_shp = NULL;
- struct s3d_vertex_data s3d_attribs;
- unsigned indices[2][3];
- unsigned medium;
- unsigned gid;
- enum senc_side side;
- double vrtx[3];
- struct context ctx;
- unsigned i, n, t, ecount;
- int conv;
- const int conv_front = (convention & SENC_CONVENTION_NORMAL_FRONT) != 0;
- const int conv_in = (convention & SENC_CONVENTION_NORMAL_INSIDE) != 0;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
- CHK(senc_scene_create(dev, convention, &scn) == RES_OK);
-
- CHK(senc_scene_get_convention(scn, &conv) == RES_OK);
- CHK(conv == convention);
-
- s3d_attribs.type = S3D_FLOAT3;
- s3d_attribs.usage = S3D_POSITION;
- s3d_attribs.get = senc_enclosure_get_vertex__;
-
- CHK(s3d_device_create(NULL, &allocator, 0, &s3d) == RES_OK);
-
- CHK(s3d_scene_create(s3d, &s3d_scn) == RES_OK);
-
- /* A 3D cube.
- * 2 enclosures (inside, outside) sharing the same triangles,
- * but opposite sides */
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = medium0;
- ctx.back_media = medium1;
-
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 2);
-
- CHK(senc_descriptor_get_enclosure(desc, 0, &enclosure) == RES_OK);
- CHK(senc_enclosure_ref_get(NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_ref_get(enclosure) == RES_OK);
- CHK(senc_enclosure_ref_put(NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
-
- CHK(senc_enclosure_get_triangle(NULL, 0, indices[0]) == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(enclosure, ntriangles, indices[0])
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(enclosure, 0, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(NULL, ntriangles, indices[0])
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(enclosure, ntriangles, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(NULL, ntriangles, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle(enclosure, 0, indices[0]) == RES_OK);
-
- CHK(senc_enclosure_get_vertex(NULL, 0, vrtx) == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(enclosure, nvertices, vrtx)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(enclosure, 0, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(NULL, nvertices, vrtx) == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(enclosure, nvertices, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(NULL, nvertices, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_vertex(enclosure, 0, vrtx) == RES_OK);
-
- CHK(senc_enclosure_get_triangle_global_id(NULL, 0, &gid, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, &gid, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, NULL, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, &gid, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, 0, NULL, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, NULL, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, NULL, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, &gid, NULL)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, 0, &gid, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, &gid, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, NULL, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, &gid, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, 0, NULL, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, NULL, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, NULL, &side)
- == RES_BAD_ARG);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, &gid, &side)
- == RES_OK);
-
- CHK(senc_enclosure_get_medium(NULL, 0, &medium) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(enclosure, 2, &medium) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(enclosure, 0, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(NULL, 2, &medium) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(enclosure, 2, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(NULL, 2, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_medium(enclosure, 0, &medium) == RES_OK);
-
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
-
- FOR_EACH(i, 0, ecount) {
- CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
-
- CHK(senc_enclosure_get_header(NULL, &header) == RES_BAD_ARG);
- CHK(senc_enclosure_get_header(enclosure, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_header(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
-
- CHK(header.enclosure_id == i);
- CHK(header.enclosed_media_count == 1);
- CHK(senc_enclosure_get_medium(enclosure, 0, &medium) == RES_OK);
- /* Geometrical normals point outside the cube in input triangles:
- * if convention is front, front medium (0) is outside,
- * that is medium 0's enclosure is infinite */
- CHK(conv_front == ((medium == 0) == header.is_infinite));
- CHK(header.triangle_count == ntriangles);
- CHK(header.unique_triangle_count == ntriangles);
- CHK(header.vertices_count == nvertices);
- CHK(header.is_infinite == (i == 0));
-
- FOR_EACH(t, 0, header.triangle_count) {
- CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side) == RES_OK);
- CHK(gid == t);
- CHK(side == (medium == 0) ? SENC_FRONT : SENC_BACK);
- }
-
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- }
-
- FOR_EACH(i, 0, 2)
- CHK(senc_descriptor_get_enclosure(desc, i, enclosures + i) == RES_OK);
- FOR_EACH(n, 0, ntriangles) {
- int same, reversed;
- /* Read same triangles in both enclosures */
- FOR_EACH(i, 0, 2)
- CHK(senc_enclosure_get_triangle(enclosures[i], n, indices[i]) == RES_OK);
- /* Same triangles and opposite sides for the 2 enclosures */
- FOR_EACH(i, 0, 3) CHK(indices[0][i] == indices[1][2 - i]);
- /* Enclosure 0 is outside (and contains medium 0 if convention is front).
- * Geometrical normals in output data point in the same direction that those
- * of input triangles for enclosure 0 iff convention is inside.
- * The opposite holds for enclosure 1. */
- cmp_trg(n, enclosures[0], box_indices + 3 * n, box_vertices, &same, &reversed);
- CHK((same && !reversed) == conv_in);
- cmp_trg(n, enclosures[1], box_indices + 3 * n, box_vertices, &same, &reversed);
- CHK(same && reversed == conv_in);
- }
- FOR_EACH(i, 0, 2)
- CHK(senc_enclosure_ref_put(enclosures[i]) == RES_OK);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- /* Same 3D cube, but with a hole (incomplete).
- * 1 single enclosure including both sides of triangles */
-
- CHK(senc_scene_create(dev, convention, &scn) == RES_OK);
-
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = medium0;
- ctx.back_media = medium1;
-
- CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 1);
-
- dump_enclosure(desc, 0, "test_enclosure_hole.obj");
-
- CHK(senc_descriptor_get_enclosure(desc, 0, &enclosure) == RES_OK);
-
- CHK(senc_enclosure_get_header(NULL, &header) == RES_BAD_ARG);
- CHK(senc_enclosure_get_header(enclosure, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_header(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
-
- CHK(header.enclosure_id == 0);
- CHK(header.enclosed_media_count == 2);
- CHK(header.triangle_count == 2 * header.unique_triangle_count);
- CHK(header.unique_triangle_count == ntriangles - 1);
- CHK(header.vertices_count == nvertices);
- CHK(header.is_infinite == 1);
-
- FOR_EACH(t, 0, header.triangle_count) {
- CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side) == RES_OK);
- /* The first unique_triangle_count triangles of an enclosure
- * are unique triangles */
- if(t < header.unique_triangle_count) CHK(gid == t);
- CHK(side == (t < header.unique_triangle_count) ? SENC_FRONT : SENC_BACK);
- }
-
- FOR_EACH(n, 0, header.unique_triangle_count) {
- /* Put geometry in a 3D view */
- CHK(s3d_shape_create_mesh(s3d, &s3d_shp) == RES_OK);
-
- CHK(s3d_mesh_setup_indexed_vertices(s3d_shp, header.triangle_count,
- senc_enclosure_get_triangle__, header.vertices_count, &s3d_attribs,
- 1, enclosure)
- == RES_OK);
-
- CHK(s3d_scene_attach_shape(s3d_scn, s3d_shp) == RES_OK);
- S3D(shape_ref_put(s3d_shp));
- }
-
- S3D(device_ref_put(s3d));
- S3D(scene_ref_put(s3d_scn));
-
- SENC(scene_ref_put(scn));
- SENC(device_ref_put(dev));
- SENC(descriptor_ref_put(desc));
- SENC(enclosure_ref_put(enclosure));
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-}
-
-int
-main(int argc, char** argv)
-{
- (void) argc, (void) argv;
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE);
- return 0;
-}
diff --git a/src/test_senc_inconsistant_cube.c b/src/test_senc_inconsistant_cube.c
@@ -1,154 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "senc_s3d_wrapper.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-
-/* The following array lists the indices toward the 3D vertices of each
-* triangle.
-* ,6---,7 ,6----7
-* ,' | ,'/| ,' | \ | Y Z
-* 2----3' / | 2', | \ | | ,'
-* |', | / ,5 | ',4---,5 0----X
-* | ',|/,' | ,' | ,'
-* 0----1' 0----1'
-* Front, right Back, left and
-* and Top faces bottom faces */
-/* Triangle #1 rotation order is not consistant with other triangles */
-static unsigned
-inconsistant_box_indices[12/*#triangles*/ * 3/*#indices per triangle*/] = {
- 0, 1, 2, 1, 2, 3, /* Front face */
- 0, 4, 2, 2, 4, 6, /* Left face*/
- 4, 5, 6, 6, 5, 7, /* Back face */
- 3, 7, 1, 1, 7, 5, /* Right face */
- 2, 6, 3, 3, 6, 7, /* Top face */
- 0, 1, 4, 4, 1, 5 /* Bottom face */
-};
-static const unsigned inconsistant_box_ntriangles
-= sizeof(inconsistant_box_indices) / (3 * sizeof(*inconsistant_box_indices));
-
-/* Media definitions reflect triangle #1 inconsistancy */
-static const unsigned
-inconsistant_medium_front[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-static const unsigned
-inconsistant_medium_back[12] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static void
-test(const int convention)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- int conv;
- int conv_front, conv_in;
- struct context ctx;
- unsigned i, e, ecount;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
- CHK(senc_scene_create(dev, convention, &scn) == RES_OK);
-
- /* A 3D cube.
- * 2 enclosures (inside, outside) sharing the same triangles,
- * but opposite sides.
- * What differs in this test is that triangle #0 vertices are given
- * in the opposite rotation order. */
- ctx.positions = box_vertices;
- ctx.indices = inconsistant_box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = inconsistant_medium_front;
- ctx.back_media = inconsistant_medium_back;
-
- CHK(senc_scene_add_geometry(scn, inconsistant_box_ntriangles, get_indices,
- get_media, nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- CHK(ecount == 2);
-
- CHK(senc_scene_get_convention(scn, &conv) == RES_OK);
- CHK(conv == convention);
- conv_front = (conv & SENC_CONVENTION_NORMAL_FRONT) != 0;
- conv_in = (conv & SENC_CONVENTION_NORMAL_INSIDE) != 0;
-
- FOR_EACH(e, 0, ecount) {
- unsigned medium, expected_external_medium, expected_medium;
- char name[128];
- enum senc_side side, expected_side;
- unsigned gid;
- CHK(senc_descriptor_get_enclosure(desc, e, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- CHK(header.enclosed_media_count == 1);
- CHK(senc_enclosure_get_medium(enclosure, 0, &medium) == RES_OK);
- /* If NORMAL_FRONT the external enclosure's medium should be 0,
- * 1 if NORMAL_BACK */
- expected_external_medium = conv_front ? 0 : 1;
- expected_medium = (header.is_infinite ?
- expected_external_medium : !expected_external_medium);
- CHK(medium == expected_medium);
-
- sprintf(name, "test_inconsistant_cube_%s_%s_%u.obj",
- conv_front ? "front" : "back", conv_in ? "in" : "out", e);
- dump_enclosure(desc, e, name);
-
- FOR_EACH(i, 0, header.triangle_count) {
- int same, reversed, fst_reversed;
- fst_reversed = ((e == 0) == conv_in);
- expected_side = (inconsistant_medium_front[i] == expected_medium)
- ? SENC_FRONT : SENC_BACK;
- cmp_trg(i, enclosure,
- inconsistant_box_indices + (3 * i), box_vertices,
- &same, &reversed);
- /* Should be made of the same triangles */
- CHK(same);
- CHK(i ? reversed != fst_reversed : reversed == fst_reversed);
- CHK(senc_enclosure_get_triangle_global_id(enclosure, i, &gid, &side) == RES_OK);
- CHK(side == expected_side);
- }
- SENC(enclosure_ref_put(enclosure));
- }
-
- SENC(scene_ref_put(scn));
- SENC(device_ref_put(dev));
- SENC(descriptor_ref_put(desc));
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-}
-
-int main(int argc, char** argv)
-{
- (void) argc, (void) argv;
-
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE);
-
- return 0;
-}
diff --git a/src/test_senc_many_enclosures.c b/src/test_senc_many_enclosures.c
@@ -1,174 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <star/s3dut.h>
-#include <rsys/double3.h>
-#include <rsys/clock_time.h>
-
-#include <limits.h>
-
-struct s3dut_context {
- struct s3dut_mesh_data data;
- struct context ctx;
-};
-
-static void
-get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context)
-{
- struct s3dut_context* ctx = context;
- ASSERT(ids && ctx);
- ASSERT(itri < ctx->data.nprimitives);
- ASSERT(ctx->data.indices[itri * 3 + 0] < UINT_MAX
- && ctx->data.indices[itri * 3 + 1] < UINT_MAX
- && ctx->data.indices[itri * 3 + 2] < UINT_MAX);
- ids[0] = (unsigned)ctx->data.indices[itri * 3 + 0];
- ids[ctx->ctx.reverse_vrtx ? 2 : 1] = (unsigned)ctx->data.indices[itri * 3 + 1];
- ids[ctx->ctx.reverse_vrtx ? 1 : 2] = (unsigned)ctx->data.indices[itri * 3 + 2];
-}
-
-static void
-get_s3dut_position(const unsigned ivert, double pos[3], void* context)
-{
- struct s3dut_context* ctx = context;
- ASSERT(pos && ctx);
- ASSERT(ivert < ctx->data.nvertices);
- pos[0]
- = ctx->data.positions[ivert * 3 + 0] * ctx->ctx.scale + ctx->ctx.offset[0];
- pos[1]
- = ctx->data.positions[ivert * 3 + 1] * ctx->ctx.scale + ctx->ctx.offset[1];
- pos[2]
- = ctx->data.positions[ivert * 3 + 2] * ctx->ctx.scale + ctx->ctx.offset[2];
-}
-
-static void
-get_s3dut_media(const unsigned itri, unsigned medium[2], void* context)
-{
- struct s3dut_context* ctx = context;
- (void)itri;
- ASSERT(medium && ctx);
- medium[ctx->ctx.reverse_med ? 1 : 0] = *ctx->ctx.front_media;
- medium[ctx->ctx.reverse_med ? 0 : 1] = *ctx->ctx.back_media;
-}
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct s3dut_mesh* cyl = NULL;
- struct s3dut_context ctx;
- unsigned m_in, m_out;
- unsigned count;
- unsigned cyl_trg_count, cyl_vrtx_count, e;
- int i, j, k;
- char dump[64];
- struct time t0, t1;
- (void)argc, (void)argv;
-
- CHK(mem_init_regular_allocator(&allocator) == RES_OK);
- CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
-#define NB_CYL_1 64
- /* 64^3 = 262144 cylinders */
-#define NB_CYL (NB_CYL_1 * NB_CYL_1 * NB_CYL_1)
- /* Create the scene */
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- ctx.ctx.positions = NULL;
- ctx.ctx.indices = NULL;
- ctx.ctx.reverse_vrtx = 0;
- ctx.ctx.reverse_med = 0;
- ctx.ctx.front_media = &m_in;
- ctx.ctx.back_media = &m_out;
- /* A 20 triangles 12 vertices cylinder template */
- S3DUT(create_cylinder(&allocator, 1, 1, 5, 1, &cyl));
- S3DUT(mesh_get_data(cyl, &ctx.data));
- ASSERT(ctx.data.nprimitives < UINT_MAX);
- ASSERT(ctx.data.nvertices < UINT_MAX);
- cyl_trg_count = (unsigned)ctx.data.nprimitives;
- cyl_vrtx_count = (unsigned)ctx.data.nvertices;
- CHK(senc_scene_reserve(scn, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)
- == RES_OK);
- FOR_EACH(i, 0, NB_CYL_1) {
- double center_x = 2 * (1 + NB_CYL_1) * (i - NB_CYL_1 / 2);
- FOR_EACH(j, 0, NB_CYL_1) {
- double misalignment = 0.01;
- FOR_EACH(k, 0, NB_CYL_1) {
- double center_y = 2 * (1 + NB_CYL_1) * (j - NB_CYL_1 / 2);
- m_in = (unsigned)k;
- m_out = (unsigned)(k + 1);
- ctx.ctx.scale = k + 1;
- /* Mitigate Embree issue #181
- * We cannot keep perfect alignment of cylinders
- * or some hits are missed */
- misalignment *= -1;
- d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0);
- CHK(senc_scene_add_geometry(scn, cyl_trg_count, get_s3dut_indices,
- get_s3dut_media, cyl_vrtx_count, get_s3dut_position, NULL, NULL, &ctx)
- == RES_OK);
- }
- }
- }
- S3DUT(mesh_ref_put(cyl));
-
- time_current(&t0);
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
- time_sub(&t0, time_current(&t1), &t0);
- time_dump(&t0, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump));
- printf("Scene analyzed in: %s\n", dump);
-
- /* dump_global(desc, "test_many_enclosures.obj"); */
-
- CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
- CHK(count == NB_CYL * cyl_vrtx_count);
- CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
- CHK(count == NB_CYL * cyl_trg_count);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
- CHK(count == 1 + NB_CYL);
-
- FOR_EACH(e, 0, count) {
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- unsigned m;
- CHK(senc_descriptor_get_enclosure(desc, e, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- CHK(header.enclosed_media_count == 1);
- CHK(senc_enclosure_get_medium(enclosure, 0, &m) == RES_OK);
- CHK(header.triangle_count ==
- (header.is_infinite /* Outermost enclosure: NB_CYL_1*NB_CYL_1 cylinders */
- ? NB_CYL_1 * NB_CYL_1 * cyl_trg_count
- : (m == 0
- ? cyl_trg_count /* Innermost enclosures: 1 cylinder */
- : 2 * cyl_trg_count))); /* Other enclosures: 2 cylinders */
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- }
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_regular_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
- return 0;
-}
diff --git a/src/test_senc_many_triangles.c b/src/test_senc_many_triangles.c
@@ -1,151 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <star/s3dut.h>
-#include <rsys/double3.h>
-#include <rsys/clock_time.h>
-
-#include <limits.h>
-
-struct s3dut_context {
- struct s3dut_mesh_data data;
- struct context ctx;
-};
-
-static void
-get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context)
-{
- struct s3dut_context* ctx = context;
- ASSERT(ids && ctx);
- ASSERT(itri < ctx->data.nprimitives);
- ASSERT(ctx->data.indices[itri * 3 + 0] < UINT_MAX
- && ctx->data.indices[itri * 3 + 1] < UINT_MAX
- && ctx->data.indices[itri * 3 + 2] < UINT_MAX);
- ids[0] = (unsigned)ctx->data.indices[itri * 3 + 0];
- ids[ctx->ctx.reverse_vrtx ? 2 : 1] = (unsigned)ctx->data.indices[itri * 3 + 1];
- ids[ctx->ctx.reverse_vrtx ? 1 : 2] = (unsigned)ctx->data.indices[itri * 3 + 2];
-}
-
-static void
-get_s3dut_position(const unsigned ivert, double pos[3], void* context)
-{
- struct s3dut_context* ctx = context;
- ASSERT(pos && ctx);
- ASSERT(ivert < ctx->data.nvertices);
- pos[0]
- = ctx->data.positions[ivert * 3 + 0] * ctx->ctx.scale + ctx->ctx.offset[0];
- pos[1]
- = ctx->data.positions[ivert * 3 + 1] * ctx->ctx.scale + ctx->ctx.offset[1];
- pos[2]
- = ctx->data.positions[ivert * 3 + 2] * ctx->ctx.scale + ctx->ctx.offset[2];
-}
-
-static void
-get_s3dut_media(const unsigned itri, unsigned medium[2], void* context)
-{
- struct s3dut_context* ctx = context;
- (void)itri;
- ASSERT(medium && ctx);
- medium[ctx->ctx.reverse_med ? 1 : 0] = *ctx->ctx.front_media;
- medium[ctx->ctx.reverse_med ? 0 : 1] = *ctx->ctx.back_media;
-}
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct s3dut_mesh* cyl = NULL;
- struct s3dut_context ctx;
- unsigned m0 = 0, m1;
- unsigned count;
- unsigned cyl_trg_count, cyl_vrtx_count, i;
- char dump[64];
- struct time t0, t1;
- (void)argc, (void)argv;
-
- CHK(mem_init_regular_allocator(&allocator) == RES_OK);
- CHK(senc_device_create (NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
-#define NB_CYL 4
- /* Create the scene */
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- ctx.ctx.positions = NULL;
- ctx.ctx.indices = NULL;
- ctx.ctx.scale = 1;
- ctx.ctx.reverse_vrtx = 0;
- ctx.ctx.reverse_med = 0;
- ctx.ctx.back_media = &m0;
- ctx.ctx.front_media = &m1;
- /* A 2,562,560 triangles 1,281,282 vertices cylinder template */
- S3DUT(create_cylinder(&allocator, 1, 2, 1280, 1000, &cyl));
- S3DUT(mesh_get_data(cyl, &ctx.data));
- ASSERT(ctx.data.nprimitives < UINT_MAX);
- ASSERT(ctx.data.nvertices < UINT_MAX);
- cyl_trg_count = (unsigned)ctx.data.nprimitives;
- cyl_vrtx_count = (unsigned)ctx.data.nvertices;
- CHK(senc_scene_reserve(scn, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)
- == RES_OK);
- FOR_EACH(i, 0, NB_CYL) {
- m1 = i;
- d3(ctx.ctx.offset, 0, 0, i * 10);
- CHK(senc_scene_add_geometry(scn, cyl_trg_count, get_s3dut_indices,
- get_s3dut_media, cyl_vrtx_count, get_s3dut_position, NULL, NULL, &ctx)
- == RES_OK);
- }
- S3DUT(mesh_ref_put(cyl));
-
- time_current(&t0);
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
- time_sub(&t0, time_current(&t1), &t0);
- time_dump(&t0, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump));
- printf("Scene analyzed in: %s\n", dump);
-
- /* dump_global(desc, "test_many_triangles.obj"); */
-
- CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
- CHK(count == NB_CYL * cyl_vrtx_count);
- CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
- CHK(count == NB_CYL * cyl_trg_count);
-
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
- CHK(count == 1 + NB_CYL);
- FOR_EACH(i, 0, count) {
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- CHK(header.triangle_count ==
- i ? cyl_trg_count : NB_CYL * cyl_trg_count);
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- }
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_regular_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
- return 0;
-}
diff --git a/src/test_senc_sample_enclosure.c b/src/test_senc_sample_enclosure.c
@@ -1,140 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "senc_s3d_wrapper.h"
-#include "test_senc_utils.h"
-
-#include <rsys/float3.h>
-#include <rsys/double3.h>
-
-#include <star/s3d.h>
-#include <star/ssp.h>
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_enclosure* enclosure = NULL;
- struct senc_enclosure_header header;
- struct s3d_device* s3d = NULL;
- struct s3d_scene* s3d_scn = NULL;
- struct s3d_scene_view* s3d_view = NULL;
- struct s3d_shape* s3d_shp = NULL;
- struct s3d_primitive prim;
- struct s3d_vertex_data vrtx_get;
- struct ssp_rng* rng;
- struct context ctx;
- int i;
- float st[2];
- (void)argc, (void)argv;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- vrtx_get.type = S3D_FLOAT3;
- vrtx_get.usage = S3D_POSITION;
- vrtx_get.get = senc_enclosure_get_vertex__;
-
- S3D(device_create(NULL, &allocator, 0, &s3d));
-
- S3D(scene_create(s3d, &s3d_scn));
-
- /* A 3D cube, but with a hole (incomplete).
- * 1 single enclosure including both sides of triangles */
-
- ctx.positions = cube_vertices; /* Need a true cube */
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = medium0;
- ctx.back_media = medium0;
-
- CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices,
- get_media, nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_enclosure(desc, 0, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
-
- /* Put enclosure in a 3D view... */
- S3D(shape_create_mesh(s3d, &s3d_shp));
- S3D(mesh_setup_indexed_vertices(s3d_shp, header.triangle_count,
- senc_enclosure_get_triangle__, header.vertices_count, &vrtx_get, 1,
- enclosure));
-
- S3D(scene_attach_shape(s3d_scn, s3d_shp));
-
- S3D(scene_view_create(s3d_scn, S3D_SAMPLE, &s3d_view));
-
- /* ... and sample it. */
- CHK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng) == RES_OK);
- FOR_EACH(i, 0, 10000) {
- struct s3d_attrib attrib;
- int n, c;
- S3D(scene_view_sample(s3d_view,
- ssp_rng_canonical_float(rng),
- ssp_rng_canonical_float(rng),
- ssp_rng_canonical_float(rng),
- &prim, st));
- S3D(primitive_get_attrib(&prim, S3D_POSITION, st, &attrib));
- c = 0;
- FOR_EACH(n, 0, 3)
- if(eq_eps(attrib.value[n], 0, FLT_EPSILON)
- || eq_eps(attrib.value[n], 1, FLT_EPSILON))
- c++;
- CHK(c == 1);
- S3D(primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, st, &attrib));
- c = 0;
- FOR_EACH(n, 0, 3)
- if(eq_eps(attrib.value[n], -1, FLT_EPSILON)
- || eq_eps(attrib.value[n], 1, FLT_EPSILON))
- c++;
- CHK(c == 1);
- c = 0;
- FOR_EACH(n, 0, 3)
- if(eq_eps(attrib.value[n], 0, FLT_EPSILON))
- c++;
- CHK(c == 2);
- }
-
- SENC(enclosure_ref_put(enclosure));
- SENC(scene_ref_put(scn));
- SENC(device_ref_put(dev));
- SENC(descriptor_ref_put(desc));
-
- SSP(rng_ref_put(rng));
-
- S3D(shape_ref_put(s3d_shp));
- S3D(scene_view_ref_put(s3d_view));
- S3D(device_ref_put(s3d));
- S3D(scene_ref_put(s3d_scn));
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-
- return 0;
-}
diff --git a/src/test_senc_scene.c b/src/test_senc_scene.c
@@ -1,286 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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 "senc.h"
-#include "test_senc_utils.h"
-
-#include <rsys/float3.h>
-#include <rsys/double3.h>
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_descriptor* desc = NULL;
- struct senc_enclosure* enc = NULL;
- struct senc_enclosure_header header;
- struct context ctx;
- unsigned medfront[2], medback[2], ind[3];
- double vrtx[3];
- unsigned count, i, maxm;
- int convention;
- (void)argc, (void)argv;
-
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
- == RES_OK);
-
- CHK(senc_scene_create(NULL,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_BAD_ARG);
- CHK(senc_scene_create(dev, 0, &scn) == RES_BAD_ARG);
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, NULL) == RES_BAD_ARG);
- CHK(senc_scene_create(NULL, 0, &scn) == RES_BAD_ARG);
- CHK(senc_scene_create(NULL,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, NULL) == RES_BAD_ARG);
- CHK(senc_scene_create(dev, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_create(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
-
- CHK(senc_scene_reserve(NULL, 0, 0, 0) == RES_BAD_ARG);
- CHK(senc_scene_reserve(scn, 0, 0, 0) == RES_OK);
-
- CHK(senc_scene_get_convention(NULL, &convention) == RES_BAD_ARG);
- CHK(senc_scene_get_convention(scn, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_convention(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_convention(scn, &convention) == RES_OK);
- CHK(convention == (SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE));
-
- CHK(senc_scene_get_triangles_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_scene_get_triangles_count(scn, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_triangles_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_triangles_count(scn, &count) == RES_OK);
- CHK(count == 0);
-
- CHK(senc_scene_get_unique_triangles_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangles_count(scn, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangles_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangles_count(scn, &count) == RES_OK);
- CHK(count == 0);
-
- CHK(senc_scene_get_vertices_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_scene_get_vertices_count(scn, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_vertices_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_vertices_count(scn, &count) == RES_OK);
- CHK(count == 0);
-
- CHK(senc_scene_get_unique_vertices_count(NULL, &count) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertices_count(scn, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertices_count(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertices_count(scn, &count) == RES_OK);
- CHK(count == 0);
-
- CHK(senc_scene_get_unique_sides_without_medium_count(NULL, &count)
- == RES_BAD_ARG);
- CHK(senc_scene_get_unique_sides_without_medium_count(scn, NULL)
- == RES_BAD_ARG);
- CHK(senc_scene_get_unique_sides_without_medium_count(NULL, NULL)
- == RES_BAD_ARG);
- CHK(senc_scene_get_unique_sides_without_medium_count(scn, &count)
- == RES_OK);
- CHK(count == 0);
-
- /* A 3D cube.
- * With this geometry front is inside with NORMAL_BACK convention,
- * outside with NORMAL_FRONT convention */
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = medium0;
- ctx.back_media = medium1;
-
- CHK(senc_scene_add_geometry(NULL, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, 0, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, ntriangles, NULL, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- 0, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, NULL, NULL, NULL, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_get_triangles_count(scn, &count) == RES_OK);
- CHK(count == ntriangles);
- CHK(senc_scene_get_unique_triangles_count(scn, &count) == RES_OK);
- CHK(count == ntriangles);
- CHK(senc_scene_get_vertices_count(scn, &count) == RES_OK);
- CHK(count == nvertices);
- CHK(senc_scene_get_unique_vertices_count(scn, &count) == RES_OK);
- CHK(count == nvertices);
-
- CHK(senc_scene_get_unique_triangle(NULL, 0, ind) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(scn, UINT_MAX, ind) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(scn, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(NULL, UINT_MAX, ind) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(scn, UINT_MAX, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(NULL, UINT_MAX, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle(scn, 0, ind) == RES_OK);
-
- CHK(senc_scene_get_unique_triangle_media(NULL, 0, ind) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(scn, UINT_MAX, ind) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(scn, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(NULL, UINT_MAX, ind) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(scn, UINT_MAX, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(NULL, UINT_MAX, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_triangle_media(scn, 0, ind) == RES_OK);
-
- CHK(senc_scene_get_unique_vertex(NULL, 0, vrtx) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(scn, UINT_MAX, vrtx) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(scn, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(NULL, UINT_MAX, vrtx) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(scn, UINT_MAX, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(NULL, UINT_MAX, NULL) == RES_BAD_ARG);
- CHK(senc_scene_get_unique_vertex(scn, 0, vrtx) == RES_OK);
-
- CHK(senc_scene_analyze(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_analyze(scn, NULL) == RES_BAD_ARG);
- CHK(senc_scene_analyze(NULL, &desc) == RES_BAD_ARG);
- CHK(senc_scene_analyze(NULL, NULL) == RES_BAD_ARG);
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_scene_ref_get(NULL) == RES_BAD_ARG);
- CHK(senc_scene_ref_get(scn) == RES_OK);
- CHK(senc_scene_ref_put(NULL) == RES_BAD_ARG);
- CHK(senc_scene_ref_put(scn) == RES_OK);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
- CHK(senc_scene_get_convention(scn, &convention) == RES_OK);
- CHK(convention == (SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE));
- /* Add the first triangle twice to create a shift in numbering */
- CHK(senc_scene_add_geometry(scn, 1, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
- /* Check that medium 0 is inside */
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK);
- CHK(senc_enclosure_get_header(enc, &header) == RES_OK);
- CHK(!header.is_infinite);
- CHK(senc_enclosure_ref_put(enc) == RES_OK);
-
- FOR_EACH(i, 0, ntriangles) {
- unsigned gid;
- CHK(senc_descriptor_get_global_triangle_global_id(desc, i, &gid) == RES_OK);
- /* Check numbering shift */
- CHK(gid == (i ? i + 1 : 0));
- }
-
- CHK(senc_descriptor_get_global_triangle_media(desc, 0, medback) == RES_OK);
- ctx.front_media = medium1_3;
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
- /* Medium mismatch between neighbour segments, but OK */
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
-
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(maxm == 3);
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 0, &count) == RES_OK);
- CHK(count == 0); /* Medium 0 unused */
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 1, &count) == RES_OK);
- CHK(count == 2); /* Medium 1 used twice */
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 2, &count) == RES_OK);
- CHK(count == 0); /* Medium 2 unused */
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 3, &count) == RES_OK);
- CHK(count == 1); /* Medium 3 used */
- check_desc(desc);
-
- ctx.front_media = medium0;
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
- CHK(senc_scene_create(dev,
- SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
- /* Add the first triangle twice to create a shift in numbering */
- CHK(senc_scene_add_geometry(scn, 1, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
- CHK(senc_scene_analyze(scn, &desc) == RES_OK);
- /* Check that medium 0 is outside */
- CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK);
- CHK(senc_enclosure_get_header(enc, &header) == RES_OK);
- CHK(header.is_infinite);
- CHK(senc_enclosure_ref_put(enc) == RES_OK);
-
- FOR_EACH(i, 0, ntriangles) {
- unsigned gid;
- CHK(senc_descriptor_get_global_triangle_global_id(desc, i, &gid) == RES_OK);
- /* Check numbering shift */
- CHK(gid == (i ? i + 1 : 0));
- }
-
- CHK(senc_descriptor_get_global_triangle_media(desc, 0, medfront) == RES_OK);
- FOR_EACH(i, 0, 2) CHK(medback[i] == medfront[i]);
-
- /* Invalid vertex ID */
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices - 1, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
-
- /* Incoherent medium on a duplicate triangle */
- ctx.back_media = medium1_3;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG);
-
- /* It is OK add geometry after a failed add */
- ctx.back_media = medium1;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- /* Coherent medium on duplicate triangle */
- ctx.back_media = medium1;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- /* Coherent medium on duplicate triangle V2 */
- ctx.reverse_med = 1;
- ctx.front_media = medium1;
- ctx.back_media = medium0;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- /* Coherent medium on duplicate triangle V3 */
- ctx.reverse_med = 0;
- ctx.reverse_vrtx = 1;
- CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx) == RES_OK);
-
- CHK(senc_scene_ref_put(scn) == RES_OK);
- CHK(senc_device_ref_put(dev) == RES_OK);
- CHK(senc_descriptor_ref_put(desc) == RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-
- return 0;
-}
diff --git a/src/test_senc_undefined_medium.c b/src/test_senc_undefined_medium.c
@@ -1,277 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "senc_s3d_wrapper.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-
-static void
-test(const int convention)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- unsigned medium, expected_external_medium, expected_internal_medium;
- unsigned gid;
- enum senc_side side;
- struct context ctx;
- unsigned i, t, ecount, vcount, tcount, scount;
- unsigned media[12];
- unsigned rev_box_indices[sizeof(box_indices) / sizeof(*box_indices)];
- const int conv_front = (convention & SENC_CONVENTION_NORMAL_FRONT) != 0;
-
- /* Create a box with reversed triangles */
- FOR_EACH(i, 0, sizeof(rev_box_indices) / sizeof(*rev_box_indices)) {
- switch (i % 3) {
- case 0: rev_box_indices[i] = box_indices[i]; break;
- case 1: rev_box_indices[i] = box_indices[i + 1]; break;
- case 2: rev_box_indices[i] = box_indices[i - 1]; break;
- }
- }
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev));
-
- OK(senc_scene_create(dev, convention, &scn));
-
- /* A 3D cube.
- * 2 enclosures (inside, outside) sharing the same triangles,
- * but opposite sides */
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = media;
- ctx.back_media = medium1;
-
- /* Can add the same triangles again defined/undefined media in any order */
-
- /* Add geometry with no media information on both sides */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = SENC_UNDEFINED_MEDIUM;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 2 * ntriangles);
-
- /* Add geometry with no media information on the front sides */
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == ntriangles);
-
- /* Analyze with undefined media on the front sides */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_get_enclosure_count(desc, &ecount));
- CHK(ecount == 2);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* ee;
- struct senc_enclosure_header hh;
- unsigned cc;
- OK(senc_descriptor_get_enclosure(desc, i, &enclosure));
- OK(senc_enclosure_get_header(enclosure, &header));
-
- CHK(header.enclosure_id == i);
- CHK(header.enclosed_media_count == 1);
-
- OK(senc_enclosure_get_medium(enclosure, 0, &medium));
- /* Geometrical normals point outside the cube in input triangles:
- * if convention is front, front medium (undef) is outside,
- * that is medium 0's enclosure is infinite */
- expected_external_medium = conv_front ? SENC_UNDEFINED_MEDIUM : 1;
- expected_internal_medium = conv_front ? 1 :SENC_UNDEFINED_MEDIUM;
-
- CHK(medium == (header.is_infinite
- ? expected_external_medium : expected_internal_medium));
- CHK(header.triangle_count == ntriangles);
- CHK(header.unique_triangle_count == ntriangles);
- CHK(header.vertices_count == nvertices);
- CHK(header.is_infinite == (i == 0));
-
- OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc));
- CHK(cc == 1);
- OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee));
- OK(senc_enclosure_get_header(ee, &hh));
- CHK(header.enclosure_id == hh.enclosure_id);
- OK(senc_enclosure_ref_put(ee));
-
- FOR_EACH(t, 0, header.triangle_count) {
- unsigned ind[3];
- OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side));
- CHK(gid == t);
- CHK(side == (medium == 1) ? SENC_BACK :SENC_FRONT);
- OK(senc_enclosure_get_triangle(enclosure, t, ind));
- }
- OK(senc_enclosure_ref_put(enclosure));
- }
- OK(senc_descriptor_ref_put(desc));
-
- /* Same geometry, front media are defined for odd triangles */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = (i % 2) ? 0 : SENC_UNDEFINED_MEDIUM;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == ntriangles / 2);
-
- /* Analyze with undefined media */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_ref_put(desc));
-
- /* Get the deduplicated geometry without (successful) analyze */
- OK(senc_scene_get_unique_vertices_count(scn, &vcount));
- CHK(vcount == nvertices);
- OK(senc_scene_get_unique_triangles_count(scn, &tcount));
- CHK(tcount == ntriangles);
- FOR_EACH(i, 0, tcount) {
- int j;
- unsigned med[2], ids[3];
- OK(senc_scene_get_unique_triangle(scn, i, ids));
- OK(senc_scene_get_unique_triangle_media(scn, i, med));
- CHK(med[0] == ((i % 2) ? 0 : SENC_UNDEFINED_MEDIUM) && med[1] == 1);
- FOR_EACH(j, 0, 3) {
- double pos[3];
- CHK(ids[j] < vcount);
- OK(senc_scene_get_unique_vertex(scn, ids[j], pos));
- }
- }
-
- /* Same information again, using a reversed box */
- ctx.indices = rev_box_indices;
- SWAP(const unsigned*, ctx.front_media, ctx.back_media);
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == ntriangles / 2);
-
- /* Analyze with undefined media */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_ref_put(desc));
-
- /* Define media for remaining triangles, using reversed box */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = (i % 2) ? SENC_UNDEFINED_MEDIUM : 0;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 0);
-
- /* Get the deduplicated geometry without (successful) analyze */
- OK(senc_scene_get_unique_vertices_count(scn, &vcount));
- CHK(vcount == nvertices);
- OK(senc_scene_get_unique_triangles_count(scn, &tcount));
- CHK(tcount == ntriangles);
- FOR_EACH(i, 0, tcount) {
- int j;
- unsigned med[2], ids[3];
- OK(senc_scene_get_unique_triangle(scn, i, ids));
- OK(senc_scene_get_unique_triangle_media(scn, i, med));
- CHK(med[0] == 0 && med[1] == 1);
- FOR_EACH(j, 0, 3) {
- double pos[3];
- CHK(ids[j] < vcount);
- OK(senc_scene_get_unique_vertex(scn, ids[j], pos));
- }
- }
-
- /* Analyze with all media defined */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_ref_put(desc));
-
- /* Define media for all triangles, nothing new here */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = 0;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 0);
-
- /* Define incoherent media for some triangles */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = (i % 2);
- BA(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, NULL, NULL, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 0);
-
- /* Scene is still OK and can be analyzed */
- OK(senc_scene_analyze(scn, &desc));
-
- OK(senc_descriptor_get_global_triangles_count(desc, &tcount));
- CHK(tcount == sizeof(media) / sizeof(*media));
-
- OK(senc_descriptor_get_enclosure_count(desc, &ecount));
- CHK(ecount == 2);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* ee;
- struct senc_enclosure_header hh;
- unsigned cc;
- OK(senc_descriptor_get_enclosure(desc, i, &enclosure));
- OK(senc_enclosure_get_header(enclosure, &header));
-
- CHK(header.enclosure_id == i);
- CHK(header.enclosed_media_count == 1);
- OK(senc_enclosure_get_medium(enclosure, 0, &medium));
- /* Geometrical normals point outside the cube in input triangles:
- * if convention is front, front medium (0) is outside,
- * that is medium 0's enclosure is infinite */
- CHK(conv_front == ((medium == 0) == header.is_infinite));
- CHK(header.triangle_count == ntriangles);
- CHK(header.unique_triangle_count == ntriangles);
- CHK(header.vertices_count == nvertices);
- CHK(header.is_infinite == (i == 0));
-
- OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc));
- CHK(cc == 1);
- OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee));
- OK(senc_enclosure_get_header(ee, &hh));
- CHK(header.enclosure_id == hh.enclosure_id);
- OK(senc_enclosure_ref_put(ee));
-
- FOR_EACH(t, 0, header.triangle_count) {
- OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side));
- CHK(gid == t);
- CHK(side == (medium == 1) ? SENC_BACK : SENC_FRONT);
- }
- OK(senc_enclosure_ref_put(enclosure));
- }
-
- SENC(scene_ref_put(scn));
- SENC(device_ref_put(dev));
- SENC(descriptor_ref_put(desc));
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-}
-
-int
-main(int argc, char** argv)
-{
- (void) argc, (void) argv;
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE);
- return 0;
-}
diff --git a/src/test_senc_undefined_medium_attr.c b/src/test_senc_undefined_medium_attr.c
@@ -1,376 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
-*
-* 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 "senc.h"
-#include "senc_s3d_wrapper.h"
-#include "test_senc_utils.h"
-
-#include <rsys/double3.h>
-#include <limits.h>
-
-#define INVALID_INTFACE_ID UINT_MAX
-
-static FINLINE void
-set_null_id(struct mem_allocator* alloc, unsigned* data)
-{
- ASSERT(data); (void)alloc;
- *data = INVALID_INTFACE_ID;
-}
-
-#include <rsys/dynamic_array.h>
-#define DARRAY_NAME intface_id
-#define DARRAY_FUNCTOR_INIT set_null_id
-#define DARRAY_DATA unsigned
-#include <rsys/dynamic_array.h>
-
-/* Manage interface properties */
-struct merge_ctx {
- struct darray_intface_id global_interf_data;
- const unsigned* current_add_interf_data;
-};
-
-static res_T
-add_trg
- (const unsigned global_id,
- const unsigned itri,
- void* context)
-{
- res_T res = RES_OK;
- struct context* ctx = context;
- struct merge_ctx* merge_ctx;
- unsigned interf;
- ASSERT(ctx);
- merge_ctx = ctx->custom;
- /* Get interface information from ctx */
- interf = merge_ctx->current_add_interf_data[itri];
- /* Keep data */
- res = darray_intface_id_resize(&merge_ctx->global_interf_data, global_id + 1);
- if(res != RES_OK) return res;
- darray_intface_id_data_get(&merge_ctx->global_interf_data)[global_id] = interf;
- return res;
-}
-
-static res_T
-merge_trg
- (const unsigned global_id,
- const unsigned itri,
- const int reversed_triangle,
- const unsigned triangle_media[2],
- const unsigned merge_media[2],
- void* context)
-{
- res_T res = RES_OK;
- struct context* ctx = context;
- struct merge_ctx* merge_ctx;
- int need_merge;
- unsigned interf;
- unsigned* interf_data;
- int i, compat;
- ASSERT(ctx); (void)reversed_triangle;
- /* Check media compatibility */
- compat = 1;
- FOR_EACH(i, 0, 2)
- compat &= (triangle_media[i] == SENC_UNDEFINED_MEDIUM
- || merge_media[i] == SENC_UNDEFINED_MEDIUM
- || triangle_media[i] == merge_media[i]);
- if (!compat) return RES_BAD_ARG;
- merge_ctx = ctx->custom;
- res = darray_intface_id_resize(&merge_ctx->global_interf_data, global_id + 1);
- if(res != RES_OK) return res;
- /* Get interface information from ctx */
- interf = merge_ctx->current_add_interf_data[itri];
-
- interf_data = darray_intface_id_data_get(&merge_ctx->global_interf_data);
-
- need_merge = (interf_data[global_id] != INVALID_INTFACE_ID);
- if(need_merge) {
- if(interf_data[global_id] != interf)
- /* Previous interface id is different: no possible merge */
- return RES_BAD_ARG;
- } else {
- /* Triangle is known, but without interface information: create */
- interf_data[global_id] = interf;
- }
- return RES_OK;
-}
-
-static void
-test(const int convention)
-{
- struct mem_allocator allocator;
- struct senc_descriptor* desc = NULL;
- struct senc_device* dev = NULL;
- struct senc_scene* scn = NULL;
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- unsigned medium, expected_external_medium, expected_internal_medium;
- unsigned gid;
- enum senc_side side;
- struct context ctx;
- unsigned i, t, ecount, vcount, tcount, scount;
- unsigned media[12], interface_ids[12] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
- unsigned rev_box_indices[sizeof(box_indices) / sizeof(*box_indices)];
- struct merge_ctx merge_ctx;
- const int conv_front = (convention & SENC_CONVENTION_NORMAL_FRONT) != 0;
-
- darray_intface_id_init(&allocator, &merge_ctx.global_interf_data);
- merge_ctx.current_add_interf_data = interface_ids;
-
- /* Create a box with reversed triangles */
- FOR_EACH(i, 0, sizeof(rev_box_indices) / sizeof(*rev_box_indices)) {
- switch (i % 3) {
- case 0: rev_box_indices[i] = box_indices[i]; break;
- case 1: rev_box_indices[i] = box_indices[i + 1]; break;
- case 2: rev_box_indices[i] = box_indices[i - 1]; break;
- }
- }
- OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
- OK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev));
-
- OK(senc_scene_create(dev, convention, &scn));
-
- /* A 3D cube.
- * 2 enclosures (inside, outside) sharing the same triangles,
- * but opposite sides */
- ctx.positions = box_vertices;
- ctx.indices = box_indices;
- ctx.scale = 1;
- ctx.reverse_vrtx = 0;
- ctx.reverse_med = 0;
- d3(ctx.offset, 0, 0, 0);
- ctx.front_media = media;
- ctx.back_media = medium1;
- ctx.custom = &merge_ctx;
-
- /* Can add the same triangles again defined/undefined media in any order */
-
- /* Add geometry with no media information on both sides */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = SENC_UNDEFINED_MEDIUM;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 2 * ntriangles);
-
- /* If merge fails, add geometry fails */
- interface_ids[0] = 6;
- BA(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- interface_ids[0] = 0;
-
- /* Add geometry with no media information on the front sides */
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == ntriangles);
-
- /* Analyze with undefined media on the front sides */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_get_enclosure_count(desc, &ecount));
- CHK(ecount == 2);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* ee;
- struct senc_enclosure_header hh;
- unsigned cc;
- OK(senc_descriptor_get_enclosure(desc, i, &enclosure));
- OK(senc_enclosure_get_header(enclosure, &header));
-
- CHK(header.enclosure_id == i);
- CHK(header.enclosed_media_count == 1);
-
- OK(senc_enclosure_get_medium(enclosure, 0, &medium));
- /* Geometrical normals point outside the cube in input triangles:
- * if convention is front, front medium (undef) is outside,
- * that is medium 0's enclosure is infinite */
- expected_external_medium = conv_front ? SENC_UNDEFINED_MEDIUM : 1;
- expected_internal_medium = conv_front ? 1 :SENC_UNDEFINED_MEDIUM;
-
- CHK(medium == (header.is_infinite
- ? expected_external_medium : expected_internal_medium));
- CHK(header.triangle_count == ntriangles);
- CHK(header.unique_triangle_count == ntriangles);
- CHK(header.vertices_count == nvertices);
- CHK(header.is_infinite == (i == 0));
-
- OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc));
- CHK(cc == 1);
- OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee));
- OK(senc_enclosure_get_header(ee, &hh));
- CHK(header.enclosure_id == hh.enclosure_id);
- OK(senc_enclosure_ref_put(ee));
-
- FOR_EACH(t, 0, header.triangle_count) {
- unsigned ind[3];
- OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side));
- CHK(gid == t);
- CHK(side == (medium == 1) ? SENC_BACK : SENC_FRONT);
- OK(senc_enclosure_get_triangle(enclosure, t, ind));
- }
- OK(senc_enclosure_ref_put(enclosure));
- }
- OK(senc_descriptor_ref_put(desc));
-
- /* Same geometry, front media are defined for odd triangles */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = (i % 2) ? 0 : SENC_UNDEFINED_MEDIUM;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == ntriangles / 2);
-
- /* Analyze with undefined media */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_ref_put(desc));
-
- /* Get the deduplicated geometry without (successful) analyze */
- OK(senc_scene_get_unique_vertices_count(scn, &vcount));
- CHK(vcount == nvertices);
- OK(senc_scene_get_unique_triangles_count(scn, &tcount));
- CHK(tcount == ntriangles);
- FOR_EACH(i, 0, tcount) {
- int j;
- unsigned med[2], ids[3];
- OK(senc_scene_get_unique_triangle(scn, i, ids));
- OK(senc_scene_get_unique_triangle_media(scn, i, med));
- CHK(med[0] == ((i % 2) ? 0 : SENC_UNDEFINED_MEDIUM) && med[1] == 1);
- FOR_EACH(j, 0, 3) {
- double pos[3];
- CHK(ids[j] < vcount);
- OK(senc_scene_get_unique_vertex(scn, ids[j], pos));
- }
- }
-
- /* Same information again, using a reversed box */
- ctx.indices = rev_box_indices;
- SWAP(const unsigned*, ctx.front_media, ctx.back_media);
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == ntriangles / 2);
-
- /* Analyze with undefined media */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_ref_put(desc));
-
- /* Define media for remaining triangles, using reversed box */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = (i % 2) ? SENC_UNDEFINED_MEDIUM : 0;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 0);
-
- /* Get the deduplicated geometry without (successful) analyze */
- OK(senc_scene_get_unique_vertices_count(scn, &vcount));
- CHK(vcount == nvertices);
- OK(senc_scene_get_unique_triangles_count(scn, &tcount));
- CHK(tcount == ntriangles);
- FOR_EACH(i, 0, tcount) {
- int j;
- unsigned med[2], ids[3];
- OK(senc_scene_get_unique_triangle(scn, i, ids));
- OK(senc_scene_get_unique_triangle_media(scn, i, med));
- CHK(med[0] == 0 && med[1] == 1);
- FOR_EACH(j, 0, 3) {
- double pos[3];
- CHK(ids[j] < vcount);
- OK(senc_scene_get_unique_vertex(scn, ids[j], pos));
- }
- }
-
- /* Analyze with all media defined */
- OK(senc_scene_analyze(scn, &desc));
- OK(senc_descriptor_ref_put(desc));
-
- /* Define media for all triangles, nothing new here */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = 0;
- OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 0);
-
- /* Define incoherent media for some triangles */
- for(i = 0; i < sizeof(media) / sizeof(*media); i++)
- media[i] = (i % 2);
- BA(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
- nvertices, get_position, add_trg, merge_trg, &ctx));
- OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount));
- CHK(scount == 0);
-
- /* Scene is still OK and can be analyzed */
- OK(senc_scene_analyze(scn, &desc));
-
- OK(senc_descriptor_get_global_triangles_count(desc, &tcount));
- CHK(tcount == sizeof(media) / sizeof(*media));
-
- OK(senc_descriptor_get_enclosure_count(desc, &ecount));
- CHK(ecount == 2);
-
- FOR_EACH(i, 0, ecount) {
- struct senc_enclosure* ee;
- struct senc_enclosure_header hh;
- unsigned cc;
- OK(senc_descriptor_get_enclosure(desc, i, &enclosure));
- OK(senc_enclosure_get_header(enclosure, &header));
-
- CHK(header.enclosure_id == i);
- CHK(header.enclosed_media_count == 1);
- OK(senc_enclosure_get_medium(enclosure, 0, &medium));
- /* Geometrical normals point outside the cube in input triangles:
- * if convention is front, front medium (0) is outside,
- * that is medium 0's enclosure is infinite */
- CHK(conv_front == ((medium == 0) == header.is_infinite));
- CHK(header.triangle_count == ntriangles);
- CHK(header.unique_triangle_count == ntriangles);
- CHK(header.vertices_count == nvertices);
- CHK(header.is_infinite == (i == 0));
-
- OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc));
- CHK(cc == 1);
- OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee));
- OK(senc_enclosure_get_header(ee, &hh));
- CHK(header.enclosure_id == hh.enclosure_id);
- OK(senc_enclosure_ref_put(ee));
-
- FOR_EACH(t, 0, header.triangle_count) {
- OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side));
- CHK(gid == t);
- CHK(side == (medium == 1) ? SENC_BACK : SENC_FRONT);
- }
- OK(senc_enclosure_ref_put(enclosure));
- }
-
- SENC(scene_ref_put(scn));
- SENC(device_ref_put(dev));
- SENC(descriptor_ref_put(desc));
- darray_intface_id_release(&merge_ctx.global_interf_data);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHK(mem_allocated_size() == 0);
-}
-
-int
-main(int argc, char** argv)
-{
- (void) argc, (void) argv;
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE);
- test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE);
- test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE);
- return 0;
-}
diff --git a/src/test_senc_utils.h b/src/test_senc_utils.h
@@ -1,293 +0,0 @@
-/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com)
- *
- * 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_UTILS_H
-#define TEST_UTILS_H
-
-#include <rsys/rsys.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/double3.h>
-
-#include <stdio.h>
-
-#define OK(Expr) CHK((Expr) == RES_OK)
-#define BA(Expr) CHK((Expr) == RES_BAD_ARG)
-
-/*******************************************************************************
- * Geometry
- ******************************************************************************/
-/* Distorded cube */
-static const double box_vertices[8/*#vertices*/*3/*#coords per vertex*/] = {
- 0.1, 0.0, 0.0,
- 1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 1.0, 1.0, 0.0,
- 0.0, 0.0, 1.1,
- 1.0, 0.0, 1.0,
- 0.0, 1.0, 1.0,
- 1.0, 1.1, 1.0
-};
-/* Need a true cube for some tests */
-static const double cube_vertices[8/*#vertices*/ * 3/*#coords per vertex*/] = {
- 0.0, 0.0, 0.0,
- 1.0, 0.0, 0.0,
- 0.0, 1.0, 0.0,
- 1.0, 1.0, 0.0,
- 0.0, 0.0, 1.0,
- 1.0, 0.0, 1.0,
- 0.0, 1.0, 1.0,
- 1.0, 1.0, 1.0
-};
-static const unsigned nvertices = sizeof(box_vertices) / sizeof(double[3]);
-STATIC_ASSERT(sizeof(box_vertices) == sizeof(cube_vertices),
- The_2_geometries_must_have_the_same_number_of_vertices);
-
-/* The following array lists the indices toward the 3D vertices of each
- * triangle.
- * ,2---,3 ,2----3
- * ,' | ,'/| ,'/| \ |
- * 6----7' / | 6' / | \ | Y
- * |', | / ,1 | / ,0---,1 |
- * | ',|/,' |/,' | ,' o--X
- * 4----5' 4----5' /
- * Front, right Back, left and Z
- * and Top faces bottom faces */
-static const unsigned
-box_indices[12/*#triangles*/*3/*#indices per triangle*/] = {
- 0, 2, 1, 1, 2, 3, /* Front face */
- 0, 4, 2, 2, 4, 6, /* Left face*/
- 4, 5, 6, 6, 5, 7, /* Back face */
- 3, 7, 1, 1, 7, 5, /* Right face */
- 2, 6, 3, 3, 6, 7, /* Top face */
- 0, 1, 4, 4, 1, 5 /* Bottom face */
-};
-static const unsigned
-ntriangles = sizeof(box_indices) / (3 * sizeof(*box_indices));
-
-struct context {
- const double* positions;
- const unsigned* indices;
- const unsigned* front_media;
- const unsigned* back_media;
- void* custom;
- double offset[3];
- double scale;
- char reverse_vrtx, reverse_med;
-};
-
-static const unsigned medium0[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-static const unsigned medium1[12] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-static const unsigned medium2[12] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
-static const unsigned medium1_3[12] = { 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1 };
-static const unsigned medium1_back0[12] = { 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1 };
-static const unsigned medium1_front0[12] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-
-static INLINE void
-get_indices(const unsigned itri, unsigned ids[3], void* context)
-{
- const struct context* ctx = context;
- ASSERT(ids && ctx);
- ids[0] = ctx->indices[itri * 3 + 0];
- ids[ctx->reverse_vrtx ? 2 : 1] = ctx->indices[itri * 3 + 1];
- ids[ctx->reverse_vrtx ? 1 : 2] = ctx->indices[itri * 3 + 2];
-}
-
-static INLINE void
-get_position(const unsigned ivert, double pos[3], void* context)
-{
- const struct context* ctx = context;
- ASSERT(pos && ctx);
- pos[0] = ctx->positions[ivert * 3 + 0] * ctx->scale + ctx->offset[0];
- pos[1] = ctx->positions[ivert * 3 + 1] * ctx->scale + ctx->offset[1];
- pos[2] = ctx->positions[ivert * 3 + 2] * ctx->scale + ctx->offset[2];
-}
-
-static INLINE void
-get_media(const unsigned itri, unsigned medium[2], void* context)
-{
- const struct context* ctx = context;
- ASSERT(medium && ctx);
- medium[ctx->reverse_med ? 1 : 0] = ctx->front_media[itri];
- medium[ctx->reverse_med ? 0 : 1] = ctx->back_media[itri];
-}
-
-/*******************************************************************************
- * Miscellaneous
- ******************************************************************************/
-static INLINE void
-dump_global
- (struct senc_descriptor* desc,
- const char* name)
-{
- FILE* stream;
- unsigned triangles_count, vertices_count, i;
-
- ASSERT(desc && name);
-
- CHK(senc_descriptor_get_global_vertices_count(desc, &vertices_count) == RES_OK);
- CHK(senc_descriptor_get_global_triangles_count(desc, &triangles_count) == RES_OK);
-
- stream = fopen(name, "w");
- CHK(stream);
- FOR_EACH(i, 0, vertices_count) {
- double tmp[3];
- CHK(senc_descriptor_get_global_vertex(desc, i, tmp) == RES_OK);
- fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
- }
- FOR_EACH(i, 0, triangles_count) {
- unsigned indices[3];
- CHK(senc_descriptor_get_global_triangle(desc, i, indices) == RES_OK);
- fprintf(stream, "f %lu %lu %lu\n", (unsigned long)(1 + indices[0]),
- (unsigned long)(1 + indices[1]), (unsigned long)(1 + indices[2]));
- }
- fclose(stream);
-}
-
-static INLINE void
-dump_enclosure
- (struct senc_descriptor* desc,
- const unsigned enc,
- const char* name)
-{
- struct senc_enclosure* enclosure;
- struct senc_enclosure_header header;
- FILE* stream;
- unsigned count, i;
-
- ASSERT(desc && name);
-
- SENC(descriptor_get_enclosure_count(desc, &count));
- ASSERT(enc < count);
- CHK(senc_descriptor_get_enclosure(desc, enc, &enclosure) == RES_OK);
- CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
-
- stream = fopen(name, "w");
- CHK(stream);
- FOR_EACH(i, 0, header.vertices_count) {
- double tmp[3];
- CHK(senc_enclosure_get_vertex(enclosure, i, tmp) == RES_OK);
- fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
- }
- FOR_EACH(i, 0, header.triangle_count) {
- unsigned indices[3];
- CHK(senc_enclosure_get_triangle(enclosure, i, indices) == RES_OK);
- fprintf(stream, "f %lu %lu %lu\n", (unsigned long)(1+indices[0]),
- (unsigned long)(1+indices[1]), (unsigned long)(1+indices[2]));
- }
- CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
- fclose(stream);
-}
-
-static INLINE void
-check_memory_allocator(struct mem_allocator* allocator)
-{
- if(MEM_ALLOCATED_SIZE(allocator)) {
- char dump[1024];
- MEM_DUMP(allocator, dump, sizeof(dump));
- fprintf(stderr, "%s\n", dump);
- FATAL("Memory leaks.\n");
- }
-}
-
-/*******************************************************************************
- * Check functions
- ******************************************************************************/
-static INLINE void check_desc(struct senc_descriptor* desc)
-{
- unsigned maxm, ecount, i;
- size_t e_cpt = 0;
- CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
- CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
- for(i = 0; i <= maxm; i++) {
- unsigned j, ecount_bym;
- unsigned found = 0;
- CHK(senc_descriptor_get_enclosure_count_by_medium(desc, i, &ecount_bym) == RES_OK);
- /* Can be 0 if media numbering is not compact */
- FOR_EACH(j, 0, ecount_bym) {
- struct senc_enclosure* enc;
- struct senc_enclosure_header h;
- unsigned k;
- int f = 0;
- CHK(senc_descriptor_get_enclosure_by_medium(desc, i, j, &enc) == RES_OK);
- CHK(senc_enclosure_get_header(enc, &h) == RES_OK);
- ASSERT(h.enclosed_media_count);
- FOR_EACH(k, 0, h.enclosed_media_count) {
- unsigned m;
- CHK(senc_enclosure_get_medium(enc, k, &m) == RES_OK);
- found += (m == i);
- f += (m == i);
- }
- ASSERT(f == 1); /* Single reference expected */
- CHK(senc_enclosure_ref_put(enc) == RES_OK);
- }
- ASSERT(found == ecount_bym); /* All the enclosures enclose medim i */
- e_cpt += ecount_bym;
- }
- ASSERT(e_cpt >= ecount); /* Every enc has been visited at least once */
-}
-
-/* Compare the itri-th triangle of enclosure with a triangle described by trg2 & vertices2 */
-static INLINE void
-cmp_trg
- (const unsigned itri,
- const struct senc_enclosure* enclosure,
- const unsigned trg2[3],
- const double* vertices2,
- int* trg_eq,
- int* trg_reversed)
-{
- unsigned trg1[3];
- double t1[3][3];
- double t2[3][3];
- unsigned trg1_eq[3] = { 3, 3, 3 };
- unsigned i, j, fst_vrtx = 3;
-
- ASSERT(enclosure && trg2 && vertices2 && trg_eq && trg_reversed);
-
- CHK(senc_enclosure_get_triangle(enclosure, itri, trg1) == RES_OK);
- FOR_EACH(i, 0, 3) {
- CHK(senc_enclosure_get_vertex(enclosure, trg1[i], t1[i]) == RES_OK);
- d3_set(t2[i], vertices2 + (3 * trg2[i]));
- }
- FOR_EACH(i, 0, 3) {
- FOR_EACH(j, 0, 3) {
- if(d3_eq(t1[i], t2[j])) {
- trg1_eq[i] = j;
- if(i == 0) fst_vrtx = j;
- break;
- }
- }
- }
- FOR_EACH(i, 0, 3) {
- if(trg1_eq[i] == 3) {
- *trg_eq = 0;
- return;
- }
- if(trg1_eq[i] == trg1_eq[(i + 1) % 3]
- || trg1_eq[i] == trg1_eq[(i + 2) % 3]) {
- *trg_eq = 0;
- return;
- }
- }
- /* Same 3 vertices */
- ASSERT(fst_vrtx != 3);
- *trg_eq = 1;
-
- *trg_reversed = (trg1_eq[1] != (fst_vrtx + 1) % 3);
- ASSERT(*trg_reversed != (trg1_eq[1] != (fst_vrtx + 2) % 3));
-}
-
-#endif /* TEST_UTILS_H */
-