star-geometry-3d

Clean and decorate 3D geometries
git clone git://git.meso-star.fr/star-geometry-3d.git
Log | Files | Refs | README | LICENSE

commit 6592a4000866ce401a86ad528a6da11873266862
parent 1ae0913afb8d9856cfd66397d122245666f328cf
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Wed,  5 Feb 2020 12:33:58 +0100

Rename everything sg3d (from sg3) for coherency reasons

Diffstat:
MREADME.md | 10+++++-----
Mcmake/CMakeLists.txt | 116++++++++++++++++++++++++++++++++++++++++----------------------------------------
Dsrc/sg3.h | 396-------------------------------------------------------------------------------
Dsrc/sg3_device.c | 139-------------------------------------------------------------------------------
Dsrc/sg3_device.h | 57---------------------------------------------------------
Dsrc/sg3_geometry.c | 1088-------------------------------------------------------------------------------
Dsrc/sg3_geometry.h | 279-------------------------------------------------------------------------------
Dsrc/sg3_misc.h | 21---------------------
Dsrc/sg3_s3d_helper.h | 61-------------------------------------------------------------
Dsrc/sg3_senc_helper.h | 76----------------------------------------------------------------------------
Asrc/sg3d.h | 396+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sg3d_device.c | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sg3d_device.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sg3d_geometry.c | 1088+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sg3d_geometry.h | 279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sg3d_misc.h | 21+++++++++++++++++++++
Asrc/sg3d_s3d_helper.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/sg3d_senc_helper.h | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/sgX3.h | 416-------------------------------------------------------------------------------
Asrc/sgX3d.h | 494+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_sg3_cube_behind_cube.c | 118-------------------------------------------------------------------------------
Dsrc/test_sg3_cube_in_cube.c | 111-------------------------------------------------------------------------------
Dsrc/test_sg3_cube_on_cube.c | 102-------------------------------------------------------------------------------
Dsrc/test_sg3_device.c | 75---------------------------------------------------------------------------
Dsrc/test_sg3_geometry.c | 293-------------------------------------------------------------------------------
Dsrc/test_sg3_geometry_2.c | 438-------------------------------------------------------------------------------
Dsrc/test_sg3_many_enclosures.c | 106-------------------------------------------------------------------------------
Dsrc/test_sg3_many_triangles.c | 87-------------------------------------------------------------------------------
Dsrc/test_sg3_some_enclosures.c | 107-------------------------------------------------------------------------------
Dsrc/test_sg3_some_triangles.c | 89-------------------------------------------------------------------------------
Dsrc/test_sg3_unspecified_properties.c | 143-------------------------------------------------------------------------------
Dsrc/test_sg3_utils.h | 150-------------------------------------------------------------------------------
Dsrc/test_sg3_utils2.h | 69---------------------------------------------------------------------
Asrc/test_sg3d_cube_behind_cube.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_cube_in_cube.c | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_cube_on_cube.c | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_device.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_geometry.c | 293+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_geometry_2.c | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_many_enclosures.c | 106+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_many_triangles.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_some_enclosures.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_some_triangles.c | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_unspecified_properties.c | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_utils.h | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_sg3d_utils2.h | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
46 files changed, 4562 insertions(+), 4484 deletions(-)

diff --git a/README.md b/README.md @@ -1,9 +1,9 @@ -Star-geometry -============= +Star-geometry-3d +================ The purpose of this library is to help create clean and decorated 3D geometries. These geometries are suitable to be partitioned into -enclosures using the star-enclosures library. It also provides +enclosures using the star-enclosures-3d library. It also provides mechanisms to construct triangle-related app data, detect inconsistencies and dump the resulting geometry in various formats (OBJ, VTK, C code chunks). @@ -11,7 +11,7 @@ VTK, C code chunks). How to build ------------ -Star-geometry relies on the [CMake](http://www.cmake.org) and the +Star-geometry-3d relies on the [CMake](http://www.cmake.org) and the [RCMake](https://gitlab.com/vaplv/rcmake/) package to build and depends on the [RSys](https://gitlab.com/vaplv/rsys/) library. Some tests also depends on the [SD3UT](https://gitlab.com/meso-star/star-3dut/) @@ -28,7 +28,7 @@ Release notes ### Version 0.1 -First version and implementation of the Star-geometry API. +First version and implementation of the star-geometry-3d API. - Creation of geometries in multiple steps, allowing advanced deduplication and application-data management; diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -14,7 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. cmake_minimum_required(VERSION 3.1) -project(star-geometry C) +project(star-geometry3D C) enable_testing() include(CMakeDependentOption) @@ -64,31 +64,31 @@ set(VERSION_MINOR 1) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) -set(SG3_FILES_SRC - sg3_device.c - sg3_geometry.c +set(SG3D_FILES_SRC + sg3d_device.c + sg3d_geometry.c ) -set(SG3_FILES_INC_API - sg3.h - sg3_s3d_helper.h - sg3_senc_helper.h - sgX3.h +set(SG3D_FILES_INC_API + sg3d.h + sg3d_s3d_helper.h + sg3d_senc_helper.h + sgX3d.h ) -set(SG3_FILES_INC - sg3_device.h - sg3_geometry.h - sg3_misc.h +set(SG3D_FILES_INC + sg3d_device.h + sg3d_geometry.h + sg3d_misc.h ) -set(SG3_FILES_DOC COPYING README.md) +set(SG3D_FILES_DOC COPYING README.md) # Prepend each file by `STAR_GEOM_SOURCE_DIR' -rcmake_prepend_path(SG3_FILES_SRC ${STAR_GEOM_SOURCE_DIR}) -rcmake_prepend_path(SG3_FILES_INC ${STAR_GEOM_SOURCE_DIR}) -rcmake_prepend_path(SG3_FILES_INC_API ${STAR_GEOM_SOURCE_DIR}) -rcmake_prepend_path(SG3_FILES_DOC ${PROJECT_SOURCE_DIR}/../) +rcmake_prepend_path(SG3D_FILES_SRC ${STAR_GEOM_SOURCE_DIR}) +rcmake_prepend_path(SG3D_FILES_INC ${STAR_GEOM_SOURCE_DIR}) +rcmake_prepend_path(SG3D_FILES_INC_API ${STAR_GEOM_SOURCE_DIR}) +rcmake_prepend_path(SG3D_FILES_DOC ${PROJECT_SOURCE_DIR}/../) if(CMAKE_COMPILER_IS_GNUCC) set(MATH_LIB m) @@ -98,19 +98,19 @@ if(MSVC) endif() -add_library(sg3 SHARED - ${SG3_FILES_SRC} - ${SG3_FILES_INC} - ${SG3_FILES_INC_API}) -target_link_libraries(sg3 RSys ${MATH_LIB}) +add_library(sg3d SHARED + ${SG3D_FILES_SRC} + ${SG3D_FILES_INC} + ${SG3D_FILES_INC_API}) +target_link_libraries(sg3d RSys ${MATH_LIB}) -set_target_properties(sg3 PROPERTIES - DEFINE_SYMBOL SG3_SHARED_BUILD +set_target_properties(sg3d PROPERTIES + DEFINE_SYMBOL SG3D_SHARED_BUILD VERSION ${VERSION} SOVERSION ${VERSION_MAJOR}) -rcmake_copy_runtime_libraries(sg3) +rcmake_copy_runtime_libraries(sg3d) -rcmake_setup_devel(sg3 StarGeom ${VERSION} star/sg3_version.h) +rcmake_setup_devel(sg3d StarGeom ${VERSION} star/sg3d_version.h) ################################################################################ # Add tests @@ -119,12 +119,12 @@ if(NOT NO_TEST) function(build_test _name) add_executable(${_name} ${STAR_GEOM_SOURCE_DIR}/${_name}.c - ${STAR_GEOM_SOURCE_DIR}/test_sg3_utils.h) + ${STAR_GEOM_SOURCE_DIR}/test_sg3d_utils.h) foreach(other ${ARGN}) target_sources(${_name} PUBLIC ${STAR_GEOM_SOURCE_DIR}/${other}) endforeach() - target_link_libraries(${_name} RSys sg3) + target_link_libraries(${_name} RSys sg3d) endfunction() function(register_test _name) @@ -137,42 +137,42 @@ if(NOT NO_TEST) register_test(${_name} ${_name}) endfunction() - new_test(test_sg3_device) - new_test(test_sg3_geometry) - new_test(test_sg3_geometry_2) + new_test(test_sg3d_device) + new_test(test_sg3d_geometry) + new_test(test_sg3d_geometry_2) - rcmake_copy_runtime_libraries(test_sg3_device) - rcmake_copy_runtime_libraries(test_sg3_geometry) - rcmake_copy_runtime_libraries(test_sg3_geometry_2) + rcmake_copy_runtime_libraries(test_sg3d_device) + rcmake_copy_runtime_libraries(test_sg3d_geometry) + rcmake_copy_runtime_libraries(test_sg3d_geometry_2) if(SMALL_ADDITIONAL_TESTS) - new_test(test_sg3_cube_behind_cube) - new_test(test_sg3_cube_in_cube) - new_test(test_sg3_cube_on_cube) - new_test(test_sg3_some_enclosures test_sg3_utils2.h) - new_test(test_sg3_some_triangles test_sg3_utils2.h) - new_test(test_sg3_unspecified_properties) + new_test(test_sg3d_cube_behind_cube) + new_test(test_sg3d_cube_in_cube) + new_test(test_sg3d_cube_on_cube) + new_test(test_sg3d_some_enclosures test_sg3d_utils2.h) + new_test(test_sg3d_some_triangles test_sg3d_utils2.h) + new_test(test_sg3d_unspecified_properties) - target_link_libraries(test_sg3_some_enclosures Star3DUT) - target_link_libraries(test_sg3_some_triangles Star3DUT) + target_link_libraries(test_sg3d_some_enclosures Star3DUT) + target_link_libraries(test_sg3d_some_triangles Star3DUT) - rcmake_copy_runtime_libraries(test_sg3_cube_behind_cube) - rcmake_copy_runtime_libraries(test_sg3_cube_in_cube) - rcmake_copy_runtime_libraries(test_sg3_cube_on_cube) - rcmake_copy_runtime_libraries(test_sg3_some_enclosures) - rcmake_copy_runtime_libraries(test_sg3_some_triangles) - rcmake_copy_runtime_libraries(test_sg3_unspecified_properties) + rcmake_copy_runtime_libraries(test_sg3d_cube_behind_cube) + rcmake_copy_runtime_libraries(test_sg3d_cube_in_cube) + rcmake_copy_runtime_libraries(test_sg3d_cube_on_cube) + rcmake_copy_runtime_libraries(test_sg3d_some_enclosures) + rcmake_copy_runtime_libraries(test_sg3d_some_triangles) + rcmake_copy_runtime_libraries(test_sg3d_unspecified_properties) endif() if(HUGE_ADDITIONAL_TESTS) - new_test(test_sg3_many_enclosures test_sg3_utils2.h) - new_test(test_sg3_many_triangles test_sg3_utils2.h) + new_test(test_sg3d_many_enclosures test_sg3d_utils2.h) + new_test(test_sg3d_many_triangles test_sg3d_utils2.h) - target_link_libraries(test_sg3_many_enclosures Star3DUT) - target_link_libraries(test_sg3_many_triangles Star3DUT) + target_link_libraries(test_sg3d_many_enclosures Star3DUT) + target_link_libraries(test_sg3d_many_triangles Star3DUT) - rcmake_copy_runtime_libraries(test_sg3_many_enclosures) - rcmake_copy_runtime_libraries(test_sg3_many_triangles) + rcmake_copy_runtime_libraries(test_sg3d_many_enclosures) + rcmake_copy_runtime_libraries(test_sg3d_many_triangles) endif() endif() @@ -180,9 +180,9 @@ endif() ################################################################################ # Define output & install directories ################################################################################ -install(TARGETS sg3 +install(TARGETS sg3d ARCHIVE DESTINATION bin LIBRARY DESTINATION lib RUNTIME DESTINATION bin) -install(FILES ${SG3_FILES_INC_API} DESTINATION include/star) -install(FILES ${SG3_FILES_DOC} DESTINATION share/doc/star-geometry) +install(FILES ${SG3D_FILES_INC_API} DESTINATION include/star) +install(FILES ${SG3D_FILES_DOC} DESTINATION share/doc/star-geometry3D) diff --git a/src/sg3.h b/src/sg3.h @@ -1,396 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 STAR_GEOMETRY_H__ -#define STAR_GEOMETRY_H__ - -#include <rsys/rsys.h> -#include <rsys/dynamic_array_uint.h> - -#include <limits.h> - -/* Library symbol management */ -#if defined(SG3_SHARED_BUILD) - #define SG3_API extern EXPORT_SYM -#elif defined(SG3_STATIC_BUILD) - #define SG3_API extern LOCAL_SYM -#else /* Use shared library */ - #define SG3_API extern IMPORT_SYM -#endif - -/* Helper macro that asserts if the invocation of the star-geometry function - * `Func' returns an error. One should use this macro on star-geometry - * function calls for which no explicit error checking is performed. */ -#ifndef NDEBUG -#define SG3(Func) ASSERT(sg3_ ## Func == RES_OK) -#else -#define SG3(Func) sg3_ ## Func -#endif - -/* Forward declaration of external opaque data types */ -struct logger; -struct mem_allocator; -struct senc_scene; - -/* Forward declaration of the star-geometry opaque data types. These data - * types are ref counted. Once created the caller implicitly owns the created - * data, i.e. its reference counter is set to 1. The sdis_<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 sg3_device; -struct sg3_geometry; - -/****************************************************************************** - * The dimension of the geometry used in the library. - *****************************************************************************/ -#define SG3_GEOMETRY_DIMENSION - -/****************************************************************************** - * A type to list the different user properties attached to triangles. - *****************************************************************************/ -enum sg3_property_type { - SG3_FRONT, - SG3_BACK, - SG3_INTFACE, - SG3_PROP_TYPES_COUNT__ -}; - -/****************************************************************************** - * A type to list the different possible partitions of triangles. - *****************************************************************************/ -enum sg3_obj_dump_content { - SG3_OBJ_DUMP_MERGE_CONFLICTS = BIT(0), - SG3_OBJ_DUMP_PROPERTY_CONFLICTS = BIT(1), - SG3_OBJ_DUMP_VALID_PRIMITIVE = BIT(2), - SG3_OBJ_DUMP_ALL = - SG3_OBJ_DUMP_MERGE_CONFLICTS - | SG3_OBJ_DUMP_PROPERTY_CONFLICTS - | SG3_OBJ_DUMP_VALID_PRIMITIVE -}; - -/****************************************************************************** - * A type to list the different qualifiers of C code variable output. - *****************************************************************************/ -enum sg3_c_dump_qualifiers { - SG3_C_DUMP_CONST = BIT(0), - SG3_C_DUMP_STATIC = BIT(1) -}; - -/****************************************************************************** - * The value that should be used for properties attached to triangles (i.e. - * media or interface) when let unspecified. - * SG3_UNSPECIFIED_PROPERTY can be used for a property that has already been - * defined; in this case the previous value will remain. - *****************************************************************************/ -#define SG3_UNSPECIFIED_PROPERTY UINT_MAX - - /***************************************************************************** - * A type to hold callbacks for sg3_geometry_add. - ****************************************************************************/ -struct sg3_geometry_add_callbacks { - /* User function that provides vertices ids for added triangles */ - void(*get_indices) - (const unsigned itri, unsigned ids[SG3_GEOMETRY_DIMENSION], void* context); - /* User function that provides properties for added triangles */ - void(*get_properties) /* Can be NULL <=> SG3_UNSPECIFIED_PROPERTY used */ - (const unsigned itri, - /* It is OK to have side and interface properties sharing the same IDs, - * i.e. side and interface IDs both starting from 0 */ - unsigned properties[SG3_PROP_TYPES_COUNT__], - void* context); - /* User function that provides coordinates for added vertices */ - void(*get_position) - (const unsigned ivert, double pos[SG3_GEOMETRY_DIMENSION], void* context); - /* Called if the itri_th triangle of the current sg3_geometry_add is a new - * triangle (i.e. not a duplicate) so that the client app can manage its own - * triangle data/properties/attributes. - * If return is not RES_OK, sg3_geometry_add stops immediately and returns - * whatever value add_triangle returned. */ - res_T(*add_triangle) /* Can be NULL */ - (const unsigned unique_id, const unsigned itri, void* context); - /* Called if the itri_th triangle of the current sg3_geometry_add is a - * duplicate of the unique_id_th unique triangle so that the client app can - * merge its own triangle data, rule merge validity, and possibly change the - * recorded properties. - * The reversed_triangle arg indicates if the triangle vertices' order is - * the same it was when the triangle was first added. - * The merge_conflict_status argument can be set to any value. Any non-0 - * value is accounted for a conflict and is kept as-is in dumps, allowing - * different shades of conflict. - * The triangle_properties and merged_properties args contain the involved - * properties. */ - res_T(*merge_triangle) /* Can be NULL */ - (const unsigned unique_id, - const unsigned itri, - const int reversed_triangle, - unsigned triangle_properties[SG3_PROP_TYPES_COUNT__], - const unsigned merged_properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* merge_conflict_status); - /* Called if the itri_th triangle is degenerated. According to the value - * of abort, sg3_geometry_add will stop and return RES_BAD_ARG or continue - * silently. */ - res_T(*degenerated_triangle) /* Can be NULL <=> Drop triangle, don't abort */ - (const unsigned itri, void* context, int* abort); -}; -#define SG3_ADD_CALLBACKS_NULL__ { NULL, NULL, NULL, NULL, NULL, NULL } - -BEGIN_DECLS - -/****************************************************************************** - * A helper function on properties compatibility. - *****************************************************************************/ -static INLINE int -sg3_compatible_property - (const unsigned p1, - const unsigned p2) -{ - if(p1 == SG3_UNSPECIFIED_PROPERTY || p2 == SG3_UNSPECIFIED_PROPERTY) return 1; - return (p1 == p2); -} - -/****************************************************************************** - * star-geometry device. It is an handle toward the star-geometry library. - * It manages the star-geometry resources. - *****************************************************************************/ -SG3_API res_T -sg3_device_create - (struct logger* logger, /* Can be NULL <=> use default logger */ - struct mem_allocator* allocator, /* Can be NULL <=> use default allocator */ - const int verbose, /* Verbosity level */ - struct sg3_device** dev); - -SG3_API res_T -sg3_device_ref_get - (struct sg3_device* dev); - -SG3_API res_T -sg3_device_ref_put - (struct sg3_device* dev); - -/****************************************************************************** - * star-geometry geometry. - * It stores decorated geometry accumulated through calls to sg3_geometry_add, - * information related to this geometry and its creation process, including - * merge conflicts. - *****************************************************************************/ -/* Create a geometry that can be used to accumulate vertices and triangles - * decorated with properties. */ -SG3_API res_T -sg3_geometry_create - (struct sg3_device* dev, - struct sg3_geometry** geometry); - -/* Reserve memory according to anticipated geometry size. */ -SG3_API res_T -sg3_geometry_reserve - (struct sg3_geometry* geometry, - const unsigned vertices_count, - const unsigned triangles_count, - const unsigned properties_count); - -/* Add a new set of 3D vertices and triangles to the geometry; triangles can - * be decorated with 3 properties (front and back media and interface) that can - * be let unspecified using the SG3_UNSPECIFIED_PROPERTY special value. - * Vertices can be duplicates and are silently deduplicated, always valid. - * Triangles can be duplicates, but this can be ruled invalid due to property - * inconsistency. Triangle duplicates are silently deduplicated, even if - * invalid. Consistency is to be understood as the consistency of the - * successive values for the same property across calls of sg3_geometry_add, - * not as the consistency of the values of the 3 properties of a triangle at - * some given time (this question has its own callback (validate) in the - * sg3_geometry_validate_properties API call). - * Duplicate triangles validity is either ruled by the user-provided - * merge_triangle callback, or is just a matter of properties consistency if no - * callback is provided. In either case, sg3_geometry_add never stops - * prematurely nor returns an error code due to a merge conflict. - * - if provided, the callback must return the consistency status using the - * merge_conflict_status int* paramater (0 for consistent; any other value - * for inconsistent, this value being recorded); regardless of - * merge_conflict_status, the callback can change the properties of the - * triangle before the SG3_UNSPECIFIED_PROPERTY overwriting step; - * - if not, a non-SG3_UNSPECIFIED_PROPERTY is only consistent with itself and - * with SG3_UNSPECIFIED_PROPERTY (if inconsistent, merge_conflict_status is - * set to 1 and recorded) ; regardless of merge_conflict_status, a - * non-SG3_UNSPECIFIED_PROPERTY property is never overridden. - * When deduplicating triangles, the first occurence remains (with its - * original index in user world). After consistency being computed, a final - * step consists in rewriting SG3_UNSPECIFIED_PROPERTY properties if the merged - * property is defined. */ -SG3_API res_T -sg3_geometry_add - (struct sg3_geometry* geometry, - const unsigned vertices_count, - const unsigned triangles_count, - const struct sg3_geometry_add_callbacks* callbacks, - void* context); /* Can be NULL */ - -/* Apply a validation callback on each triangle included in this geometry that - * is not already flagged with a merge error. If validate returns a non-RES_OK - * value, the validation stops and returns the same error value; on the other - * hand, validation goes to the end regardless of properties conflicts. - * The properties_conflict_status argument can be set to any value. Any non-0 - * value is accounted for a conflict and is kept as-is in dumps, allowing - * different shades of conflict. - * If validation is processed again, the properties conflict count is reset, - * as well as the properties_conflict_status status of the triangles. */ -SG3_API res_T -sg3_geometry_validate_properties - (struct sg3_geometry* geometry, - res_T(*validate) - (const unsigned itri, - const unsigned properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* properties_conflict_status), - void* context); /* Can be NULL */ - -/* Get the number of unique vertices. */ -SG3_API res_T -sg3_geometry_get_unique_vertices_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Get the ivtx_th vertex. */ -SG3_API res_T -sg3_geometry_get_unique_vertex - (const struct sg3_geometry* geometry, - const unsigned ivtx, - double coord[SG3_GEOMETRY_DIMENSION]); - -/* Get the number of triangles added to the geometry, regardless of unicity. */ -SG3_API res_T -sg3_geometry_get_added_triangles_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Get the number of unique triangles. */ -SG3_API res_T -sg3_geometry_get_unique_triangles_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Get the vertex indices of the itri_th unique triangle. */ -SG3_API res_T -sg3_geometry_get_unique_triangle_vertices - (const struct sg3_geometry* geometry, - const unsigned itri, - unsigned indices[SG3_GEOMETRY_DIMENSION]); - -/* Get the properties of the itri_th unique triangle. */ -SG3_API res_T -sg3_geometry_get_unique_triangle_properties - (const struct sg3_geometry* geometry, - const unsigned itri, - unsigned properties[SG3_PROP_TYPES_COUNT__]); - -/* Get the user ID of the itri_th unique triangle, that is the user world's - * index of the triangle that first created this unique triangle. - * User world index starts at 0 and increases for every triangle that is - * submitted to sg3_geometry_add calls, regardless of duplication or - * sg3_geometry_add failures (non-RES_OK return value). */ -SG3_API res_T -sg3_geometry_get_unique_triangle_user_id - (const struct sg3_geometry* geometry, - const unsigned itri, - unsigned* user_id); - -/* Get the number of triangles with (at least) one unspecified side. */ -SG3_API res_T -sg3_geometry_get_unique_triangles_with_unspecified_side_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Get the number of triangles with unspecified interface. */ -SG3_API res_T -sg3_geometry_get_unique_triangles_with_unspecified_interface_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Get the number of triangles flagged with a merge conflict. */ -SG3_API res_T -sg3_geometry_get_unique_triangles_with_merge_conflict_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Get the number of triangles flagged with a property conflict. Only - * meaningful after sg3_geometry_validate_properties has been called. */ -SG3_API res_T -sg3_geometry_get_unique_triangles_with_properties_conflict_count - (const struct sg3_geometry* geometry, - unsigned* count); - -/* Dump a geometry in the provided stream in the OBJ format. - * The geometry can include conflicts, but cannot be empty. - * The dump is made of the vertices and some triangles, without their - * properties. The dumped triangles are defined by the flags argument, that - * must be ORed enum sg3_obj_dump_content values. - * The dumped triangles are partitioned in the following groups: - * - Valid_triangles - * - Merge_conflicts - * - Property_conflict */ -SG3_API res_T -sg3_geometry_dump_as_obj - (const struct sg3_geometry* geometry, - FILE* stream, - int flags); - -/* Dump a geometry in the provided stream in the VTK ascii format. - * The geometry can include conflicts, but cannot be empty. - * The dump is made of the vertices and triangles, with most of their - * properties: - * - Front_medium (medium ID of the front side, INT_MAX for both unspecified - * and conflicted) - * - Back_medium (medium ID of the back side, INT_MAX for both unspecified and - * conflicted) - * - Interface (interface ID, INT_MAX for both unspecified and conflicted) - * - Merge_conflict (merge conflict status) - * - Property_conflict (property conflict status) - * - Created_at_sg3_geometry_add (rank of the sg3_geometry_add that created the - * triangle) */ -SG3_API res_T -sg3_geometry_dump_as_vtk - (const struct sg3_geometry* geometry, - FILE* stream); - -/* Dump the geometry as C code. - * The geometry cannot be empty and must be conflict-free. - * The C code defines the 3 variables: - * - [static] [const] unsigned <name_prefix>_vertices_count = N1; - * - [static] [const] double <name_prefix>_vertices[<N1>] = { .... }; - * - [static] [const] unsigned <name_prefix>_triangles_count = N2; - * - [static] [const] unsigned <name_prefix>_triangles[<N2>] = { .... }; - * - [static] [const] unsigned <name_prefix>_properties[<N2>] = { .... }; - * Where <N1> is 3 * vertices_count and <N2> is 3 * triangles_count. - * The two qualifiers static and const are output or not according to flags; - * flags must be ORed enum sg3_c_dump_qualifiers values. */ -SG3_API res_T -sg3_geometry_dump_as_c_code - (const struct sg3_geometry* geometry, - FILE* stream, - const char* name_prefix, /* Can be NULL or "" */ - const int flags); - -SG3_API res_T -sg3_geometry_ref_get - (struct sg3_geometry* geometry); - -SG3_API res_T -sg3_geometry_ref_put - (struct sg3_geometry* geometry); - -END_DECLS - -#endif /* STAR_GEOMETRY_H__ */ diff --git a/src/sg3_device.c b/src/sg3_device.c @@ -1,139 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "sg3_device.h" - -#include <rsys/logger.h> -#include <rsys/mem_allocator.h> - -#include <stdarg.h> - - /******************************************************************************* - * Helper functions - ******************************************************************************/ -static void -log_msg - (struct sg3_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 sg3_device* dev; - ASSERT(ref); - dev = CONTAINER_OF(ref, struct sg3_device, ref); - MEM_RM(dev->allocator, dev); -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -sg3_device_create - (struct logger* logger, - struct mem_allocator* mem_allocator, - const int verbose, - struct sg3_device** out_dev) -{ - struct logger* log = NULL; - struct sg3_device* dev = NULL; - struct mem_allocator* allocator = NULL; - res_T res = RES_OK; - - if(!out_dev) { - res = RES_BAD_ARG; - goto error; - } - - log = logger ? logger : LOGGER_DEFAULT; - allocator = mem_allocator ? mem_allocator : &mem_default_allocator; - dev = MEM_CALLOC(allocator, 1, sizeof(struct sg3_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-geometry device.\n", FUNC_NAME) - == RES_OK); - } - res = RES_MEM_ERR; - goto error; - } - dev->logger = log; - dev->allocator = allocator; - dev->verbose = verbose; - ref_init(&dev->ref); - -exit: - if(out_dev) *out_dev = dev; - return res; -error: - if(dev) { - SG3(device_ref_put(dev)); - dev = NULL; - } - goto exit; -} - -res_T -sg3_device_ref_get(struct sg3_device* dev) -{ - if(!dev) return RES_BAD_ARG; - ref_get(&dev->ref); - return RES_OK; -} - -res_T -sg3_device_ref_put(struct sg3_device* dev) -{ - if(!dev) return RES_BAD_ARG; - ref_put(&dev->ref, device_release); - return RES_OK; -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -void -log_err(struct sg3_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 sg3_device* dev, const char* msg, ...) -{ - va_list vargs_list; - ASSERT(dev && msg); - - va_start(vargs_list, msg); - log_msg(dev, LOG_WARNING, msg, vargs_list); - va_end(vargs_list); -} diff --git a/src/sg3_device.h b/src/sg3_device.h @@ -1,57 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3_DEVICE_H__ -#define SG3_DEVICE_H__ - -#include <rsys/ref_count.h> - - /* Forward declaration of external opaque data types */ -struct logger; -struct mem_allocator; - -struct sg3_device { - struct logger* logger; - struct mem_allocator* allocator; - int verbose; - - 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 sg3_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 sg3_device* dev, - const char* msg, - ...) -#ifdef COMPILER_GCC - __attribute((format(printf, 2, 3))) -#endif - ; - -#endif /* SG3_DEVICE_H__ */ diff --git a/src/sg3_geometry.c b/src/sg3_geometry.c @@ -1,1088 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "sg3_geometry.h" -#include "sg3_device.h" - -#include <rsys/double3.h> - -#include <limits.h> - - /******************************************************************************* - * Helper functions - ******************************************************************************/ -static void -geometry_release(ref_T* ref) -{ - struct sg3_geometry* geom; - struct sg3_device* dev; - ASSERT(ref); - geom = CONTAINER_OF(ref, struct sg3_geometry, ref); - dev = geom->dev; - darray_triangle_release(&geom->unique_triangles); - darray_vertex_release(&geom->unique_vertices); - htable_trg_release(&geom->unique_triangles_ids); - htable_vrtx_release(&geom->unique_vertices_ids); - darray_trg_descriptions_release(&geom->trg_descriptions); - MEM_RM(dev->allocator, geom); - SG3(device_ref_put(dev)); -} - -static FINLINE int /* Return 1 if reversed */ -trg_make_key(struct unsigned3* k, const unsigned 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->x[0] = t[0]; - if(t[1] < t[2]) { - k->x[1] = t[1]; - k->x[2] = t[2]; - return 0; - } else { - k->x[1] = t[2]; - k->x[2] = t[1]; - return 1; - } - } else { - k->x[0] = t[1]; - if(t[0] < t[2]) { - k->x[1] = t[0]; - k->x[2] = t[2]; - return 1; - } else { - k->x[1] = t[2]; - k->x[2] = t[0]; - return 0; - } - } - } - else if(t[2] < t[1]) { - k->x[0] = t[2]; - if(t[0] < t[1]) { - k->x[1] = t[0]; - k->x[2] = t[1]; - return 0; - } else { - k->x[1] = t[1]; - k->x[2] = t[0]; - return 1; - } - } else { - k->x[0] = t[1]; - if(t[0] < t[2]) { - k->x[1] = t[0]; - k->x[2] = t[2]; - return 1; - } else { - k->x[1] = t[2]; - k->x[2] = t[0]; - return 0; - } - } -} - -static void -dump_trg_property - (const struct sg3_geometry* geom, - FILE* stream, - const enum sg3_property_type type) -{ - size_t i; - const struct trg_descriptions* descriptions; - ASSERT(geom && stream && type < SG3_PROP_TYPES_COUNT__); - - descriptions - = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); - FOR_EACH(i, 0, darray_triangle_size_get(&geom->unique_triangles)) { - unsigned property = SG3_UNSPECIFIED_PROPERTY; - size_t tdefs_count - = darray_definition_size_get(&descriptions[i].defs[type]); - if(tdefs_count && descriptions[i].property_defined[type]) { - const struct definition* tdefs - = darray_definition_cdata_get(&descriptions[i].defs[type]); - size_t j; - FOR_EACH(j, 0, tdefs_count) { - if(tdefs->property_value != SG3_UNSPECIFIED_PROPERTY) { - property = tdefs->property_value; - break; /* Found the defined value */ - } - tdefs++; /* Next value */ - } - } - /* In VTK dumps INT_MAX is used for both unspecified and conflict */ - fprintf(stream, "%u\n", MMIN(property, INT_MAX)); - } -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -res_T -geometry_register_triangle - (struct sg3_geometry* geom, - const struct triangle* triangle, - const unsigned triangle_unique_id, - const unsigned set_id, - const int merge_conflict) -{ - res_T res = RES_OK; - struct trg_descriptions* trg_d; - int i; - char keep_prop_def[SG3_PROP_TYPES_COUNT__]; - - ASSERT(geom && triangle); - - ERR(geometry_enlarge_trg_descriptions(geom, triangle_unique_id + 1)); - trg_d = (darray_trg_descriptions_data_get(&geom->trg_descriptions) - + triangle_unique_id); - /* Record information */ - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) { - struct darray_definition* definitions; - struct definition* defs; - int done = 0; - size_t j; - keep_prop_def[i] = trg_d->property_defined[i]; - if(triangle->properties[i] == SG3_UNSPECIFIED_PROPERTY) - trg_d->defs_include_unspecified = 1; - else trg_d->property_defined[i] = 1; - definitions = trg_d->defs + i; - defs = darray_definition_data_get(definitions); - FOR_EACH(j, 0, darray_definition_size_get(definitions)) { - if(defs[j].property_value == triangle->properties[i]) { - /* This property_value is already registered: no conflict */ - const unsigned* ids = darray_uint_cdata_get(&defs[j].set_ids); - size_t k; - /* Search if property_value already includes set_id */ - FOR_EACH(k, 0, darray_uint_size_get(&defs[j].set_ids)) { - if(ids[k] == set_id) { - /* Same value+set_id was there already */ - done = 1; - break; - } - } - if(!done) { - /* Need to add the set_id for this property_value */ - ERR(darray_uint_push_back(&defs[j].set_ids, &set_id)); - done = 1; - } - break; - } - } - if(!done) { - /* This property_value was not recorded already */ - size_t defs_sz = darray_definition_size_get(definitions); - struct definition* new_def; - ERR(darray_definition_resize(definitions, 1 + defs_sz)); - new_def = darray_definition_data_get(definitions) + defs_sz; - ERR(darray_uint_push_back(&new_def->set_ids, &set_id)); - new_def->property_value = triangle->properties[i]; - if(!trg_d->merge_conflict && merge_conflict) { - /* If more than 1 merge_conflict occur, the first one remains */ - trg_d->merge_conflict = merge_conflict; - geom->merge_conflict_count++; - } - } - } - - if((!keep_prop_def[SG3_FRONT] || !keep_prop_def[SG3_BACK]) - && trg_d->property_defined[SG3_FRONT] && trg_d->property_defined[SG3_BACK]) - { - /* Both sides are now defined */ - ASSERT(geom->trg_with_unspecified_sides_count > 0); - geom->trg_with_unspecified_sides_count--; - } - - if(!keep_prop_def[SG3_INTFACE] && trg_d->property_defined[SG3_INTFACE]) { - /* Interface is now defined */ - ASSERT(geom->trg_with_unspecified_intface_count > 0); - geom->trg_with_unspecified_intface_count--; - } - -exit: - return res; -error: - goto exit; -} - -res_T -geometry_enlarge_trg_descriptions - (struct sg3_geometry* geom, - const size_t sz) -{ - res_T res = RES_OK; - size_t old_sz = - darray_trg_descriptions_size_get(&geom->trg_descriptions); - if(sz <= old_sz) return RES_OK; - ASSERT(sz - old_sz < UINT_MAX); - ERR(darray_trg_descriptions_resize(&geom->trg_descriptions, sz)); - geom->trg_with_unspecified_sides_count += (unsigned)(sz - old_sz); - geom->trg_with_unspecified_intface_count += (unsigned)(sz - old_sz); - -exit: - return res; -error: - goto exit; -} - -static void -dump_partition - (const struct sg3_geometry* geom, - FILE* stream, - const char* group_name, - enum sg3_obj_dump_content partition) -{ - const struct trg_descriptions* trg_descriptions; - const struct triangle* triangles; - size_t sz, i; - ASSERT(geom && stream && group_name); - ASSERT(partition == SG3_OBJ_DUMP_MERGE_CONFLICTS - || partition == SG3_OBJ_DUMP_PROPERTY_CONFLICTS - || partition == SG3_OBJ_DUMP_VALID_PRIMITIVE); - trg_descriptions - = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); - sz = darray_trg_descriptions_size_get(&geom->trg_descriptions); - triangles = darray_triangle_cdata_get(&geom->unique_triangles); - fprintf(stream, "g %s\n", group_name); - FOR_EACH(i, 0, sz) { - int dump; - if(partition == SG3_OBJ_DUMP_VALID_PRIMITIVE) - dump = !(trg_descriptions[i].merge_conflict - || trg_descriptions[i].properties_conflict); - else if(partition == SG3_OBJ_DUMP_MERGE_CONFLICTS) - dump = trg_descriptions[i].merge_conflict; - else { - ASSERT(partition == SG3_OBJ_DUMP_PROPERTY_CONFLICTS); - dump = trg_descriptions[i].properties_conflict; - } - if(!dump) continue; - fprintf(stream, "f %u %u %u\n", - /* OBJ indexing starts at 1 */ - 1 + triangles[i].vertex_ids[0], - 1 + triangles[i].vertex_ids[1], - 1 + triangles[i].vertex_ids[2]); - } -} - -/******************************************************************************* - * Exported functions - ******************************************************************************/ -res_T -sg3_geometry_create - (struct sg3_device* dev, - struct sg3_geometry** out_geometry) -{ - struct sg3_geometry* geom = NULL; - res_T res = RES_OK; - - if(!dev || !out_geometry) { - res = RES_BAD_ARG; - goto error; - } - - geom = MEM_CALLOC(dev->allocator, 1, sizeof(struct sg3_geometry)); - if(!geom) { - log_err(dev, - "%s: could not allocate the sg3.\n", FUNC_NAME); - res = RES_MEM_ERR; - goto error; - } - - SG3(device_ref_get(dev)); - darray_triangle_init(dev->allocator, &geom->unique_triangles); - darray_vertex_init(dev->allocator, &geom->unique_vertices); - htable_trg_init(dev->allocator, &geom->unique_triangles_ids); - htable_vrtx_init(dev->allocator, &geom->unique_vertices_ids); - darray_trg_descriptions_init(dev->allocator, &geom->trg_descriptions); - geom->triangle_count_including_duplicates = 0; - geom->sides_with_defined_medium_count = 0; - geom->set_id = 0; - geom->trg_with_unspecified_sides_count = 0; - geom->trg_with_unspecified_intface_count = 0; - geom->merge_conflict_count = 0; - geom->properties_conflict_count = 0; - geom->dev = dev; - - ref_init(&geom->ref); - -exit: - if(out_geometry) *out_geometry = geom; - return res; -error: - if(geom) { - SG3(geometry_ref_put(geom)); - geom = NULL; - } - goto exit; -} - -res_T -sg3_geometry_reserve - (struct sg3_geometry* geom, - const unsigned vertices_count, - const unsigned triangles_count, - const unsigned properties_count) -{ - res_T res = RES_OK; - if(!geom) return RES_BAD_ARG; - - ERR(darray_triangle_reserve(&geom->unique_triangles, triangles_count)); - ERR(darray_vertex_reserve(&geom->unique_vertices, vertices_count)); - ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, vertices_count)); - ERR(htable_trg_reserve(&geom->unique_triangles_ids, triangles_count)); - ERR(darray_trg_descriptions_reserve(&geom->trg_descriptions, - properties_count)); - -end: - return res; -error: - goto end; -} - -res_T -sg3_geometry_add - (struct sg3_geometry* geom, - const unsigned nverts, - const unsigned ntris, - const struct sg3_geometry_add_callbacks* callbacks, - void* ctx) /* Can be NULL */ -{ - res_T res = RES_OK; - struct mem_allocator* alloc; - size_t nutris, nuverts; - unsigned i, n_new_uverts = 0, n_new_utris = 0; - struct triangle* trg; - /* Tmp table of IDs to record unique IDs of the currently added vertices */ - struct darray_uint unique_vertice_ids; - int unique_vertice_ids_initialized = 0; - - if(!geom || !callbacks || !callbacks->get_indices || !callbacks->get_position) - { - res = RES_BAD_ARG; - goto error; - } - - alloc = geom->dev->allocator; - nuverts = darray_vertex_size_get(&geom->unique_vertices); - nutris = darray_triangle_size_get(&geom->unique_triangles); - - /* Make room for new geometry; suppose no more duplicates */ - darray_uint_init(alloc, &unique_vertice_ids); - unique_vertice_ids_initialized = 1; - ERR(darray_uint_reserve(&unique_vertice_ids, nverts)); - ERR(darray_vertex_reserve(&geom->unique_vertices, nuverts + nverts)); - ERR(darray_triangle_reserve(&geom->unique_triangles, nutris + ntris)); - ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, nuverts + nverts)); - ERR(htable_trg_reserve(&geom->unique_triangles_ids, nutris + ntris)); - ASSERT(nutris == darray_trg_descriptions_size_get(&geom->trg_descriptions)); - ERR(darray_trg_descriptions_reserve(&geom->trg_descriptions, nutris + ntris)); - /* Get vertices and deduplicate */ - FOR_EACH(i, 0, nverts) { - unsigned* p_vrtx; - struct vertex tmp; - unsigned v_idx; - callbacks->get_position(i, tmp.coord, ctx); - p_vrtx = htable_vrtx_find(&geom->unique_vertices_ids, &tmp); - if(p_vrtx) { - /* Duplicate vertex */ - v_idx = *p_vrtx; - } else { - /* New vertex */ - ASSERT(nuverts + n_new_uverts < UINT_MAX); - v_idx = (unsigned)(nuverts + n_new_uverts); - ASSERT(v_idx == htable_vrtx_size_get(&geom->unique_vertices_ids)); - ERR(darray_vertex_push_back(&geom->unique_vertices, &tmp)); - ERR(htable_vrtx_set(&geom->unique_vertices_ids, &tmp, &v_idx)); - ++n_new_uverts; - } - /* Keep the unique ID for vertex i */ - ERR(darray_uint_push_back(&unique_vertice_ids, &v_idx)); - } - - /* Get triangles and deduplicate */ - trg = darray_triangle_data_get(&geom->unique_triangles); - FOR_EACH(i, 0, ntris) { - int j, reversed; - struct unsigned3 trg_key; - struct triangle tmp = TRG_UNDEF__; - unsigned* p_trg; - struct trg_descriptions* trg_descriptions = NULL; - unsigned unique_id; - - callbacks->get_indices(i, tmp.vertex_ids, ctx); - FOR_EACH(j, 0, 3) { - if(tmp.vertex_ids[j] >= nverts) { - res = RES_BAD_ARG; - goto error; - } - /* Replace the vertex ID by its the unique ID */ - tmp.vertex_ids[j] - = darray_uint_cdata_get(&unique_vertice_ids)[tmp.vertex_ids[j]]; - } - if(tmp.vertex_ids[0] == tmp.vertex_ids[1] - || tmp.vertex_ids[0] == tmp.vertex_ids[2] - || tmp.vertex_ids[1] == tmp.vertex_ids[2]) - { - int abort = 0; - if(callbacks->degenerated_triangle) { - /* Let the client app rule. */ - ERR(callbacks->degenerated_triangle(i, ctx, &abort)); - } else { - log_warn(geom->dev, "%s: triangle %u is degenerated.\n", - FUNC_NAME, i); - } - if(abort) { - res = RES_BAD_ARG; - goto error; - } - else continue; - } - /* Get properties */ - if(callbacks->get_properties) - callbacks->get_properties(i, tmp.properties, ctx); - /* Find duplicate triangles */ - reversed = trg_make_key(&trg_key, tmp.vertex_ids); - p_trg = htable_trg_find(&geom->unique_triangles_ids, &trg_key); - if(p_trg) { - /* Duplicate triangle. Need to check duplicate validity */ - struct unsigned3 utrg_key; - int ureversed = trg_make_key(&utrg_key, trg[*p_trg].vertex_ids); - int same = (reversed == ureversed); - int already_conflict; - ASSERT(trg_key_eq(&trg_key, &utrg_key)); - unique_id = *p_trg; - ERR(geometry_enlarge_trg_descriptions(geom, 1 + unique_id)); - trg_descriptions - = darray_trg_descriptions_data_get(&geom->trg_descriptions); - if(!same) - SWAP(unsigned, tmp.properties[SG3_FRONT], tmp.properties[SG3_BACK]); - already_conflict = trg_descriptions[i].merge_conflict; - if(callbacks->merge_triangle) { - /* Let the client app rule. */ - ERR(callbacks->merge_triangle(*p_trg, i, !same, trg[*p_trg].properties, - tmp.properties, ctx, &trg_descriptions[i].merge_conflict)); - } else { - FOR_EACH(j, 0, SG3_PROP_TYPES_COUNT__) { - if(!sg3_compatible_property(trg[*p_trg].properties[j], - tmp.properties[j])) - { - trg_descriptions[i].merge_conflict = 1; - break; - } - } - } - if(trg_descriptions[i].merge_conflict && !already_conflict) - geom->merge_conflict_count++; - /* Replace SG3_UNSPECIFIED_PROPERTY properties */ - FOR_EACH(j, 0, SG3_PROP_TYPES_COUNT__) { - if(trg[*p_trg].properties[j] == SG3_UNSPECIFIED_PROPERTY - && tmp.properties[j] != SG3_UNSPECIFIED_PROPERTY) { - trg[*p_trg].properties[j] = tmp.properties[j]; - if(j == SG3_FRONT || j == SG3_BACK) - geom->sides_with_defined_medium_count++; - } - } - } else { - /* New triangle */ - ASSERT(nutris + n_new_utris < UINT_MAX); - unique_id = (unsigned)(nutris + n_new_utris); - tmp.user_id = geom->triangle_count_including_duplicates + i; - if(callbacks->add_triangle) - ERR(callbacks->add_triangle(unique_id, i, ctx)); - ERR(geometry_enlarge_trg_descriptions(geom, 1 + unique_id)); - trg_descriptions - = darray_trg_descriptions_data_get(&geom->trg_descriptions); - ERR(darray_triangle_push_back(&geom->unique_triangles, &tmp)); - FOR_EACH(j, 0, SG3_PROP_TYPES_COUNT__) { - if((j == SG3_FRONT || j == SG3_BACK) - && tmp.properties[j] != SG3_UNSPECIFIED_PROPERTY) - geom->sides_with_defined_medium_count++; - } - ASSERT(unique_id == htable_trg_size_get(&geom->unique_triangles_ids)); - ERR(htable_trg_set(&geom->unique_triangles_ids, &trg_key, &unique_id)); - n_new_utris++; - } - ERR(geometry_register_triangle(geom, &tmp, unique_id, geom->set_id, - trg_descriptions[i].properties_conflict)); - if(trg_descriptions[i].properties_conflict) - geom->merge_conflict_count++; - } - - ASSERT(nuverts + n_new_uverts - == htable_vrtx_size_get(&geom->unique_vertices_ids)); - ASSERT(nutris + n_new_utris - == htable_trg_size_get(&geom->unique_triangles_ids)); -exit: - if(geom) { - geom->set_id++; - geom->triangle_count_including_duplicates += ntris; - } - if(unique_vertice_ids_initialized) - darray_uint_release(&unique_vertice_ids); - return res; -error: - goto exit; -} - -res_T -sg3_geometry_validate_properties - (struct sg3_geometry* geom, - res_T(*validate)(const unsigned, const unsigned*, void*, int*), - void* ctx) -{ - size_t sz__; - unsigned i, sz; - struct trg_descriptions* trg_descriptions; - res_T res = RES_OK; - - if(!geom || !validate) { - res = RES_BAD_ARG; - goto error; - } - - sz__ = darray_trg_descriptions_size_get(&geom->trg_descriptions); - ASSERT(sz__ <= UINT_MAX); - sz = (unsigned)sz__; - trg_descriptions - = darray_trg_descriptions_data_get(&geom->trg_descriptions); - geom->properties_conflict_count = 0; /* Reset count */ - FOR_EACH(i, 0, sz) { - unsigned p, j; - unsigned props[SG3_PROP_TYPES_COUNT__]; - struct trg_descriptions* trgd = trg_descriptions + i; - /* Validate only triangle not flagged with merge_conflict */ - if(trgd->merge_conflict) { - trgd->properties_conflict = 0; - continue; - } - /* Get properties for non-conflict triangles */ - FOR_EACH(p, 0, SG3_PROP_TYPES_COUNT__) { - const struct definition* defs = darray_definition_cdata_get(trgd->defs + p); - props[p] = SG3_UNSPECIFIED_PROPERTY; - FOR_EACH(j, 0, darray_definition_size_get(trgd->defs + p)) { - if(defs[j].property_value != SG3_UNSPECIFIED_PROPERTY) { - props[p] = defs[j].property_value; - break; - } - } - } - /* Call vaildation */ - ERR(validate(i, props, ctx, &trgd->properties_conflict)); - if(trgd->properties_conflict) - geom->properties_conflict_count++; - } - -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_vertices_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - size_t sz; - if(!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - sz = darray_vertex_size_get(&geom->unique_vertices); - ASSERT(sz <= UINT_MAX); - *count = (unsigned)sz; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_vertex - (const struct sg3_geometry* geom, - const unsigned ivtx, - double coord[3]) -{ - res_T res = RES_OK; - const struct vertex* vertices; - if(!geom || !coord - || ivtx >= darray_vertex_size_get(&geom->unique_vertices)) - { - res = RES_BAD_ARG; - goto error; - } - vertices = darray_vertex_cdata_get(&geom->unique_vertices); - d3_set(coord, vertices[ivtx].coord); -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_added_triangles_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - if (!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - *count = geom->triangle_count_including_duplicates; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangles_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - size_t sz; - if(!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - sz = darray_triangle_size_get(&geom->unique_triangles); - ASSERT(sz <= UINT_MAX); - *count = (unsigned)sz; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangle_vertices - (const struct sg3_geometry* geom, - const unsigned itri, - unsigned indices[3]) -{ - res_T res = RES_OK; - const struct triangle* triangles; - size_t i; - if(!geom || !indices - || itri >= darray_triangle_size_get(&geom->unique_triangles)) - { - res = RES_BAD_ARG; - goto error; - } - triangles = darray_triangle_cdata_get(&geom->unique_triangles); - FOR_EACH(i, 0, 3) indices[i] = triangles[itri].vertex_ids[i]; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangle_properties - (const struct sg3_geometry* geom, - const unsigned itri, - unsigned properties[SG3_PROP_TYPES_COUNT__]) -{ - res_T res = RES_OK; - const struct triangle* triangles; - size_t i; - if(!geom || !properties - || itri >= darray_triangle_size_get(&geom->unique_triangles)) - { - res = RES_BAD_ARG; - goto error; - } - triangles = darray_triangle_cdata_get(&geom->unique_triangles); - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - properties[i] = triangles[itri].properties[i]; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangle_user_id - (const struct sg3_geometry* geom, - const unsigned itri, - unsigned* user_id) -{ - res_T res = RES_OK; - const struct triangle* triangles; - if(!geom || !user_id - || itri >= darray_triangle_size_get(&geom->unique_triangles)) - { - res = RES_BAD_ARG; - goto error; - } - triangles = darray_triangle_cdata_get(&geom->unique_triangles); - *user_id = triangles[itri].user_id; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangles_with_unspecified_side_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - if(!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - *count = geom->trg_with_unspecified_sides_count; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangles_with_unspecified_interface_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - if(!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - *count = geom->trg_with_unspecified_intface_count; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangles_with_merge_conflict_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - if(!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - *count = geom->merge_conflict_count; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_get_unique_triangles_with_properties_conflict_count - (const struct sg3_geometry* geom, - unsigned* count) -{ - res_T res = RES_OK; - if(!geom || !count) { - res = RES_BAD_ARG; - goto error; - } - *count = geom->properties_conflict_count; -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_dump_as_obj - (const struct sg3_geometry* geom, - FILE* stream, - int flags) -{ - res_T res = RES_OK; - const struct vertex* vertices; - size_t vsz, tsz, i; - if(!geom || !stream || !flags - || !geom->triangle_count_including_duplicates) - { - if(geom && !geom->triangle_count_including_duplicates) - log_err(geom->dev, - "%s: cannot dump empty geometries as OBJ\n", - FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - /* Headers */ - fprintf(stream, "# Dump of star-geometry\n"); - fprintf(stream, "# Geometry counts:\n"); - vsz = darray_vertex_size_get(&geom->unique_vertices); - ASSERT(vsz <= UINT_MAX); - fprintf(stream, "# . %u vertices\n", (unsigned)vsz); - tsz = darray_triangle_size_get(&geom->unique_triangles); - ASSERT(tsz <= UINT_MAX); - fprintf(stream, "# . %u triangles\n", (unsigned)tsz); - fprintf(stream, - "# . %u triangles flagged with a merge conflict\n", - geom->merge_conflict_count); - fprintf(stream, - "# . %u triangles flagged with a property conflict\n", - geom->merge_conflict_count); - - /* Dump vertices */ - vertices = darray_vertex_cdata_get(&geom->unique_vertices); - FOR_EACH(i, 0, vsz) - fprintf(stream, "v %g %g %g\n", SPLIT3(vertices[i].coord)); - - /* Dump triangles by groups */ - dump_partition(geom, stream, "Valid_triangles", SG3_OBJ_DUMP_VALID_PRIMITIVE); - dump_partition(geom, stream, "Merge_conflicts", SG3_OBJ_DUMP_MERGE_CONFLICTS); - dump_partition(geom, stream, "Property_conflicts", SG3_OBJ_DUMP_PROPERTY_CONFLICTS); - -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_dump_as_vtk - (const struct sg3_geometry* geom, - FILE* stream) -{ - res_T res = RES_OK; - const struct vertex* vertices; - const struct triangle* triangles; - const struct trg_descriptions* descriptions; - size_t vsz, tsz, i; - if(!geom || !stream || !geom->triangle_count_including_duplicates) { - if(geom && !geom->triangle_count_including_duplicates) - log_err(geom->dev, - "%s: cannot dump empty geometries as VTK\n", - FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - /* Headers */ - fprintf(stream, "# vtk DataFile Version 3.0\n"); - fprintf(stream, "Dump of star-geometry geometry\n"); - fprintf(stream, "ASCII\n"); - fprintf(stream, "DATASET POLYDATA\n"); - - /* Dump vertices */ - vsz = darray_vertex_size_get(&geom->unique_vertices); - ASSERT(vsz <= UINT_MAX); - fprintf(stream, "POINTS %u double\n", (unsigned)vsz); - vertices = darray_vertex_cdata_get(&geom->unique_vertices); - FOR_EACH(i, 0, vsz) - fprintf(stream, "%g %g %g\n", SPLIT3(vertices[i].coord)); - - /* Dump triangles */ - tsz = darray_triangle_size_get(&geom->unique_triangles); - ASSERT(4 * tsz <= UINT_MAX); - fprintf(stream, "POLYGONS %u %u\n", (unsigned)tsz, (unsigned)(4 * tsz)); - triangles = darray_triangle_cdata_get(&geom->unique_triangles); - FOR_EACH(i, 0, tsz) - fprintf(stream, "3 %u %u %u\n", SPLIT3(triangles[i].vertex_ids)); - - /* Start triangles properties */ - fprintf(stream, "CELL_DATA %u\n", (unsigned)tsz); - descriptions = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); - - /* Dump front medium */ - fprintf(stream, "SCALARS Front_medium int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - dump_trg_property(geom, stream, SG3_FRONT); - - /* Dump back medium */ - fprintf(stream, "SCALARS Back_medium int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - dump_trg_property(geom, stream, SG3_BACK); - - /* Dump interface */ - fprintf(stream, "SCALARS Interface int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - dump_trg_property(geom, stream, SG3_INTFACE); - - /* Dump user_id */ - fprintf(stream, "SCALARS User_ID int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - FOR_EACH(i, 0, tsz) - fprintf(stream, "%u\n", triangles[i].user_id); - - /* Dump merge conflict status */ - fprintf(stream, "SCALARS Merge_conflict int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - FOR_EACH(i, 0, tsz) - fprintf(stream, "%d\n", descriptions[i].merge_conflict); - - /* Dump property conflict status */ - fprintf(stream, "SCALARS Property_conflict int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - FOR_EACH(i, 0, tsz) - fprintf(stream, "%d\n", descriptions[i].properties_conflict); - - /* Dump rank of the sg3_geometry_add that created the triangle */ - fprintf(stream, "SCALARS Created_at_sg3_geometry_add int\n"); - fprintf(stream, "LOOKUP_TABLE default\n"); - FOR_EACH(i, 0, tsz) { - const struct definition* tdefs; - const unsigned* ranks; - ASSERT(darray_definition_size_get(&descriptions[i].defs[SG3_FRONT]) > 0); - /* Rank is the first set_id of the first definition of any property */ - tdefs = darray_definition_cdata_get(&descriptions[i].defs[SG3_FRONT]); - ranks = darray_uint_cdata_get(&tdefs[0].set_ids); - fprintf(stream, "%u\n", ranks[0]); - } - -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_dump_as_c_code - (const struct sg3_geometry* geom, - FILE* stream, - const char* name_prefix, - const int flags) -{ - res_T res = RES_OK; - const struct vertex* vertices; - const struct triangle* triangles; - const char* qualifiers; - size_t vsz, tsz, i; - if(!geom || !stream - || geom->merge_conflict_count - || geom->properties_conflict_count - || !geom->triangle_count_including_duplicates) - { - if(geom - && (geom->merge_conflict_count - || geom->properties_conflict_count)) - log_err(geom->dev, - "%s: cannot dump geometries with conflict as C code\n", - FUNC_NAME); - if(geom && !geom->triangle_count_including_duplicates) - log_err(geom->dev, - "%s: cannot dump empty geometries as C code\n", - FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - if(!name_prefix) name_prefix = ""; - /* Headers */ - if(name_prefix && name_prefix[0] != '\0') - fprintf(stream, "/* Dump of star-geometry '%s'. */\n", name_prefix); - else - fprintf(stream, "/* Dump of star-geometry. */\n"); - vsz = darray_vertex_size_get(&geom->unique_vertices); - ASSERT(3 * vsz <= UINT_MAX); - tsz = darray_triangle_size_get(&geom->unique_triangles); - ASSERT(3 * tsz <= UINT_MAX); - - if(vsz == 0 || tsz == 0) { - log_err(geom->dev, - "%s: no geometry to dump\n", - FUNC_NAME); - res = RES_BAD_ARG; - goto error; - } - - if(flags & SG3_C_DUMP_CONST && flags & SG3_C_DUMP_STATIC) - qualifiers = "static const "; - else if(flags & SG3_C_DUMP_CONST) - qualifiers = "const "; - else if(flags & SG3_C_DUMP_STATIC) - qualifiers = "static "; - else qualifiers = ""; - - /* Dump vertices */ - fprintf(stream, "%sunsigned %s_vertices_count = %u;\n", - qualifiers, name_prefix, (unsigned)vsz); - - vertices = darray_vertex_cdata_get(&geom->unique_vertices); - fprintf(stream, - "%sdouble %s_vertices[%u] =\n" - "{\n", - qualifiers, name_prefix, (unsigned)(3 * vsz)); - FOR_EACH(i, 0, vsz - 1) - fprintf(stream, - " %g, %g, %g,\n", SPLIT3(vertices[i].coord)); - fprintf(stream, - " %g, %g, %g\n", SPLIT3(vertices[vsz - 1].coord)); - fprintf(stream, - "};\n"); - - /* Dump triangles */ - fprintf(stream, "%sunsigned %s_triangles_count = %u;\n", - qualifiers, name_prefix, (unsigned)tsz); - - triangles = darray_triangle_cdata_get(&geom->unique_triangles); - fprintf(stream, - "%sunsigned %s_triangles[%u] =\n" - "{\n", - qualifiers, name_prefix, (unsigned)(3 * tsz)); - FOR_EACH(i, 0, tsz - 1) - fprintf(stream, - " %u, %u, %u,\n", SPLIT3(triangles[i].vertex_ids)); - fprintf(stream, - " %u, %u, %u\n", SPLIT3(triangles[tsz - 1].vertex_ids)); - fprintf(stream, - "};\n"); - - /* Dump properties */ - fprintf(stream, - "%sunsigned %s_properties[%u] =\n" - "{\n", - qualifiers, name_prefix, (unsigned)(SG3_PROP_TYPES_COUNT__ * tsz)); - FOR_EACH(i, 0, tsz) { - int p; - fprintf(stream, " "); - FOR_EACH(p, 0, SG3_PROP_TYPES_COUNT__) { - if(triangles[i].properties[p] == SG3_UNSPECIFIED_PROPERTY) - fprintf(stream, " SG3_UNSPECIFIED_PROPERTY"); - else fprintf(stream," %u", triangles[i].properties[p]); - if(i < tsz-1 || p < 2) fprintf(stream, ","); - if(p == 2) fprintf(stream, "\n"); - } - } - fprintf(stream, - "};\n"); - -exit: - return res; -error: - goto exit; -} - -res_T -sg3_geometry_ref_get(struct sg3_geometry* geom) -{ - if(!geom) return RES_BAD_ARG; - ref_get(&geom->ref); - return RES_OK; -} - -res_T -sg3_geometry_ref_put(struct sg3_geometry* geom) -{ - if(!geom) return RES_BAD_ARG; - ref_put(&geom->ref, geometry_release); - return RES_OK; -} diff --git a/src/sg3_geometry.h b/src/sg3_geometry.h @@ -1,279 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3_GEOMETRY_H__ -#define SG3_GEOMETRY_H__ - -#include "sg3.h" -#include "sg3_misc.h" - -#include <rsys/ref_count.h> -#include <rsys/dynamic_array.h> -#include <rsys/hash_table.h> - -/* Forward declaration of external opaque data types */ - -/******************************************************************************* - * A type to store triangles - ******************************************************************************/ -struct triangle { - unsigned vertex_ids[3]; - /* FRONT/BACK/INTERFACE property */ - unsigned properties[SG3_PROP_TYPES_COUNT__]; - /* ID of the triangle in user world, i.e. without deduplication */ - unsigned user_id; -}; -#define TRG_UNDEF__ {\ - { SG3_UNSPECIFIED_PROPERTY, SG3_UNSPECIFIED_PROPERTY, SG3_UNSPECIFIED_PROPERTY },\ - { SG3_UNSPECIFIED_PROPERTY, SG3_UNSPECIFIED_PROPERTY, SG3_UNSPECIFIED_PROPERTY },\ - SG3_UNSPECIFIED_PROPERTY\ -} -#define DARRAY_NAME triangle -#define DARRAY_DATA struct triangle -#include <rsys/dynamic_array.h> - -/******************************************************************************* - * A type to store vertices - ******************************************************************************/ -struct vertex { - double coord[3]; -}; -#define DARRAY_NAME vertex -#define DARRAY_DATA struct vertex -#include <rsys/dynamic_array.h> - -/******************************************************************************* - * A type to map triangle vertices to IDs in unique_triangles - ******************************************************************************/ -struct unsigned3 { unsigned x[3]; }; - -static FINLINE int -trg_key_eq(const struct unsigned3* k1, const struct unsigned3* k2) -{ - ASSERT(k1 && k2); - ASSERT(k1->x[0] < k1->x[1] && k1->x[1] < k1->x[2]); - ASSERT(k2->x[0] < k2->x[1] && k2->x[1] < k2->x[2]); - return (k1->x[0] == k2->x[0]) - && (k1->x[1] == k2->x[1]) - && (k1->x[2] == k2->x[2]); -} - -#define HTABLE_NAME trg -#define HTABLE_KEY struct unsigned3 -#define HTABLE_DATA unsigned -#define HTABLE_KEY_FUNCTOR_EQ trg_key_eq -#include <rsys/hash_table.h> - - /******************************************************************************* - * A type to map vertex coordinates to IDs in unique_vertices - ******************************************************************************/ -static FINLINE int -vrtx_eq(const struct vertex* v1, const struct vertex* v2) -{ - int i; - ASSERT(v1 && v2); - FOR_EACH(i, 0, 3) if(v1->coord[i] != v2->coord[i]) return 0; - return 1; -} - -#define HTABLE_NAME vrtx -#define HTABLE_KEY struct vertex -#define HTABLE_DATA unsigned -#define HTABLE_KEY_FUNCTOR_EQ vrtx_eq -#include <rsys/hash_table.h> - -/******************************************************************************* - * Types to record sources and values of triangle descriptions. - ******************************************************************************/ - - /* A type to store a value and the files defining this value - * (usualy a single file) */ -struct definition { - /* The value */ - unsigned property_value; - /* The IDs of the geometry sets that defined the value */ - struct darray_uint set_ids; -}; - -static FINLINE void -init_definition - (struct mem_allocator* alloc, - struct definition* data) -{ - ASSERT(alloc && data); - data->property_value = SG3_UNSPECIFIED_PROPERTY; - darray_uint_init(alloc, &data->set_ids); -} - -static INLINE res_T -copy_definition - (struct definition* dst, - const struct definition* src) -{ - res_T res = RES_OK; - ASSERT(dst && src); - dst->property_value = src->property_value; - ERR(darray_uint_copy(&dst->set_ids, &src->set_ids)); -exit: - return res; -error: - goto exit; -} - -static FINLINE void -release_definition - (struct definition* data) -{ - ASSERT(data); - darray_uint_release(&data->set_ids); -} - -#define DARRAY_NAME definition -#define DARRAY_DATA struct definition -#define DARRAY_FUNCTOR_INIT init_definition -#define DARRAY_FUNCTOR_COPY copy_definition -#define DARRAY_FUNCTOR_RELEASE release_definition -#include <rsys/dynamic_array.h> - -/* A type to accumulate information for a triangle. - * If there is more than 1 definition / field, it is a conflict */ -struct trg_descriptions { - struct darray_definition defs[SG3_PROP_TYPES_COUNT__]; - int merge_conflict; - int properties_conflict; - char defs_include_unspecified; - char property_defined[SG3_PROP_TYPES_COUNT__]; -}; - -static FINLINE void -init_trg_descriptions - (struct mem_allocator* alloc, - struct trg_descriptions* data) -{ - int i; - ASSERT(alloc && data); - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - darray_definition_init(alloc, data->defs + i); - data->merge_conflict = 0; - data->properties_conflict = 0; - data->defs_include_unspecified = 0; - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - data->property_defined[i] = 0; -} - -static INLINE res_T -copy_trg_descriptions - (struct trg_descriptions* dst, - const struct trg_descriptions* src) -{ - res_T res = RES_OK; - int i; - ASSERT(dst && src); - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - ERR(darray_definition_copy(&dst->defs[i], &src->defs[i])); - dst->merge_conflict = src->merge_conflict; - dst->properties_conflict = src->properties_conflict; - dst->defs_include_unspecified = src->defs_include_unspecified; - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - dst->property_defined[i] = src->property_defined[i]; -exit: - return res; -error: - goto exit; -} - -static FINLINE void -release_trg_descriptions - (struct trg_descriptions* data) -{ - int i; - ASSERT(data); - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - darray_definition_release(data->defs + i); -} - -#define DARRAY_NAME trg_descriptions -#define DARRAY_DATA struct trg_descriptions -#define DARRAY_FUNCTOR_INIT init_trg_descriptions -#define DARRAY_FUNCTOR_COPY copy_trg_descriptions -#define DARRAY_FUNCTOR_RELEASE release_trg_descriptions -#include <rsys/dynamic_array.h> - -/******************************************************************************* - * A type to store interface IDs, as star-enclosures doesn't manage them. - ******************************************************************************/ -static FINLINE void -init_trg_intfaceid - (struct mem_allocator* alloc, - unsigned* data) -{ - ASSERT(data); (void)alloc; - *data = SG3_UNSPECIFIED_PROPERTY; -} - -#define DARRAY_NAME intface_id -#define DARRAY_DATA unsigned -#define DARRAY_FUNCTOR_INIT init_trg_intfaceid -#include <rsys/dynamic_array.h> - -/******************************************************************************* - * Types to store geometry amid sg3_geometry_add calls. - ******************************************************************************/ -struct sg3_geometry { - /* Record unique (i.e. deduplicated) triangles */ - struct darray_triangle unique_triangles; - /* Record coordinates for unique (i.e. deduplicated) vertices */ - struct darray_vertex unique_vertices; - - /* A table to map triangle vertices to IDs in unique_triangles */ - struct htable_trg unique_triangles_ids; - /* A table to map vertex coordinates to IDs in unique_vertices */ - struct htable_vrtx unique_vertices_ids; - - /* Record which set defined what */ - struct darray_trg_descriptions trg_descriptions; - - /* Counts */ - unsigned set_id; - unsigned triangle_count_including_duplicates; - unsigned sides_with_defined_medium_count; - unsigned trg_with_unspecified_sides_count; - unsigned trg_with_unspecified_intface_count; - unsigned merge_conflict_count; - unsigned properties_conflict_count; - - struct sg3_device* dev; - ref_T ref; -}; - -/******************************************************************************* - * Local functions - ******************************************************************************/ - -extern res_T -geometry_register_triangle - (struct sg3_geometry* geometry, - const struct triangle* triangle, - const unsigned triangle_unique_id, - const unsigned set_id, - const int merge_conflict); - -/* Add new undefined triangle descriptions to a geometry */ -extern res_T -geometry_enlarge_trg_descriptions - (struct sg3_geometry* geom, - const size_t sz); - -#endif /* SG3_GEOMETRY_H__ */ diff --git a/src/sg3_misc.h b/src/sg3_misc.h @@ -1,21 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3_MISC_H__ -#define SG3_MISC_H__ - -#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; - -#endif /* SG3_MISC_H__ */ diff --git a/src/sg3_s3d_helper.h b/src/sg3_s3d_helper.h @@ -1,61 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3_SENC_HELPER_H__ -#define SG3_SENC_HELPER_H__ - -#include "sg3.h" -#include <star/senc.h> - -#include <rsys/rsys.h> -#include <rsys/float3.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 -sg3_s3d_geometry_get_indices__ - (const unsigned itri, - unsigned indices[3], - void* ctx) -{ - const struct sg3_geometry* geometry = ctx; - res_T r; - ASSERT(indices && geometry); - r = sg3_geometry_get_unique_triangle_vertices(geometry, itri, indices); - ASSERT(r == RES_OK); (void)r; -} - -/* 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 -sg3_s3d_geometry_get_position__ - (const unsigned ivert, - float coord[3], - void* ctx) -{ - const struct sg3_geometry* geometry = ctx; - double tmp[3]; - res_T r; - ASSERT(coord && geometry); - r = sg3_geometry_get_unique_vertex(geometry, ivert, tmp); - ASSERT(r == RES_OK); (void)r; - f3_set_d3(coord, tmp); -} - -END_DECLS - -#endif /* SG3_SENC_HELPER_H__ */ diff --git a/src/sg3_senc_helper.h b/src/sg3_senc_helper.h @@ -1,76 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3_SENC_HELPER_H__ -#define SG3_SENC_HELPER_H__ - -#include "sg3.h" -#include <star/senc.h> - -#include <rsys/rsys.h> - - /* Get vertex indices for the itri_th triangle. - * Suitable for use as get_indices callback in senc_scene_create calls. */ -static FINLINE void -sg3_senc_geometry_get_indices__ - (const unsigned itri, - unsigned indices[3], - void* ctx) -{ - const struct sg3_geometry* geometry = ctx; - res_T r; - ASSERT(indices && geometry); - r = sg3_geometry_get_unique_triangle_vertices(geometry, itri, indices); - ASSERT(r == RES_OK); (void)r; -} - -/* Get vertex indices for the itri_th triangle. - * Suitable for use as get_media callback in senc_scene_create calls. */ -static FINLINE void -sg3_senc_geometry_get_media__ - (const unsigned itri, - unsigned media[2], - void* ctx) -{ - const struct sg3_geometry* geometry = ctx; - unsigned tmp[SG3_PROP_TYPES_COUNT__]; - res_T r; - ASSERT(media && geometry); - r = sg3_geometry_get_unique_triangle_properties(geometry, itri, tmp); - ASSERT(r == RES_OK); (void)r; - media[SENC_FRONT] = (tmp[SG3_FRONT] == SG3_UNSPECIFIED_PROPERTY) - ? SENC_UNSPECIFIED_MEDIUM : tmp[SG3_FRONT]; - media[SENC_BACK] = (tmp[SG3_BACK] == SG3_UNSPECIFIED_PROPERTY) - ? SENC_UNSPECIFIED_MEDIUM : tmp[SG3_BACK]; -} - -/* Get vertex indices for the itri_th triangle. - * Suitable for use as get_position callback in senc_scene_create calls. */ -static FINLINE void -sg3_senc_geometry_get_position__ - (const unsigned ivert, - double coord[3], - void* ctx) -{ - const struct sg3_geometry* geometry = ctx; - res_T r; - ASSERT(coord && geometry); - r = sg3_geometry_get_unique_vertex(geometry, ivert, coord); - ASSERT(r == RES_OK); (void)r; -} - -END_DECLS - -#endif /* SG3_SENC_HELPER_H__ */ diff --git a/src/sg3d.h b/src/sg3d.h @@ -0,0 +1,396 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 STAR_GEOMETRY3D_H__ +#define STAR_GEOMETRY3D_H__ + +#include <rsys/rsys.h> +#include <rsys/dynamic_array_uint.h> + +#include <limits.h> + +/* Library symbol management */ +#if defined(SG3D_SHARED_BUILD) + #define SG3D_API extern EXPORT_SYM +#elif defined(SG3D_STATIC_BUILD) + #define SG3D_API extern LOCAL_SYM +#else /* Use shared library */ + #define SG3D_API extern IMPORT_SYM +#endif + +/* Helper macro that asserts if the invocation of the star-geometry function + * `Func' returns an error. One should use this macro on star-geometry + * function calls for which no explicit error checking is performed. */ +#ifndef NDEBUG +#define SG3D(Func) ASSERT(sg3d_ ## Func == RES_OK) +#else +#define SG3D(Func) sg3d_ ## Func +#endif + +/* Forward declaration of external opaque data types */ +struct logger; +struct mem_allocator; +struct senc_scene; + +/* Forward declaration of the star-geometry opaque data types. These data + * types are ref counted. Once created the caller implicitly owns the created + * data, i.e. its reference counter is set to 1. The sdis_<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 sg3d_device; +struct sg3d_geometry; + +/****************************************************************************** + * The dimension of the geometry used in the library. + *****************************************************************************/ +#define SG3D_GEOMETRY_DIMENSION 3 + +/****************************************************************************** + * A type to list the different user properties attached to triangles. + *****************************************************************************/ +enum sg3d_property_type { + SG3D_FRONT, + SG3D_BACK, + SG3D_INTFACE, + SG3D_PROP_TYPES_COUNT__ +}; + +/****************************************************************************** + * A type to list the different possible partitions of triangles. + *****************************************************************************/ +enum sg3d_obj_dump_content { + SG3D_OBJ_DUMP_MERGE_CONFLICTS = BIT(0), + SG3D_OBJ_DUMP_PROPERTY_CONFLICTS = BIT(1), + SG3D_OBJ_DUMP_VALID_PRIMITIVE = BIT(2), + SG3D_OBJ_DUMP_ALL = + SG3D_OBJ_DUMP_MERGE_CONFLICTS + | SG3D_OBJ_DUMP_PROPERTY_CONFLICTS + | SG3D_OBJ_DUMP_VALID_PRIMITIVE +}; + +/****************************************************************************** + * A type to list the different qualifiers of C code variable output. + *****************************************************************************/ +enum sg3d_c_dump_qualifiers { + SG3D_C_DUMP_CONST = BIT(0), + SG3D_C_DUMP_STATIC = BIT(1) +}; + +/****************************************************************************** + * The value that should be used for properties attached to triangles (i.e. + * media or interface) when let unspecified. + * SG3D_UNSPECIFIED_PROPERTY can be used for a property that has already been + * defined; in this case the previous value will remain. + *****************************************************************************/ +#define SG3D_UNSPECIFIED_PROPERTY UINT_MAX + + /***************************************************************************** + * A type to hold callbacks for sg3d_geometry_add. + ****************************************************************************/ +struct sg3d_geometry_add_callbacks { + /* User function that provides vertices ids for added triangles */ + void(*get_indices) + (const unsigned itri, unsigned ids[SG3D_GEOMETRY_DIMENSION], void* context); + /* User function that provides properties for added triangles */ + void(*get_properties) /* Can be NULL <=> SG3D_UNSPECIFIED_PROPERTY used */ + (const unsigned itri, + /* It is OK to have side and interface properties sharing the same IDs, + * i.e. side and interface IDs both starting from 0 */ + unsigned properties[SG3D_PROP_TYPES_COUNT__], + void* context); + /* User function that provides coordinates for added vertices */ + void(*get_position) + (const unsigned ivert, double pos[SG3D_GEOMETRY_DIMENSION], void* context); + /* Called if the itri_th triangle of the current sg3d_geometry_add is a new + * triangle (i.e. not a duplicate) so that the client app can manage its own + * triangle data/properties/attributes. + * If return is not RES_OK, sg3d_geometry_add stops immediately and returns + * whatever value add_triangle returned. */ + res_T(*add_triangle) /* Can be NULL */ + (const unsigned unique_id, const unsigned itri, void* context); + /* Called if the itri_th triangle of the current sg3d_geometry_add is a + * duplicate of the unique_id_th unique triangle so that the client app can + * merge its own triangle data, rule merge validity, and possibly change the + * recorded properties. + * The reversed_triangle arg indicates if the triangle vertices' order is + * the same it was when the triangle was first added. + * The merge_conflict_status argument can be set to any value. Any non-0 + * value is accounted for a conflict and is kept as-is in dumps, allowing + * different shades of conflict. + * The triangle_properties and merged_properties args contain the involved + * properties. */ + res_T(*merge_triangle) /* Can be NULL */ + (const unsigned unique_id, + const unsigned itri, + const int reversed_triangle, + unsigned triangle_properties[SG3D_PROP_TYPES_COUNT__], + const unsigned merged_properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* merge_conflict_status); + /* Called if the itri_th triangle is degenerated. According to the value + * of abort, sg3d_geometry_add will stop and return RES_BAD_ARG or continue + * silently. */ + res_T(*degenerated_triangle) /* Can be NULL <=> Drop triangle, don't abort */ + (const unsigned itri, void* context, int* abort); +}; +#define SG3D_ADD_CALLBACKS_NULL__ { NULL, NULL, NULL, NULL, NULL, NULL } + +BEGIN_DECLS + +/****************************************************************************** + * A helper function on properties compatibility. + *****************************************************************************/ +static INLINE int +sg3d_compatible_property + (const unsigned p1, + const unsigned p2) +{ + if(p1 == SG3D_UNSPECIFIED_PROPERTY || p2 == SG3D_UNSPECIFIED_PROPERTY) return 1; + return (p1 == p2); +} + +/****************************************************************************** + * star-geometry device. It is an handle toward the star-geometry library. + * It manages the star-geometry resources. + *****************************************************************************/ +SG3D_API res_T +sg3d_device_create + (struct logger* logger, /* Can be NULL <=> use default logger */ + struct mem_allocator* allocator, /* Can be NULL <=> use default allocator */ + const int verbose, /* Verbosity level */ + struct sg3d_device** dev); + +SG3D_API res_T +sg3d_device_ref_get + (struct sg3d_device* dev); + +SG3D_API res_T +sg3d_device_ref_put + (struct sg3d_device* dev); + +/****************************************************************************** + * star-geometry geometry. + * It stores decorated geometry accumulated through calls to sg3d_geometry_add, + * information related to this geometry and its creation process, including + * merge conflicts. + *****************************************************************************/ +/* Create a geometry that can be used to accumulate vertices and triangles + * decorated with properties. */ +SG3D_API res_T +sg3d_geometry_create + (struct sg3d_device* dev, + struct sg3d_geometry** geometry); + +/* Reserve memory according to anticipated geometry size. */ +SG3D_API res_T +sg3d_geometry_reserve + (struct sg3d_geometry* geometry, + const unsigned vertices_count, + const unsigned triangles_count, + const unsigned properties_count); + +/* Add a new set of 3D vertices and triangles to the geometry; triangles can + * be decorated with 3 properties (front and back media and interface) that can + * be let unspecified using the SG3D_UNSPECIFIED_PROPERTY special value. + * Vertices can be duplicates and are silently deduplicated, always valid. + * Triangles can be duplicates, but this can be ruled invalid due to property + * inconsistency. Triangle duplicates are silently deduplicated, even if + * invalid. Consistency is to be understood as the consistency of the + * successive values for the same property across calls of sg3d_geometry_add, + * not as the consistency of the values of the 3 properties of a triangle at + * some given time (this question has its own callback (validate) in the + * sg3d_geometry_validate_properties API call). + * Duplicate triangles validity is either ruled by the user-provided + * merge_triangle callback, or is just a matter of properties consistency if no + * callback is provided. In either case, sg3d_geometry_add never stops + * prematurely nor returns an error code due to a merge conflict. + * - if provided, the callback must return the consistency status using the + * merge_conflict_status int* paramater (0 for consistent; any other value + * for inconsistent, this value being recorded); regardless of + * merge_conflict_status, the callback can change the properties of the + * triangle before the SG3D_UNSPECIFIED_PROPERTY overwriting step; + * - if not, a non-SG3D_UNSPECIFIED_PROPERTY is only consistent with itself and + * with SG3D_UNSPECIFIED_PROPERTY (if inconsistent, merge_conflict_status is + * set to 1 and recorded) ; regardless of merge_conflict_status, a + * non-SG3D_UNSPECIFIED_PROPERTY property is never overridden. + * When deduplicating triangles, the first occurence remains (with its + * original index in user world). After consistency being computed, a final + * step consists in rewriting SG3D_UNSPECIFIED_PROPERTY properties if the merged + * property is defined. */ +SG3D_API res_T +sg3d_geometry_add + (struct sg3d_geometry* geometry, + const unsigned vertices_count, + const unsigned triangles_count, + const struct sg3d_geometry_add_callbacks* callbacks, + void* context); /* Can be NULL */ + +/* Apply a validation callback on each triangle included in this geometry that + * is not already flagged with a merge error. If validate returns a non-RES_OK + * value, the validation stops and returns the same error value; on the other + * hand, validation goes to the end regardless of properties conflicts. + * The properties_conflict_status argument can be set to any value. Any non-0 + * value is accounted for a conflict and is kept as-is in dumps, allowing + * different shades of conflict. + * If validation is processed again, the properties conflict count is reset, + * as well as the properties_conflict_status status of the triangles. */ +SG3D_API res_T +sg3d_geometry_validate_properties + (struct sg3d_geometry* geometry, + res_T(*validate) + (const unsigned itri, + const unsigned properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* properties_conflict_status), + void* context); /* Can be NULL */ + +/* Get the number of unique vertices. */ +SG3D_API res_T +sg3d_geometry_get_unique_vertices_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Get the ivtx_th vertex. */ +SG3D_API res_T +sg3d_geometry_get_unique_vertex + (const struct sg3d_geometry* geometry, + const unsigned ivtx, + double coord[SG3D_GEOMETRY_DIMENSION]); + +/* Get the number of triangles added to the geometry, regardless of unicity. */ +SG3D_API res_T +sg3d_geometry_get_added_triangles_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Get the number of unique triangles. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangles_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Get the vertex indices of the itri_th unique triangle. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangle_vertices + (const struct sg3d_geometry* geometry, + const unsigned itri, + unsigned indices[SG3D_GEOMETRY_DIMENSION]); + +/* Get the properties of the itri_th unique triangle. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangle_properties + (const struct sg3d_geometry* geometry, + const unsigned itri, + unsigned properties[SG3D_PROP_TYPES_COUNT__]); + +/* Get the user ID of the itri_th unique triangle, that is the user world's + * index of the triangle that first created this unique triangle. + * User world index starts at 0 and increases for every triangle that is + * submitted to sg3d_geometry_add calls, regardless of duplication or + * sg3d_geometry_add failures (non-RES_OK return value). */ +SG3D_API res_T +sg3d_geometry_get_unique_triangle_user_id + (const struct sg3d_geometry* geometry, + const unsigned itri, + unsigned* user_id); + +/* Get the number of triangles with (at least) one unspecified side. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangles_with_unspecified_side_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Get the number of triangles with unspecified interface. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangles_with_unspecified_interface_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Get the number of triangles flagged with a merge conflict. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangles_with_merge_conflict_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Get the number of triangles flagged with a property conflict. Only + * meaningful after sg3d_geometry_validate_properties has been called. */ +SG3D_API res_T +sg3d_geometry_get_unique_triangles_with_properties_conflict_count + (const struct sg3d_geometry* geometry, + unsigned* count); + +/* Dump a geometry in the provided stream in the OBJ format. + * The geometry can include conflicts, but cannot be empty. + * The dump is made of the vertices and some triangles, without their + * properties. The dumped triangles are defined by the flags argument, that + * must be ORed enum sg3d_obj_dump_content values. + * The dumped triangles are partitioned in the following groups: + * - Valid_triangles + * - Merge_conflicts + * - Property_conflict */ +SG3D_API res_T +sg3d_geometry_dump_as_obj + (const struct sg3d_geometry* geometry, + FILE* stream, + int flags); + +/* Dump a geometry in the provided stream in the VTK ascii format. + * The geometry can include conflicts, but cannot be empty. + * The dump is made of the vertices and triangles, with most of their + * properties: + * - Front_medium (medium ID of the front side, INT_MAX for both unspecified + * and conflicted) + * - Back_medium (medium ID of the back side, INT_MAX for both unspecified and + * conflicted) + * - Interface (interface ID, INT_MAX for both unspecified and conflicted) + * - Merge_conflict (merge conflict status) + * - Property_conflict (property conflict status) + * - Created_at_sg3d_geometry_add (rank of the sg3d_geometry_add that created the + * triangle) */ +SG3D_API res_T +sg3d_geometry_dump_as_vtk + (const struct sg3d_geometry* geometry, + FILE* stream); + +/* Dump the geometry as C code. + * The geometry cannot be empty and must be conflict-free. + * The C code defines the 3 variables: + * - [static] [const] unsigned <name_prefix>_vertices_count = N1; + * - [static] [const] double <name_prefix>_vertices[<N1>] = { .... }; + * - [static] [const] unsigned <name_prefix>_triangles_count = N2; + * - [static] [const] unsigned <name_prefix>_triangles[<N2>] = { .... }; + * - [static] [const] unsigned <name_prefix>_properties[<N2>] = { .... }; + * Where <N1> is 3 * vertices_count and <N2> is 3 * triangles_count. + * The two qualifiers static and const are output or not according to flags; + * flags must be ORed enum sg3d_c_dump_qualifiers values. */ +SG3D_API res_T +sg3d_geometry_dump_as_c_code + (const struct sg3d_geometry* geometry, + FILE* stream, + const char* name_prefix, /* Can be NULL or "" */ + const int flags); + +SG3D_API res_T +sg3d_geometry_ref_get + (struct sg3d_geometry* geometry); + +SG3D_API res_T +sg3d_geometry_ref_put + (struct sg3d_geometry* geometry); + +END_DECLS + +#endif /* STAR_GEOMETRY3D_H__ */ diff --git a/src/sg3d_device.c b/src/sg3d_device.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "sg3d_device.h" + +#include <rsys/logger.h> +#include <rsys/mem_allocator.h> + +#include <stdarg.h> + + /******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +log_msg + (struct sg3d_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 sg3d_device* dev; + ASSERT(ref); + dev = CONTAINER_OF(ref, struct sg3d_device, ref); + MEM_RM(dev->allocator, dev); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +sg3d_device_create + (struct logger* logger, + struct mem_allocator* mem_allocator, + const int verbose, + struct sg3d_device** out_dev) +{ + struct logger* log = NULL; + struct sg3d_device* dev = NULL; + struct mem_allocator* allocator = NULL; + res_T res = RES_OK; + + if(!out_dev) { + res = RES_BAD_ARG; + goto error; + } + + log = logger ? logger : LOGGER_DEFAULT; + allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + dev = MEM_CALLOC(allocator, 1, sizeof(struct sg3d_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-geometry device.\n", FUNC_NAME) + == RES_OK); + } + res = RES_MEM_ERR; + goto error; + } + dev->logger = log; + dev->allocator = allocator; + dev->verbose = verbose; + ref_init(&dev->ref); + +exit: + if(out_dev) *out_dev = dev; + return res; +error: + if(dev) { + SG3D(device_ref_put(dev)); + dev = NULL; + } + goto exit; +} + +res_T +sg3d_device_ref_get(struct sg3d_device* dev) +{ + if(!dev) return RES_BAD_ARG; + ref_get(&dev->ref); + return RES_OK; +} + +res_T +sg3d_device_ref_put(struct sg3d_device* dev) +{ + if(!dev) return RES_BAD_ARG; + ref_put(&dev->ref, device_release); + return RES_OK; +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +void +log_err(struct sg3d_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 sg3d_device* dev, const char* msg, ...) +{ + va_list vargs_list; + ASSERT(dev && msg); + + va_start(vargs_list, msg); + log_msg(dev, LOG_WARNING, msg, vargs_list); + va_end(vargs_list); +} diff --git a/src/sg3d_device.h b/src/sg3d_device.h @@ -0,0 +1,57 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3D_DEVICE_H__ +#define SG3D_DEVICE_H__ + +#include <rsys/ref_count.h> + + /* Forward declaration of external opaque data types */ +struct logger; +struct mem_allocator; + +struct sg3d_device { + struct logger* logger; + struct mem_allocator* allocator; + int verbose; + + 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 sg3d_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 sg3d_device* dev, + const char* msg, + ...) +#ifdef COMPILER_GCC + __attribute((format(printf, 2, 3))) +#endif + ; + +#endif /* SG3D_DEVICE_H__ */ diff --git a/src/sg3d_geometry.c b/src/sg3d_geometry.c @@ -0,0 +1,1088 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "sg3d_geometry.h" +#include "sg3d_device.h" + +#include <rsys/double3.h> + +#include <limits.h> + + /******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +geometry_release(ref_T* ref) +{ + struct sg3d_geometry* geom; + struct sg3d_device* dev; + ASSERT(ref); + geom = CONTAINER_OF(ref, struct sg3d_geometry, ref); + dev = geom->dev; + darray_triangle_release(&geom->unique_triangles); + darray_vertex_release(&geom->unique_vertices); + htable_trg_release(&geom->unique_triangles_ids); + htable_vrtx_release(&geom->unique_vertices_ids); + darray_trg_descriptions_release(&geom->trg_descriptions); + MEM_RM(dev->allocator, geom); + SG3D(device_ref_put(dev)); +} + +static FINLINE int /* Return 1 if reversed */ +trg_make_key(struct unsigned3* k, const unsigned 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->x[0] = t[0]; + if(t[1] < t[2]) { + k->x[1] = t[1]; + k->x[2] = t[2]; + return 0; + } else { + k->x[1] = t[2]; + k->x[2] = t[1]; + return 1; + } + } else { + k->x[0] = t[1]; + if(t[0] < t[2]) { + k->x[1] = t[0]; + k->x[2] = t[2]; + return 1; + } else { + k->x[1] = t[2]; + k->x[2] = t[0]; + return 0; + } + } + } + else if(t[2] < t[1]) { + k->x[0] = t[2]; + if(t[0] < t[1]) { + k->x[1] = t[0]; + k->x[2] = t[1]; + return 0; + } else { + k->x[1] = t[1]; + k->x[2] = t[0]; + return 1; + } + } else { + k->x[0] = t[1]; + if(t[0] < t[2]) { + k->x[1] = t[0]; + k->x[2] = t[2]; + return 1; + } else { + k->x[1] = t[2]; + k->x[2] = t[0]; + return 0; + } + } +} + +static void +dump_trg_property + (const struct sg3d_geometry* geom, + FILE* stream, + const enum sg3d_property_type type) +{ + size_t i; + const struct trg_descriptions* descriptions; + ASSERT(geom && stream && type < SG3D_PROP_TYPES_COUNT__); + + descriptions + = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); + FOR_EACH(i, 0, darray_triangle_size_get(&geom->unique_triangles)) { + unsigned property = SG3D_UNSPECIFIED_PROPERTY; + size_t tdefs_count + = darray_definition_size_get(&descriptions[i].defs[type]); + if(tdefs_count && descriptions[i].property_defined[type]) { + const struct definition* tdefs + = darray_definition_cdata_get(&descriptions[i].defs[type]); + size_t j; + FOR_EACH(j, 0, tdefs_count) { + if(tdefs->property_value != SG3D_UNSPECIFIED_PROPERTY) { + property = tdefs->property_value; + break; /* Found the defined value */ + } + tdefs++; /* Next value */ + } + } + /* In VTK dumps INT_MAX is used for both unspecified and conflict */ + fprintf(stream, "%u\n", MMIN(property, INT_MAX)); + } +} + +/******************************************************************************* + * Local functions + ******************************************************************************/ +res_T +geometry_register_triangle + (struct sg3d_geometry* geom, + const struct triangle* triangle, + const unsigned triangle_unique_id, + const unsigned set_id, + const int merge_conflict) +{ + res_T res = RES_OK; + struct trg_descriptions* trg_d; + int i; + char keep_prop_def[SG3D_PROP_TYPES_COUNT__]; + + ASSERT(geom && triangle); + + ERR(geometry_enlarge_trg_descriptions(geom, triangle_unique_id + 1)); + trg_d = (darray_trg_descriptions_data_get(&geom->trg_descriptions) + + triangle_unique_id); + /* Record information */ + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) { + struct darray_definition* definitions; + struct definition* defs; + int done = 0; + size_t j; + keep_prop_def[i] = trg_d->property_defined[i]; + if(triangle->properties[i] == SG3D_UNSPECIFIED_PROPERTY) + trg_d->defs_include_unspecified = 1; + else trg_d->property_defined[i] = 1; + definitions = trg_d->defs + i; + defs = darray_definition_data_get(definitions); + FOR_EACH(j, 0, darray_definition_size_get(definitions)) { + if(defs[j].property_value == triangle->properties[i]) { + /* This property_value is already registered: no conflict */ + const unsigned* ids = darray_uint_cdata_get(&defs[j].set_ids); + size_t k; + /* Search if property_value already includes set_id */ + FOR_EACH(k, 0, darray_uint_size_get(&defs[j].set_ids)) { + if(ids[k] == set_id) { + /* Same value+set_id was there already */ + done = 1; + break; + } + } + if(!done) { + /* Need to add the set_id for this property_value */ + ERR(darray_uint_push_back(&defs[j].set_ids, &set_id)); + done = 1; + } + break; + } + } + if(!done) { + /* This property_value was not recorded already */ + size_t defs_sz = darray_definition_size_get(definitions); + struct definition* new_def; + ERR(darray_definition_resize(definitions, 1 + defs_sz)); + new_def = darray_definition_data_get(definitions) + defs_sz; + ERR(darray_uint_push_back(&new_def->set_ids, &set_id)); + new_def->property_value = triangle->properties[i]; + if(!trg_d->merge_conflict && merge_conflict) { + /* If more than 1 merge_conflict occur, the first one remains */ + trg_d->merge_conflict = merge_conflict; + geom->merge_conflict_count++; + } + } + } + + if((!keep_prop_def[SG3D_FRONT] || !keep_prop_def[SG3D_BACK]) + && trg_d->property_defined[SG3D_FRONT] && trg_d->property_defined[SG3D_BACK]) + { + /* Both sides are now defined */ + ASSERT(geom->trg_with_unspecified_sides_count > 0); + geom->trg_with_unspecified_sides_count--; + } + + if(!keep_prop_def[SG3D_INTFACE] && trg_d->property_defined[SG3D_INTFACE]) { + /* Interface is now defined */ + ASSERT(geom->trg_with_unspecified_intface_count > 0); + geom->trg_with_unspecified_intface_count--; + } + +exit: + return res; +error: + goto exit; +} + +res_T +geometry_enlarge_trg_descriptions + (struct sg3d_geometry* geom, + const size_t sz) +{ + res_T res = RES_OK; + size_t old_sz = + darray_trg_descriptions_size_get(&geom->trg_descriptions); + if(sz <= old_sz) return RES_OK; + ASSERT(sz - old_sz < UINT_MAX); + ERR(darray_trg_descriptions_resize(&geom->trg_descriptions, sz)); + geom->trg_with_unspecified_sides_count += (unsigned)(sz - old_sz); + geom->trg_with_unspecified_intface_count += (unsigned)(sz - old_sz); + +exit: + return res; +error: + goto exit; +} + +static void +dump_partition + (const struct sg3d_geometry* geom, + FILE* stream, + const char* group_name, + enum sg3d_obj_dump_content partition) +{ + const struct trg_descriptions* trg_descriptions; + const struct triangle* triangles; + size_t sz, i; + ASSERT(geom && stream && group_name); + ASSERT(partition == SG3D_OBJ_DUMP_MERGE_CONFLICTS + || partition == SG3D_OBJ_DUMP_PROPERTY_CONFLICTS + || partition == SG3D_OBJ_DUMP_VALID_PRIMITIVE); + trg_descriptions + = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); + sz = darray_trg_descriptions_size_get(&geom->trg_descriptions); + triangles = darray_triangle_cdata_get(&geom->unique_triangles); + fprintf(stream, "g %s\n", group_name); + FOR_EACH(i, 0, sz) { + int dump; + if(partition == SG3D_OBJ_DUMP_VALID_PRIMITIVE) + dump = !(trg_descriptions[i].merge_conflict + || trg_descriptions[i].properties_conflict); + else if(partition == SG3D_OBJ_DUMP_MERGE_CONFLICTS) + dump = trg_descriptions[i].merge_conflict; + else { + ASSERT(partition == SG3D_OBJ_DUMP_PROPERTY_CONFLICTS); + dump = trg_descriptions[i].properties_conflict; + } + if(!dump) continue; + fprintf(stream, "f %u %u %u\n", + /* OBJ indexing starts at 1 */ + 1 + triangles[i].vertex_ids[0], + 1 + triangles[i].vertex_ids[1], + 1 + triangles[i].vertex_ids[2]); + } +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +sg3d_geometry_create + (struct sg3d_device* dev, + struct sg3d_geometry** out_geometry) +{ + struct sg3d_geometry* geom = NULL; + res_T res = RES_OK; + + if(!dev || !out_geometry) { + res = RES_BAD_ARG; + goto error; + } + + geom = MEM_CALLOC(dev->allocator, 1, sizeof(struct sg3d_geometry)); + if(!geom) { + log_err(dev, + "%s: could not allocate the sg3d.\n", FUNC_NAME); + res = RES_MEM_ERR; + goto error; + } + + SG3D(device_ref_get(dev)); + darray_triangle_init(dev->allocator, &geom->unique_triangles); + darray_vertex_init(dev->allocator, &geom->unique_vertices); + htable_trg_init(dev->allocator, &geom->unique_triangles_ids); + htable_vrtx_init(dev->allocator, &geom->unique_vertices_ids); + darray_trg_descriptions_init(dev->allocator, &geom->trg_descriptions); + geom->triangle_count_including_duplicates = 0; + geom->sides_with_defined_medium_count = 0; + geom->set_id = 0; + geom->trg_with_unspecified_sides_count = 0; + geom->trg_with_unspecified_intface_count = 0; + geom->merge_conflict_count = 0; + geom->properties_conflict_count = 0; + geom->dev = dev; + + ref_init(&geom->ref); + +exit: + if(out_geometry) *out_geometry = geom; + return res; +error: + if(geom) { + SG3D(geometry_ref_put(geom)); + geom = NULL; + } + goto exit; +} + +res_T +sg3d_geometry_reserve + (struct sg3d_geometry* geom, + const unsigned vertices_count, + const unsigned triangles_count, + const unsigned properties_count) +{ + res_T res = RES_OK; + if(!geom) return RES_BAD_ARG; + + ERR(darray_triangle_reserve(&geom->unique_triangles, triangles_count)); + ERR(darray_vertex_reserve(&geom->unique_vertices, vertices_count)); + ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, vertices_count)); + ERR(htable_trg_reserve(&geom->unique_triangles_ids, triangles_count)); + ERR(darray_trg_descriptions_reserve(&geom->trg_descriptions, + properties_count)); + +end: + return res; +error: + goto end; +} + +res_T +sg3d_geometry_add + (struct sg3d_geometry* geom, + const unsigned nverts, + const unsigned ntris, + const struct sg3d_geometry_add_callbacks* callbacks, + void* ctx) /* Can be NULL */ +{ + res_T res = RES_OK; + struct mem_allocator* alloc; + size_t nutris, nuverts; + unsigned i, n_new_uverts = 0, n_new_utris = 0; + struct triangle* trg; + /* Tmp table of IDs to record unique IDs of the currently added vertices */ + struct darray_uint unique_vertice_ids; + int unique_vertice_ids_initialized = 0; + + if(!geom || !callbacks || !callbacks->get_indices || !callbacks->get_position) + { + res = RES_BAD_ARG; + goto error; + } + + alloc = geom->dev->allocator; + nuverts = darray_vertex_size_get(&geom->unique_vertices); + nutris = darray_triangle_size_get(&geom->unique_triangles); + + /* Make room for new geometry; suppose no more duplicates */ + darray_uint_init(alloc, &unique_vertice_ids); + unique_vertice_ids_initialized = 1; + ERR(darray_uint_reserve(&unique_vertice_ids, nverts)); + ERR(darray_vertex_reserve(&geom->unique_vertices, nuverts + nverts)); + ERR(darray_triangle_reserve(&geom->unique_triangles, nutris + ntris)); + ERR(htable_vrtx_reserve(&geom->unique_vertices_ids, nuverts + nverts)); + ERR(htable_trg_reserve(&geom->unique_triangles_ids, nutris + ntris)); + ASSERT(nutris == darray_trg_descriptions_size_get(&geom->trg_descriptions)); + ERR(darray_trg_descriptions_reserve(&geom->trg_descriptions, nutris + ntris)); + /* Get vertices and deduplicate */ + FOR_EACH(i, 0, nverts) { + unsigned* p_vrtx; + struct vertex tmp; + unsigned v_idx; + callbacks->get_position(i, tmp.coord, ctx); + p_vrtx = htable_vrtx_find(&geom->unique_vertices_ids, &tmp); + if(p_vrtx) { + /* Duplicate vertex */ + v_idx = *p_vrtx; + } else { + /* New vertex */ + ASSERT(nuverts + n_new_uverts < UINT_MAX); + v_idx = (unsigned)(nuverts + n_new_uverts); + ASSERT(v_idx == htable_vrtx_size_get(&geom->unique_vertices_ids)); + ERR(darray_vertex_push_back(&geom->unique_vertices, &tmp)); + ERR(htable_vrtx_set(&geom->unique_vertices_ids, &tmp, &v_idx)); + ++n_new_uverts; + } + /* Keep the unique ID for vertex i */ + ERR(darray_uint_push_back(&unique_vertice_ids, &v_idx)); + } + + /* Get triangles and deduplicate */ + trg = darray_triangle_data_get(&geom->unique_triangles); + FOR_EACH(i, 0, ntris) { + int j, reversed; + struct unsigned3 trg_key; + struct triangle tmp = TRG_UNDEF__; + unsigned* p_trg; + struct trg_descriptions* trg_descriptions = NULL; + unsigned unique_id; + + callbacks->get_indices(i, tmp.vertex_ids, ctx); + FOR_EACH(j, 0, 3) { + if(tmp.vertex_ids[j] >= nverts) { + res = RES_BAD_ARG; + goto error; + } + /* Replace the vertex ID by its the unique ID */ + tmp.vertex_ids[j] + = darray_uint_cdata_get(&unique_vertice_ids)[tmp.vertex_ids[j]]; + } + if(tmp.vertex_ids[0] == tmp.vertex_ids[1] + || tmp.vertex_ids[0] == tmp.vertex_ids[2] + || tmp.vertex_ids[1] == tmp.vertex_ids[2]) + { + int abort = 0; + if(callbacks->degenerated_triangle) { + /* Let the client app rule. */ + ERR(callbacks->degenerated_triangle(i, ctx, &abort)); + } else { + log_warn(geom->dev, "%s: triangle %u is degenerated.\n", + FUNC_NAME, i); + } + if(abort) { + res = RES_BAD_ARG; + goto error; + } + else continue; + } + /* Get properties */ + if(callbacks->get_properties) + callbacks->get_properties(i, tmp.properties, ctx); + /* Find duplicate triangles */ + reversed = trg_make_key(&trg_key, tmp.vertex_ids); + p_trg = htable_trg_find(&geom->unique_triangles_ids, &trg_key); + if(p_trg) { + /* Duplicate triangle. Need to check duplicate validity */ + struct unsigned3 utrg_key; + int ureversed = trg_make_key(&utrg_key, trg[*p_trg].vertex_ids); + int same = (reversed == ureversed); + int already_conflict; + ASSERT(trg_key_eq(&trg_key, &utrg_key)); + unique_id = *p_trg; + ERR(geometry_enlarge_trg_descriptions(geom, 1 + unique_id)); + trg_descriptions + = darray_trg_descriptions_data_get(&geom->trg_descriptions); + if(!same) + SWAP(unsigned, tmp.properties[SG3D_FRONT], tmp.properties[SG3D_BACK]); + already_conflict = trg_descriptions[i].merge_conflict; + if(callbacks->merge_triangle) { + /* Let the client app rule. */ + ERR(callbacks->merge_triangle(*p_trg, i, !same, trg[*p_trg].properties, + tmp.properties, ctx, &trg_descriptions[i].merge_conflict)); + } else { + FOR_EACH(j, 0, SG3D_PROP_TYPES_COUNT__) { + if(!sg3d_compatible_property(trg[*p_trg].properties[j], + tmp.properties[j])) + { + trg_descriptions[i].merge_conflict = 1; + break; + } + } + } + if(trg_descriptions[i].merge_conflict && !already_conflict) + geom->merge_conflict_count++; + /* Replace SG3D_UNSPECIFIED_PROPERTY properties */ + FOR_EACH(j, 0, SG3D_PROP_TYPES_COUNT__) { + if(trg[*p_trg].properties[j] == SG3D_UNSPECIFIED_PROPERTY + && tmp.properties[j] != SG3D_UNSPECIFIED_PROPERTY) { + trg[*p_trg].properties[j] = tmp.properties[j]; + if(j == SG3D_FRONT || j == SG3D_BACK) + geom->sides_with_defined_medium_count++; + } + } + } else { + /* New triangle */ + ASSERT(nutris + n_new_utris < UINT_MAX); + unique_id = (unsigned)(nutris + n_new_utris); + tmp.user_id = geom->triangle_count_including_duplicates + i; + if(callbacks->add_triangle) + ERR(callbacks->add_triangle(unique_id, i, ctx)); + ERR(geometry_enlarge_trg_descriptions(geom, 1 + unique_id)); + trg_descriptions + = darray_trg_descriptions_data_get(&geom->trg_descriptions); + ERR(darray_triangle_push_back(&geom->unique_triangles, &tmp)); + FOR_EACH(j, 0, SG3D_PROP_TYPES_COUNT__) { + if((j == SG3D_FRONT || j == SG3D_BACK) + && tmp.properties[j] != SG3D_UNSPECIFIED_PROPERTY) + geom->sides_with_defined_medium_count++; + } + ASSERT(unique_id == htable_trg_size_get(&geom->unique_triangles_ids)); + ERR(htable_trg_set(&geom->unique_triangles_ids, &trg_key, &unique_id)); + n_new_utris++; + } + ERR(geometry_register_triangle(geom, &tmp, unique_id, geom->set_id, + trg_descriptions[i].properties_conflict)); + if(trg_descriptions[i].properties_conflict) + geom->merge_conflict_count++; + } + + ASSERT(nuverts + n_new_uverts + == htable_vrtx_size_get(&geom->unique_vertices_ids)); + ASSERT(nutris + n_new_utris + == htable_trg_size_get(&geom->unique_triangles_ids)); +exit: + if(geom) { + geom->set_id++; + geom->triangle_count_including_duplicates += ntris; + } + if(unique_vertice_ids_initialized) + darray_uint_release(&unique_vertice_ids); + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_validate_properties + (struct sg3d_geometry* geom, + res_T(*validate)(const unsigned, const unsigned*, void*, int*), + void* ctx) +{ + size_t sz__; + unsigned i, sz; + struct trg_descriptions* trg_descriptions; + res_T res = RES_OK; + + if(!geom || !validate) { + res = RES_BAD_ARG; + goto error; + } + + sz__ = darray_trg_descriptions_size_get(&geom->trg_descriptions); + ASSERT(sz__ <= UINT_MAX); + sz = (unsigned)sz__; + trg_descriptions + = darray_trg_descriptions_data_get(&geom->trg_descriptions); + geom->properties_conflict_count = 0; /* Reset count */ + FOR_EACH(i, 0, sz) { + unsigned p, j; + unsigned props[SG3D_PROP_TYPES_COUNT__]; + struct trg_descriptions* trgd = trg_descriptions + i; + /* Validate only triangle not flagged with merge_conflict */ + if(trgd->merge_conflict) { + trgd->properties_conflict = 0; + continue; + } + /* Get properties for non-conflict triangles */ + FOR_EACH(p, 0, SG3D_PROP_TYPES_COUNT__) { + const struct definition* defs = darray_definition_cdata_get(trgd->defs + p); + props[p] = SG3D_UNSPECIFIED_PROPERTY; + FOR_EACH(j, 0, darray_definition_size_get(trgd->defs + p)) { + if(defs[j].property_value != SG3D_UNSPECIFIED_PROPERTY) { + props[p] = defs[j].property_value; + break; + } + } + } + /* Call vaildation */ + ERR(validate(i, props, ctx, &trgd->properties_conflict)); + if(trgd->properties_conflict) + geom->properties_conflict_count++; + } + +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_vertices_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + size_t sz; + if(!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + sz = darray_vertex_size_get(&geom->unique_vertices); + ASSERT(sz <= UINT_MAX); + *count = (unsigned)sz; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_vertex + (const struct sg3d_geometry* geom, + const unsigned ivtx, + double coord[3]) +{ + res_T res = RES_OK; + const struct vertex* vertices; + if(!geom || !coord + || ivtx >= darray_vertex_size_get(&geom->unique_vertices)) + { + res = RES_BAD_ARG; + goto error; + } + vertices = darray_vertex_cdata_get(&geom->unique_vertices); + d3_set(coord, vertices[ivtx].coord); +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_added_triangles_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + if (!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + *count = geom->triangle_count_including_duplicates; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangles_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + size_t sz; + if(!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + sz = darray_triangle_size_get(&geom->unique_triangles); + ASSERT(sz <= UINT_MAX); + *count = (unsigned)sz; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangle_vertices + (const struct sg3d_geometry* geom, + const unsigned itri, + unsigned indices[3]) +{ + res_T res = RES_OK; + const struct triangle* triangles; + size_t i; + if(!geom || !indices + || itri >= darray_triangle_size_get(&geom->unique_triangles)) + { + res = RES_BAD_ARG; + goto error; + } + triangles = darray_triangle_cdata_get(&geom->unique_triangles); + FOR_EACH(i, 0, 3) indices[i] = triangles[itri].vertex_ids[i]; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangle_properties + (const struct sg3d_geometry* geom, + const unsigned itri, + unsigned properties[SG3D_PROP_TYPES_COUNT__]) +{ + res_T res = RES_OK; + const struct triangle* triangles; + size_t i; + if(!geom || !properties + || itri >= darray_triangle_size_get(&geom->unique_triangles)) + { + res = RES_BAD_ARG; + goto error; + } + triangles = darray_triangle_cdata_get(&geom->unique_triangles); + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + properties[i] = triangles[itri].properties[i]; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangle_user_id + (const struct sg3d_geometry* geom, + const unsigned itri, + unsigned* user_id) +{ + res_T res = RES_OK; + const struct triangle* triangles; + if(!geom || !user_id + || itri >= darray_triangle_size_get(&geom->unique_triangles)) + { + res = RES_BAD_ARG; + goto error; + } + triangles = darray_triangle_cdata_get(&geom->unique_triangles); + *user_id = triangles[itri].user_id; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangles_with_unspecified_side_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + if(!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + *count = geom->trg_with_unspecified_sides_count; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangles_with_unspecified_interface_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + if(!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + *count = geom->trg_with_unspecified_intface_count; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangles_with_merge_conflict_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + if(!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + *count = geom->merge_conflict_count; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_get_unique_triangles_with_properties_conflict_count + (const struct sg3d_geometry* geom, + unsigned* count) +{ + res_T res = RES_OK; + if(!geom || !count) { + res = RES_BAD_ARG; + goto error; + } + *count = geom->properties_conflict_count; +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_dump_as_obj + (const struct sg3d_geometry* geom, + FILE* stream, + int flags) +{ + res_T res = RES_OK; + const struct vertex* vertices; + size_t vsz, tsz, i; + if(!geom || !stream || !flags + || !geom->triangle_count_including_duplicates) + { + if(geom && !geom->triangle_count_including_duplicates) + log_err(geom->dev, + "%s: cannot dump empty geometries as OBJ\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + /* Headers */ + fprintf(stream, "# Dump of star-geometry\n"); + fprintf(stream, "# Geometry counts:\n"); + vsz = darray_vertex_size_get(&geom->unique_vertices); + ASSERT(vsz <= UINT_MAX); + fprintf(stream, "# . %u vertices\n", (unsigned)vsz); + tsz = darray_triangle_size_get(&geom->unique_triangles); + ASSERT(tsz <= UINT_MAX); + fprintf(stream, "# . %u triangles\n", (unsigned)tsz); + fprintf(stream, + "# . %u triangles flagged with a merge conflict\n", + geom->merge_conflict_count); + fprintf(stream, + "# . %u triangles flagged with a property conflict\n", + geom->merge_conflict_count); + + /* Dump vertices */ + vertices = darray_vertex_cdata_get(&geom->unique_vertices); + FOR_EACH(i, 0, vsz) + fprintf(stream, "v %g %g %g\n", SPLIT3(vertices[i].coord)); + + /* Dump triangles by groups */ + dump_partition(geom, stream, "Valid_triangles", SG3D_OBJ_DUMP_VALID_PRIMITIVE); + dump_partition(geom, stream, "Merge_conflicts", SG3D_OBJ_DUMP_MERGE_CONFLICTS); + dump_partition(geom, stream, "Property_conflicts", SG3D_OBJ_DUMP_PROPERTY_CONFLICTS); + +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_dump_as_vtk + (const struct sg3d_geometry* geom, + FILE* stream) +{ + res_T res = RES_OK; + const struct vertex* vertices; + const struct triangle* triangles; + const struct trg_descriptions* descriptions; + size_t vsz, tsz, i; + if(!geom || !stream || !geom->triangle_count_including_duplicates) { + if(geom && !geom->triangle_count_including_duplicates) + log_err(geom->dev, + "%s: cannot dump empty geometries as VTK\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + /* Headers */ + fprintf(stream, "# vtk DataFile Version 3.0\n"); + fprintf(stream, "Dump of star-geometry geometry\n"); + fprintf(stream, "ASCII\n"); + fprintf(stream, "DATASET POLYDATA\n"); + + /* Dump vertices */ + vsz = darray_vertex_size_get(&geom->unique_vertices); + ASSERT(vsz <= UINT_MAX); + fprintf(stream, "POINTS %u double\n", (unsigned)vsz); + vertices = darray_vertex_cdata_get(&geom->unique_vertices); + FOR_EACH(i, 0, vsz) + fprintf(stream, "%g %g %g\n", SPLIT3(vertices[i].coord)); + + /* Dump triangles */ + tsz = darray_triangle_size_get(&geom->unique_triangles); + ASSERT(4 * tsz <= UINT_MAX); + fprintf(stream, "POLYGONS %u %u\n", (unsigned)tsz, (unsigned)(4 * tsz)); + triangles = darray_triangle_cdata_get(&geom->unique_triangles); + FOR_EACH(i, 0, tsz) + fprintf(stream, "3 %u %u %u\n", SPLIT3(triangles[i].vertex_ids)); + + /* Start triangles properties */ + fprintf(stream, "CELL_DATA %u\n", (unsigned)tsz); + descriptions = darray_trg_descriptions_cdata_get(&geom->trg_descriptions); + + /* Dump front medium */ + fprintf(stream, "SCALARS Front_medium int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + dump_trg_property(geom, stream, SG3D_FRONT); + + /* Dump back medium */ + fprintf(stream, "SCALARS Back_medium int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + dump_trg_property(geom, stream, SG3D_BACK); + + /* Dump interface */ + fprintf(stream, "SCALARS Interface int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + dump_trg_property(geom, stream, SG3D_INTFACE); + + /* Dump user_id */ + fprintf(stream, "SCALARS User_ID int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + FOR_EACH(i, 0, tsz) + fprintf(stream, "%u\n", triangles[i].user_id); + + /* Dump merge conflict status */ + fprintf(stream, "SCALARS Merge_conflict int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + FOR_EACH(i, 0, tsz) + fprintf(stream, "%d\n", descriptions[i].merge_conflict); + + /* Dump property conflict status */ + fprintf(stream, "SCALARS Property_conflict int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + FOR_EACH(i, 0, tsz) + fprintf(stream, "%d\n", descriptions[i].properties_conflict); + + /* Dump rank of the sg3d_geometry_add that created the triangle */ + fprintf(stream, "SCALARS Created_at_sg3d_geometry_add int\n"); + fprintf(stream, "LOOKUP_TABLE default\n"); + FOR_EACH(i, 0, tsz) { + const struct definition* tdefs; + const unsigned* ranks; + ASSERT(darray_definition_size_get(&descriptions[i].defs[SG3D_FRONT]) > 0); + /* Rank is the first set_id of the first definition of any property */ + tdefs = darray_definition_cdata_get(&descriptions[i].defs[SG3D_FRONT]); + ranks = darray_uint_cdata_get(&tdefs[0].set_ids); + fprintf(stream, "%u\n", ranks[0]); + } + +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_dump_as_c_code + (const struct sg3d_geometry* geom, + FILE* stream, + const char* name_prefix, + const int flags) +{ + res_T res = RES_OK; + const struct vertex* vertices; + const struct triangle* triangles; + const char* qualifiers; + size_t vsz, tsz, i; + if(!geom || !stream + || geom->merge_conflict_count + || geom->properties_conflict_count + || !geom->triangle_count_including_duplicates) + { + if(geom + && (geom->merge_conflict_count + || geom->properties_conflict_count)) + log_err(geom->dev, + "%s: cannot dump geometries with conflict as C code\n", + FUNC_NAME); + if(geom && !geom->triangle_count_including_duplicates) + log_err(geom->dev, + "%s: cannot dump empty geometries as C code\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + if(!name_prefix) name_prefix = ""; + /* Headers */ + if(name_prefix && name_prefix[0] != '\0') + fprintf(stream, "/* Dump of star-geometry '%s'. */\n", name_prefix); + else + fprintf(stream, "/* Dump of star-geometry. */\n"); + vsz = darray_vertex_size_get(&geom->unique_vertices); + ASSERT(3 * vsz <= UINT_MAX); + tsz = darray_triangle_size_get(&geom->unique_triangles); + ASSERT(3 * tsz <= UINT_MAX); + + if(vsz == 0 || tsz == 0) { + log_err(geom->dev, + "%s: no geometry to dump\n", + FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + if(flags & SG3D_C_DUMP_CONST && flags & SG3D_C_DUMP_STATIC) + qualifiers = "static const "; + else if(flags & SG3D_C_DUMP_CONST) + qualifiers = "const "; + else if(flags & SG3D_C_DUMP_STATIC) + qualifiers = "static "; + else qualifiers = ""; + + /* Dump vertices */ + fprintf(stream, "%sunsigned %s_vertices_count = %u;\n", + qualifiers, name_prefix, (unsigned)vsz); + + vertices = darray_vertex_cdata_get(&geom->unique_vertices); + fprintf(stream, + "%sdouble %s_vertices[%u] =\n" + "{\n", + qualifiers, name_prefix, (unsigned)(3 * vsz)); + FOR_EACH(i, 0, vsz - 1) + fprintf(stream, + " %g, %g, %g,\n", SPLIT3(vertices[i].coord)); + fprintf(stream, + " %g, %g, %g\n", SPLIT3(vertices[vsz - 1].coord)); + fprintf(stream, + "};\n"); + + /* Dump triangles */ + fprintf(stream, "%sunsigned %s_triangles_count = %u;\n", + qualifiers, name_prefix, (unsigned)tsz); + + triangles = darray_triangle_cdata_get(&geom->unique_triangles); + fprintf(stream, + "%sunsigned %s_triangles[%u] =\n" + "{\n", + qualifiers, name_prefix, (unsigned)(3 * tsz)); + FOR_EACH(i, 0, tsz - 1) + fprintf(stream, + " %u, %u, %u,\n", SPLIT3(triangles[i].vertex_ids)); + fprintf(stream, + " %u, %u, %u\n", SPLIT3(triangles[tsz - 1].vertex_ids)); + fprintf(stream, + "};\n"); + + /* Dump properties */ + fprintf(stream, + "%sunsigned %s_properties[%u] =\n" + "{\n", + qualifiers, name_prefix, (unsigned)(SG3D_PROP_TYPES_COUNT__ * tsz)); + FOR_EACH(i, 0, tsz) { + int p; + fprintf(stream, " "); + FOR_EACH(p, 0, SG3D_PROP_TYPES_COUNT__) { + if(triangles[i].properties[p] == SG3D_UNSPECIFIED_PROPERTY) + fprintf(stream, " SG3D_UNSPECIFIED_PROPERTY"); + else fprintf(stream," %u", triangles[i].properties[p]); + if(i < tsz-1 || p < 2) fprintf(stream, ","); + if(p == 2) fprintf(stream, "\n"); + } + } + fprintf(stream, + "};\n"); + +exit: + return res; +error: + goto exit; +} + +res_T +sg3d_geometry_ref_get(struct sg3d_geometry* geom) +{ + if(!geom) return RES_BAD_ARG; + ref_get(&geom->ref); + return RES_OK; +} + +res_T +sg3d_geometry_ref_put(struct sg3d_geometry* geom) +{ + if(!geom) return RES_BAD_ARG; + ref_put(&geom->ref, geometry_release); + return RES_OK; +} diff --git a/src/sg3d_geometry.h b/src/sg3d_geometry.h @@ -0,0 +1,279 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3D_GEOMETRY_H__ +#define SG3D_GEOMETRY_H__ + +#include "sg3d.h" +#include "sg3d_misc.h" + +#include <rsys/ref_count.h> +#include <rsys/dynamic_array.h> +#include <rsys/hash_table.h> + +/* Forward declaration of external opaque data types */ + +/******************************************************************************* + * A type to store triangles + ******************************************************************************/ +struct triangle { + unsigned vertex_ids[3]; + /* FRONT/BACK/INTERFACE property */ + unsigned properties[SG3D_PROP_TYPES_COUNT__]; + /* ID of the triangle in user world, i.e. without deduplication */ + unsigned user_id; +}; +#define TRG_UNDEF__ {\ + { SG3D_UNSPECIFIED_PROPERTY, SG3D_UNSPECIFIED_PROPERTY, SG3D_UNSPECIFIED_PROPERTY },\ + { SG3D_UNSPECIFIED_PROPERTY, SG3D_UNSPECIFIED_PROPERTY, SG3D_UNSPECIFIED_PROPERTY },\ + SG3D_UNSPECIFIED_PROPERTY\ +} +#define DARRAY_NAME triangle +#define DARRAY_DATA struct triangle +#include <rsys/dynamic_array.h> + +/******************************************************************************* + * A type to store vertices + ******************************************************************************/ +struct vertex { + double coord[3]; +}; +#define DARRAY_NAME vertex +#define DARRAY_DATA struct vertex +#include <rsys/dynamic_array.h> + +/******************************************************************************* + * A type to map triangle vertices to IDs in unique_triangles + ******************************************************************************/ +struct unsigned3 { unsigned x[3]; }; + +static FINLINE int +trg_key_eq(const struct unsigned3* k1, const struct unsigned3* k2) +{ + ASSERT(k1 && k2); + ASSERT(k1->x[0] < k1->x[1] && k1->x[1] < k1->x[2]); + ASSERT(k2->x[0] < k2->x[1] && k2->x[1] < k2->x[2]); + return (k1->x[0] == k2->x[0]) + && (k1->x[1] == k2->x[1]) + && (k1->x[2] == k2->x[2]); +} + +#define HTABLE_NAME trg +#define HTABLE_KEY struct unsigned3 +#define HTABLE_DATA unsigned +#define HTABLE_KEY_FUNCTOR_EQ trg_key_eq +#include <rsys/hash_table.h> + + /******************************************************************************* + * A type to map vertex coordinates to IDs in unique_vertices + ******************************************************************************/ +static FINLINE int +vrtx_eq(const struct vertex* v1, const struct vertex* v2) +{ + int i; + ASSERT(v1 && v2); + FOR_EACH(i, 0, 3) if(v1->coord[i] != v2->coord[i]) return 0; + return 1; +} + +#define HTABLE_NAME vrtx +#define HTABLE_KEY struct vertex +#define HTABLE_DATA unsigned +#define HTABLE_KEY_FUNCTOR_EQ vrtx_eq +#include <rsys/hash_table.h> + +/******************************************************************************* + * Types to record sources and values of triangle descriptions. + ******************************************************************************/ + + /* A type to store a value and the files defining this value + * (usualy a single file) */ +struct definition { + /* The value */ + unsigned property_value; + /* The IDs of the geometry sets that defined the value */ + struct darray_uint set_ids; +}; + +static FINLINE void +init_definition + (struct mem_allocator* alloc, + struct definition* data) +{ + ASSERT(alloc && data); + data->property_value = SG3D_UNSPECIFIED_PROPERTY; + darray_uint_init(alloc, &data->set_ids); +} + +static INLINE res_T +copy_definition + (struct definition* dst, + const struct definition* src) +{ + res_T res = RES_OK; + ASSERT(dst && src); + dst->property_value = src->property_value; + ERR(darray_uint_copy(&dst->set_ids, &src->set_ids)); +exit: + return res; +error: + goto exit; +} + +static FINLINE void +release_definition + (struct definition* data) +{ + ASSERT(data); + darray_uint_release(&data->set_ids); +} + +#define DARRAY_NAME definition +#define DARRAY_DATA struct definition +#define DARRAY_FUNCTOR_INIT init_definition +#define DARRAY_FUNCTOR_COPY copy_definition +#define DARRAY_FUNCTOR_RELEASE release_definition +#include <rsys/dynamic_array.h> + +/* A type to accumulate information for a triangle. + * If there is more than 1 definition / field, it is a conflict */ +struct trg_descriptions { + struct darray_definition defs[SG3D_PROP_TYPES_COUNT__]; + int merge_conflict; + int properties_conflict; + char defs_include_unspecified; + char property_defined[SG3D_PROP_TYPES_COUNT__]; +}; + +static FINLINE void +init_trg_descriptions + (struct mem_allocator* alloc, + struct trg_descriptions* data) +{ + int i; + ASSERT(alloc && data); + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + darray_definition_init(alloc, data->defs + i); + data->merge_conflict = 0; + data->properties_conflict = 0; + data->defs_include_unspecified = 0; + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + data->property_defined[i] = 0; +} + +static INLINE res_T +copy_trg_descriptions + (struct trg_descriptions* dst, + const struct trg_descriptions* src) +{ + res_T res = RES_OK; + int i; + ASSERT(dst && src); + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + ERR(darray_definition_copy(&dst->defs[i], &src->defs[i])); + dst->merge_conflict = src->merge_conflict; + dst->properties_conflict = src->properties_conflict; + dst->defs_include_unspecified = src->defs_include_unspecified; + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + dst->property_defined[i] = src->property_defined[i]; +exit: + return res; +error: + goto exit; +} + +static FINLINE void +release_trg_descriptions + (struct trg_descriptions* data) +{ + int i; + ASSERT(data); + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + darray_definition_release(data->defs + i); +} + +#define DARRAY_NAME trg_descriptions +#define DARRAY_DATA struct trg_descriptions +#define DARRAY_FUNCTOR_INIT init_trg_descriptions +#define DARRAY_FUNCTOR_COPY copy_trg_descriptions +#define DARRAY_FUNCTOR_RELEASE release_trg_descriptions +#include <rsys/dynamic_array.h> + +/******************************************************************************* + * A type to store interface IDs, as star-enclosures doesn't manage them. + ******************************************************************************/ +static FINLINE void +init_trg_intfaceid + (struct mem_allocator* alloc, + unsigned* data) +{ + ASSERT(data); (void)alloc; + *data = SG3D_UNSPECIFIED_PROPERTY; +} + +#define DARRAY_NAME intface_id +#define DARRAY_DATA unsigned +#define DARRAY_FUNCTOR_INIT init_trg_intfaceid +#include <rsys/dynamic_array.h> + +/******************************************************************************* + * Types to store geometry amid sg3d_geometry_add calls. + ******************************************************************************/ +struct sg3d_geometry { + /* Record unique (i.e. deduplicated) triangles */ + struct darray_triangle unique_triangles; + /* Record coordinates for unique (i.e. deduplicated) vertices */ + struct darray_vertex unique_vertices; + + /* A table to map triangle vertices to IDs in unique_triangles */ + struct htable_trg unique_triangles_ids; + /* A table to map vertex coordinates to IDs in unique_vertices */ + struct htable_vrtx unique_vertices_ids; + + /* Record which set defined what */ + struct darray_trg_descriptions trg_descriptions; + + /* Counts */ + unsigned set_id; + unsigned triangle_count_including_duplicates; + unsigned sides_with_defined_medium_count; + unsigned trg_with_unspecified_sides_count; + unsigned trg_with_unspecified_intface_count; + unsigned merge_conflict_count; + unsigned properties_conflict_count; + + struct sg3d_device* dev; + ref_T ref; +}; + +/******************************************************************************* + * Local functions + ******************************************************************************/ + +extern LOCAL_SYM res_T +geometry_register_triangle + (struct sg3d_geometry* geometry, + const struct triangle* triangle, + const unsigned triangle_unique_id, + const unsigned set_id, + const int merge_conflict); + +/* Add new undefined triangle descriptions to a geometry */ +extern LOCAL_SYM res_T +geometry_enlarge_trg_descriptions + (struct sg3d_geometry* geom, + const size_t sz); + +#endif /* SG3D_GEOMETRY_H__ */ diff --git a/src/sg3d_misc.h b/src/sg3d_misc.h @@ -0,0 +1,21 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3D_MISC_H__ +#define SG3D_MISC_H__ + +#define ERR(Expr) if((res = (Expr)) != RES_OK) goto error; + +#endif /* SG3D_MISC_H__ */ diff --git a/src/sg3d_s3d_helper.h b/src/sg3d_s3d_helper.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3D_SENC_3D_HELPER_H__ +#define SG3D_SENC_3D_HELPER_H__ + +#include "sg3d.h" +#include <star/senc.h> + +#include <rsys/rsys.h> +#include <rsys/float3.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 +sg3d_s3d_geometry_get_indices + (const unsigned itri, + unsigned indices[SG3D_GEOMETRY_DIMENSION], + void* ctx) +{ + const struct sg3d_geometry* geometry = ctx; + res_T r; + ASSERT(indices && geometry); + r = sg3d_geometry_get_unique_triangle_vertices(geometry, itri, indices); + ASSERT(r == RES_OK); (void)r; +} + +/* 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 +sg3d_s3d_geometry_get_position + (const unsigned ivert, + float coord[SG3D_GEOMETRY_DIMENSION], + void* ctx) +{ + const struct sg3d_geometry* geometry = ctx; + double tmp[3]; + res_T r; + ASSERT(coord && geometry); + r = sg3d_geometry_get_unique_vertex(geometry, ivert, tmp); + ASSERT(r == RES_OK); (void)r; + f3_set_d3(coord, tmp); +} + +END_DECLS + +#endif /* SG3D_SENC_3D_HELPER_H__ */ diff --git a/src/sg3d_senc_helper.h b/src/sg3d_senc_helper.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 SG3D_SENC_3D_HELPER_H__ +#define SG3D_SENC_3D_HELPER_H__ + +#include "sg3d.h" +#include <star/senc.h> + +#include <rsys/rsys.h> + +/* Get vertex indices for the itri_th triangle. + * Suitable for use as get_indices callback in senc_scene_create calls. */ +static FINLINE void +sg3_senc_geometry_get_indices + (const unsigned itri, + unsigned indices[SG3D_GEOMETRY_DIMENSION], + void* ctx) +{ + const struct sg3d_geometry* geometry = ctx; + res_T r; + ASSERT(indices && geometry); + r = sg3d_geometry_get_unique_triangle_vertices(geometry, itri, indices); + ASSERT(r == RES_OK); (void)r; +} + +/* Get vertex indices for the itri_th triangle. + * Suitable for use as get_media callback in senc_scene_create calls. */ +static FINLINE void +sg3_senc_geometry_get_media + (const unsigned itri, + unsigned media[2], + void* ctx) +{ + const struct sg3d_geometry* geometry = ctx; + unsigned tmp[SG3D_PROP_TYPES_COUNT__]; + res_T r; + ASSERT(media && geometry); + r = sg3d_geometry_get_unique_triangle_properties(geometry, itri, tmp); + ASSERT(r == RES_OK); (void)r; + media[SENC_FRONT] = (tmp[SG3D_FRONT] == SG3D_UNSPECIFIED_PROPERTY) + ? SENC_UNSPECIFIED_MEDIUM : tmp[SG3D_FRONT]; + media[SENC_BACK] = (tmp[SG3D_BACK] == SG3D_UNSPECIFIED_PROPERTY) + ? SENC_UNSPECIFIED_MEDIUM : tmp[SG3D_BACK]; +} + +/* Get vertex indices for the itri_th triangle. + * Suitable for use as get_position callback in senc_scene_create calls. */ +static FINLINE void +sg3_senc_geometry_get_position + (const unsigned ivert, + double coord[SG3D_GEOMETRY_DIMENSION], + void* ctx) +{ + const struct sg3d_geometry* geometry = ctx; + res_T r; + ASSERT(coord && geometry); + r = sg3d_geometry_get_unique_vertex(geometry, ivert, coord); + ASSERT(r == RES_OK); (void)r; +} + +END_DECLS + +#endif /* SG2_SENC_3D_HELPER_H__ */ diff --git a/src/sgX3.h b/src/sgX3.h @@ -1,416 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 STAR_GEOMETRY_X_3D_H__ -#define STAR_GEOMETRY_X_3D_H__ - -#include <star/sg3.h> -#include <rsys/rsys.h> - -#include <stdio.h> - -/* This file can be used in conjunction with sgX2.h from the the - * star-geometry-2D library to write code for both 2D and 3D geometries using - * the following pattern: - * - * #if (DIM==2) - * #include <star/sgX2.h> - * #elif (DIM==3) - * #include <star/sgX3.h> - * #else - * #error DIM should be defined; possible values are 2 and 3 - * #endif - * - * Then use the sgX_... types and functions in your code. - */ - - -/* Forward declaration of the star-geometry opaque data types. These data - * types are ref counted. Once created the caller implicitly owns the created - * data, i.e. its reference counter is set to 1. The sdis_<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. */ -typedef struct sg3_device sgX_device; -typedef struct sg3_geometry sgX_geometry; - -/****************************************************************************** - * The dimension of the geometry used in the library. - *****************************************************************************/ -#define SGX_GEOMETRY_DIMENSION SG3_GEOMETRY_DIMENSION - -/****************************************************************************** - * A type to list the different user properties attached to triangles. - *****************************************************************************/ -enum sgX_property_type { - SGX_FRONT = SG3_FRONT, - SGX_BACK = SG3_BACK, - SGX_INTFACE = SG3_INTFACE, - SGX_PROP_TYPES_COUNT__ = SG3_PROP_TYPES_COUNT__ -}; - -/****************************************************************************** - * A type to list the different possible partitions of triangles. - *****************************************************************************/ -enum sgX_obj_dump_content { - SGX_OBJ_DUMP_MERGE_CONFLICTS = SG3_OBJ_DUMP_MERGE_CONFLICTS, - SGX_OBJ_DUMP_PROPERTY_CONFLICTS = SG3_OBJ_DUMP_PROPERTY_CONFLICTS, - SGX_OBJ_DUMP_VALID_PRIMITIVE = SG3_OBJ_DUMP_VALID_PRIMITIVE, - SGX_OBJ_DUMP_ALL = SG3_OBJ_DUMP_ALL -}; - -/****************************************************************************** - * A type to list the different qualifiers of C code variable output. - *****************************************************************************/ -enum sgX_c_dump_qualifiers { - SGX_C_DUMP_CONST = SG3_C_DUMP_CONST, - SGX_C_DUMP_STATIC = SG3_C_DUMP_STATIC -}; - -/****************************************************************************** - * The value that should be used for properties attached to triangles (i.e. - * media or interface) when let unspecified. - * SG3_UNSPECIFIED_PROPERTY can be used for a property that has already been - * defined; in this case the previous value will remain. - *****************************************************************************/ -#define SGX_UNSPECIFIED_PROPERTY SG3_UNSPECIFIED_PROPERTY - - /***************************************************************************** - * A type to hold callbacks for sg3_geometry_add. - ****************************************************************************/ -typedef struct sg3_geometry_add_callbacks sgX_geometry_add_callbacks; -#define SGX_ADD_CALLBACKS_NULL__ SG3_ADD_CALLBACKS_NULL__ - -BEGIN_DECLS - -/****************************************************************************** - * A helper function on properties compatibility. - *****************************************************************************/ -static FINLINE int -sgX_compatible_property - (const unsigned p1, - const unsigned p2) -{ - return sg3_compatible_property(p1, p2); -} - -/****************************************************************************** - * star-geometry device. It is an handle toward the star-geometry library. - * It manages the star-geometry resources. - *****************************************************************************/ -static FINLINE res_T -sgX_device_create - (struct logger* logger, /* Can be NULL <=> use default logger */ - struct mem_allocator* allocator, /* Can be NULL <=> use default allocator */ - const int verbose, /* Verbosity level */ - sgX_device** dev) -{ - return sg3_device_create(logger, allocator, verbose, dev); -} - -static FINLINE res_T -sgX_device_ref_get - (sgX_device* dev) -{ - return sg3_device_ref_get(dev); -} - -static FINLINE res_T -sgX_device_ref_put - (sgX_device* dev) -{ - return sg3_device_ref_put(dev); -} - -/****************************************************************************** - * star-geometry geometry. - * It stores decorated geometry accumulated through calls to sg3_geometry_add, - * information related to this geometry and its creation process, including - * merge conflicts. - *****************************************************************************/ -/* Create a geometry that can be used to accumulate vertices and triangles - * decorated with properties. */ -static FINLINE res_T -sgX_geometry_create - (sgX_device* dev, - sgX_geometry** geometry) -{ - return sg3_geometry_create(dev, geometry); -} - -/* Reserve memory according to anticipated geometry size. */ -static FINLINE res_T -sgX_geometry_reserve - (sgX_geometry* geometry, - const unsigned vertices_count, - const unsigned triangles_count, - const unsigned properties_count) -{ - return sg3_geometry_reserve( - geometry, vertices_count, triangles_count, properties_count); -} - -/* Add a new set of 3D vertices and triangles to the geometry; triangles can - * be decorated with 3 properties (front and back media and interface) that can - * be let unspecified using the SG3_UNSPECIFIED_PROPERTY special value. - * Vertices can be duplicates and are silently deduplicated, always valid. - * Triangles can be duplicates, but this can be ruled invalid due to property - * inconsistency. Triangle duplicates are silently deduplicated, even if - * invalid. Consistency is to be understood as the consistency of the - * successive values for the same property across calls of sg3_geometry_add, - * not as the consistency of the values of the 3 properties of a triangle at - * some given time (this question has its own callback (validate) in the - * sg3_geometry_validate_properties API call). - * Duplicate triangles validity is either ruled by the user-provided - * merge_triangle callback, or is just a matter of properties consistency if no - * callback is provided. In either case, sg3_geometry_add never stops - * prematurely nor returns an error code due to a merge conflict. - * - if provided, the callback must return the consistency status using the - * merge_conflict_status int* paramater (0 for consistent; any other value - * for inconsistent, this value being recorded); regardless of - * merge_conflict_status, the callback can change the properties of the - * triangle before the SG3_UNSPECIFIED_PROPERTY overwriting step; - * - if not, a non-SG3_UNSPECIFIED_PROPERTY is only consistent with itself and - * with SG3_UNSPECIFIED_PROPERTY (if inconsistent, merge_conflict_status is - * set to 1 and recorded) ; regardless of merge_conflict_status, a - * non-SG3_UNSPECIFIED_PROPERTY property is never overridden. - * When deduplicating triangles, the first occurence remains (with its - * original index in user world). After consistency being computed, a final - * step consists in rewriting SG3_UNSPECIFIED_PROPERTY properties if the merged - * property is defined. */ -static FINLINE res_T -sgX_geometry_add - (sgX_geometry* geometry, - const unsigned vertices_count, - const unsigned triangles_count, - const sgX_geometry_add_callbacks* callbacks, - void* context) /* Can be NULL */ -{ - return sg3_geometry_add( - geometry, vertices_count, triangles_count, callbacks, context); -} - -/* Apply a validation callback on each triangle included in this geometry that - * is not already flagged with a merge error. If validate returns a non-RES_OK - * value, the validation stops and returns the same error value; on the other - * hand, validation goes to the end regardless of properties conflicts. - * The properties_conflict_status argument can be set to any value. Any non-0 - * value is accounted for a conflict and is kept as-is in dumps, allowing - * different shades of conflict. - * If validation is processed again, the properties conflict count is reset, - * as well as the properties_conflict_status status of the triangles. */ -static FINLINE res_T -sgX_geometry_validate_properties - (sgX_geometry* geometry, - res_T(*validate) - (const unsigned itri, - const unsigned properties[SGX_PROP_TYPES_COUNT__], - void* context, - int* properties_conflict_status), - void* context) /* Can be NULL */ -{ - return sg3_geometry_validate_properties(geometry, validate, context); -} - -/* Get the number of unique vertices. */ -static FINLINE res_T -sgX_geometry_get_unique_vertices_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_unique_vertices_count(geometry, count); -} - -/* Get the ivtx_th vertex. */ -static FINLINE res_T -sgX_geometry_get_unique_vertex - (const sgX_geometry* geometry, - const unsigned ivtx, - double coord[SGX_GEOMETRY_DIMENSION]) -{ - return sg3_geometry_get_unique_vertex(geometry, ivtx, coord); -} - -/* Get the number of triangles added to the geometry, regardless of unicity. */ -static FINLINE res_T -sgX_geometry_get_added_primitives_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_added_triangles_count(geometry, count); -} - -/* Get the number of unique triangles. */ -static FINLINE res_T -sgX_geometry_get_unique_primitives_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_unique_triangles_count(geometry, count); -} - -/* Get the vertex indices of the itri_th unique triangle. */ -static FINLINE res_T -sgX_geometry_get_unique_primitive_vertices - (const sgX_geometry* geometry, - const unsigned itri, - unsigned indices[SGX_GEOMETRY_DIMENSION]) -{ - return sg3_geometry_get_unique_triangle_vertices(geometry, itri, indices); -} - -/* Get the properties of the itri_th unique triangle. */ -static FINLINE res_T -sgX_geometry_get_unique_primitive_properties - (const sgX_geometry* geometry, - const unsigned itri, - unsigned properties[SG3_PROP_TYPES_COUNT__]) -{ - return sg3_geometry_get_unique_triangle_properties( - geometry, itri, properties); -} - -/* Get the user ID of the itri_th unique triangle, that is the user world's - * index of the triangle that first created this unique triangle. - * User world index starts at 0 and increases for every triangle that is - * submitted to sg3_geometry_add calls, regardless of duplication or - * sg3_geometry_add failures (non-RES_OK return value). */ -static FINLINE res_T -sgX_geometry_get_unique_primitive_user_id - (const sgX_geometry* geometry, - const unsigned itri, - unsigned* user_id) -{ - return sg3_geometry_get_unique_triangle_user_id(geometry, itri, user_id); -} - -/* Get the number of triangles with (at least) one unspecified side. */ -static FINLINE res_T -sgX_geometry_get_unique_primitives_with_unspecified_side_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_unique_triangles_with_unspecified_side_count( - geometry, count); -} - -/* Get the number of triangles with unspecified interface. */ -static FINLINE res_T -sgX_geometry_get_unique_primitives_with_unspecified_interface_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_unique_triangles_with_unspecified_interface_count( - geometry, count); -} - -/* Get the number of triangles flagged with a merge conflict. */ -static FINLINE res_T -sgX_geometry_get_unique_primitives_with_merge_conflict_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_unique_triangles_with_merge_conflict_count( - geometry, count); -} - -/* Get the number of triangles flagged with a property conflict. Only - * meaningful after sg3_geometry_validate_properties has been called. */ -static FINLINE res_T -sgX_geometry_get_unique_primitives_with_properties_conflict_count - (const sgX_geometry* geometry, - unsigned* count) -{ - return sg3_geometry_get_unique_triangles_with_properties_conflict_count( - geometry, count); -} - -/* Dump a geometry in the provided stream in the OBJ format. - * The geometry can include conflicts, but cannot be empty. - * The dump is made of the vertices and some triangles, without their - * properties. The dumped triangles are defined by the flags argument, that - * must be ORed enum sg3_obj_dump_content values. - * The dumped triangles are partitioned in the following groups: - * - Valid_triangles - * - Merge_conflicts - * - Property_conflict */ -static FINLINE res_T -sgX_geometry_dump_as_obj - (const sgX_geometry* geometry, - FILE* stream, - const int flags) -{ - return sg3_geometry_dump_as_obj(geometry, stream, flags); -} - -/* Dump a geometry in the provided stream in the VTK ascii format. - * The geometry can include conflicts, but cannot be empty. - * The dump is made of the vertices and triangles, with most of their - * properties: - * - Front_medium (medium ID of the front side, INT_MAX for both unspecified - * and conflicted) - * - Back_medium (medium ID of the back side, INT_MAX for both unspecified and - * conflicted) - * - Interface (interface ID, INT_MAX for both unspecified and conflicted) - * - Merge_conflict (merge conflict status) - * - Property_conflict (property conflict status) - * - Created_at_sg3_geometry_add (rank of the sg3_geometry_add that created the - * triangle) */ -static FINLINE res_T -sgX_geometry_dump_as_vtk - (const sgX_geometry* geometry, - FILE* stream) -{ - return sg3_geometry_dump_as_vtk(geometry, stream); -} - -/* Dump the geometry as C code. - * The geometry cannot be empty and must be conflict-free. - * The C code defines the 3 variables: - * - [static] [const] unsigned <name_prefix>_vertices_count = N1; - * - [static] [const] double <name_prefix>_vertices[<N1>] = { .... }; - * - [static] [const] unsigned <name_prefix>_triangles_count = N2; - * - [static] [const] unsigned <name_prefix>_triangles[<N2>] = { .... }; - * - [static] [const] unsigned <name_prefix>_properties[<N2>] = { .... }; - * Where <N1> is 3 * vertices_count and <N2> is 3 * triangles_count. - * The two qualifiers static and const are output or not according to flags; - * flags must be ORed enum sg3_c_dump_qualifiers values. */ -static FINLINE res_T -sgX_geometry_dump_as_c_code - (const sgX_geometry* geometry, - FILE* stream, - const char* name_prefix, /* Can be NULL or "" */ - const int flags) -{ - return sg3_geometry_dump_as_c_code(geometry, stream, flags); -} - -static FINLINE res_T -sgX_geometry_ref_get - (sgX_geometry* geometry) -{ - return sg3_geometry_ref_get(geometry); -} - -static FINLINE res_T -sgX_geometry_ref_put - (sgX_geometry* geometry) -{ - return sg3_geometry_ref_put(geometry); -} - -END_DECLS - -#endif /* STAR_GEOMETRY_X_3D_H__ */ diff --git a/src/sgX3d.h b/src/sgX3d.h @@ -0,0 +1,494 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 STAR_GEOMETRY3D_X_H__ +#define STAR_GEOMETRY3D_X_H__ + +#include <star/sg3d.h> +#include <star/sg3_senc_helper.h> +#include <star/sg3d_s3d_helper.h> +#include <rsys/rsys.h> + +#include <stdio.h> + +/* This file can be used in conjunction with sgX2.h from the the + * star-geometry-2D library to write code for both 2D and 3D geometries using + * the following pattern: + * + * #if (DIM==2) + * #include <star/sgX2.h> + * #elif (DIM==3) + * #include <star/sgX3.h> + * #else + * #error DIM should be defined; possible values are 2 and 3 + * #endif + * + * Then use the sgX_... types and functions in your code. + * + * Definitions from sgX2.h and sgX3.h cannot be visible at the same time + * as some of them conflict. + */ + +/* Helper macro that asserts if the invocation of the StarGeometry 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 SGX(Func) ASSERT(sgX_ ## Func == RES_OK) +#else +#define SGX(Func) sgX_ ## Func +#endif + +/* Forward declaration of the star-geometry opaque data types. These data + * types are ref counted. Once created the caller implicitly owns the created + * data, i.e. its reference counter is set to 1. The sdis_<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. */ +typedef struct sg3d_device sgX_device; +typedef struct sg3d_geometry sgX_geometry; + +/****************************************************************************** + * The dimension of the geometry used in the library. + *****************************************************************************/ +#define SGX_GEOMETRY_DIMENSION SG3D_GEOMETRY_DIMENSION + +/****************************************************************************** + * A type to list the different user properties attached to triangles. + *****************************************************************************/ +enum sgX_property_type { + SGX_FRONT = SG3D_FRONT, + SGX_BACK = SG3D_BACK, + SGX_INTFACE = SG3D_INTFACE, + SGX_PROP_TYPES_COUNT__ = SG3D_PROP_TYPES_COUNT__ +}; + +/****************************************************************************** + * A type to list the different possible partitions of triangles. + *****************************************************************************/ +enum sgX_obj_dump_content { + SGX_OBJ_DUMP_MERGE_CONFLICTS = SG3D_OBJ_DUMP_MERGE_CONFLICTS, + SGX_OBJ_DUMP_PROPERTY_CONFLICTS = SG3D_OBJ_DUMP_PROPERTY_CONFLICTS, + SGX_OBJ_DUMP_VALID_PRIMITIVE = SG3D_OBJ_DUMP_VALID_PRIMITIVE, + SGX_OBJ_DUMP_ALL = SG3D_OBJ_DUMP_ALL +}; + +/****************************************************************************** + * A type to list the different qualifiers of C code variable output. + *****************************************************************************/ +enum sgX_c_dump_qualifiers { + SGX_C_DUMP_CONST = SG3D_C_DUMP_CONST, + SGX_C_DUMP_STATIC = SG3D_C_DUMP_STATIC +}; + +/****************************************************************************** + * The value that should be used for properties attached to triangles (i.e. + * media or interface) when let unspecified. + * SG3D_UNSPECIFIED_PROPERTY can be used for a property that has already been + * defined; in this case the previous value will remain. + *****************************************************************************/ +#define SGX_UNSPECIFIED_PROPERTY SG3D_UNSPECIFIED_PROPERTY + + /***************************************************************************** + * A type to hold callbacks for sg3d_geometry_add. + ****************************************************************************/ +typedef struct sg3d_geometry_add_callbacks sgX_geometry_add_callbacks; +#define SGX_ADD_CALLBACKS_NULL__ SG3D_ADD_CALLBACKS_NULL__ + +BEGIN_DECLS + +/****************************************************************************** + * A helper function on properties compatibility. + *****************************************************************************/ +static FINLINE int +sgX_compatible_property + (const unsigned p1, + const unsigned p2) +{ + return sg3d_compatible_property(p1, p2); +} + +/****************************************************************************** + * star-geometry device. It is an handle toward the star-geometry library. + * It manages the star-geometry resources. + *****************************************************************************/ +static FINLINE res_T +sgX_device_create + (struct logger* logger, /* Can be NULL <=> use default logger */ + struct mem_allocator* allocator, /* Can be NULL <=> use default allocator */ + const int verbose, /* Verbosity level */ + sgX_device** dev) +{ + return sg3d_device_create(logger, allocator, verbose, dev); +} + +static FINLINE res_T +sgX_device_ref_get + (sgX_device* dev) +{ + return sg3d_device_ref_get(dev); +} + +static FINLINE res_T +sgX_device_ref_put + (sgX_device* dev) +{ + return sg3d_device_ref_put(dev); +} + +/****************************************************************************** + * star-geometry geometry. + * It stores decorated geometry accumulated through calls to sg3d_geometry_add, + * information related to this geometry and its creation process, including + * merge conflicts. + *****************************************************************************/ +/* Create a geometry that can be used to accumulate vertices and triangles + * decorated with properties. */ +static FINLINE res_T +sgX_geometry_create + (sgX_device* dev, + sgX_geometry** geometry) +{ + return sg3d_geometry_create(dev, geometry); +} + +/* Reserve memory according to anticipated geometry size. */ +static FINLINE res_T +sgX_geometry_reserve + (sgX_geometry* geometry, + const unsigned vertices_count, + const unsigned triangles_count, + const unsigned properties_count) +{ + return sg3d_geometry_reserve( + geometry, vertices_count, triangles_count, properties_count); +} + +/* Add a new set of 3D vertices and triangles to the geometry; triangles can + * be decorated with 3 properties (front and back media and interface) that can + * be let unspecified using the SG3D_UNSPECIFIED_PROPERTY special value. + * Vertices can be duplicates and are silently deduplicated, always valid. + * Triangles can be duplicates, but this can be ruled invalid due to property + * inconsistency. Triangle duplicates are silently deduplicated, even if + * invalid. Consistency is to be understood as the consistency of the + * successive values for the same property across calls of sg3d_geometry_add, + * not as the consistency of the values of the 3 properties of a triangle at + * some given time (this question has its own callback (validate) in the + * sg3d_geometry_validate_properties API call). + * Duplicate triangles validity is either ruled by the user-provided + * merge_triangle callback, or is just a matter of properties consistency if no + * callback is provided. In either case, sg3d_geometry_add never stops + * prematurely nor returns an error code due to a merge conflict. + * - if provided, the callback must return the consistency status using the + * merge_conflict_status int* paramater (0 for consistent; any other value + * for inconsistent, this value being recorded); regardless of + * merge_conflict_status, the callback can change the properties of the + * triangle before the SG3D_UNSPECIFIED_PROPERTY overwriting step; + * - if not, a non-SG3D_UNSPECIFIED_PROPERTY is only consistent with itself and + * with SG3D_UNSPECIFIED_PROPERTY (if inconsistent, merge_conflict_status is + * set to 1 and recorded) ; regardless of merge_conflict_status, a + * non-SG3D_UNSPECIFIED_PROPERTY property is never overridden. + * When deduplicating triangles, the first occurence remains (with its + * original index in user world). After consistency being computed, a final + * step consists in rewriting SG3D_UNSPECIFIED_PROPERTY properties if the merged + * property is defined. */ +static FINLINE res_T +sgX_geometry_add + (sgX_geometry* geometry, + const unsigned vertices_count, + const unsigned triangles_count, + const sgX_geometry_add_callbacks* callbacks, + void* context) /* Can be NULL */ +{ + return sg3d_geometry_add( + geometry, vertices_count, triangles_count, callbacks, context); +} + +/* Apply a validation callback on each triangle included in this geometry that + * is not already flagged with a merge error. If validate returns a non-RES_OK + * value, the validation stops and returns the same error value; on the other + * hand, validation goes to the end regardless of properties conflicts. + * The properties_conflict_status argument can be set to any value. Any non-0 + * value is accounted for a conflict and is kept as-is in dumps, allowing + * different shades of conflict. + * If validation is processed again, the properties conflict count is reset, + * as well as the properties_conflict_status status of the triangles. */ +static FINLINE res_T +sgX_geometry_validate_properties + (sgX_geometry* geometry, + res_T(*validate) + (const unsigned itri, + const unsigned properties[SGX_PROP_TYPES_COUNT__], + void* context, + int* properties_conflict_status), + void* context) /* Can be NULL */ +{ + return sg3d_geometry_validate_properties(geometry, validate, context); +} + +/* Get the number of unique vertices. */ +static FINLINE res_T +sgX_geometry_get_unique_vertices_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_unique_vertices_count(geometry, count); +} + +/* Get the ivtx_th vertex. */ +static FINLINE res_T +sgX_geometry_get_unique_vertex + (const sgX_geometry* geometry, + const unsigned ivtx, + double coord[SGX_GEOMETRY_DIMENSION]) +{ + return sg3d_geometry_get_unique_vertex(geometry, ivtx, coord); +} + +/* Get the number of triangles added to the geometry, regardless of unicity. */ +static FINLINE res_T +sgX_geometry_get_added_primitives_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_added_triangles_count(geometry, count); +} + +/* Get the number of unique triangles. */ +static FINLINE res_T +sgX_geometry_get_unique_primitives_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_unique_triangles_count(geometry, count); +} + +/* Get the vertex indices of the itri_th unique triangle. */ +static FINLINE res_T +sgX_geometry_get_unique_primitive_vertices + (const sgX_geometry* geometry, + const unsigned itri, + unsigned indices[SGX_GEOMETRY_DIMENSION]) +{ + return sg3d_geometry_get_unique_triangle_vertices(geometry, itri, indices); +} + +/* Get the properties of the itri_th unique triangle. */ +static FINLINE res_T +sgX_geometry_get_unique_primitive_properties + (const sgX_geometry* geometry, + const unsigned itri, + unsigned properties[SG3D_PROP_TYPES_COUNT__]) +{ + return sg3d_geometry_get_unique_triangle_properties( + geometry, itri, properties); +} + +/* Get the user ID of the itri_th unique triangle, that is the user world's + * index of the triangle that first created this unique triangle. + * User world index starts at 0 and increases for every triangle that is + * submitted to sg3d_geometry_add calls, regardless of duplication or + * sg3d_geometry_add failures (non-RES_OK return value). */ +static FINLINE res_T +sgX_geometry_get_unique_primitive_user_id + (const sgX_geometry* geometry, + const unsigned itri, + unsigned* user_id) +{ + return sg3d_geometry_get_unique_triangle_user_id(geometry, itri, user_id); +} + +/* Get the number of triangles with (at least) one unspecified side. */ +static FINLINE res_T +sgX_geometry_get_unique_primitives_with_unspecified_side_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_unique_triangles_with_unspecified_side_count( + geometry, count); +} + +/* Get the number of triangles with unspecified interface. */ +static FINLINE res_T +sgX_geometry_get_unique_primitives_with_unspecified_interface_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_unique_triangles_with_unspecified_interface_count( + geometry, count); +} + +/* Get the number of triangles flagged with a merge conflict. */ +static FINLINE res_T +sgX_geometry_get_unique_primitives_with_merge_conflict_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_unique_triangles_with_merge_conflict_count( + geometry, count); +} + +/* Get the number of triangles flagged with a property conflict. Only + * meaningful after sg3d_geometry_validate_properties has been called. */ +static FINLINE res_T +sgX_geometry_get_unique_primitives_with_properties_conflict_count + (const sgX_geometry* geometry, + unsigned* count) +{ + return sg3d_geometry_get_unique_triangles_with_properties_conflict_count( + geometry, count); +} + +/* Dump a geometry in the provided stream in the OBJ format. + * The geometry can include conflicts, but cannot be empty. + * The dump is made of the vertices and some triangles, without their + * properties. The dumped triangles are defined by the flags argument, that + * must be ORed enum sg3d_obj_dump_content values. + * The dumped triangles are partitioned in the following groups: + * - Valid_triangles + * - Merge_conflicts + * - Property_conflict */ +static FINLINE res_T +sgX_geometry_dump_as_obj + (const sgX_geometry* geometry, + FILE* stream, + const int flags) +{ + return sg3d_geometry_dump_as_obj(geometry, stream, flags); +} + +/* Dump a geometry in the provided stream in the VTK ascii format. + * The geometry can include conflicts, but cannot be empty. + * The dump is made of the vertices and triangles, with most of their + * properties: + * - Front_medium (medium ID of the front side, INT_MAX for both unspecified + * and conflicted) + * - Back_medium (medium ID of the back side, INT_MAX for both unspecified and + * conflicted) + * - Interface (interface ID, INT_MAX for both unspecified and conflicted) + * - Merge_conflict (merge conflict status) + * - Property_conflict (property conflict status) + * - Created_at_sg3d_geometry_add (rank of the sg3d_geometry_add that created the + * triangle) */ +static FINLINE res_T +sgX_geometry_dump_as_vtk + (const sgX_geometry* geometry, + FILE* stream) +{ + return sg3d_geometry_dump_as_vtk(geometry, stream); +} + +/* Dump the geometry as C code. + * The geometry cannot be empty and must be conflict-free. + * The C code defines the 3 variables: + * - [static] [const] unsigned <name_prefix>_vertices_count = N1; + * - [static] [const] double <name_prefix>_vertices[<N1>] = { .... }; + * - [static] [const] unsigned <name_prefix>_triangles_count = N2; + * - [static] [const] unsigned <name_prefix>_triangles[<N2>] = { .... }; + * - [static] [const] unsigned <name_prefix>_properties[<N2>] = { .... }; + * Where <N1> is 3 * vertices_count and <N2> is 3 * triangles_count. + * The two qualifiers static and const are output or not according to flags; + * flags must be ORed enum sg3d_c_dump_qualifiers values. */ +static FINLINE res_T +sgX_geometry_dump_as_c_code + (const sgX_geometry* geometry, + FILE* stream, + const char* name_prefix, /* Can be NULL or "" */ + const int flags) +{ + return sg3d_geometry_dump_as_c_code(geometry, stream, name_prefix, flags); +} + +static FINLINE res_T +sgX_geometry_ref_get + (sgX_geometry* geometry) +{ + return sg3d_geometry_ref_get(geometry); +} + +static FINLINE res_T +sgX_geometry_ref_put + (sgX_geometry* geometry) +{ + return sg3d_geometry_ref_put(geometry); +} + +/****************************************************************************** + * StarGeometryXD to StarEnclosuresXD helper. + *****************************************************************************/ + + /* Get vertex indices for the itri_th triangle. + * Suitable for use as get_indices callback in senc_scene_create calls. */ +static FINLINE void +sgX_sencX_geometry_get_indices + (const unsigned itri, + unsigned indices[SGX_GEOMETRY_DIMENSION], + void* ctx) +{ + sg3_senc_geometry_get_indices(itri, indices, ctx); +} + +/* Get vertex indices for the itri_th triangle. + * Suitable for use as get_media callback in senc_scene_create calls. */ +static FINLINE void +sgX_sencX_geometry_get_media + (const unsigned itri, + unsigned media[2], + void* ctx) +{ + sg3_senc_geometry_get_media(itri, media, ctx); +} + +/* Get vertex indices for the itri_th triangle. + * Suitable for use as get_position callback in senc_scene_create calls. */ +static FINLINE void +sgX_sencX_geometry_get_position + (const unsigned ivert, + double coord[SGX_GEOMETRY_DIMENSION], + void* ctx) +{ + sg3_senc_geometry_get_position(ivert, coord, ctx); +} + +/****************************************************************************** + * StarGeometryXD to StarXD helper. + *****************************************************************************/ + + /* 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 +sgX_sXd_geometry_get_indices + (const unsigned itri, + unsigned indices[SGX_GEOMETRY_DIMENSION], + void* ctx) +{ + sg3d_s3d_geometry_get_indices(itri, indices, ctx); +} + +/* 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 +sgX_sXd_geometry_get_position + (const unsigned ivert, + float coord[SGX_GEOMETRY_DIMENSION], + void* ctx) +{ + sg3d_s3d_geometry_get_position(ivert, coord, ctx); +} + +END_DECLS + +#endif /* STAR_GEOMETRY3D_X_H__ */ diff --git a/src/test_sg3_cube_behind_cube.c b/src/test_sg3_cube_behind_cube.c @@ -1,117 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" - -#include <rsys/double3.h> - -#include <stdio.h> - -/* - 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 sg3_device* dev; - struct sg3_geometry* geom; - struct context ctx = CONTEXT_NULL__; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned count; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_indices; - callbacks.get_properties = get_properties; - callbacks.get_position = get_position; - - ctx.positions = box_vertices; - ctx.indices = cube_indices; - ctx.front_media = medium0; - ctx.back_media = medium1; - ctx.intface = intface0; - - /* First cube (front: 0, back: 1), right-handed normal outside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - d3(ctx.offset, -2, -2, 20); - ctx.scale = 5; - - /* Second cube (front: 0, back: 1), right-handed normal outside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "cube_behind_cube_2", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - d3(ctx.offset, -3, -3, 30); - ctx.scale = 7; - ctx.front_media = medium1; - ctx.back_media = medium0; - - /* Third cube (front: 1, back: 0), right-handed normal outside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "cube_behind_cube_3", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_cube_in_cube.c b/src/test_sg3_cube_in_cube.c @@ -1,110 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" - -#include <rsys/double3.h> - -#include <stdio.h> - -/* - cube_2 cube_3 - - +-------------------------+ - | B - +-------------+ | +-------------+ | - m1 | m0 M m1 | m1 | m0 M | - | +------+ | | m0 | +------+ | | - | | m1 S | | | | m1 S | | - | | N <--| | | | | N <--| | | - | +------+ | | | +------+ | | - | N <--| | | N <--| | - +-------------+ | +-------------+ | - | N <--| - +-------------------------+ - */ - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct context ctx = CONTEXT_NULL__; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned count; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_indices; - callbacks.get_properties = get_properties; - callbacks.get_position = get_position; - - ctx.positions = box_vertices; - ctx.indices = cube_indices; - ctx.front_media = medium0; - ctx.back_media = medium1; - ctx.intface = intface0; - - /* First cube (front: 0, back: 1), right-handed normal outside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - d3(ctx.offset, -1, -1, -1); - ctx.scale = 3; - ctx.reverse_vrtx = 1; - - /* Second cube (front: 0, back: 1), right-handed normal inside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "cube_in_cube_2", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - d3(ctx.offset, -4, -4, -4); - ctx.scale = 10; - ctx.reverse_vrtx = 1; - ctx.reverse_med = 1; - ctx.front_media = medium1; - ctx.back_media = medium0; - - /* Third cube (front: 0, back: 1), right-handed normal inside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "cube_in_cube_3", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_cube_on_cube.c b/src/test_sg3_cube_on_cube.c @@ -1,101 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" - -#include <rsys/double3.h> - -#include <stdio.h> - -/* - +-----------------------+ - | 3 - | +------+ | - m2 | m1 | m0 2 | - | | |--> N | - | +------+ | - | | m0 1 | - | | |--> N | - | +------+ | - |--> N | - +-----------------------+ - */ - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct context ctx = CONTEXT_NULL__; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned count; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_indices; - callbacks.get_properties = get_properties; - callbacks.get_position = get_position; - - ctx.positions = cube_vertices; - ctx.indices = cube_indices; - d3(ctx.offset, 1, 1, 2); - ctx.front_media = medium1_front0; - ctx.back_media = medium0; - ctx.intface = intface0; - - /* First cube (front: 0 on top face, 1 elsewhere, back: 0), - * right-handed normal outside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - d3(ctx.offset, 1, 1, 1); - ctx.front_media = medium1_back0; - - /* Second cube (front: 0 on bottom face, 1 elsewhere, back: 0), - * right-handed normal outside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - 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; - ctx.front_media = medium2; - ctx.back_media = medium1; - - /* Third cube (front: 2, back: 1), right-handed normal inside */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "cube_on_cube", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_device.c b/src/test_sg3_device.c @@ -1,75 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_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 sg3_device* dev; - (void)argc, (void)argv; - - BA(sg3_device_create(NULL, NULL, 0, NULL)); - OK(sg3_device_create(NULL, NULL, 0, &dev)); - BA(sg3_device_ref_get(NULL)); - OK(sg3_device_ref_get(dev)); - BA(sg3_device_ref_put(NULL)); - OK(sg3_device_ref_put(dev)); - OK(sg3_device_ref_put(dev)); - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - - CHK(MEM_ALLOCATED_SIZE(&allocator) == 0); - BA(sg3_device_create(NULL, &allocator, 0, NULL)); - OK(sg3_device_create(NULL, &allocator, 0, &dev)); - OK(sg3_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(sg3_device_create(&logger, NULL, 0, NULL)); - OK(sg3_device_create(&logger, NULL, 1, &dev)); - OK(sg3_device_ref_put(dev)); - - BA(sg3_device_create(&logger, &allocator, 0, NULL)); - OK(sg3_device_create(&logger, &allocator, 0, &dev)); - OK(sg3_device_ref_put(dev)); - - OK(sg3_device_create(&logger, &allocator, 0, &dev)); - OK(sg3_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_sg3_geometry.c b/src/test_sg3_geometry.c @@ -1,293 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" - -#include <stdio.h> - -static res_T -validate - (const unsigned itri, - const unsigned properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* properties_conflict) -{ - (void)itri; (void)properties; (void)context; - *properties_conflict = 0; - return RES_OK; -} - -static res_T -merge_trg - (const unsigned user_id, - const unsigned itri, - const int reversed_triangle, - unsigned triangle_properties[SG3_PROP_TYPES_COUNT__], - const unsigned merged_properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* merge_conflict) -{ - ASSERT(triangle_properties && merged_properties && merge_conflict); - (void)user_id; (void)reversed_triangle; (void)context; - (void)triangle_properties; (void)merged_properties; (void)merge_conflict; - *merge_conflict = (int)itri; - return RES_OK; -} - -static res_T -degenerated_triangle - (const unsigned itri, - void* context, - int* abort) -{ - struct context* ctx = context; - ASSERT(abort && ctx); - (void)itri; - *abort = *(int*)ctx->custom; - return RES_OK; -} - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - double coord[3]; - unsigned indices[3]; - const unsigned degenerated[3] = { 0 , 0, 0 }; - unsigned properties[SG3_PROP_TYPES_COUNT__]; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned user_id; - unsigned count, i; - struct context ctx = CONTEXT_NULL__; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - - BA(sg3_geometry_create(NULL, &geom)); - BA(sg3_geometry_create(dev, NULL)); - OK(sg3_geometry_create(dev, &geom)); - - BA(sg3_geometry_ref_get(NULL)); - OK(sg3_geometry_ref_get(geom)); - - BA(sg3_geometry_ref_put(NULL)); - OK(sg3_geometry_ref_put(geom)); - OK(sg3_geometry_ref_put(geom)); - - OK(sg3_geometry_create(dev, &geom)); - - BA(sg3_geometry_validate_properties(NULL, NULL, NULL)); - BA(sg3_geometry_validate_properties(geom, NULL, NULL)); - BA(sg3_geometry_validate_properties(NULL, validate, NULL)); - OK(sg3_geometry_validate_properties(geom, validate, NULL)); - - BA(sg3_geometry_get_unique_vertices_count(NULL, NULL)); - BA(sg3_geometry_get_unique_vertices_count(geom, NULL)); - BA(sg3_geometry_get_unique_vertices_count(NULL, &count)); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - - BA(sg3_geometry_get_added_triangles_count(NULL, NULL)); - BA(sg3_geometry_get_added_triangles_count(geom, NULL)); - BA(sg3_geometry_get_added_triangles_count(NULL, &count)); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - - BA(sg3_geometry_get_unique_triangles_count(NULL, NULL)); - BA(sg3_geometry_get_unique_triangles_count(geom, NULL)); - BA(sg3_geometry_get_unique_triangles_count(NULL, &count)); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - - BA(sg3_geometry_get_unique_triangles_with_unspecified_side_count(NULL, NULL)); - BA(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, NULL)); - BA(sg3_geometry_get_unique_triangles_with_unspecified_side_count(NULL, &count)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - - BA(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(NULL, NULL)); - BA(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, NULL)); - BA(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(NULL, &count)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - - BA(sg3_geometry_get_unique_triangles_with_merge_conflict_count(NULL, NULL)); - BA(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, NULL)); - BA(sg3_geometry_get_unique_triangles_with_merge_conflict_count(NULL, &count)); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - - BA(sg3_geometry_get_unique_triangles_with_properties_conflict_count(NULL, NULL)); - BA(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, NULL)); - BA(sg3_geometry_get_unique_triangles_with_properties_conflict_count(NULL, &count)); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - - BA(sg3_geometry_dump_as_obj(NULL, NULL, 0)); - BA(sg3_geometry_dump_as_obj(geom, NULL, 0)); - BA(sg3_geometry_dump_as_obj(NULL, stdout, 0)); - BA(sg3_geometry_dump_as_obj(NULL, NULL, SG3_OBJ_DUMP_ALL)); - BA(sg3_geometry_dump_as_obj(geom, stdout, 0)); - BA(sg3_geometry_dump_as_obj(geom, NULL, SG3_OBJ_DUMP_ALL)); - BA(sg3_geometry_dump_as_obj(NULL, stdout, SG3_OBJ_DUMP_ALL)); - /* BA because geometry is empty */ - BA(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - - BA(sg3_geometry_dump_as_vtk(NULL, NULL)); - BA(sg3_geometry_dump_as_vtk(geom, NULL)); - BA(sg3_geometry_dump_as_vtk(NULL, stdout)); - /* BA because geometry is empty */ - BA(sg3_geometry_dump_as_vtk(geom, stdout)); - - BA(sg3_geometry_dump_as_c_code(NULL, NULL, NULL, 0)); - BA(sg3_geometry_dump_as_c_code(geom, NULL, NULL, 0)); - BA(sg3_geometry_dump_as_c_code(NULL, stdout, NULL, 0)); - BA(sg3_geometry_dump_as_c_code(NULL, NULL, "test", 0)); - BA(sg3_geometry_dump_as_c_code(geom, NULL, "test", 0)); - BA(sg3_geometry_dump_as_c_code(NULL, stdout, "test", 0)); - /* BA because geometry is empty */ - BA(sg3_geometry_dump_as_c_code(geom, stdout, NULL, 0)); - BA(sg3_geometry_dump_as_c_code(geom, stdout, "test", 0)); - - BA(sg3_geometry_add(NULL, 0, 0, &callbacks, NULL)); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 0); - BA(sg3_geometry_add(geom, nvertices, ntriangles, NULL, NULL)); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles); - /* Mandatory callbacks are NULL */ - callbacks.get_indices = NULL; - callbacks.get_position = get_position; - BA(sg3_geometry_add(geom, 0, 0, &callbacks, NULL)); - callbacks.get_indices = get_indices; - callbacks.get_position = NULL; - BA(sg3_geometry_add(geom, 0, 0, &callbacks, NULL)); - callbacks.get_indices = NULL; - callbacks.get_position = NULL; - BA(sg3_geometry_add(geom, 0, 0, &callbacks, NULL)); - /* Add 0 items */ - callbacks.get_indices = get_indices; - callbacks.get_position = get_position; - OK(sg3_geometry_add(geom, 0, 0, &callbacks, NULL)); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles); - - /* A 3D cube. - * 2 enclosures (inside, outside) sharing the same triangles, - * but opposite sides */ - ctx.positions = cube_vertices; - ctx.indices = cube_indices; - ctx.front_media = medium0; - ctx.back_media = medium1; - ctx.intface = intface0; - - callbacks.get_indices = get_indices; - callbacks.get_properties = get_properties; - callbacks.get_position = get_position; - - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - OK(sg3_geometry_dump_as_vtk(geom, stdout)); - OK(sg3_geometry_dump_as_c_code(geom, stdout, NULL, 0)); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "test", - SG3_C_DUMP_STATIC | SG3_C_DUMP_CONST)); - - BA(sg3_geometry_get_unique_vertex(NULL, ntriangles, NULL)); - BA(sg3_geometry_get_unique_vertex(geom, ntriangles, NULL)); - BA(sg3_geometry_get_unique_vertex(NULL, 0, NULL)); - BA(sg3_geometry_get_unique_vertex(NULL, ntriangles, coord)); - BA(sg3_geometry_get_unique_vertex(geom, 0, NULL)); - BA(sg3_geometry_get_unique_vertex(geom, ntriangles, coord)); - BA(sg3_geometry_get_unique_vertex(NULL, 0, coord)); - OK(sg3_geometry_get_unique_vertex(geom, 0, coord)); - - BA(sg3_geometry_get_unique_triangle_vertices(NULL, ntriangles, NULL)); - BA(sg3_geometry_get_unique_triangle_vertices(geom, ntriangles, NULL)); - BA(sg3_geometry_get_unique_triangle_vertices(NULL, 0, NULL)); - BA(sg3_geometry_get_unique_triangle_vertices(NULL, ntriangles, indices)); - BA(sg3_geometry_get_unique_triangle_vertices(geom, 0, NULL)); - BA(sg3_geometry_get_unique_triangle_vertices(geom, ntriangles, indices)); - BA(sg3_geometry_get_unique_triangle_vertices(NULL, 0, indices)); - OK(sg3_geometry_get_unique_triangle_vertices(geom, 0, indices)); - FOR_EACH(i, 0 , 3) CHK(indices[i] == cube_indices[i]); - - BA(sg3_geometry_get_unique_triangle_properties(NULL, ntriangles, NULL)); - BA(sg3_geometry_get_unique_triangle_properties(geom, ntriangles, NULL)); - BA(sg3_geometry_get_unique_triangle_properties(NULL, 0, NULL)); - BA(sg3_geometry_get_unique_triangle_properties(NULL, ntriangles, properties)); - BA(sg3_geometry_get_unique_triangle_properties(geom, 0, NULL)); - BA(sg3_geometry_get_unique_triangle_properties(geom, ntriangles, properties)); - BA(sg3_geometry_get_unique_triangle_properties(NULL, 0, properties)); - OK(sg3_geometry_get_unique_triangle_properties(geom, 0, properties)); - CHK(medium0[0] == properties[SG3_FRONT]); - CHK(medium1[0] == properties[SG3_BACK]); - CHK(intface0[0] == properties[SG3_INTFACE]); - - BA(sg3_geometry_get_unique_triangle_user_id(NULL, ntriangles, NULL)); - BA(sg3_geometry_get_unique_triangle_user_id(geom, ntriangles, NULL)); - BA(sg3_geometry_get_unique_triangle_user_id(NULL, 0, NULL)); - BA(sg3_geometry_get_unique_triangle_user_id(NULL, ntriangles, &user_id)); - BA(sg3_geometry_get_unique_triangle_user_id(geom, 0, NULL)); - BA(sg3_geometry_get_unique_triangle_user_id(geom, ntriangles, &user_id)); - BA(sg3_geometry_get_unique_triangle_user_id(NULL, 0, &user_id)); - OK(sg3_geometry_get_unique_triangle_user_id(geom, 0, &user_id)); - /* Due to a failed attempt to add ntriangles triangles, user_id for the - * first successfully added triangle is shifted */ - CHK(user_id == ntriangles); - - /* Conflicts with merge_trg callback */ - callbacks.merge_triangle = merge_trg; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - /* Due to merge_trg internals, all but the first triangle have conflict */ - CHK(count == ntriangles - 1); - OK(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - OK(sg3_geometry_dump_as_vtk(geom, stdout)); - /* BA because of conflicts */ - BA(sg3_geometry_dump_as_c_code(geom, stdout, "test", SG3_C_DUMP_STATIC)); - OK(sg3_geometry_ref_put(geom)); - - /* Conflicts without merge_trg callback */ - OK(sg3_geometry_create(dev, &geom)); - callbacks.merge_triangle = NULL; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - ctx.front_media = medium1_front0; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - FOR_EACH(i, 0, ntriangles) if(medium0[i] != medium1_front0[i]) count--; - CHK(count == 0); - OK(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - OK(sg3_geometry_dump_as_vtk(geom, stdout)); - /* BA because of conflicts */ - BA(sg3_geometry_dump_as_c_code(geom, stdout, "test", SG3_C_DUMP_CONST)); - - /* Degenerated triangles */ - ctx.indices = degenerated; - /* Without callback : OK */ - OK(sg3_geometry_add(geom, nvertices, 1, &callbacks, &ctx)); - /* With callback : OK */ - callbacks.degenerated_triangle = degenerated_triangle; - ctx.custom = &i; - i = 0; - OK(sg3_geometry_add(geom, nvertices, 1, &callbacks, &ctx)); - /* With callback : KO */ - i= 1; - BA(sg3_geometry_add(geom, nvertices, 1, &callbacks, &ctx)); - - OK(sg3_geometry_ref_put(geom)); - OK(sg3_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_sg3_geometry_2.c b/src/test_sg3_geometry_2.c @@ -1,438 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" - -#include <stdio.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 unique_id, - const unsigned iseg, - void* context) -{ - struct context* ctx = context; - struct add_geom_ctx* add_geom_ctx; - ASSERT(ctx); (void)unique_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 unique_id, - const unsigned itri, - const int reversed_triangle, - unsigned triangle_properties[SG3_PROP_TYPES_COUNT__], - const unsigned merged_properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* merge_conflict) -{ - struct context* ctx = context; - struct add_geom_ctx* add_geom_ctx; - int i; - ASSERT(ctx && triangle_properties && merged_properties && merge_conflict); - (void)unique_id; (void)itri; (void)reversed_triangle; - (void)triangle_properties; (void)merged_properties; - add_geom_ctx = ctx->custom; - if(add_geom_ctx->merge_res == RES_OK) ++add_geom_ctx->merge_cpt; - FOR_EACH(i, 0, SG3_PROP_TYPES_COUNT__) - if(!sg3_compatible_property(triangle_properties[i], merged_properties[i])) - *merge_conflict = 1; - return add_geom_ctx->merge_res; -} - -static res_T -validate - (const unsigned itri, - const unsigned properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* properties_conflict) -{ - (void)itri; (void)properties; (void)context; - *properties_conflict = 0; - return RES_OK; -} - -static res_T -validate2 - (const unsigned itri, - const unsigned properties[SG3_PROP_TYPES_COUNT__], - void* context, - int* properties_conflict) -{ - (void)itri; (void)properties; (void)context; - *properties_conflict = (itri % 2 == 0) ? 0 : (int)itri; - return RES_OK; -} - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct context ctx = CONTEXT_NULL__; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - struct add_geom_ctx add_geom_ctx; - unsigned property[12]; - unsigned i; - const unsigned property_count = sizeof(property) / sizeof(*property); - unsigned count; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - - /* A 3D cube. - * 2 enclosures (inside, outside) sharing the same triangles, - * but opposite sides */ - ctx.positions = cube_vertices; - ctx.indices = cube_indices; - 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 < property_count; i++) property[i] = SG3_UNSPECIFIED_PROPERTY; - ctx.front_media = property; - ctx.back_media = property; - ctx.intface = property; - - callbacks.get_indices = get_indices; - callbacks.get_properties = get_properties; - callbacks.get_position = get_position; - callbacks.add_triangle = add_trg; - callbacks.merge_triangle = merge_trg; - - /* If add fails, add geometry fails the same way */ - add_geom_ctx.add_res = RES_BAD_ARG; - - BA(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.add_cpt == 0); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == 0); - add_geom_ctx.add_res = RES_MEM_ERR; - ME(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.add_cpt == 0); - CHK(count == 0); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 2 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Successful add geometry with add callback */ - add_geom_ctx.add_res = RES_OK; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.add_cpt == ntriangles); - CHK(add_geom_ctx.merge_cpt == 0); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 3 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - OK(sg3_geometry_dump_as_c_code(geom, stdout, "test_unspecified", - SG3_C_DUMP_STATIC | SG3_C_DUMP_CONST)); - - /* Clear geometry */ - SG3(geometry_ref_put(geom)); - OK(sg3_geometry_create(dev, &geom)); - - /* Successful add geometry without add callback */ - add_geom_ctx.add_cpt = 0; - callbacks.add_triangle = NULL; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.add_cpt == 0); - CHK(add_geom_ctx.merge_cpt == 0); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* If merge fails, add geometry fails the same way */ - add_geom_ctx.merge_res = RES_BAD_ARG; - callbacks.add_triangle = add_trg; - BA(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == 0); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 2 * ntriangles); - add_geom_ctx.merge_res = RES_MEM_ERR; - ME(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == 0); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 3 * ntriangles); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); /* merge failed but with a no-conflict status */ - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Successful add geometry without merge callback */ - callbacks.merge_triangle = NULL; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == 0); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 4 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Successful add geometry with merge callback */ - add_geom_ctx.merge_res = RES_OK; - callbacks.merge_triangle = merge_trg; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == ntriangles); - add_geom_ctx.merge_cpt = 0; - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 5 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); /* merge failed but with a no-conflict status */ - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Geometry with media information on both sides */ - ctx.front_media = medium0; - ctx.back_media = medium1; - - /* Clear geometry */ - SG3(geometry_ref_put(geom)); - OK(sg3_geometry_create(dev, &geom)); - - /* Successful add geometry with add callback - * First half of the triangles, then all of them */ - add_geom_ctx.add_res = RES_OK; - OK(sg3_geometry_add(geom, nvertices, ntriangles / 2, &callbacks, &ctx)); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles / 2); - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.add_cpt == ntriangles); - CHK(add_geom_ctx.merge_cpt == ntriangles / 2); - add_geom_ctx.add_cpt = 0; - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles + ntriangles / 2); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); /* media where defined */ - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); /* interfaces where unspecified */ - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_vtk(geom, stdout)); - /* Second add was half duplicated, so numbering is shifted */ - FOR_EACH(i, 0, ntriangles) { - unsigned id; - OK(sg3_geometry_get_unique_triangle_user_id(geom, i, &id)); - CHK(i < ntriangles / 2 ? id == i : id == i + ntriangles / 2); - } - - /* Clear geometry */ - SG3(geometry_ref_put(geom)); - OK(sg3_geometry_create(dev, &geom)); - add_geom_ctx.merge_cpt = 0; - - /* Successful add geometry with add callback and no defined properties */ - add_geom_ctx.add_res = RES_OK; - callbacks.get_properties = NULL; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.add_cpt == ntriangles); - CHK(add_geom_ctx.merge_cpt == 0); - add_geom_ctx.add_cpt = 0; - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); /* media where unspecified */ - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == ntriangles); /* interfaces where unspecified */ - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Define interface */ - ctx.intface = intface0; - - /* Successful add geometry with merge callback and properties */ - add_geom_ctx.merge_res = RES_OK; - callbacks.get_properties = get_properties; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == ntriangles); - add_geom_ctx.merge_cpt = 0; - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 2 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); /* media where defined */ - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); /* interfaces where defined */ - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Geometry with incompatible media information on both sides */ - ctx.front_media = medium1; - ctx.back_media = medium0; - - /* Add geometry without merge callback and conflicts */ - callbacks.merge_triangle = NULL; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == 0); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 3 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); /* media where defined */ - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); /* interfaces where defined */ - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Incompatible interface */ - ctx.intface = intface1; - - /* Successful add geometry with merge callback */ - add_geom_ctx.merge_res = RES_OK; - callbacks.merge_triangle = merge_trg; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - CHK(add_geom_ctx.merge_cpt == ntriangles); - add_geom_ctx.merge_cpt = 0; - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 4 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); /* media where defined */ - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); /* interfaces where defined */ - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - /* Clear geometry */ - SG3(geometry_ref_put(geom)); - OK(sg3_geometry_create(dev, &geom)); - - /* Successful add geometry with merge callback */ - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - - OK(sg3_geometry_validate_properties(geom, validate, NULL)); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - - OK(sg3_geometry_validate_properties(geom, validate, NULL)); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - - OK(sg3_geometry_validate_properties(geom, validate2, NULL)); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == ntriangles / 2); - - OK(sg3_geometry_ref_put(geom)); - OK(sg3_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_sg3_many_enclosures.c b/src/test_sg3_many_enclosures.c @@ -1,105 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" -#include "test_sg3_utils2.h" - -#include <rsys/double3.h> - -#include <star/s3dut.h> - -#include <stdio.h> -#include <limits.h> - -#define NB_CYL_X 32 -#define NB_CYL_Y 32 -#define NB_CYL_Z 64 -#define NB_CYL (NB_CYL_X * NB_CYL_Y * NB_CYL_Z) - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned cyl_trg_count, cyl_vrtx_count, count; - int i, j, k; - unsigned m_in, m_out, itf = 0; - struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; - struct s3dut_mesh* cyl = NULL; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_s3dut_indices; - callbacks.get_properties = get_s3dut_properties; - callbacks.get_position = get_s3dut_position; - - ctx.ctx.positions = box_vertices; - ctx.ctx.indices = cube_indices; - ctx.ctx.front_media = &m_in; - ctx.ctx.back_media = &m_out; - ctx.ctx.intface = &itf; - - /* 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; - OK(sg3_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); - FOR_EACH(i, 0, NB_CYL_X) { - double center_x = 2 * (1 + NB_CYL_Z) * (i - NB_CYL_X / 2); - FOR_EACH(j, 0, NB_CYL_Y) { - double misalignment = 0; - FOR_EACH(k, 0, NB_CYL_Z) { - double center_y = 2 * (1 + NB_CYL_Z) * (j - NB_CYL_Y / 2); - m_in = (unsigned)k; - m_out = (unsigned)(k + 1); - ctx.ctx.scale = k + 1; -#ifdef MITIGATE_EMBREE_181 - /* Mitigate Embree issue #181 - * We cannot keep perfect alignment of cylinders - * or some hits are missed in some raytracing tasks */ - misalignment = (k % 2) ? -0.01 : +0.01; -#endif - d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0); - OK(sg3_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); - } - } - } - S3DUT(mesh_ref_put(cyl)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_many_triangles.c b/src/test_sg3_many_triangles.c @@ -1,86 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" -#include "test_sg3_utils2.h" - -#include <rsys/double3.h> - -#include <star/s3dut.h> - -#include <stdio.h> -#include <limits.h> - -#define NB_CYL 2 - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned cyl_trg_count, cyl_vrtx_count, i, count; - unsigned m0 = 0, m1, itf = 0; - struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; - struct s3dut_mesh* cyl = NULL; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_s3dut_indices; - callbacks.get_properties = get_s3dut_properties; - callbacks.get_position = get_s3dut_position; - - ctx.ctx.positions = box_vertices; - ctx.ctx.indices = cube_indices; - ctx.ctx.front_media = &m1; - ctx.ctx.back_media = &m0; - ctx.ctx.intface = &itf; - - /* 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; - OK(sg3_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); - FOR_EACH(i, 0, NB_CYL) { - m1 = i; - d3(ctx.ctx.offset, 0, 0, i * 10); - OK(sg3_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); - } - S3DUT(mesh_ref_put(cyl)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_obj(geom, stdout, SG3_OBJ_DUMP_ALL)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_some_enclosures.c b/src/test_sg3_some_enclosures.c @@ -1,106 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" -#include "test_sg3_utils2.h" - -#include <rsys/double3.h> - -#include <star/s3dut.h> - -#include <stdio.h> -#include <limits.h> - -#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) - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned cyl_trg_count, cyl_vrtx_count, count; - int i, j, k; - unsigned m_in, m_out, itf = 0; - struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; - struct s3dut_mesh* cyl = NULL; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_s3dut_indices; - callbacks.get_properties = get_s3dut_properties; - callbacks.get_position = get_s3dut_position; - - ctx.ctx.positions = box_vertices; - ctx.ctx.indices = cube_indices; - ctx.ctx.front_media = &m_in; - ctx.ctx.back_media = &m_out; - ctx.ctx.intface = &itf; - - /* 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; - OK(sg3_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); - FOR_EACH(i, 0, NB_CYL_X) { - double center_x = 2 * (1 + NB_CYL_Z) * (i - NB_CYL_X / 2); - FOR_EACH(j, 0, NB_CYL_Y) { - double misalignment = 0; - FOR_EACH(k, 0, NB_CYL_Z) { - double center_y = 2 * (1 + NB_CYL_Z) * (j - NB_CYL_Y / 2); - m_in = (unsigned)k; - m_out = (unsigned)(k + 1); - ctx.ctx.scale = k + 1; -#ifdef MITIGATE_EMBREE_181 - /* Mitigate Embree issue #181 - * We cannot keep perfect alignment of cylinders - * or some hits are missed in some raytracing tasks */ - misalignment = (k % 2) ? -0.01 : +0.01; -#endif - d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0); - OK(sg3_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); - } - } - } - S3DUT(mesh_ref_put(cyl)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_dump_as_c_code(geom, stdout, "some_enclosures", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_some_triangles.c b/src/test_sg3_some_triangles.c @@ -1,88 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" -#include "test_sg3_utils2.h" - -#include <rsys/double3.h> - -#include <star/s3dut.h> - -#include <stdio.h> -#include <limits.h> - -#define NB_CYL 4 - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned cyl_trg_count, cyl_vrtx_count, i, count; - unsigned m0 = 0, m1, itf = 0; - struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; - struct s3dut_mesh* cyl = NULL; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - SG3(device_ref_put(dev)); - - callbacks.get_indices = get_s3dut_indices; - callbacks.get_properties = get_s3dut_properties; - callbacks.get_position = get_s3dut_position; - - ctx.ctx.positions = box_vertices; - ctx.ctx.indices = cube_indices; - ctx.ctx.front_media = &m1; - ctx.ctx.back_media = &m0; - ctx.ctx.intface = &itf; - - /* A 264 triangles 134 vertices cylinder template */ - S3DUT(create_cylinder(&allocator, 1, 2, 12, 10, &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; - OK(sg3_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); - FOR_EACH(i, 0, NB_CYL) { - m1 = i; - d3(ctx.ctx.offset, 0, 0, i * 10); - OK(sg3_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); - } - S3DUT(mesh_ref_put(cyl)); - - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - - OK(sg3_geometry_dump_as_c_code(geom, stdout, "some_triangles", - SG3_C_DUMP_CONST | SG3_C_DUMP_STATIC)); - - SG3(geometry_ref_put(geom)); - - check_memory_allocator(&allocator); - mem_shutdown_proxy_allocator(&allocator); - CHK(mem_allocated_size() == 0); - return 0; -} -\ No newline at end of file diff --git a/src/test_sg3_unspecified_properties.c b/src/test_sg3_unspecified_properties.c @@ -1,143 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3.h" -#include "test_sg3_utils.h" - -#include <stdio.h> - -int -main(int argc, char** argv) -{ - struct mem_allocator allocator; - struct sg3_device* dev; - struct sg3_geometry* geom; - struct context ctx = CONTEXT_NULL__; - struct sg3_geometry_add_callbacks callbacks = SG3_ADD_CALLBACKS_NULL__; - unsigned property[12]; - unsigned i; - const unsigned property_count = sizeof(property) / sizeof(*property); - unsigned count; - (void)argc, (void)argv; - - OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); - OK(sg3_device_create(NULL, &allocator, 1, &dev)); - OK(sg3_geometry_create(dev, &geom)); - - FOR_EACH(i, 0, property_count) property[i] = SG3_UNSPECIFIED_PROPERTY; - - callbacks.get_indices = get_indices; - callbacks.get_position = get_position; - - /* A 3D cube. - * 2 enclosures (inside, outside) sharing the same triangles, - * but opposite sides */ - ctx.positions = box_vertices; - ctx.indices = cube_indices; - - /* Add geometry with no properties */ - ctx.front_media = property; - ctx.back_media = medium1; - ctx.intface = property; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == ntriangles); - - /* Add same geometry with no properties on front/intface */ - callbacks.get_properties = get_properties; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 2 * ntriangles); - - OK(sg3_geometry_dump_as_c_code(geom, stdout, "front_unspecified", - SG3_C_DUMP_STATIC | SG3_C_DUMP_CONST)); - - /* Add same geometry, front/intface properties are defined for odd triangles */ - FOR_EACH(i, 0, sizeof(property) / sizeof(*property)) - property[i] = (i % 2) ? 0 : SG3_UNSPECIFIED_PROPERTY; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles / 2); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 3 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - FOR_EACH(i, 0, count) { - unsigned prop[SG3_PROP_TYPES_COUNT__]; - OK(sg3_geometry_get_unique_triangle_properties(geom, i, prop)); - CHK(prop[SG3_FRONT] == ((i % 2) ? 0 : SG3_UNSPECIFIED_PROPERTY) - && prop[SG3_BACK] == 1 - && prop[SG3_INTFACE] == ((i % 2) ? 0 : SG3_UNSPECIFIED_PROPERTY)); - } - - /* Same information again, using a reversed box */ - ctx.reverse_vrtx = 1; - SWAP(const unsigned*, ctx.front_media, ctx.back_media); - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == ntriangles / 2); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 4 * ntriangles); - - OK(sg3_geometry_dump_as_c_code(geom, stdout, "front_half_unspecified", - SG3_C_DUMP_STATIC | SG3_C_DUMP_CONST)); - - /* Define properties for remaining triangles, using reversed box */ - FOR_EACH(i, 0, sizeof(property) / sizeof(*property)) - property[i] = (i % 2) ? SG3_UNSPECIFIED_PROPERTY : 0; - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_unique_vertices_count(geom, &count)); - CHK(count == nvertices); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 5 * ntriangles); - OK(sg3_geometry_get_unique_triangles_count(geom, &count)); - CHK(count == ntriangles); - FOR_EACH(i, 0, count) { - unsigned prop[3]; - OK(sg3_geometry_get_unique_triangle_properties(geom, i, prop)); - CHK(prop[SG3_FRONT] == 0 && prop[SG3_BACK] == 1 - && prop[SG3_INTFACE] == 0); - } - - OK(sg3_geometry_dump_as_c_code(geom, stdout, "all_defined", - SG3_C_DUMP_STATIC | SG3_C_DUMP_CONST)); - - /* Define incoherent properties for some triangles */ - FOR_EACH(i, 0, sizeof(property) / sizeof(*property)) - property[i] = (i % 2); - OK(sg3_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); - OK(sg3_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); - CHK(count == ntriangles / 2); - OK(sg3_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); - CHK(count == 0); - OK(sg3_geometry_get_added_triangles_count(geom, &count)); - CHK(count == 6 * ntriangles); - - OK(sg3_geometry_ref_put(geom)); - OK(sg3_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_sg3_utils.h b/src/test_sg3_utils.h @@ -1,150 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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_SG3_UTILS_H -#define TEST_SG3_UTILS_H - -#include <rsys/mem_allocator.h> -#include <stdio.h> - -#define OK(Cond) CHK((Cond) == RES_OK) -#define BA(Cond) CHK((Cond) == RES_BAD_ARG) -#define ME(Cond) CHK((Cond) == RES_MEM_ERR) - - -/******************************************************************************* - * Memory allocator - ******************************************************************************/ -static INLINE void -check_memory_allocator(struct mem_allocator* allocator) -{ - if(MEM_ALLOCATED_SIZE(allocator)) { - char dump[80192]; - MEM_DUMP(allocator, dump, sizeof(dump)); - fprintf(stderr, "%s\n", dump); - FATAL("Memory leaks.\n"); - } -} - -/******************************************************************************* - * Geometry - ******************************************************************************/ -/* 3D cube */ -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(cube_vertices) / sizeof(double[3]); -/* 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 -}; - -/* 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 - * - * The right-handed geometrical normal is outside the cube */ -static const unsigned -cube_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(cube_indices) / (3 * sizeof(*cube_indices)); - -struct context { - const double* positions; - const unsigned* indices; - const unsigned* front_media; - const unsigned* back_media; - const unsigned* intface; - 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 const unsigned intface0[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static const unsigned intface1[12] = { 1, 1, 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_properties - (const unsigned itri, - unsigned property[SG3_PROP_TYPES_COUNT__], - void* context) -{ - const struct context* ctx = context; - ASSERT(property && ctx); - property[ctx->reverse_med ? SG3_BACK : SG3_FRONT] = ctx->front_media[itri]; - property[ctx->reverse_med ? SG3_FRONT : SG3_BACK] = ctx->back_media[itri]; - property[SG3_INTFACE] = ctx->intface[itri]; -} - -#endif /* TEST_SG3_UTILS_H */ diff --git a/src/test_sg3_utils2.h b/src/test_sg3_utils2.h @@ -1,69 +0,0 @@ -/* Copyright (C) 2019-2020 |Meso|Star> (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_SG3_UTILS2_H -#define TEST_SG3_UTILS2_H - -#include "test_sg3_utils.h" - -#include <rsys/double3.h> -#include <star/s3dut.h> - -struct s3dut_context { - struct s3dut_mesh_data data; - struct context ctx; -}; - -static INLINE void -get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context) -{ - const 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 INLINE void -get_s3dut_position(const unsigned ivert, double pos[3], void* context) -{ - const struct s3dut_context* ctx = context; - double tmp[3]; - ASSERT(pos && ctx); - ASSERT(ivert < ctx->data.nvertices); - (void)ivert; - d3_add(pos, d3_muld(tmp, ctx->data.positions + ivert * 3, ctx->ctx.scale), - ctx->ctx.offset); -} - -static INLINE void -get_s3dut_properties - (const unsigned itri, - unsigned property[SG3_PROP_TYPES_COUNT__], - void* context) -{ - const struct s3dut_context* ctx = context; - ASSERT(property && ctx); - (void)itri; - property[ctx->ctx.reverse_med ? SG3_BACK : SG3_FRONT] = *ctx->ctx.front_media; - property[ctx->ctx.reverse_med ? SG3_FRONT : SG3_BACK] = *ctx->ctx.back_media; - property[SG3_INTFACE] = *ctx->ctx.intface; -} - -#endif /* TEST_SG3_UTILS2_H */ diff --git a/src/test_sg3d_cube_behind_cube.c b/src/test_sg3d_cube_behind_cube.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" + +#include <rsys/double3.h> + +#include <stdio.h> + +/* + 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 sg3d_device* dev; + struct sg3d_geometry* geom; + struct context ctx = CONTEXT_NULL__; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned count; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_indices; + callbacks.get_properties = get_properties; + callbacks.get_position = get_position; + + ctx.positions = box_vertices; + ctx.indices = cube_indices; + ctx.front_media = medium0; + ctx.back_media = medium1; + ctx.intface = intface0; + + /* First cube (front: 0, back: 1), right-handed normal outside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + d3(ctx.offset, -2, -2, 20); + ctx.scale = 5; + + /* Second cube (front: 0, back: 1), right-handed normal outside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "cube_behind_cube_2", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + d3(ctx.offset, -3, -3, 30); + ctx.scale = 7; + ctx.front_media = medium1; + ctx.back_media = medium0; + + /* Third cube (front: 1, back: 0), right-handed normal outside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "cube_behind_cube_3", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_cube_in_cube.c b/src/test_sg3d_cube_in_cube.c @@ -0,0 +1,110 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" + +#include <rsys/double3.h> + +#include <stdio.h> + +/* + cube_2 cube_3 + + +-------------------------+ + | B + +-------------+ | +-------------+ | + m1 | m0 M m1 | m1 | m0 M | + | +------+ | | m0 | +------+ | | + | | m1 S | | | | m1 S | | + | | N <--| | | | | N <--| | | + | +------+ | | | +------+ | | + | N <--| | | N <--| | + +-------------+ | +-------------+ | + | N <--| + +-------------------------+ + */ + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct context ctx = CONTEXT_NULL__; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned count; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_indices; + callbacks.get_properties = get_properties; + callbacks.get_position = get_position; + + ctx.positions = box_vertices; + ctx.indices = cube_indices; + ctx.front_media = medium0; + ctx.back_media = medium1; + ctx.intface = intface0; + + /* First cube (front: 0, back: 1), right-handed normal outside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + d3(ctx.offset, -1, -1, -1); + ctx.scale = 3; + ctx.reverse_vrtx = 1; + + /* Second cube (front: 0, back: 1), right-handed normal inside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "cube_in_cube_2", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + d3(ctx.offset, -4, -4, -4); + ctx.scale = 10; + ctx.reverse_vrtx = 1; + ctx.reverse_med = 1; + ctx.front_media = medium1; + ctx.back_media = medium0; + + /* Third cube (front: 0, back: 1), right-handed normal inside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "cube_in_cube_3", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_cube_on_cube.c b/src/test_sg3d_cube_on_cube.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" + +#include <rsys/double3.h> + +#include <stdio.h> + +/* + +-----------------------+ + | 3 + | +------+ | + m2 | m1 | m0 2 | + | | |--> N | + | +------+ | + | | m0 1 | + | | |--> N | + | +------+ | + |--> N | + +-----------------------+ + */ + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct context ctx = CONTEXT_NULL__; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned count; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_indices; + callbacks.get_properties = get_properties; + callbacks.get_position = get_position; + + ctx.positions = cube_vertices; + ctx.indices = cube_indices; + d3(ctx.offset, 1, 1, 2); + ctx.front_media = medium1_front0; + ctx.back_media = medium0; + ctx.intface = intface0; + + /* First cube (front: 0 on top face, 1 elsewhere, back: 0), + * right-handed normal outside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + d3(ctx.offset, 1, 1, 1); + ctx.front_media = medium1_back0; + + /* Second cube (front: 0 on bottom face, 1 elsewhere, back: 0), + * right-handed normal outside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + 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; + ctx.front_media = medium2; + ctx.back_media = medium1; + + /* Third cube (front: 2, back: 1), right-handed normal inside */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "cube_on_cube", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_device.c b/src/test_sg3d_device.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_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 sg3d_device* dev; + (void)argc, (void)argv; + + BA(sg3d_device_create(NULL, NULL, 0, NULL)); + OK(sg3d_device_create(NULL, NULL, 0, &dev)); + BA(sg3d_device_ref_get(NULL)); + OK(sg3d_device_ref_get(dev)); + BA(sg3d_device_ref_put(NULL)); + OK(sg3d_device_ref_put(dev)); + OK(sg3d_device_ref_put(dev)); + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + + CHK(MEM_ALLOCATED_SIZE(&allocator) == 0); + BA(sg3d_device_create(NULL, &allocator, 0, NULL)); + OK(sg3d_device_create(NULL, &allocator, 0, &dev)); + OK(sg3d_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(sg3d_device_create(&logger, NULL, 0, NULL)); + OK(sg3d_device_create(&logger, NULL, 1, &dev)); + OK(sg3d_device_ref_put(dev)); + + BA(sg3d_device_create(&logger, &allocator, 0, NULL)); + OK(sg3d_device_create(&logger, &allocator, 0, &dev)); + OK(sg3d_device_ref_put(dev)); + + OK(sg3d_device_create(&logger, &allocator, 0, &dev)); + OK(sg3d_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_sg3d_geometry.c b/src/test_sg3d_geometry.c @@ -0,0 +1,293 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" + +#include <stdio.h> + +static res_T +validate + (const unsigned itri, + const unsigned properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* properties_conflict) +{ + (void)itri; (void)properties; (void)context; + *properties_conflict = 0; + return RES_OK; +} + +static res_T +merge_trg + (const unsigned user_id, + const unsigned itri, + const int reversed_triangle, + unsigned triangle_properties[SG3D_PROP_TYPES_COUNT__], + const unsigned merged_properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* merge_conflict) +{ + ASSERT(triangle_properties && merged_properties && merge_conflict); + (void)user_id; (void)reversed_triangle; (void)context; + (void)triangle_properties; (void)merged_properties; (void)merge_conflict; + *merge_conflict = (int)itri; + return RES_OK; +} + +static res_T +degenerated_triangle + (const unsigned itri, + void* context, + int* abort) +{ + struct context* ctx = context; + ASSERT(abort && ctx); + (void)itri; + *abort = *(int*)ctx->custom; + return RES_OK; +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + double coord[3]; + unsigned indices[3]; + const unsigned degenerated[3] = { 0 , 0, 0 }; + unsigned properties[SG3D_PROP_TYPES_COUNT__]; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned user_id; + unsigned count, i; + struct context ctx = CONTEXT_NULL__; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + + BA(sg3d_geometry_create(NULL, &geom)); + BA(sg3d_geometry_create(dev, NULL)); + OK(sg3d_geometry_create(dev, &geom)); + + BA(sg3d_geometry_ref_get(NULL)); + OK(sg3d_geometry_ref_get(geom)); + + BA(sg3d_geometry_ref_put(NULL)); + OK(sg3d_geometry_ref_put(geom)); + OK(sg3d_geometry_ref_put(geom)); + + OK(sg3d_geometry_create(dev, &geom)); + + BA(sg3d_geometry_validate_properties(NULL, NULL, NULL)); + BA(sg3d_geometry_validate_properties(geom, NULL, NULL)); + BA(sg3d_geometry_validate_properties(NULL, validate, NULL)); + OK(sg3d_geometry_validate_properties(geom, validate, NULL)); + + BA(sg3d_geometry_get_unique_vertices_count(NULL, NULL)); + BA(sg3d_geometry_get_unique_vertices_count(geom, NULL)); + BA(sg3d_geometry_get_unique_vertices_count(NULL, &count)); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + + BA(sg3d_geometry_get_added_triangles_count(NULL, NULL)); + BA(sg3d_geometry_get_added_triangles_count(geom, NULL)); + BA(sg3d_geometry_get_added_triangles_count(NULL, &count)); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + + BA(sg3d_geometry_get_unique_triangles_count(NULL, NULL)); + BA(sg3d_geometry_get_unique_triangles_count(geom, NULL)); + BA(sg3d_geometry_get_unique_triangles_count(NULL, &count)); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + + BA(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(NULL, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(NULL, &count)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + + BA(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(NULL, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(NULL, &count)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + + BA(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(NULL, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(NULL, &count)); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + + BA(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(NULL, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, NULL)); + BA(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(NULL, &count)); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + + BA(sg3d_geometry_dump_as_obj(NULL, NULL, 0)); + BA(sg3d_geometry_dump_as_obj(geom, NULL, 0)); + BA(sg3d_geometry_dump_as_obj(NULL, stdout, 0)); + BA(sg3d_geometry_dump_as_obj(NULL, NULL, SG3D_OBJ_DUMP_ALL)); + BA(sg3d_geometry_dump_as_obj(geom, stdout, 0)); + BA(sg3d_geometry_dump_as_obj(geom, NULL, SG3D_OBJ_DUMP_ALL)); + BA(sg3d_geometry_dump_as_obj(NULL, stdout, SG3D_OBJ_DUMP_ALL)); + /* BA because geometry is empty */ + BA(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + + BA(sg3d_geometry_dump_as_vtk(NULL, NULL)); + BA(sg3d_geometry_dump_as_vtk(geom, NULL)); + BA(sg3d_geometry_dump_as_vtk(NULL, stdout)); + /* BA because geometry is empty */ + BA(sg3d_geometry_dump_as_vtk(geom, stdout)); + + BA(sg3d_geometry_dump_as_c_code(NULL, NULL, NULL, 0)); + BA(sg3d_geometry_dump_as_c_code(geom, NULL, NULL, 0)); + BA(sg3d_geometry_dump_as_c_code(NULL, stdout, NULL, 0)); + BA(sg3d_geometry_dump_as_c_code(NULL, NULL, "test", 0)); + BA(sg3d_geometry_dump_as_c_code(geom, NULL, "test", 0)); + BA(sg3d_geometry_dump_as_c_code(NULL, stdout, "test", 0)); + /* BA because geometry is empty */ + BA(sg3d_geometry_dump_as_c_code(geom, stdout, NULL, 0)); + BA(sg3d_geometry_dump_as_c_code(geom, stdout, "test", 0)); + + BA(sg3d_geometry_add(NULL, 0, 0, &callbacks, NULL)); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 0); + BA(sg3d_geometry_add(geom, nvertices, ntriangles, NULL, NULL)); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles); + /* Mandatory callbacks are NULL */ + callbacks.get_indices = NULL; + callbacks.get_position = get_position; + BA(sg3d_geometry_add(geom, 0, 0, &callbacks, NULL)); + callbacks.get_indices = get_indices; + callbacks.get_position = NULL; + BA(sg3d_geometry_add(geom, 0, 0, &callbacks, NULL)); + callbacks.get_indices = NULL; + callbacks.get_position = NULL; + BA(sg3d_geometry_add(geom, 0, 0, &callbacks, NULL)); + /* Add 0 items */ + callbacks.get_indices = get_indices; + callbacks.get_position = get_position; + OK(sg3d_geometry_add(geom, 0, 0, &callbacks, NULL)); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles); + + /* A 3D cube. + * 2 enclosures (inside, outside) sharing the same triangles, + * but opposite sides */ + ctx.positions = cube_vertices; + ctx.indices = cube_indices; + ctx.front_media = medium0; + ctx.back_media = medium1; + ctx.intface = intface0; + + callbacks.get_indices = get_indices; + callbacks.get_properties = get_properties; + callbacks.get_position = get_position; + + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + OK(sg3d_geometry_dump_as_vtk(geom, stdout)); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, NULL, 0)); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "test", + SG3D_C_DUMP_STATIC | SG3D_C_DUMP_CONST)); + + BA(sg3d_geometry_get_unique_vertex(NULL, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_vertex(geom, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_vertex(NULL, 0, NULL)); + BA(sg3d_geometry_get_unique_vertex(NULL, ntriangles, coord)); + BA(sg3d_geometry_get_unique_vertex(geom, 0, NULL)); + BA(sg3d_geometry_get_unique_vertex(geom, ntriangles, coord)); + BA(sg3d_geometry_get_unique_vertex(NULL, 0, coord)); + OK(sg3d_geometry_get_unique_vertex(geom, 0, coord)); + + BA(sg3d_geometry_get_unique_triangle_vertices(NULL, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_triangle_vertices(geom, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_triangle_vertices(NULL, 0, NULL)); + BA(sg3d_geometry_get_unique_triangle_vertices(NULL, ntriangles, indices)); + BA(sg3d_geometry_get_unique_triangle_vertices(geom, 0, NULL)); + BA(sg3d_geometry_get_unique_triangle_vertices(geom, ntriangles, indices)); + BA(sg3d_geometry_get_unique_triangle_vertices(NULL, 0, indices)); + OK(sg3d_geometry_get_unique_triangle_vertices(geom, 0, indices)); + FOR_EACH(i, 0 , 3) CHK(indices[i] == cube_indices[i]); + + BA(sg3d_geometry_get_unique_triangle_properties(NULL, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_triangle_properties(geom, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_triangle_properties(NULL, 0, NULL)); + BA(sg3d_geometry_get_unique_triangle_properties(NULL, ntriangles, properties)); + BA(sg3d_geometry_get_unique_triangle_properties(geom, 0, NULL)); + BA(sg3d_geometry_get_unique_triangle_properties(geom, ntriangles, properties)); + BA(sg3d_geometry_get_unique_triangle_properties(NULL, 0, properties)); + OK(sg3d_geometry_get_unique_triangle_properties(geom, 0, properties)); + CHK(medium0[0] == properties[SG3D_FRONT]); + CHK(medium1[0] == properties[SG3D_BACK]); + CHK(intface0[0] == properties[SG3D_INTFACE]); + + BA(sg3d_geometry_get_unique_triangle_user_id(NULL, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_triangle_user_id(geom, ntriangles, NULL)); + BA(sg3d_geometry_get_unique_triangle_user_id(NULL, 0, NULL)); + BA(sg3d_geometry_get_unique_triangle_user_id(NULL, ntriangles, &user_id)); + BA(sg3d_geometry_get_unique_triangle_user_id(geom, 0, NULL)); + BA(sg3d_geometry_get_unique_triangle_user_id(geom, ntriangles, &user_id)); + BA(sg3d_geometry_get_unique_triangle_user_id(NULL, 0, &user_id)); + OK(sg3d_geometry_get_unique_triangle_user_id(geom, 0, &user_id)); + /* Due to a failed attempt to add ntriangles triangles, user_id for the + * first successfully added triangle is shifted */ + CHK(user_id == ntriangles); + + /* Conflicts with merge_trg callback */ + callbacks.merge_triangle = merge_trg; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + /* Due to merge_trg internals, all but the first triangle have conflict */ + CHK(count == ntriangles - 1); + OK(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + OK(sg3d_geometry_dump_as_vtk(geom, stdout)); + /* BA because of conflicts */ + BA(sg3d_geometry_dump_as_c_code(geom, stdout, "test", SG3D_C_DUMP_STATIC)); + OK(sg3d_geometry_ref_put(geom)); + + /* Conflicts without merge_trg callback */ + OK(sg3d_geometry_create(dev, &geom)); + callbacks.merge_triangle = NULL; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + ctx.front_media = medium1_front0; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + FOR_EACH(i, 0, ntriangles) if(medium0[i] != medium1_front0[i]) count--; + CHK(count == 0); + OK(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + OK(sg3d_geometry_dump_as_vtk(geom, stdout)); + /* BA because of conflicts */ + BA(sg3d_geometry_dump_as_c_code(geom, stdout, "test", SG3D_C_DUMP_CONST)); + + /* Degenerated triangles */ + ctx.indices = degenerated; + /* Without callback : OK */ + OK(sg3d_geometry_add(geom, nvertices, 1, &callbacks, &ctx)); + /* With callback : OK */ + callbacks.degenerated_triangle = degenerated_triangle; + ctx.custom = &i; + i = 0; + OK(sg3d_geometry_add(geom, nvertices, 1, &callbacks, &ctx)); + /* With callback : KO */ + i= 1; + BA(sg3d_geometry_add(geom, nvertices, 1, &callbacks, &ctx)); + + OK(sg3d_geometry_ref_put(geom)); + OK(sg3d_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_sg3d_geometry_2.c b/src/test_sg3d_geometry_2.c @@ -0,0 +1,438 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" + +#include <stdio.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 unique_id, + const unsigned iseg, + void* context) +{ + struct context* ctx = context; + struct add_geom_ctx* add_geom_ctx; + ASSERT(ctx); (void)unique_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 unique_id, + const unsigned itri, + const int reversed_triangle, + unsigned triangle_properties[SG3D_PROP_TYPES_COUNT__], + const unsigned merged_properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* merge_conflict) +{ + struct context* ctx = context; + struct add_geom_ctx* add_geom_ctx; + int i; + ASSERT(ctx && triangle_properties && merged_properties && merge_conflict); + (void)unique_id; (void)itri; (void)reversed_triangle; + (void)triangle_properties; (void)merged_properties; + add_geom_ctx = ctx->custom; + if(add_geom_ctx->merge_res == RES_OK) ++add_geom_ctx->merge_cpt; + FOR_EACH(i, 0, SG3D_PROP_TYPES_COUNT__) + if(!sg3d_compatible_property(triangle_properties[i], merged_properties[i])) + *merge_conflict = 1; + return add_geom_ctx->merge_res; +} + +static res_T +validate + (const unsigned itri, + const unsigned properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* properties_conflict) +{ + (void)itri; (void)properties; (void)context; + *properties_conflict = 0; + return RES_OK; +} + +static res_T +validate2 + (const unsigned itri, + const unsigned properties[SG3D_PROP_TYPES_COUNT__], + void* context, + int* properties_conflict) +{ + (void)itri; (void)properties; (void)context; + *properties_conflict = (itri % 2 == 0) ? 0 : (int)itri; + return RES_OK; +} + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct context ctx = CONTEXT_NULL__; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + struct add_geom_ctx add_geom_ctx; + unsigned property[12]; + unsigned i; + const unsigned property_count = sizeof(property) / sizeof(*property); + unsigned count; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + + /* A 3D cube. + * 2 enclosures (inside, outside) sharing the same triangles, + * but opposite sides */ + ctx.positions = cube_vertices; + ctx.indices = cube_indices; + 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 < property_count; i++) property[i] = SG3D_UNSPECIFIED_PROPERTY; + ctx.front_media = property; + ctx.back_media = property; + ctx.intface = property; + + callbacks.get_indices = get_indices; + callbacks.get_properties = get_properties; + callbacks.get_position = get_position; + callbacks.add_triangle = add_trg; + callbacks.merge_triangle = merge_trg; + + /* If add fails, add geometry fails the same way */ + add_geom_ctx.add_res = RES_BAD_ARG; + + BA(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.add_cpt == 0); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == 0); + add_geom_ctx.add_res = RES_MEM_ERR; + ME(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.add_cpt == 0); + CHK(count == 0); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 2 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Successful add geometry with add callback */ + add_geom_ctx.add_res = RES_OK; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.add_cpt == ntriangles); + CHK(add_geom_ctx.merge_cpt == 0); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 3 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "test_unspecified", + SG3D_C_DUMP_STATIC | SG3D_C_DUMP_CONST)); + + /* Clear geometry */ + SG3D(geometry_ref_put(geom)); + OK(sg3d_geometry_create(dev, &geom)); + + /* Successful add geometry without add callback */ + add_geom_ctx.add_cpt = 0; + callbacks.add_triangle = NULL; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.add_cpt == 0); + CHK(add_geom_ctx.merge_cpt == 0); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* If merge fails, add geometry fails the same way */ + add_geom_ctx.merge_res = RES_BAD_ARG; + callbacks.add_triangle = add_trg; + BA(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == 0); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 2 * ntriangles); + add_geom_ctx.merge_res = RES_MEM_ERR; + ME(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == 0); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 3 * ntriangles); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); /* merge failed but with a no-conflict status */ + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Successful add geometry without merge callback */ + callbacks.merge_triangle = NULL; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == 0); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 4 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Successful add geometry with merge callback */ + add_geom_ctx.merge_res = RES_OK; + callbacks.merge_triangle = merge_trg; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == ntriangles); + add_geom_ctx.merge_cpt = 0; + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 5 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); /* merge failed but with a no-conflict status */ + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Geometry with media information on both sides */ + ctx.front_media = medium0; + ctx.back_media = medium1; + + /* Clear geometry */ + SG3D(geometry_ref_put(geom)); + OK(sg3d_geometry_create(dev, &geom)); + + /* Successful add geometry with add callback + * First half of the triangles, then all of them */ + add_geom_ctx.add_res = RES_OK; + OK(sg3d_geometry_add(geom, nvertices, ntriangles / 2, &callbacks, &ctx)); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles / 2); + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.add_cpt == ntriangles); + CHK(add_geom_ctx.merge_cpt == ntriangles / 2); + add_geom_ctx.add_cpt = 0; + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles + ntriangles / 2); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); /* media where defined */ + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); /* interfaces where unspecified */ + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_vtk(geom, stdout)); + /* Second add was half duplicated, so numbering is shifted */ + FOR_EACH(i, 0, ntriangles) { + unsigned id; + OK(sg3d_geometry_get_unique_triangle_user_id(geom, i, &id)); + CHK(i < ntriangles / 2 ? id == i : id == i + ntriangles / 2); + } + + /* Clear geometry */ + SG3D(geometry_ref_put(geom)); + OK(sg3d_geometry_create(dev, &geom)); + add_geom_ctx.merge_cpt = 0; + + /* Successful add geometry with add callback and no defined properties */ + add_geom_ctx.add_res = RES_OK; + callbacks.get_properties = NULL; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.add_cpt == ntriangles); + CHK(add_geom_ctx.merge_cpt == 0); + add_geom_ctx.add_cpt = 0; + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); /* media where unspecified */ + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == ntriangles); /* interfaces where unspecified */ + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Define interface */ + ctx.intface = intface0; + + /* Successful add geometry with merge callback and properties */ + add_geom_ctx.merge_res = RES_OK; + callbacks.get_properties = get_properties; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == ntriangles); + add_geom_ctx.merge_cpt = 0; + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 2 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); /* media where defined */ + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); /* interfaces where defined */ + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Geometry with incompatible media information on both sides */ + ctx.front_media = medium1; + ctx.back_media = medium0; + + /* Add geometry without merge callback and conflicts */ + callbacks.merge_triangle = NULL; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == 0); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 3 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); /* media where defined */ + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); /* interfaces where defined */ + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Incompatible interface */ + ctx.intface = intface1; + + /* Successful add geometry with merge callback */ + add_geom_ctx.merge_res = RES_OK; + callbacks.merge_triangle = merge_trg; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + CHK(add_geom_ctx.merge_cpt == ntriangles); + add_geom_ctx.merge_cpt = 0; + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 4 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); /* media where defined */ + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); /* interfaces where defined */ + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + /* Clear geometry */ + SG3D(geometry_ref_put(geom)); + OK(sg3d_geometry_create(dev, &geom)); + + /* Successful add geometry with merge callback */ + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + + OK(sg3d_geometry_validate_properties(geom, validate, NULL)); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + + OK(sg3d_geometry_validate_properties(geom, validate, NULL)); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + + OK(sg3d_geometry_validate_properties(geom, validate2, NULL)); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == ntriangles / 2); + + OK(sg3d_geometry_ref_put(geom)); + OK(sg3d_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_sg3d_many_enclosures.c b/src/test_sg3d_many_enclosures.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" +#include "test_sg3d_utils2.h" + +#include <rsys/double3.h> + +#include <star/s3dut.h> + +#include <stdio.h> +#include <limits.h> + +#define NB_CYL_X 32 +#define NB_CYL_Y 32 +#define NB_CYL_Z 64 +#define NB_CYL (NB_CYL_X * NB_CYL_Y * NB_CYL_Z) + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned cyl_trg_count, cyl_vrtx_count, count; + int i, j, k; + unsigned m_in, m_out, itf = 0; + struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; + struct s3dut_mesh* cyl = NULL; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_s3dut_indices; + callbacks.get_properties = get_s3dut_properties; + callbacks.get_position = get_s3dut_position; + + ctx.ctx.positions = box_vertices; + ctx.ctx.indices = cube_indices; + ctx.ctx.front_media = &m_in; + ctx.ctx.back_media = &m_out; + ctx.ctx.intface = &itf; + + /* 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; + OK(sg3d_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); + FOR_EACH(i, 0, NB_CYL_X) { + double center_x = 2 * (1 + NB_CYL_Z) * (i - NB_CYL_X / 2); + FOR_EACH(j, 0, NB_CYL_Y) { + double misalignment = 0; + FOR_EACH(k, 0, NB_CYL_Z) { + double center_y = 2 * (1 + NB_CYL_Z) * (j - NB_CYL_Y / 2); + m_in = (unsigned)k; + m_out = (unsigned)(k + 1); + ctx.ctx.scale = k + 1; +#ifdef MITIGATE_EMBREE_181 + /* Mitigate Embree issue #181 + * We cannot keep perfect alignment of cylinders + * or some hits are missed in some raytracing tasks */ + misalignment = (k % 2) ? -0.01 : +0.01; +#endif + d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0); + OK(sg3d_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); + } + } + } + S3DUT(mesh_ref_put(cyl)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_many_triangles.c b/src/test_sg3d_many_triangles.c @@ -0,0 +1,86 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" +#include "test_sg3d_utils2.h" + +#include <rsys/double3.h> + +#include <star/s3dut.h> + +#include <stdio.h> +#include <limits.h> + +#define NB_CYL 2 + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned cyl_trg_count, cyl_vrtx_count, i, count; + unsigned m0 = 0, m1, itf = 0; + struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; + struct s3dut_mesh* cyl = NULL; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_s3dut_indices; + callbacks.get_properties = get_s3dut_properties; + callbacks.get_position = get_s3dut_position; + + ctx.ctx.positions = box_vertices; + ctx.ctx.indices = cube_indices; + ctx.ctx.front_media = &m1; + ctx.ctx.back_media = &m0; + ctx.ctx.intface = &itf; + + /* 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; + OK(sg3d_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); + FOR_EACH(i, 0, NB_CYL) { + m1 = i; + d3(ctx.ctx.offset, 0, 0, i * 10); + OK(sg3d_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); + } + S3DUT(mesh_ref_put(cyl)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_obj(geom, stdout, SG3D_OBJ_DUMP_ALL)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_some_enclosures.c b/src/test_sg3d_some_enclosures.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" +#include "test_sg3d_utils2.h" + +#include <rsys/double3.h> + +#include <star/s3dut.h> + +#include <stdio.h> +#include <limits.h> + +#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) + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned cyl_trg_count, cyl_vrtx_count, count; + int i, j, k; + unsigned m_in, m_out, itf = 0; + struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; + struct s3dut_mesh* cyl = NULL; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_s3dut_indices; + callbacks.get_properties = get_s3dut_properties; + callbacks.get_position = get_s3dut_position; + + ctx.ctx.positions = box_vertices; + ctx.ctx.indices = cube_indices; + ctx.ctx.front_media = &m_in; + ctx.ctx.back_media = &m_out; + ctx.ctx.intface = &itf; + + /* 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; + OK(sg3d_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); + FOR_EACH(i, 0, NB_CYL_X) { + double center_x = 2 * (1 + NB_CYL_Z) * (i - NB_CYL_X / 2); + FOR_EACH(j, 0, NB_CYL_Y) { + double misalignment = 0; + FOR_EACH(k, 0, NB_CYL_Z) { + double center_y = 2 * (1 + NB_CYL_Z) * (j - NB_CYL_Y / 2); + m_in = (unsigned)k; + m_out = (unsigned)(k + 1); + ctx.ctx.scale = k + 1; +#ifdef MITIGATE_EMBREE_181 + /* Mitigate Embree issue #181 + * We cannot keep perfect alignment of cylinders + * or some hits are missed in some raytracing tasks */ + misalignment = (k % 2) ? -0.01 : +0.01; +#endif + d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0); + OK(sg3d_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); + } + } + } + S3DUT(mesh_ref_put(cyl)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "some_enclosures", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_some_triangles.c b/src/test_sg3d_some_triangles.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" +#include "test_sg3d_utils2.h" + +#include <rsys/double3.h> + +#include <star/s3dut.h> + +#include <stdio.h> +#include <limits.h> + +#define NB_CYL 4 + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned cyl_trg_count, cyl_vrtx_count, i, count; + unsigned m0 = 0, m1, itf = 0; + struct s3dut_context ctx = { {NULL,NULL,0,0}, CONTEXT_NULL__ }; + struct s3dut_mesh* cyl = NULL; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + SG3D(device_ref_put(dev)); + + callbacks.get_indices = get_s3dut_indices; + callbacks.get_properties = get_s3dut_properties; + callbacks.get_position = get_s3dut_position; + + ctx.ctx.positions = box_vertices; + ctx.ctx.indices = cube_indices; + ctx.ctx.front_media = &m1; + ctx.ctx.back_media = &m0; + ctx.ctx.intface = &itf; + + /* A 264 triangles 134 vertices cylinder template */ + S3DUT(create_cylinder(&allocator, 1, 2, 12, 10, &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; + OK(sg3d_geometry_reserve(geom, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0)); + FOR_EACH(i, 0, NB_CYL) { + m1 = i; + d3(ctx.ctx.offset, 0, 0, i * 10); + OK(sg3d_geometry_add(geom, cyl_vrtx_count, cyl_trg_count, &callbacks, &ctx)); + } + S3DUT(mesh_ref_put(cyl)); + + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_interface_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "some_triangles", + SG3D_C_DUMP_CONST | SG3D_C_DUMP_STATIC)); + + SG3D(geometry_ref_put(geom)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); + return 0; +} +\ No newline at end of file diff --git a/src/test_sg3d_unspecified_properties.c b/src/test_sg3d_unspecified_properties.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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 "sg3d.h" +#include "test_sg3d_utils.h" + +#include <stdio.h> + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct sg3d_device* dev; + struct sg3d_geometry* geom; + struct context ctx = CONTEXT_NULL__; + struct sg3d_geometry_add_callbacks callbacks = SG3D_ADD_CALLBACKS_NULL__; + unsigned property[12]; + unsigned i; + const unsigned property_count = sizeof(property) / sizeof(*property); + unsigned count; + (void)argc, (void)argv; + + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(sg3d_device_create(NULL, &allocator, 1, &dev)); + OK(sg3d_geometry_create(dev, &geom)); + + FOR_EACH(i, 0, property_count) property[i] = SG3D_UNSPECIFIED_PROPERTY; + + callbacks.get_indices = get_indices; + callbacks.get_position = get_position; + + /* A 3D cube. + * 2 enclosures (inside, outside) sharing the same triangles, + * but opposite sides */ + ctx.positions = box_vertices; + ctx.indices = cube_indices; + + /* Add geometry with no properties */ + ctx.front_media = property; + ctx.back_media = medium1; + ctx.intface = property; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == ntriangles); + + /* Add same geometry with no properties on front/intface */ + callbacks.get_properties = get_properties; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 2 * ntriangles); + + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "front_unspecified", + SG3D_C_DUMP_STATIC | SG3D_C_DUMP_CONST)); + + /* Add same geometry, front/intface properties are defined for odd triangles */ + FOR_EACH(i, 0, sizeof(property) / sizeof(*property)) + property[i] = (i % 2) ? 0 : SG3D_UNSPECIFIED_PROPERTY; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles / 2); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 3 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + FOR_EACH(i, 0, count) { + unsigned prop[SG3D_PROP_TYPES_COUNT__]; + OK(sg3d_geometry_get_unique_triangle_properties(geom, i, prop)); + CHK(prop[SG3D_FRONT] == ((i % 2) ? 0 : SG3D_UNSPECIFIED_PROPERTY) + && prop[SG3D_BACK] == 1 + && prop[SG3D_INTFACE] == ((i % 2) ? 0 : SG3D_UNSPECIFIED_PROPERTY)); + } + + /* Same information again, using a reversed box */ + ctx.reverse_vrtx = 1; + SWAP(const unsigned*, ctx.front_media, ctx.back_media); + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == ntriangles / 2); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 4 * ntriangles); + + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "front_half_unspecified", + SG3D_C_DUMP_STATIC | SG3D_C_DUMP_CONST)); + + /* Define properties for remaining triangles, using reversed box */ + FOR_EACH(i, 0, sizeof(property) / sizeof(*property)) + property[i] = (i % 2) ? SG3D_UNSPECIFIED_PROPERTY : 0; + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_unspecified_side_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_unique_vertices_count(geom, &count)); + CHK(count == nvertices); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 5 * ntriangles); + OK(sg3d_geometry_get_unique_triangles_count(geom, &count)); + CHK(count == ntriangles); + FOR_EACH(i, 0, count) { + unsigned prop[3]; + OK(sg3d_geometry_get_unique_triangle_properties(geom, i, prop)); + CHK(prop[SG3D_FRONT] == 0 && prop[SG3D_BACK] == 1 + && prop[SG3D_INTFACE] == 0); + } + + OK(sg3d_geometry_dump_as_c_code(geom, stdout, "all_defined", + SG3D_C_DUMP_STATIC | SG3D_C_DUMP_CONST)); + + /* Define incoherent properties for some triangles */ + FOR_EACH(i, 0, sizeof(property) / sizeof(*property)) + property[i] = (i % 2); + OK(sg3d_geometry_add(geom, nvertices, ntriangles, &callbacks, &ctx)); + OK(sg3d_geometry_get_unique_triangles_with_merge_conflict_count(geom, &count)); + CHK(count == ntriangles / 2); + OK(sg3d_geometry_get_unique_triangles_with_properties_conflict_count(geom, &count)); + CHK(count == 0); + OK(sg3d_geometry_get_added_triangles_count(geom, &count)); + CHK(count == 6 * ntriangles); + + OK(sg3d_geometry_ref_put(geom)); + OK(sg3d_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_sg3d_utils.h b/src/test_sg3d_utils.h @@ -0,0 +1,150 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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_SG3D_UTILS_H +#define TEST_SG3D_UTILS_H + +#include <rsys/mem_allocator.h> +#include <stdio.h> + +#define OK(Cond) CHK((Cond) == RES_OK) +#define BA(Cond) CHK((Cond) == RES_BAD_ARG) +#define ME(Cond) CHK((Cond) == RES_MEM_ERR) + + +/******************************************************************************* + * Memory allocator + ******************************************************************************/ +static INLINE void +check_memory_allocator(struct mem_allocator* allocator) +{ + if(MEM_ALLOCATED_SIZE(allocator)) { + char dump[80192]; + MEM_DUMP(allocator, dump, sizeof(dump)); + fprintf(stderr, "%s\n", dump); + FATAL("Memory leaks.\n"); + } +} + +/******************************************************************************* + * Geometry + ******************************************************************************/ +/* 3D cube */ +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(cube_vertices) / sizeof(double[3]); +/* 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 +}; + +/* 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 + * + * The right-handed geometrical normal is outside the cube */ +static const unsigned +cube_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(cube_indices) / (3 * sizeof(*cube_indices)); + +struct context { + const double* positions; + const unsigned* indices; + const unsigned* front_media; + const unsigned* back_media; + const unsigned* intface; + 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 const unsigned intface0[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +static const unsigned intface1[12] = { 1, 1, 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_properties + (const unsigned itri, + unsigned property[SG3D_PROP_TYPES_COUNT__], + void* context) +{ + const struct context* ctx = context; + ASSERT(property && ctx); + property[ctx->reverse_med ? SG3D_BACK : SG3D_FRONT] = ctx->front_media[itri]; + property[ctx->reverse_med ? SG3D_FRONT : SG3D_BACK] = ctx->back_media[itri]; + property[SG3D_INTFACE] = ctx->intface[itri]; +} + +#endif /* TEST_SG3D_UTILS_H */ diff --git a/src/test_sg3d_utils2.h b/src/test_sg3d_utils2.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2019-2020 |Meso|Star> (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_SG3D_UTILS2_H +#define TEST_SG3D_UTILS2_H + +#include "test_sg3d_utils.h" + +#include <rsys/double3.h> +#include <star/s3dut.h> + +struct s3dut_context { + struct s3dut_mesh_data data; + struct context ctx; +}; + +static INLINE void +get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context) +{ + const 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 INLINE void +get_s3dut_position(const unsigned ivert, double pos[3], void* context) +{ + const struct s3dut_context* ctx = context; + double tmp[3]; + ASSERT(pos && ctx); + ASSERT(ivert < ctx->data.nvertices); + (void)ivert; + d3_add(pos, d3_muld(tmp, ctx->data.positions + ivert * 3, ctx->ctx.scale), + ctx->ctx.offset); +} + +static INLINE void +get_s3dut_properties + (const unsigned itri, + unsigned property[SG3D_PROP_TYPES_COUNT__], + void* context) +{ + const struct s3dut_context* ctx = context; + ASSERT(property && ctx); + (void)itri; + property[ctx->ctx.reverse_med ? SG3D_BACK : SG3D_FRONT] = *ctx->ctx.front_media; + property[ctx->ctx.reverse_med ? SG3D_FRONT : SG3D_BACK] = *ctx->ctx.back_media; + property[SG3D_INTFACE] = *ctx->ctx.intface; +} + +#endif /* TEST_SG3D_UTILS2_H */