star-enclosures-3d

Extract enclosures from 3D geometry
git clone git://git.meso-star.fr/star-enclosures-3d.git
Log | Files | Refs | README | LICENSE

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:
MREADME.md | 10+++++-----
Mcmake/CMakeLists.txt | 208+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Dsrc/senc.h | 487-------------------------------------------------------------------------------
Asrc/senc3d.h | 365+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_descriptor.c | 157+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_device.c | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_device_c.h | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_enclosure.c | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_enclosure_c.h | 38++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_enclosure_data.h | 233+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_internal_types.h | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_sXd_helper.h | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_scene.c | 327+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_scene_analyze.c | 1382+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_scene_analyze_c.h | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_scene_c.h | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/senc3d_side_range.h | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/sencX3d.h | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/sencX3d_undefs.h | 33+++++++++++++++++++++++++++++++++
Dsrc/senc_descriptor.c | 333-------------------------------------------------------------------------------
Dsrc/senc_descriptor_c.h | 168-------------------------------------------------------------------------------
Dsrc/senc_device.c | 148-------------------------------------------------------------------------------
Dsrc/senc_device_c.h | 71-----------------------------------------------------------------------
Dsrc/senc_enclosure.c | 168-------------------------------------------------------------------------------
Dsrc/senc_enclosure_c.h | 37-------------------------------------
Dsrc/senc_enclosure_data.h | 205-------------------------------------------------------------------------------
Dsrc/senc_internal_types.h | 139-------------------------------------------------------------------------------
Dsrc/senc_s3d_wrapper.h | 80-------------------------------------------------------------------------------
Dsrc/senc_scene.c | 456-------------------------------------------------------------------------------
Dsrc/senc_scene_analyze.c | 1374-------------------------------------------------------------------------------
Dsrc/senc_scene_analyze_c.h | 197-------------------------------------------------------------------------------
Dsrc/senc_scene_c.h | 227-------------------------------------------------------------------------------
Asrc/test_senc3d_cube_behind_cube.c | 311+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_cube_in_cube.c | 314+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_cube_on_cube.c | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_device.c | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_enclosure.c | 248+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_inconsistant_cube.c | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_many_enclosures.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_many_triangles.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_sample_enclosure.c | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_scene.c | 304+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_some_enclosures.c | 3427+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_some_triangles.c | 2737+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_unspecified_medium.c | 327+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_utils.h | 271+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc3d_utils2.h | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_senc_add_n_merge.c | 205-------------------------------------------------------------------------------
Dsrc/test_senc_cube_behind_cube.c | 119-------------------------------------------------------------------------------
Dsrc/test_senc_cube_in_cube.c | 116-------------------------------------------------------------------------------
Dsrc/test_senc_cube_on_cube.c | 131-------------------------------------------------------------------------------
Dsrc/test_senc_descriptor.c | 238-------------------------------------------------------------------------------
Dsrc/test_senc_device.c | 77-----------------------------------------------------------------------------
Dsrc/test_senc_enclosure.c | 291------------------------------------------------------------------------------
Dsrc/test_senc_inconsistant_cube.c | 154-------------------------------------------------------------------------------
Dsrc/test_senc_many_enclosures.c | 174-------------------------------------------------------------------------------
Dsrc/test_senc_many_triangles.c | 151------------------------------------------------------------------------------
Dsrc/test_senc_sample_enclosure.c | 140-------------------------------------------------------------------------------
Dsrc/test_senc_scene.c | 286-------------------------------------------------------------------------------
Dsrc/test_senc_undefined_medium.c | 277-------------------------------------------------------------------------------
Dsrc/test_senc_undefined_medium_attr.c | 376-------------------------------------------------------------------------------
Dsrc/test_senc_utils.h | 293-------------------------------------------------------------------------------
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, &current_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(&current_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(&current_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(&current_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(&current_component); + FOR_EACH(ii, 0, sz) { + side_id_t used_side + = darray_side_id_cdata_get(&current_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(&current_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(&current_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(&current_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(&current_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, &current_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(&current_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(&current_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(&current_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(&current_component); - FOR_EACH(ii, 0, sz) { - side_id_t used_side - = darray_side_id_cdata_get(&current_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(&current_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(&current_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(&current_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(&current_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 */ -