star-enclosures-3d

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

commit cf7e02233ee52e2de9acfd037b8efe1576455d09
parent d8f9b28fbbd7a20a3f231db809b3dc8fa5ae595e
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue,  5 Nov 2019 11:22:05 +0100

Merge branch 'release_0.4.0'

Diffstat:
MREADME.md | 9+++++++++
Mcmake/CMakeLists.txt | 10++++++----
Msrc/senc.h | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/senc_descriptor.c | 43+++++++++++++++++++------------------------
Msrc/senc_enclosure.c | 47+++++++++++++----------------------------------
Msrc/senc_enclosure_data.h | 44+++++++++++++++++++++++++++-----------------
Msrc/senc_internal_types.h | 25++++++++++---------------
Msrc/senc_s3d_wrapper.h | 4++--
Msrc/senc_scene.c | 203+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/senc_scene_analyze.c | 217+++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/senc_scene_c.h | 14+++++---------
Msrc/test_senc_cube_behind_cube.c | 12++++++------
Msrc/test_senc_cube_in_cube.c | 12++++++------
Msrc/test_senc_cube_on_cube.c | 6+++---
Msrc/test_senc_descriptor.c | 23++++++-----------------
Msrc/test_senc_enclosure.c | 75+++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/test_senc_inconsistant_cube.c | 22++++++++++------------
Msrc/test_senc_many_enclosures.c | 4+++-
Msrc/test_senc_many_triangles.c | 4+++-
Msrc/test_senc_sample_enclosure.c | 2+-
Msrc/test_senc_scene.c | 107+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Asrc/test_senc_undefined_medium.c | 277+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_senc_undefined_medium_attr.c | 366+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_senc_utils.h | 23++++++++---------------
24 files changed, 1235 insertions(+), 432 deletions(-)

diff --git a/README.md b/README.md @@ -39,6 +39,15 @@ variable the install directories of its dependencies. Release notes ------------- +### Version 0.4 + +- Change signature of the senc_scene_add_geometry API. Thus this release + is **not compatible** with previous ones. + The global_id callback that was ill-defined is removed and 2 callbacks + are added to manage client-app data when deduplicating geometry. + These 2 callback allow a proper client-app management of global ids. +- Remove execution time for analysis steps from the log. + ### Version 0.3.1 - Performance Fix: when a connex component was canceled by a thread the diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -24,8 +24,8 @@ option(NO_TEST "Do not build tests" OFF) # Check dependencies ################################################################################ find_package(RCMake 0.4 REQUIRED) -find_package(Star3D 0.5 REQUIRED) -find_package(RSys 0.6.1 REQUIRED) +find_package(Star3D 0.6 REQUIRED) +find_package(RSys 0.8.1 REQUIRED) find_package(OpenMP 2.0 REQUIRED) if(NOT NO_TEST) @@ -47,8 +47,8 @@ endif() # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 3) -set(VERSION_PATCH 1) +set(VERSION_MINOR 4) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SENC_FILES_SRC @@ -131,6 +131,8 @@ if(NOT NO_TEST) new_test(test_senc_many_triangles) new_test(test_senc_sample_enclosure) new_test(test_senc_scene) + new_test(test_senc_undefined_medium) + new_test(test_senc_undefined_medium_attr) target_link_libraries(test_senc_sample_enclosure StarSP) target_link_libraries(test_senc_many_enclosures Star3DUT) diff --git a/src/senc.h b/src/senc.h @@ -18,6 +18,8 @@ #include <rsys/rsys.h> +#include <limits.h> + /* Library symbol management */ #if defined(SENC_SHARED_BUILD) #define SENC_API extern EXPORT_SYM @@ -40,6 +42,9 @@ * as CPU cores */ #define SENC_NTHREADS_DEFAULT (~0u) +/* A constant to specify an undefined medium */ +#define SENC_UNDEFINED_MEDIUM UINT_MAX + /* Forward declaration of external opaque data types */ struct logger; struct mem_allocator; @@ -56,6 +61,12 @@ struct senc_device; struct senc_scene; struct senc_enclosure; +/* A type to discriminate triangle sides */ +enum senc_side { + SENC_FRONT, + SENC_BACK +}; + /* Enclosure header type */ struct senc_enclosure_header { /* The ID of the enclosure; 0, 1, ... */ @@ -66,7 +77,8 @@ struct senc_enclosure_header { unsigned unique_triangle_count; /* Number of vertices */ unsigned vertices_count; - /* The number of media inside the enclosure */ + /* The number of media inside the enclosure, + * SENC_UNDEFINED_MEDIUM included */ unsigned enclosed_media_count; /* Is the enclosure open/infinite? * Only the outermost enclosure is infinite. */ @@ -148,26 +160,55 @@ senc_device_ref_put SENC_API res_T senc_scene_create (struct senc_device* device, - const enum senc_convention convention, + const int convention, struct senc_scene** scene); +/* Reserve memory according to anticipated scene size. */ +SENC_API res_T +senc_scene_reserve + (struct senc_scene* scene, + const unsigned vertices_count, + const unsigned triangles_count, + const unsigned media_count); + /* Add a new set of vertices and triangles to the scene. * Vertices can be duplicates and are deduplicated on the fly. * Triangles can be duplicates as long as they constantly define the same - * medium on both sides (or an error will be reported) and are deduplicated. - * When deduplicating triangles, the first occurence is kept (with it original - * global_id). Users can provide their own global ids for triangles; these ids - * are not used by the library but are returned as-is by some API calls. */ + * medium on both sides (or an error will be reported, with the exception + * of SENC_UNDEFINED_MEDIUM that causes no error) and are deduplicated. + * The special value SENC_UNDEFINED_MEDIUM denotes an undefined medium. + * It can be used to define the 2 sides of a triangle at different times. + * When deduplicating triangles, the first occurence remains. + * The add_triangle and merge_triangle callbacks can be used for attributes + * management including triangle IDs; they allow the client app to store + * its own data. They can also fail and stop the add_geometry call. */ SENC_API res_T senc_scene_add_geometry (struct senc_scene* scene, + /* Number of added triangles */ const unsigned triangles_count, + /* User function that provides vertices ids for added triangles */ void(*indices)(const unsigned itri, unsigned ids[3], void* context), - void(*media)(const unsigned itri, unsigned med[2], void* context), - void(*global_id) /* May be NULL <=> use triangle rank */ - (const unsigned itri, unsigned* gid, void* context), + /* User function that provides media ids for added triangles */ + void(*media) /* Can be NULL <=> SENC_UNDEFINED_MEDIUM medium used */ + (const unsigned itri, unsigned med[2], void* context), + /* Number of added vertices */ const unsigned vertices_count, + /* User function that provides coordinates for added vertices */ void(*position)(const unsigned ivert, double pos[3], void* context), + /* Called for each new triangle so that the client app can manage its own + * triangle data/properties/attributes. + * If return is not RES_OK, add_geometry stops and fails. */ + res_T(*add_triangle) /* Can be NULL */ + (const unsigned global_id, const unsigned itri, void* context), + /* Called if the IVERTth triangle of the current add_geometry is equal to + * the global_id_th global triangle so that the client app can try to merge + * its own triangle data. The reversed_triangle arg indicates if the triangle + * vertices' order is the same it was when the triangle was first added. + * If return is not RES_OK, add_geometry stops and fails. */ + res_T(*merge_triangle) /* Can be NULL */ + (const unsigned global_id, const unsigned itri, const int reversed_triangle, + void* context), void* context); /* Returns a descriptor of the scene that holds the analysis' result. */ @@ -180,7 +221,7 @@ senc_scene_analyze SENC_API res_T senc_scene_get_convention (const struct senc_scene* scene, - enum senc_convention* convention); + int* convention); /* Returns the number of triangles in the scene. */ SENC_API res_T @@ -195,6 +236,30 @@ senc_scene_get_unique_triangles_count (const struct senc_scene* scene, unsigned* count); +/* Returns the number of unique sides with SENC_UNDEFINED_MEDIUM medium. */ +SENC_API res_T +senc_scene_get_unique_sides_without_medium_count + (const struct senc_scene* scene, + unsigned* count); + +/* Returns the itri_th unique triangle; the returned indices are + * unique vertex indices. + * Can be called anytime, before or after a call to analyze. */ +SENC_API res_T +senc_scene_get_unique_triangle + (const struct senc_scene* scene, + const unsigned itri, + unsigned indices[3]); + +/* Returns the itri_th unique triangle; the returned indices are + * unique vertex indices. + * Can be called anytime, before or after a call to analyze. */ +SENC_API res_T +senc_scene_get_unique_triangle_media + (const struct senc_scene* scene, + const unsigned itri, + unsigned media[2]); + /* Returns the number of vertices in the scene. */ SENC_API res_T senc_scene_get_vertices_count @@ -208,6 +273,14 @@ senc_scene_get_unique_vertices_count (const struct senc_scene* scene, unsigned* count); +/* Returns the coordinates of the ivert_th unique vertex. + * Can be called anytime, before or after a call to analyze. */ +SENC_API res_T +senc_scene_get_unique_vertex + (const struct senc_scene* scene, + const unsigned ivert, + double coord[3]); + SENC_API res_T senc_scene_ref_get (struct senc_scene* scene); @@ -301,14 +374,6 @@ senc_descriptor_get_global_triangle_enclosures const unsigned itri, unsigned enclosures[2]); -/* Returns the global id of the itri_th global unique triangles, either the - * user provided one or the default one. */ -SENC_API res_T -senc_descriptor_get_global_triangle_global_id - (const struct senc_descriptor* descriptor, - const unsigned itri, - unsigned* gid); - /* Returns the number of segments that are frontier segments: * - that have arity 1 (single triangle using the segment) * - that connect 2 different media */ @@ -353,7 +418,8 @@ senc_enclosure_get_header (const struct senc_enclosure* enclosure, struct senc_enclosure_header* header); -/* Returns the itri_th triangle of an enclosure. */ +/* Returns the itri_th triangle of an enclosure. + * Indices are local to the enclosure. */ SENC_API res_T senc_enclosure_get_triangle (const struct senc_enclosure* enclosure, @@ -367,20 +433,14 @@ senc_enclosure_get_vertex const unsigned ivert, double coord[3]); -/* Returns the front and back side media ids of the itri_th triangle of an - * enclosure. */ -SENC_API res_T -senc_enclosure_get_triangle_media - (const struct senc_enclosure* enclosure, - const unsigned itri, - unsigned medium[2]); - -/* Returns the global id of the itri_th triangle of an enclosure. */ +/* Returns the global id of the itri_th triangle of an enclosure + * and the involved side. */ SENC_API res_T senc_enclosure_get_triangle_global_id (const struct senc_enclosure* enclosure, const unsigned itri, - unsigned* gid); + unsigned* gid, + enum senc_side* side); /* Returns the id of the imed_th medium of an enclosure. */ SENC_API res_T diff --git a/src/senc_descriptor.c b/src/senc_descriptor.c @@ -61,7 +61,8 @@ descriptor_create(struct senc_scene* scn) darray_enclosure_init(scn->dev->allocator, &desc->enclosures); darray_enc_ids_array_init(scn->dev->allocator, &desc->enc_ids_array_by_medium); - OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium, scn->nmeds)); + OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium, + 1 + scn->next_medium_idx)); /* +1 is for undef */ darray_frontier_edge_init(scn->dev->allocator, &desc->frontiers); /* Enclosure 0 is always defined for infinite */ OK(darray_enclosure_resize(&desc->enclosures, 1)); @@ -91,8 +92,8 @@ senc_descriptor_get_max_medium (const struct senc_descriptor* desc, unsigned* max_medium_id) { if(!desc || !max_medium_id) return RES_BAD_ARG; - ASSERT(desc->scene->nmeds < UINT_MAX); /* API type */ - *max_medium_id = (unsigned)desc->scene->nmeds - 1; + ASSERT(desc->scene->next_medium_idx < UINT_MAX); /* API type */ + *max_medium_id = (unsigned)desc->scene->next_medium_idx - 1; return RES_OK; } @@ -115,13 +116,16 @@ senc_descriptor_get_enclosure_count_by_medium const unsigned imed, unsigned* count) { - size_t tmp; + size_t tmp, m_idx; const struct darray_enc_id* enc_ids; - if(!desc || !count || imed >= desc->scene->nmeds) + if(!desc || !count + || (imed != SENC_UNDEFINED_MEDIUM && imed >= desc->scene->next_medium_idx)) return RES_BAD_ARG; ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium) - == desc->scene->nmeds); - enc_ids = darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + imed; + == 1 + desc->scene->next_medium_idx); + m_idx = (imed == SENC_UNDEFINED_MEDIUM) ? desc->scene->next_medium_idx : imed; + enc_ids = darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + + m_idx; tmp = darray_enc_id_size_get(enc_ids); ASSERT(tmp < UINT_MAX); /* API type */ *count = (unsigned)tmp; @@ -150,11 +154,17 @@ senc_descriptor_get_enclosure_by_medium const unsigned idx, struct senc_enclosure** out_enc) { + size_t m_idx; const struct darray_enc_id* enc_ids; unsigned index; - if(!desc || imed >= desc->scene->nmeds || !out_enc) return RES_BAD_ARG; + if(!desc || !out_enc + || (imed != SENC_UNDEFINED_MEDIUM && imed >= desc->scene->next_medium_idx)) + return RES_BAD_ARG; + ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium) + == 1 + desc->scene->next_medium_idx); + m_idx = (imed == SENC_UNDEFINED_MEDIUM) ? desc->scene->next_medium_idx : imed; enc_ids = - darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + imed; + darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + m_idx; if(idx >= darray_enc_id_size_get(enc_ids)) return RES_BAD_ARG; index = darray_enc_id_cdata_get(enc_ids)[idx]; return senc_descriptor_get_enclosure(desc, index, out_enc); @@ -262,21 +272,6 @@ senc_descriptor_get_global_triangle_enclosures } res_T -senc_descriptor_get_global_triangle_global_id - (const struct senc_descriptor* desc, - const unsigned itri, - unsigned* gid) -{ - const struct triangle_in* trg; - if(!gid || !desc - || itri >= darray_triangle_in_size_get(&desc->scene->triangles_in)) - return RES_BAD_ARG; - trg = darray_triangle_in_cdata_get(&desc->scene->triangles_in) + itri; - *gid = trg->global_id; - return RES_OK; -} - -res_T senc_descriptor_get_frontier_segments_count (const struct senc_descriptor* desc, unsigned* count) diff --git a/src/senc_enclosure.c b/src/senc_enclosure.c @@ -81,17 +81,17 @@ senc_enclosure_get_triangle const unsigned itri, unsigned indices[3]) { - const struct triangle_in* triangle; + const struct side_enc* side; int i; if(!enclosure || !indices || itri >= enclosure->data->header.triangle_count) return RES_BAD_ARG; - ASSERT(darray_triangle_in_size_get(&enclosure->data->sides) + ASSERT(darray_sides_enc_size_get(&enclosure->data->sides) == enclosure->data->header.triangle_count); - triangle = darray_triangle_in_cdata_get(&enclosure->data->sides) + itri; + side = darray_sides_enc_cdata_get(&enclosure->data->sides) + itri; FOR_EACH(i, 0, 3) { - ASSERT(triangle->vertice_id[i] < UINT_MAX); - indices[i] = (unsigned)triangle->vertice_id[i]; /* Back to API type */ + ASSERT(side->vertice_id[i] < UINT_MAX); + indices[i] = (unsigned)side->vertice_id[i]; /* Back to API type */ } return RES_OK; } @@ -118,42 +118,21 @@ senc_enclosure_get_vertex } res_T -senc_enclosure_get_triangle_media - (const struct senc_enclosure* enclosure, - const unsigned itri, - unsigned medium[2]) -{ - const struct triangle_in* triangle; - int i; - if(!enclosure || !medium - || itri >= enclosure->data->header.triangle_count) - return RES_BAD_ARG; - ASSERT(darray_triangle_in_size_get(&enclosure->data->sides) - == enclosure->data->header.triangle_count); - triangle = darray_triangle_in_cdata_get(&enclosure->data->sides) + itri; - FOR_EACH(i, 0, 2) { -#if (UINT_MAX < MEDIUM_MAX__) - ASSERT(triangle->medium[i] < UINT_MAX); -#endif - medium[i] = (unsigned)triangle->medium[i]; /* Back to API type */ - } - return RES_OK; -} - -res_T senc_enclosure_get_triangle_global_id (const struct senc_enclosure* enclosure, const unsigned itri, - unsigned* gid) + unsigned* gid, + enum senc_side* sde) { - const struct triangle_in* triangle; - if(!enclosure || !gid + const struct side_enc* side; + if(!enclosure || !gid || !sde || itri >= enclosure->data->header.triangle_count) return RES_BAD_ARG; - ASSERT(darray_triangle_in_size_get(&enclosure->data->sides) + ASSERT(darray_sides_enc_size_get(&enclosure->data->sides) == enclosure->data->header.triangle_count); - triangle = darray_triangle_in_cdata_get(&enclosure->data->sides) + itri; - *gid = triangle->global_id; + side = darray_sides_enc_cdata_get(&enclosure->data->sides) + itri; + *gid = (unsigned)TRGSIDE_2_TRG(side->side_id); + *sde = TRGSIDE_2_SIDE(side->side_id); return RES_OK; } diff --git a/src/senc_enclosure_data.h b/src/senc_enclosure_data.h @@ -21,6 +21,21 @@ #include <rsys/hash_table.h> #include <rsys/dynamic_array.h> +#include "senc.h" +#include "senc_scene_c.h" +#include "senc_internal_types.h" + +#include <limits.h> + +struct side_enc { + vrtx_id_t vertice_id[3]; + side_id_t side_id; +}; + +#define DARRAY_NAME sides_enc +#define DARRAY_DATA struct side_enc +#include <rsys/dynamic_array.h> + /* unsigned char array with init to zero */ static FINLINE void zero_init_uchar @@ -32,12 +47,6 @@ zero_init_uchar #define DARRAY_FUNCTOR_INIT zero_init_uchar #include <rsys/dynamic_array_uchar.h> -#include "senc.h" -#include "senc_scene_c.h" -#include "senc_internal_types.h" - -#include <limits.h> - static void init_header(struct senc_enclosure_header* header) { @@ -83,23 +92,24 @@ error: static FINLINE res_T bool_array_of_media_to_darray_media (struct darray_media* dst, - struct darray_uchar* src) + const struct darray_uchar* src, + const medium_id_t undef_idx) { res_T res = RES_OK; medium_id_t i; - size_t sz; const unsigned char* data; ASSERT(src && dst); data = darray_uchar_cdata_get(src); - sz = darray_uchar_size_get(src); - ASSERT(sz <= MEDIUM_MAX__); + ASSERT(undef_idx + 1 == darray_uchar_size_get(src)); + ASSERT(undef_idx < MEDIUM_MAX__); darray_media_clear(dst); if(res != RES_OK) goto error; - FOR_EACH(i, 0, (medium_id_t)sz) { + FOR_EACH(i, 0, undef_idx + 1) { + medium_id_t v = (i == undef_idx) ? SENC_UNDEFINED_MEDIUM : i; if(!data[i]) continue; - res = darray_media_push_back(dst, &i); + res = darray_media_push_back(dst, &v); if(res != RES_OK) goto error; } end: @@ -111,7 +121,7 @@ error: struct enclosure_data { struct senc_enclosure_header header; /* Same triangle can appear twice if both sides */ - struct darray_triangle_in sides; + struct darray_sides_enc sides; /* Index of vertices in scene's unique vertices */ struct darray_vrtx_id vertices; /* List of the enclosed media */ @@ -136,7 +146,7 @@ enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) { enc->side_range.first = SIDE_NULL__; enc->side_range.last = 0; enc->side_count = 0; - darray_triangle_in_init(alloc, &enc->sides); + darray_sides_enc_init(alloc, &enc->sides); darray_vrtx_id_init(alloc, &enc->vertices); darray_uchar_init(alloc, &enc->tmp_enclosed_media); darray_media_init(alloc, &enc->enclosed_media); @@ -154,7 +164,7 @@ enclosure_data_copy dst->first_component = src->first_component; dst->side_range = src->side_range; dst->side_count = src->side_count; - OK(darray_triangle_in_copy(&dst->sides, &src->sides)); + OK(darray_sides_enc_copy(&dst->sides, &src->sides)); OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices)); OK(darray_uchar_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media)); OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media)); @@ -165,7 +175,7 @@ error: static FINLINE void enclosure_data_release(struct enclosure_data* n) { ASSERT(n); - darray_triangle_in_release(&n->sides); + darray_sides_enc_release(&n->sides); darray_vrtx_id_release(&n->vertices); darray_uchar_release(&n->tmp_enclosed_media); darray_media_release(&n->enclosed_media); @@ -183,7 +193,7 @@ enclosure_data_copy_and_release dst->first_component = src->first_component; dst->side_range = src->side_range; dst->side_count = src->side_count; - OK(darray_triangle_in_copy_and_release(&dst->sides, &src->sides)); + OK(darray_sides_enc_copy_and_release(&dst->sides, &src->sides)); OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices)); OK(darray_uchar_copy_and_release(&dst->tmp_enclosed_media, &src->tmp_enclosed_media)); diff --git a/src/senc_internal_types.h b/src/senc_internal_types.h @@ -95,12 +95,6 @@ enum side_flag { FLAG_BACK = BIT(1) }; -/* This one is used as an index to arrays */ -enum side_id { - SIDE_FRONT = 0, - SIDE_BACK = 1 -}; - /* Utility macros */ static FINLINE trg_id_t TRGSIDE_2_TRG(side_id_t s) { @@ -113,9 +107,9 @@ TRGSIDE_IS_FRONT(side_id_t s) { return (s & 1) == 0; } -static FINLINE enum side_id +static FINLINE enum senc_side TRGSIDE_2_SIDE(side_id_t s) { - return (s & 1) ? SIDE_BACK : SIDE_FRONT; + return (s & 1) ? SENC_BACK : SENC_FRONT; } static FINLINE enum side_flag @@ -123,22 +117,23 @@ TRGSIDE_2_SIDEFLAG(side_id_t s) { return (s & 1) ? FLAG_BACK : FLAG_FRONT; } -static FINLINE enum side_flag +static FINLINE unsigned char SIDE_CANCELED_FLAG(enum side_flag f) { - return ((unsigned char)f) << 4; + ASSERT((f << 4) <= UCHAR_MAX); + return (unsigned char)(f << 4); } static FINLINE side_id_t -TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum side_id i) { - ASSERT((((size_t)t << 1) | (i == SIDE_BACK)) < SIDE_MAX__); - ASSERT(i == SIDE_FRONT || i == SIDE_BACK); - return (side_id_t)((t << 1) | (i == SIDE_BACK)); +TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum senc_side i) { + ASSERT((((size_t)t << 1) | (i == SENC_BACK)) < SIDE_MAX__); + ASSERT(i == SENC_FRONT || i == SENC_BACK); + return (side_id_t)((t << 1) | (i == SENC_BACK)); } static FINLINE side_id_t TRGSIDE_OPPOSITE(side_id_t s) { return TRGIDxSIDE_2_TRGSIDE(TRGSIDE_2_TRG(s), - TRGSIDE_IS_FRONT(s) ? SIDE_BACK : SIDE_FRONT); + TRGSIDE_IS_FRONT(s) ? SENC_BACK : SENC_FRONT); } #endif /* SENC_INTERNAL_TYPES_H */ diff --git a/src/senc_s3d_wrapper.h b/src/senc_s3d_wrapper.h @@ -21,7 +21,7 @@ #include <rsys/rsys.h> #include <rsys/float3.h> -FINLINE void +static FINLINE void senc_descriptor_get_global_indices__ (const unsigned itri, unsigned indices[3], @@ -49,7 +49,7 @@ senc_descriptor_get_global_vertices__ f3_set_d3(coord, tmp); } -FINLINE void +static FINLINE void senc_enclosure_get_triangle__ (const unsigned itri, unsigned indices[3], diff --git a/src/senc_scene.c b/src/senc_scene.c @@ -18,6 +18,7 @@ #include "senc_scene_c.h" #include <rsys/rsys.h> +#include <rsys/double3.h> #include <rsys/mem_allocator.h> #include <limits.h> @@ -42,13 +43,22 @@ scene_release(ref_T * ref) SENC(device_ref_put(dev)); } +static INLINE int +compatible_medium + (const medium_id_t m1, + const medium_id_t m2) +{ + if(m1 == SENC_UNDEFINED_MEDIUM || m2 == SENC_UNDEFINED_MEDIUM) return 1; + return (m1 == m2); +} + /******************************************************************************* * Exported functions ******************************************************************************/ res_T senc_scene_create (struct senc_device* dev, - const enum senc_convention conv, + const int conv, struct senc_scene** out_scn) { struct senc_scene* scn = NULL; @@ -73,9 +83,10 @@ senc_scene_create scn->ngeoms = 0; scn->ntris = 0; scn->nutris = 0; - scn->nmeds = 0; + scn->next_medium_idx = 0; scn->nverts = 0; scn->nuverts = 0; + scn->sides_with_defined_medium_count = 0; darray_triangle_in_init(dev->allocator, &scn->triangles_in); darray_position_init(dev->allocator, &scn->vertices); htable_vrtx_init(dev->allocator, &scn->unique_vertices); @@ -94,14 +105,37 @@ error: } res_T +senc_scene_reserve + (struct senc_scene* scn, + const unsigned vertices_count, + const unsigned triangles_count, + const unsigned media_count) +{ + res_T res = RES_OK; + if(!scn) return RES_BAD_ARG; + + OK(darray_position_reserve(&scn->vertices, vertices_count)); + OK(darray_triangle_in_reserve(&scn->triangles_in, triangles_count)); + OK(htable_vrtx_reserve(&scn->unique_vertices, vertices_count)); + OK(htable_trg_reserve(&scn->unique_triangles, triangles_count)); + OK(darray_side_range_reserve(&scn->media_use, media_count)); + +end: + return res; +error: + goto end; +} + +res_T senc_scene_add_geometry (struct senc_scene* scn, const unsigned ntris, - void(*indices)(const unsigned itri, unsigned ids[3], void* ctx), - void(*media)(const unsigned itri, unsigned med[2], void* ctx), - void(*global_id)(const unsigned itri, unsigned* gid, void* context), + void(*indices)(const unsigned, unsigned*, void*), + void(*media)(const unsigned, unsigned*, void*), const unsigned nverts, - void(*position)(const unsigned ivert, double pos[3], void* ctx), + void(*position)(const unsigned, double*, void* ctx), + res_T(*add_triangle)(const unsigned, const unsigned, void*), + res_T(*merge_triangle)(const unsigned, const unsigned, const int, void*), void* ctx) { struct darray_vrtx_id unique_vertice_ids; @@ -114,7 +148,7 @@ senc_scene_add_geometry res_T res = RES_OK; if(!scn - || !indices || !media || !position + || !indices || !position || !nverts || ((size_t)scn->nverts + (size_t)nverts) > VRTX_MAX__ || !ntris || ((size_t)scn->ntris + (size_t)ntris) > TRG_MAX__) return RES_BAD_ARG; @@ -147,8 +181,8 @@ senc_scene_add_geometry } else { /* New vertex */ unique_v = scn->nuverts + actual_nuverts; - OK(darray_position_push_back(&scn->vertices, &tmp)); ASSERT(unique_v == htable_vrtx_size_get(&scn->unique_vertices)); + OK(darray_position_push_back(&scn->vertices, &tmp)); OK(htable_vrtx_set(&scn->unique_vertices, &tmp, &unique_v)); ++actual_nuverts; } @@ -160,18 +194,13 @@ senc_scene_add_geometry FOR_EACH(i, 0, ntris) { int j; - unsigned med[2]; + unsigned med[2] = { SENC_UNDEFINED_MEDIUM, SENC_UNDEFINED_MEDIUM }; unsigned ind[3]; union vrtx_id3 trg_key; - struct triangle_in tmp; + struct triangle_in tmp, *range_adjust_ptr = NULL; trg_id_t* p_trg; char reversed; - if(global_id) { - global_id(i, &tmp.global_id, ctx); - } else { - tmp.global_id = (unsigned)(scn->ntris + i); - } - indices(i, ind, ctx); /* API: indices needs an unsigned */ + indices(i, ind, ctx); /* API: indices need unsigneds */ FOR_EACH(j, 0, 3) { if(ind[j] >= nverts) { res = RES_BAD_ARG; @@ -187,7 +216,7 @@ senc_scene_add_geometry const union double3* positions = darray_position_cdata_get(&scn->vertices); log_err(scn->dev, "%s: triangle %lu is degenerate.\n", - FUNC_NAME, (unsigned long)tmp.global_id); + FUNC_NAME, (unsigned long)(scn->ntris + i)); log_err(scn->dev, " (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n", SPLIT3(positions[trg[i].vertice_id[0]].vec), SPLIT3(positions[trg[i].vertice_id[1]].vec), @@ -196,12 +225,12 @@ senc_scene_add_geometry goto error; } /* Get media */ - media(i, med, ctx); /* API: media needs an unsigned */ + if(media) media(i, med, ctx); /* API: media needs an unsigned */ FOR_EACH(j, 0, 2) { - if(med[j] >= scn->nmeds) { - ASSERT(med[j] <= MEDIUM_MAX__); - scn->nmeds = med[j] + 1; - darray_side_range_resize(&scn->media_use, scn->nmeds); + if(med[j] != SENC_UNDEFINED_MEDIUM && med[j] >= scn->next_medium_idx) { + ASSERT(med[j] < MEDIUM_MAX__); + scn->next_medium_idx = med[j] + 1; + darray_side_range_resize(&scn->media_use, scn->next_medium_idx); } tmp.medium[j] = (medium_id_t)med[j]; } @@ -215,57 +244,81 @@ senc_scene_add_geometry const medium_id_t* umed; /* Duplicate triangle. Need to check duplicate validity */ ASSERT(trg_key_eq(&trg_key, &utrg_key)); + if(!same) SWAP(unsigned, tmp.medium[0], tmp.medium[1]); umed = trg[*p_trg].medium; - if(umed[0] != (same ? med[0] : med[1]) - || umed[1] != (same ? med[1] : med[0])) { + if(!compatible_medium(umed[0], tmp.medium[0]) + || !compatible_medium(umed[1], tmp.medium[1])) + { /* Same triangles with different media: invalid! */ const union double3* positions = darray_position_cdata_get(&scn->vertices); log_err(scn->dev, "%s: triangle %lu is a duplicate" " of triangle %lu with incoherent media.\n", - FUNC_NAME, (unsigned long)tmp.global_id, - (unsigned long)trg[*p_trg].global_id); + FUNC_NAME, (unsigned long)(scn->ntris + i), (unsigned long)*p_trg); log_err(scn->dev, "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n", - (unsigned long)trg[*p_trg].global_id, + (unsigned long)*p_trg, SPLIT3(positions[trg[*p_trg].vertice_id[0]].vec), SPLIT3(positions[trg[*p_trg].vertice_id[1]].vec), SPLIT3(positions[trg[*p_trg].vertice_id[2]].vec)); log_err(scn->dev, "Media: (%lu, %lu) VS (%lu, %lu)\n", (unsigned long)umed[ureversed? 1 : 0], (unsigned long)umed[ureversed ? 0 : 1], - (unsigned long)med[reversed ? 1 : 0], - (unsigned long)med[reversed ? 0 : 1]); + (unsigned long)tmp.medium[reversed ? 1 : 0], + (unsigned long)tmp.medium[reversed ? 0 : 1]); res = RES_BAD_ARG; goto error; } else { /* Legit duplicate */ - log_warn(scn->dev, "%s: triangle %lu is a duplicate of triangle %lu.\n", - FUNC_NAME, (unsigned long)tmp.global_id, - (unsigned long)trg[*p_trg].global_id); - if(!same) { - FOR_EACH(j, 0, 2) { - tmp.medium[j] = (medium_id_t)med[1-j]; + range_adjust_ptr = darray_triangle_in_data_get(&scn->triangles_in) + *p_trg; + /* Replace possible undefined media */ + FOR_EACH(j, 0, 2) { + if(range_adjust_ptr->medium[j] == SENC_UNDEFINED_MEDIUM + && tmp.medium[j] != SENC_UNDEFINED_MEDIUM) { + range_adjust_ptr->medium[j] = tmp.medium[j]; + scn->sides_with_defined_medium_count++; } } + if(merge_triangle) { + OK(merge_triangle((unsigned)*p_trg, i, same, ctx)); + } else { + log_warn(scn->dev, + "%s: triangle %lu is a duplicate of triangle %lu.\n", + FUNC_NAME, (unsigned long)(scn->ntris + i), (unsigned long)*p_trg); + } } } else { /* New triangle */ trg_id_t u = scn->nutris + actual_nutris; - struct side_range* media_use; ASSERT(u == htable_trg_size_get(&scn->unique_triangles)); OK(htable_trg_set(&scn->unique_triangles, &trg_key, &u)); OK(darray_triangle_in_push_back(&scn->triangles_in, &tmp)); + range_adjust_ptr = darray_triangle_in_data_get(&scn->triangles_in) + u; + FOR_EACH(j, 0, 2) { + if(tmp.medium[j] != SENC_UNDEFINED_MEDIUM) + scn->sides_with_defined_medium_count++; + } + if(add_triangle) { + OK(add_triangle((unsigned)u, i, ctx)); + } + ++actual_nutris; + } + if(range_adjust_ptr) { + ptrdiff_t u = range_adjust_ptr - trg; + ASSERT(u < scn->nutris + actual_nutris && u < TRG_MAX__); FOR_EACH(j, 0, 2) { - ASSERT(tmp.medium[j] < scn->nmeds); + struct side_range* media_use; + if(tmp.medium[j] == SENC_UNDEFINED_MEDIUM) continue; + ASSERT(tmp.medium[j] < scn->next_medium_idx); media_use = darray_side_range_data_get(&scn->media_use) + tmp.medium[j]; - media_use->first = MMIN(media_use->first, TRGIDxSIDE_2_TRGSIDE(u, j)); + media_use->first = + MMIN(media_use->first, TRGIDxSIDE_2_TRGSIDE((trg_id_t)u, j)); ASSERT(media_use->first < 2 * (scn->nutris + actual_nutris + 1)); - media_use->last = MMAX(media_use->last, TRGIDxSIDE_2_TRGSIDE(u, j)); + media_use->last = + MMAX(media_use->last, TRGIDxSIDE_2_TRGSIDE((trg_id_t)u, j)); ASSERT(media_use->last < 2 * (scn->nutris + actual_nutris + 1)); ASSERT(media_use->first <= media_use->last); } - ++actual_nutris; } ++actual_ntris; } @@ -288,7 +341,7 @@ error: res_T senc_scene_get_convention (const struct senc_scene* scn, - enum senc_convention* convention) + int* convention) { if(!scn || !convention) return RES_BAD_ARG; *convention = scn->convention; @@ -317,6 +370,57 @@ senc_scene_get_unique_triangles_count } res_T +senc_scene_get_unique_sides_without_medium_count + (const struct senc_scene* scn, + unsigned* count) +{ + if(!scn || !count) return RES_BAD_ARG; + ASSERT(2 * scn->nutris >= scn->sides_with_defined_medium_count); + *count = 2 * scn->nutris - scn->sides_with_defined_medium_count; + return RES_OK; +} + +res_T +senc_scene_get_unique_triangle + (const struct senc_scene* scn, + const unsigned itri, + unsigned indices[3]) +{ + const struct triangle_in* trg; + int i; + if(!scn || !indices + || itri >= darray_triangle_in_size_get(&scn->triangles_in)) + return RES_BAD_ARG; + trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri; + + FOR_EACH(i, 0, 3) { + ASSERT(trg->vertice_id[i] < UINT_MAX); + indices[i] = (unsigned)trg->vertice_id[i]; /* Back to API type */ + } + return RES_OK; +} + +res_T +senc_scene_get_unique_triangle_media + (const struct senc_scene* scn, + const unsigned itri, + unsigned media[2]) +{ + const struct triangle_in* trg; + int i; + if(!scn || !media + || itri >= darray_triangle_in_size_get(&scn->triangles_in)) + return RES_BAD_ARG; + trg = darray_triangle_in_cdata_get(&scn->triangles_in) + itri; + + FOR_EACH(i, 0, 2) { + ASSERT(trg->vertice_id[i] < UINT_MAX); + media[i] = (unsigned)trg->medium[i]; /* Back to API type */ + } + return RES_OK; +} + +res_T senc_scene_get_vertices_count (const struct senc_scene* scn, unsigned* count) @@ -337,6 +441,23 @@ senc_scene_get_unique_vertices_count } res_T +senc_scene_get_unique_vertex + (const struct senc_scene* scn, + const unsigned ivert, + double coord[3]) +{ + + const union double3* v; + if(!scn || !coord + || ivert >= darray_position_size_get(&scn->vertices)) + return RES_BAD_ARG; + + v = darray_position_cdata_get(&scn->vertices) + ivert; + d3_set(coord, v->vec); + return RES_OK; +} + +res_T senc_scene_ref_get(struct senc_scene* scn) { if(!scn) return RES_BAD_ARG; diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -108,16 +108,16 @@ get_scn_position(const unsigned ivert, float pos[3], void* ctx) { static int self_hit_filter -(const struct s3d_hit* hit, - const float ray_org[3], - const float ray_dir[3], - void* ray_data, - void* filter_data) + (const struct s3d_hit* hit, + const float ray_org[3], + const float ray_dir[3], + void* ray_data, + void* filter_data) { const struct darray_triangle_comp* triangles_comp = filter_data; const component_id_t* origin_component = ray_data; const struct triangle_comp* hit_trg_comp; - enum side_id hit_side; + enum senc_side hit_side; component_id_t hit_component; (void)ray_org; (void)ray_dir; @@ -125,7 +125,7 @@ self_hit_filter ASSERT(hit->prim.prim_id < darray_triangle_comp_size_get(triangles_comp)); hit_trg_comp = darray_triangle_comp_cdata_get(triangles_comp) + hit->prim.prim_id; - hit_side = (hit->normal[2] > 0) ? SIDE_FRONT : SIDE_BACK; + hit_side = (hit->normal[2] > 0) ? SENC_FRONT : SENC_BACK; hit_component = hit_trg_comp->component[hit_side]; /* Not self hit or distance should be small */ @@ -148,9 +148,9 @@ extract_connex_components { /* This function is called from an omp parallel block and executed * concurrently. */ - const struct senc_scene* scn; + struct senc_scene* scn; struct mem_allocator* alloc; - int64_t mm; + int64_t mm, undefs; struct darray_side_id stack; struct darray_side_id ids_of_sides_around_max_z_vertex; const union double3* positions; @@ -180,6 +180,19 @@ extract_connex_components return; } + /* If there are sides with undefined medium, its like another medium */ + undefs = (scn->sides_with_defined_medium_count < 2 * scn->nutris) ? 1 : 0; +#pragma omp single + { + if(undefs) { + /* Range is unknown, process each side */ + struct side_range und; + und.first = 0; + und.last = 2 * scn->nutris - 1; + darray_side_range_push_back(&scn->media_use, &und); + } + } /* Implicit barrier here */ + #ifndef NDEBUG #pragma omp single { @@ -192,7 +205,8 @@ extract_connex_components = darray_side_range_cdata_get(&scn->media_use); FOR_EACH(mm, 0, 2) { const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t_, mm); - const medium_id_t medium = trg_in->medium[mm]; + medium_id_t medium = trg_in->medium[mm]; + if(medium == SENC_UNDEFINED_MEDIUM) medium = scn->next_medium_idx; ASSERT(media_use[medium].first <= side && side <= media_use[medium].last); } @@ -202,11 +216,14 @@ extract_connex_components /* We loop on sides to build connex components. */ #pragma omp for schedule(dynamic) nowait - for(mm = 0; mm < (int64_t)scn->nmeds; mm++) { /* Process all media */ - const medium_id_t m = (medium_id_t)mm; + /* Process all media, including undef */ + for(mm = 0; mm < undefs + (int64_t)scn->next_medium_idx; mm++) { + const medium_id_t m_idx = (medium_id_t)mm; + const medium_id_t m = (mm == scn->next_medium_idx) + ? SENC_UNDEFINED_MEDIUM : (medium_id_t)mm; /* Any not-already-used side is used as a starting point */ const struct side_range* media_use = - darray_side_range_cdata_get(&scn->media_use) + m; + darray_side_range_cdata_get(&scn->media_use) + m_idx; side_id_t first_side_not_in_component = media_use->first; double max_nz; side_id_t max_nz_side_id = SIDE_NULL__; @@ -240,7 +257,7 @@ extract_connex_components #ifndef NDEBUG { trg_id_t tid = TRGSIDE_2_TRG(start_side_id); - enum side_id s = TRGSIDE_2_SIDE(start_side_id); + enum senc_side s = TRGSIDE_2_SIDE(start_side_id); medium_id_t side_med = darray_triangle_in_data_get(&desc->scene->triangles_in)[tid].medium[s]; ASSERT(side_med == m); @@ -249,15 +266,15 @@ extract_connex_components /* Reuse array if possible, or create a new one */ if(current_media) { - memset(current_media, 0, scn->nmeds); + memset(current_media, 0, 1 + scn->next_medium_idx); /* +1 for possible undef */ } else { - current_media = MEM_CALLOC(alloc, scn->nmeds, sizeof(unsigned char)); + current_media = MEM_CALLOC(alloc, 1 + scn->next_medium_idx, sizeof(unsigned char)); if(!current_media) { *p_res = RES_MEM_ERR; continue; } } - current_media[m] = 1; + current_media[m_idx] = 1; for(;;) { /* Process all sides of this component */ int i; enum side_flag crt_side_flag = TRGSIDE_2_SIDEFLAG(crt_side_id); @@ -308,7 +325,7 @@ extract_connex_components /* Record crt_side both as component and triangle level */ if((*trg_used & crt_side_flag) == 0) { OK2(darray_side_id_push_back(&current_component, &crt_side_id)); - *trg_used |= (unsigned char)crt_side_flag; + *trg_used = *trg_used | (unsigned char)crt_side_flag; } /* Store neighbour's sides in a waiting stack */ @@ -318,8 +335,10 @@ extract_connex_components enum side_flag nbour_side_id = TRGSIDE_2_SIDEFLAG(neighbour_id); unsigned char* nbour_used = processed + nbour_trg_id; const struct trgside* neighbour = trgsides + neighbour_id; + medium_id_t nbour_med_idx = (neighbour->medium == SENC_UNDEFINED_MEDIUM) + ? scn->next_medium_idx : neighbour->medium; if(neighbour->medium < m - || (*nbour_used & (unsigned char)SIDE_CANCELED_FLAG(nbour_side_id))) + || (*nbour_used & SIDE_CANCELED_FLAG(nbour_side_id))) { /* 1) Not the same medium. * Neighbour's medium id is less than current medium: the whole @@ -344,7 +363,7 @@ extract_connex_components ASSERT(*used & (unsigned char)used_side_flag); /* Set the used flag for sides in cancelled component as leading * to further cancellations */ - *used |= (unsigned char)SIDE_CANCELED_FLAG(used_side_flag); + *used |= SIDE_CANCELED_FLAG(used_side_flag); } goto canceled; @@ -354,7 +373,7 @@ extract_connex_components *nbour_used |= (unsigned char)nbour_side_id; OK2(darray_side_id_push_back(&stack, &neighbour_id)); OK2(darray_side_id_push_back(&current_component, &neighbour_id)); - current_media[neighbour->medium] = 1; + current_media[nbour_med_idx] = 1; } sz = darray_side_id_size_get(&stack); if(sz == 0) break; /* Empty stack => component is done! */ @@ -394,7 +413,7 @@ extract_connex_components FOR_EACH(ii, 0, sz) { const side_id_t s = darray_side_id_cdata_get(&current_component)[ii]; trg_id_t tid = TRGSIDE_2_TRG(s); - enum side_id sid = TRGSIDE_2_SIDE(s); + enum senc_side sid = TRGSIDE_2_SIDE(s); component_id_t* cmp = triangles_comp[tid].component; ASSERT(cmp[sid] == COMPONENT_NULL__); ASSERT(trgsides[s].medium >= m); @@ -409,7 +428,7 @@ extract_connex_components const side_id_t side_id = darray_side_id_cdata_get(&ids_of_sides_around_max_z_vertex)[ii]; const trg_id_t trg_id = TRGSIDE_2_TRG(side_id); - enum side_id s = TRGSIDE_2_SIDE(side_id); + enum senc_side s = TRGSIDE_2_SIDE(side_id); const struct triangle_in* trg_in = darray_triangle_in_cdata_get(&scn->triangles_in) + trg_id; const struct triangle_comp* trg_comp = triangles_comp + trg_id; @@ -421,7 +440,7 @@ extract_connex_components * regardless of numeric accuracy, we need to prevent them to * contribute (remember than x + y - y == x can be false). */ ASSERT(trg_comp->component[s] == cc->cc_id); (void)s; - if(trg_comp->component[SIDE_FRONT] == trg_comp->component[SIDE_BACK]) + if(trg_comp->component[SENC_FRONT] == trg_comp->component[SENC_BACK]) continue; d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec, @@ -502,7 +521,7 @@ extract_connex_components ASSERT(desc->scene->nuverts < UINT_MAX); OK(s3d_mesh_setup_indexed_vertices(s3d_shp, (unsigned)desc->scene->nutris, get_scn_indices, - (unsigned)desc->scene->nuverts, &attribs, 1, desc->scene)); + (unsigned)desc->scene->nuverts, &attribs, 1, scn)); s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter, triangles_comp_array); OK(s3d_scene_attach_shape(s3d_scn, s3d_shp)); @@ -527,8 +546,8 @@ extract_connex_components FOR_EACH(t_, 0, scn->nutris) { struct triangle_comp* trg_comp = darray_triangle_comp_data_get(triangles_comp_array) + t_; - ASSERT(trg_comp->component[SIDE_FRONT] != COMPONENT_NULL__); - ASSERT(trg_comp->component[SIDE_BACK] != COMPONENT_NULL__); + ASSERT(trg_comp->component[SENC_FRONT] != COMPONENT_NULL__); + ASSERT(trg_comp->component[SENC_BACK] != COMPONENT_NULL__); } FOR_EACH(c, 0, ATOMIC_GET(component_count)) { struct cc_descriptor** components = @@ -617,13 +636,13 @@ group_connex_components const trg_id_t hit_trg_id = (trg_id_t)hit.prim.prim_id; const struct triangle_comp* hit_trg_comp = darray_triangle_comp_cdata_get(triangles_comp) + hit_trg_id; - enum side_id hit_side = + enum senc_side hit_side = ((hit.normal[2] < 0) /* Facing geometrical normal of hit */ == ((desc->scene->convention & SENC_CONVENTION_NORMAL_FRONT) != 0)) /* Warning: following Embree 2 convention for geometrical normals, * the Star3D hit normal is left-handed while star-enclosure uses * right-handed convention */ - ? SIDE_BACK : SIDE_FRONT; + ? SENC_BACK : SENC_FRONT; ASSERT(hit.normal[2] != 0); ASSERT(hit_trg_id < desc->scene->nutris); @@ -669,7 +688,7 @@ group_connex_components enc->side_range.last = MMAX(enc->side_range.last, cc->side_range.last); enc->side_count += cc->side_count; tmp_res = bool_array_of_media_merge(&enc->tmp_enclosed_media, cc->media, - desc->scene->nmeds); + desc->scene->next_medium_idx + 1); if(tmp_res != RES_OK) { *res = tmp_res; break; @@ -692,8 +711,8 @@ collect_and_link_neighbours { /* This function is called from an omp parallel block and executed * concurrently. */ - const struct triangle_in *triangles_in; - struct triangle_tmp *triangles_tmp; + const struct triangle_in* triangles_in; + struct triangle_tmp* triangles_tmp; const union double3* vertices; const int thread_count = omp_get_num_threads(); const int rank = omp_get_thread_num(); @@ -743,7 +762,7 @@ collect_and_link_neighbours const vrtx_id_t v0 = triangles_in[t].vertice_id[ee]; const vrtx_id_t v1 = triangles_in[t].vertice_id[(ee + 1) % 3]; /* Process only "my" edges! */ - const int64_t h = + const int64_t h = /* v0,v1 and v1,v0 must give the same hash!!! */ v0 + v1 + (int64_t)MMIN(v0, v1); if(h % thread_count != rank) continue; @@ -872,11 +891,11 @@ collect_and_link_neighbours const trg_id_t ccw_id = ccw_neighbour->trg_id; /* Facing sides of triangles */ const int front = ((scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0); - const enum side_id crt_side - = current->normal_toward_next_neighbour == front ? SIDE_FRONT : SIDE_BACK; - const enum side_id ccw_side + const enum senc_side crt_side + = current->normal_toward_next_neighbour == front ? SENC_FRONT : SENC_BACK; + const enum senc_side ccw_side = ccw_neighbour->normal_toward_next_neighbour == front ? - SIDE_BACK : SIDE_FRONT; + SENC_BACK : SENC_FRONT; /* Index of sides in trgsides */ const side_id_t crt_side_idx = TRGIDxSIDE_2_TRGSIDE(crt_id, crt_side); const side_id_t ccw_side_idx = TRGIDxSIDE_2_TRGSIDE(ccw_id, ccw_side); @@ -894,8 +913,7 @@ collect_and_link_neighbours prev_id = previous->trg_id; log_err(scn->dev, "%s: found 2 overlying triangles (%lu & %lu).\n", FUNC_NAME, - (unsigned long)triangles_in[crt_id].global_id, - (unsigned long)triangles_in[prev_id].global_id); + (unsigned long)crt_id, (unsigned long)prev_id); tmp_res = RES_BAD_OP; goto tmp_error; } @@ -912,8 +930,10 @@ collect_and_link_neighbours || p_ccw_side->medium == triangles_in[ccw_id].medium[ccw_side]); p_crt_side->medium = triangles_in[crt_id].medium[crt_side]; p_ccw_side->medium = triangles_in[ccw_id].medium[ccw_side]; - ASSERT(p_crt_side->medium < scn->nmeds); - ASSERT(p_ccw_side->medium < scn->nmeds); + ASSERT(p_crt_side->medium == SENC_UNDEFINED_MEDIUM + || p_crt_side->medium < scn->next_medium_idx); + ASSERT(p_ccw_side->medium == SENC_UNDEFINED_MEDIUM + || p_ccw_side->medium < scn->next_medium_idx); /* Detect triangles that could surround a hole: * - single triangle on (one of) its edge * - different media on its sides */ @@ -924,7 +944,7 @@ collect_and_link_neighbours struct trg_edge disc; log_warn(scn->dev, "%s: found frontier involving triangle %lu.\n", - FUNC_NAME, (unsigned long)triangles_in[crt_id].global_id); + FUNC_NAME, (unsigned long)crt_id); disc.vrtx0 = v0; disc.vrtx1 = v1; darray_frontier_edge_push_back(frontiers, &disc); @@ -992,16 +1012,16 @@ build_result #pragma omp for for(tt = 0; tt < (int64_t)scn->nutris; tt++) { trg_id_t t = (trg_id_t)tt; - const component_id_t cf_id = triangles_comp[t].component[SIDE_FRONT]; - const component_id_t cb_id = triangles_comp[t].component[SIDE_BACK]; + const component_id_t cf_id = triangles_comp[t].component[SENC_FRONT]; + const component_id_t cb_id = triangles_comp[t].component[SENC_BACK]; const struct cc_descriptor* cf = cc_descriptors[cf_id]; const struct cc_descriptor* cb = cc_descriptors[cb_id]; const enclosure_id_t ef_id = cf->enclosure_id; const enclosure_id_t eb_id = cb->enclosure_id; - ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_FRONT] = ef_id; - ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_BACK] = eb_id; + ASSERT(triangles_enc[t].enclosure[SENC_FRONT] == ENCLOSURE_NULL__); + triangles_enc[t].enclosure[SENC_FRONT] = ef_id; + ASSERT(triangles_enc[t].enclosure[SENC_BACK] == ENCLOSURE_NULL__); + triangles_enc[t].enclosure[SENC_BACK] = eb_id; } /* Implicit barrier here */ @@ -1032,9 +1052,9 @@ build_result enc->header.is_infinite = (e == 0); ASSERT(darray_uchar_size_get(&enc->tmp_enclosed_media) <= UINT_MAX); - ASSERT(enc->header.enclosed_media_count <= scn->nmeds); + ASSERT(enc->header.enclosed_media_count < 1 + scn->next_medium_idx); OK2(bool_array_of_media_to_darray_media - (&enc->enclosed_media, &enc->tmp_enclosed_media)); + (&enc->enclosed_media, &enc->tmp_enclosed_media, scn->next_medium_idx)); enc->header.enclosed_media_count = (unsigned)darray_media_size_get(&enc->enclosed_media); darray_uchar_purge(&enc->tmp_enclosed_media); @@ -1042,8 +1062,14 @@ build_result /* Add this enclosure in relevant by-medium lists */ FOR_EACH(m, 0, enc->header.enclosed_media_count) { medium_id_t medium = darray_media_data_get(&enc->enclosed_media)[m]; - struct darray_enc_id* enc_ids_by_medium = - darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + medium; + size_t m_idx = (medium == SENC_UNDEFINED_MEDIUM) + ? scn->next_medium_idx : medium; + struct darray_enc_id* enc_ids_by_medium; + ASSERT(medium == SENC_UNDEFINED_MEDIUM || medium < scn->next_medium_idx); + ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium) + == 1 + scn->next_medium_idx); + enc_ids_by_medium = + darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + m_idx; #pragma omp critical { tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e); @@ -1056,7 +1082,7 @@ build_result if(*res != RES_OK) continue; /* Build side and vertex lists. */ - OK2(darray_triangle_in_resize(&enc->sides, enc->side_count)); + OK2(darray_sides_enc_resize(&enc->sides, enc->side_count)); /* Size is just a int */ OK2(darray_vrtx_id_reserve(&enc->vertices, (size_t)(enc->side_count * 0.6))); @@ -1070,11 +1096,11 @@ build_result t++) { const struct triangle_in* trg_in = triangles_in + t; - struct triangle_in* trg; + struct side_enc* side_enc; unsigned vertice_id[3]; int i; - if(triangles_enc[t].enclosure[SIDE_FRONT] != e - && triangles_enc[t].enclosure[SIDE_BACK] != e) + if(triangles_enc[t].enclosure[SENC_FRONT] != e + && triangles_enc[t].enclosure[SENC_BACK] != e) continue; ++enc->header.unique_triangle_count; @@ -1094,41 +1120,33 @@ build_result ++enc->header.vertices_count; } } - ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == e - || triangles_enc[t].enclosure[SIDE_BACK] == e); - if(triangles_enc[t].enclosure[SIDE_FRONT] == e) { + ASSERT(triangles_enc[t].enclosure[SENC_FRONT] == e + || triangles_enc[t].enclosure[SENC_BACK] == e); + if(triangles_enc[t].enclosure[SENC_FRONT] == e) { /* Front side of the original triangle is member of the enclosure */ int input_normal_in = normals_front; int revert_triangle = (input_normal_in != output_normal_in); ++enc->header.triangle_count; - trg = darray_triangle_in_data_get(&enc->sides) + fst_idx++; - FOR_EACH(i, 0, 2) { - int ii = revert_triangle ? 1 - i : i; - trg->medium[i] = trg_in->medium[ii]; - } - trg->global_id = trg_in->global_id; + side_enc = darray_sides_enc_data_get(&enc->sides) + fst_idx++; FOR_EACH(i, 0, 3) { int ii = revert_triangle ? 2 - i : i; - trg->vertice_id[i] = vertice_id[ii]; + side_enc->vertice_id[i] = vertice_id[ii]; } + side_enc->side_id = TRGIDxSIDE_2_TRGSIDE(t, SENC_FRONT); } - if(triangles_enc[t].enclosure[SIDE_BACK] == e) { + if(triangles_enc[t].enclosure[SENC_BACK] == e) { /* Back side of the original triangle is member of the enclosure */ int input_normal_in = normals_back; int revert_triangle = (input_normal_in != output_normal_in); ++enc->header.triangle_count; /* If both sides are in the enclosure, put the second side at the end */ - trg = darray_triangle_in_data_get(&enc->sides) + - ((triangles_enc[t].enclosure[SIDE_FRONT] == e) ? --sgd_idx : fst_idx++); - FOR_EACH(i, 0, 2) { - int ii = revert_triangle ? 1 - i : i; - trg->medium[i] = trg_in->medium[ii]; - } - trg->global_id = trg_in->global_id; + side_enc = darray_sides_enc_data_get(&enc->sides) + + ((triangles_enc[t].enclosure[SENC_FRONT] == e) ? --sgd_idx : fst_idx++); FOR_EACH(i, 0, 3) { int ii = revert_triangle ? 2 - i : i; - trg->vertice_id[i] = vertice_id[ii]; + side_enc->vertice_id[i] = vertice_id[ii]; } + side_enc->side_id = TRGIDxSIDE_2_TRGSIDE(t, SENC_BACK); } if(fst_idx == sgd_idx) break; } @@ -1148,7 +1166,9 @@ build_result * Exported functions ******************************************************************************/ res_T -senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) +senc_scene_analyze + (struct senc_scene* scn, + struct senc_descriptor** out_desc) { struct senc_descriptor* desc = NULL; /* By triangle tmp data */ @@ -1170,8 +1190,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) /* Atomic counters to share beetwen threads */ ATOMIC component_count = 0; ATOMIC next_enclosure_id = 1; - char dump[64]; - struct time t0, t1; res_T res = RES_OK; res_T res2 = RES_OK; @@ -1185,11 +1203,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) if(!scn->nutris) goto exit; -#pragma omp single nowait - if(scn->dev->verbose) { - time_current(&t0); - } - darray_triangle_tmp_init(scn->dev->allocator, &triangles_tmp); triangles_tmp_initialized = 1; darray_frontier_edge_init(scn->dev->allocator, &frontiers); @@ -1232,7 +1245,7 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) connex_components_initialized = 1; /* Just a hint; to limit contention */ OK2(darray_ptr_component_descriptor_reserve(&connex_components, - 2 * scn->nmeds)); + 2 + 2 * scn->next_medium_idx)); darray_triangle_comp_init(scn->dev->allocator, &triangles_comp); triangles_comp_initialized = 1; OK2(darray_triangle_comp_resize(&triangles_comp, scn->nutris)); @@ -1254,15 +1267,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) goto error_; } - #pragma omp single nowait - if(scn->dev->verbose) { - time_sub(&t1, time_current(&t1), &t0); - time_current(&t0); - time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); - log_info(scn->dev, - "senc_scene_analyze: collect_and_link_neighbours step in %s\n", dump); - } - /* Step 2: extract triangle connex components */ extract_connex_components(desc, trgsides, &connex_components, &triangles_tmp, &triangles_comp, &s3d_view, &component_count, &res); @@ -1290,15 +1294,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) triangles_tmp_initialized = 0; } /* No barrier here */ - #pragma omp single nowait - if(scn->dev->verbose) { - time_sub(&t1, time_current(&t1), &t0); - time_current(&t0); - time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); - log_info(scn->dev, - "senc_scene_analyze: extract_connex_components step in %s\n", dump); - } - /* Step 3: group components */ group_connex_components(desc, trgsides, &triangles_comp, &connex_components, s3d_view, &next_enclosure_id, &res); @@ -1322,15 +1317,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) s3d_view = NULL; } /* No barrier here */ - #pragma omp single nowait - if(scn->dev->verbose) { - time_sub(&t1, time_current(&t1), &t0); - time_current(&t0); - time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); - log_info(scn->dev, - "senc_scene_analyze: group_connex_components step in %s\n", dump); - } - /* Step 4: Build result */ build_result(desc, &connex_components, &triangles_comp, &frontiers, &res); /* No barrier at the end of step 4: data used in step 4 cannot be @@ -1363,15 +1349,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) } } /* No barrier here */ - #pragma omp single nowait - if(scn->dev->verbose) { - time_sub(&t1, time_current(&t1), &t0); - time_current(&t0); - time_dump(&t1, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump)); - log_info(scn->dev, - "senc_scene_analyze: build_result step in %s\n", dump); - } - error_: ; } /* Implicit barrier here */ diff --git a/src/senc_scene_c.h b/src/senc_scene_c.h @@ -48,25 +48,20 @@ struct triangle_in { vrtx_id_t vertice_id[3]; /* Ids of this triangle's media */ medium_id_t medium[2]; - /* Triangle index in user world (that is regardless of deduplication). */ - unsigned global_id; }; -#ifndef NDEBUG static FINLINE void triangle_in_init(struct mem_allocator* alloc, struct triangle_in* trg) { int i; (void)alloc; ASSERT(trg); FOR_EACH(i, 0, 3) trg->vertice_id[i] = VRTX_NULL__; - FOR_EACH(i, 0, 2) trg->medium[i] = MEDIUM_NULL__; - trg->global_id = 0; + FOR_EACH(i, 0, 2) trg->medium[i] = SENC_UNDEFINED_MEDIUM; } -#define DARRAY_FUNCTOR_INIT triangle_in_init -#endif #define DARRAY_NAME triangle_in #define DARRAY_DATA struct triangle_in +#define DARRAY_FUNCTOR_INIT triangle_in_init #include <rsys/dynamic_array.h> static FINLINE void @@ -197,7 +192,7 @@ side_range_init(struct mem_allocator* alloc, struct side_range* data) struct senc_scene { /* Front / Back sides convention */ - enum senc_convention convention; + int convention; /* Triangle information as given by user; no duplicates here */ struct darray_triangle_in triangles_in; @@ -219,8 +214,9 @@ struct senc_scene { unsigned ngeoms; /* Not used yet (just counted). */ trg_id_t ntris, nutris; /* Trg count, unique trg count */ vrtx_id_t nverts, nuverts; /* Vrtx count, unique vrtx count */ - medium_id_t nmeds; + medium_id_t next_medium_idx; struct darray_side_range media_use; + side_id_t sides_with_defined_medium_count; ref_T ref; struct senc_device* dev; diff --git a/src/test_senc_cube_behind_cube.c b/src/test_senc_cube_behind_cube.c @@ -47,8 +47,8 @@ main(int argc, char** argv) ctx.back_media = medium1; /* First cube */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); /* +Z from the first cube, * big enough to prevent rays from the first cube to miss this one */ @@ -56,8 +56,8 @@ main(int argc, char** argv) ctx.scale = 5; /* Second cube */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -85,8 +85,8 @@ main(int argc, char** argv) ctx.back_media = medium0; /* Third cube */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); desc = NULL; diff --git a/src/test_senc_cube_in_cube.c b/src/test_senc_cube_in_cube.c @@ -49,8 +49,8 @@ main(int argc, char** argv) ctx.back_media = medium1; /* First cube */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); d3(ctx.offset, -1, -1, -1); ctx.scale = 3; @@ -59,8 +59,8 @@ main(int argc, char** argv) ctx.reverse_vrtx = 1; /* Second cube */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -91,8 +91,8 @@ main(int argc, char** argv) ctx.back_media = medium0; /* Third cube */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); desc = NULL; diff --git a/src/test_senc_cube_on_cube.c b/src/test_senc_cube_on_cube.c @@ -74,7 +74,7 @@ main(int argc, char** argv) /* Add cube #1 */ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); d3(ctx.offset, 1, 1, 1); ctx.scale = 1; @@ -86,7 +86,7 @@ main(int argc, char** argv) /* Add cube #2 (has a duplicate face with cube #1) */ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); ctx.positions = box_vertices; /* Can use distorded cube for cube #3 */ d3(ctx.offset, 0, 0, 0); @@ -100,7 +100,7 @@ main(int argc, char** argv) /* Add cube #3 */ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); diff --git a/src/test_senc_descriptor.c b/src/test_senc_descriptor.c @@ -52,8 +52,8 @@ main(int argc, char** argv) ctx.front_media = medium0; ctx.back_media = medium1; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -164,22 +164,11 @@ main(int argc, char** argv) CHK(enclosures[0] == 0 && enclosures[1] == 1); - CHK(senc_descriptor_get_global_triangle_global_id(NULL, 0, indices) - == RES_BAD_ARG); - CHK(senc_descriptor_get_global_triangle_global_id(NULL, nvertices, indices) - == RES_BAD_ARG); - CHK(senc_descriptor_get_global_triangle_global_id(desc, 0, NULL) - == RES_BAD_ARG); - CHK(senc_descriptor_get_global_triangle_global_id(desc, 0, indices) - == RES_OK); - /* No duplicates and no custom id: user id is unique vertex id */ - CHK(indices[0] == 0); - /* Add valid duplicate geometry */ CHK(senc_descriptor_ref_put(desc) == RES_OK); desc = NULL; CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK); @@ -195,8 +184,8 @@ main(int argc, char** argv) desc = NULL; ctx.front_media = medium1; ctx.back_media = medium0; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_BAD_ARG); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); CHK(senc_scene_ref_put(scn) == RES_OK); if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); @@ -209,7 +198,7 @@ main(int argc, char** argv) == RES_OK); CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); diff --git a/src/test_senc_enclosure.c b/src/test_senc_enclosure.c @@ -22,7 +22,7 @@ #include <star/s3d.h> static void -test(enum senc_convention convention) +test(const int convention) { struct mem_allocator allocator; struct senc_descriptor* desc = NULL; @@ -36,13 +36,15 @@ test(enum senc_convention convention) struct s3d_shape* s3d_shp = NULL; struct s3d_vertex_data s3d_attribs; unsigned indices[2][3]; - unsigned medium, media[2]; + unsigned medium; unsigned gid; + enum senc_side side; double vrtx[3]; struct context ctx; unsigned i, n, t, ecount; - enum senc_convention conv; - int is_front, is_in; + int conv; + const int conv_front = (convention & SENC_CONVENTION_NORMAL_FRONT) != 0; + const int conv_in = (convention & SENC_CONVENTION_NORMAL_INSIDE) != 0; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) @@ -52,8 +54,6 @@ test(enum senc_convention convention) CHK(senc_scene_get_convention(scn, &conv) == RES_OK); CHK(conv == convention); - is_front = (conv & SENC_CONVENTION_NORMAL_FRONT) != 0; - is_in = (conv & SENC_CONVENTION_NORMAL_INSIDE) != 0; s3d_attribs.type = S3D_FLOAT3; s3d_attribs.usage = S3D_POSITION; @@ -76,7 +76,7 @@ test(enum senc_convention convention) ctx.back_media = medium1; CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -112,32 +112,38 @@ test(enum senc_convention convention) CHK(senc_enclosure_get_vertex(NULL, nvertices, NULL) == RES_BAD_ARG); CHK(senc_enclosure_get_vertex(enclosure, 0, vrtx) == RES_OK); - CHK(senc_enclosure_get_triangle_media(NULL, 0, media) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(enclosure, ntriangles, media) + CHK(senc_enclosure_get_triangle_global_id(NULL, 0, &gid, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(enclosure, 0, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(NULL, ntriangles, media) + CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, &gid, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(NULL, 0, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(enclosure, ntriangles, NULL) + CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, NULL, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(NULL, ntriangles, NULL) + CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, &gid, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_media(enclosure, 0, media) == RES_OK); - - CHK(senc_enclosure_get_triangle_global_id(NULL, 0, &gid) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, &gid) + CHK(senc_enclosure_get_triangle_global_id(NULL, 0, NULL, NULL) + == RES_BAD_ARG); + CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, NULL, NULL) + == RES_BAD_ARG); + CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, NULL, NULL) + == RES_BAD_ARG); + CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, &gid, NULL) + == RES_BAD_ARG); + CHK(senc_enclosure_get_triangle_global_id(NULL, 0, &gid, &side) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, NULL) + CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, &gid, &side) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, &gid) + CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, NULL, &side) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(NULL, 0, NULL) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, NULL) + CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, &gid, &side) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, NULL) + CHK(senc_enclosure_get_triangle_global_id(NULL, 0, NULL, &side) == RES_BAD_ARG); - CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, &gid) == RES_OK); + CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, NULL, &side) + == RES_BAD_ARG); + CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, NULL, &side) + == RES_BAD_ARG); + CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, &gid, &side) + == RES_OK); CHK(senc_enclosure_get_medium(NULL, 0, &medium) == RES_BAD_ARG); CHK(senc_enclosure_get_medium(enclosure, 2, &medium) == RES_BAD_ARG); @@ -164,15 +170,16 @@ test(enum senc_convention convention) /* Geometrical normals point outside the cube in input triangles: * if convention is front, front medium (0) is outside, * that is medium 0's enclosure is infinite */ - CHK(is_front == ((medium == 0) == header.is_infinite)); + CHK(conv_front == ((medium == 0) == header.is_infinite)); CHK(header.triangle_count == ntriangles); CHK(header.unique_triangle_count == ntriangles); CHK(header.vertices_count == nvertices); CHK(header.is_infinite == (i == 0)); FOR_EACH(t, 0, header.triangle_count) { - CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid) == RES_OK); + CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side) == RES_OK); CHK(gid == t); + CHK(side == (medium == 0) ? SENC_FRONT : SENC_BACK); } CHK(senc_enclosure_ref_put(enclosure) == RES_OK); @@ -192,9 +199,9 @@ test(enum senc_convention convention) * of input triangles for enclosure 0 iff convention is inside. * The opposite holds for enclosure 1. */ cmp_trg(n, enclosures[0], box_indices + 3 * n, box_vertices, &same, &reversed); - CHK((same && !reversed) == is_in); + CHK((same && !reversed) == conv_in); cmp_trg(n, enclosures[1], box_indices + 3 * n, box_vertices, &same, &reversed); - CHK(same && reversed == is_in); + CHK(same && reversed == conv_in); } FOR_EACH(i, 0, 2) CHK(senc_enclosure_ref_put(enclosures[i]) == RES_OK); @@ -205,8 +212,7 @@ test(enum senc_convention convention) /* Same 3D cube, but with a hole (incomplete). * 1 single enclosure including both sides of triangles */ - CHK(senc_scene_create(dev, - SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK); + CHK(senc_scene_create(dev, convention, &scn) == RES_OK); ctx.positions = box_vertices; ctx.indices = box_indices; @@ -216,7 +222,7 @@ test(enum senc_convention convention) ctx.back_media = medium1; CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, get_media, - NULL, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -239,11 +245,12 @@ test(enum senc_convention convention) CHK(header.vertices_count == nvertices); CHK(header.is_infinite == 1); - FOR_EACH(t, 0, header.unique_triangle_count) { + FOR_EACH(t, 0, header.triangle_count) { + CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side) == RES_OK); /* The first unique_triangle_count triangles of an enclosure * are unique triangles */ - CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid) == RES_OK); - CHK(gid == t); + if (t < header.unique_triangle_count) CHK(gid == t); + CHK(side == (t < header.unique_triangle_count) ? SENC_FRONT : SENC_BACK); } FOR_EACH(n, 0, header.unique_triangle_count) { diff --git a/src/test_senc_inconsistant_cube.c b/src/test_senc_inconsistant_cube.c @@ -49,7 +49,7 @@ static const unsigned inconsistant_medium_back[12] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; static void -test(enum senc_convention convention) +test(const int convention) { struct mem_allocator allocator; struct senc_descriptor* desc = NULL; @@ -57,7 +57,7 @@ test(enum senc_convention convention) struct senc_scene* scn = NULL; struct senc_enclosure* enclosure; struct senc_enclosure_header header; - enum senc_convention conv; + int conv; int conv_front, conv_in; struct context ctx; unsigned i, e, ecount; @@ -83,7 +83,7 @@ test(enum senc_convention convention) ctx.back_media = inconsistant_medium_back; CHK(senc_scene_add_geometry(scn, inconsistant_box_ntriangles, get_indices, - get_media, NULL, nvertices, get_position, &ctx) == RES_OK); + get_media, nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -98,8 +98,8 @@ test(enum senc_convention convention) FOR_EACH(e, 0, ecount) { unsigned medium, expected_external_medium, expected_medium; char name[128]; - int front_inside; - int expected_side; + enum senc_side side, expected_side; + unsigned gid; CHK(senc_descriptor_get_enclosure(desc, e, &enclosure) == RES_OK); CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); CHK(header.enclosed_media_count == 1); @@ -110,9 +110,6 @@ test(enum senc_convention convention) expected_medium = (header.is_infinite ? expected_external_medium : !expected_external_medium); CHK(medium == expected_medium); - /* Common media, for non input triangles */ - front_inside = (conv_front == conv_in); - expected_side = front_inside ? 0 : 1; sprintf(name, "test_inconsistant_cube_%s_%s_%u.obj", conv_front ? "front" : "back", conv_in ? "in" : "out", e); @@ -120,16 +117,17 @@ test(enum senc_convention convention) FOR_EACH(i, 0, header.triangle_count) { int same, reversed, fst_reversed; - unsigned med[2]; - fst_reversed = (e == 0) == conv_in; - CHK(senc_enclosure_get_triangle_media(enclosure, i, med) == RES_OK); - CHK(med[expected_side] == medium); + fst_reversed = ((e == 0) == conv_in); + expected_side = (inconsistant_medium_front[i] == expected_medium) + ? SENC_FRONT : SENC_BACK; cmp_trg(i, enclosure, inconsistant_box_indices + (3 * i), box_vertices, &same, &reversed); /* Should be made of the same triangles */ CHK(same); CHK(i ? reversed != fst_reversed : reversed == fst_reversed); + CHK(senc_enclosure_get_triangle_global_id(enclosure, i, &gid, &side) == RES_OK); + CHK(side == expected_side); } SENC(enclosure_ref_put(enclosure)); } diff --git a/src/test_senc_many_enclosures.c b/src/test_senc_many_enclosures.c @@ -106,6 +106,8 @@ main(int argc, char** argv) ASSERT(ctx.data.nvertices < UINT_MAX); cyl_trg_count = (unsigned)ctx.data.nprimitives; cyl_vrtx_count = (unsigned)ctx.data.nvertices; + CHK(senc_scene_reserve(scn, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0) + == RES_OK); FOR_EACH(i, 0, NB_CYL_1) { double center_x = 2 * (1 + NB_CYL_1) * (i - NB_CYL_1 / 2); FOR_EACH(j, 0, NB_CYL_1) { @@ -121,7 +123,7 @@ main(int argc, char** argv) misalignment *= -1; d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0); CHK(senc_scene_add_geometry(scn, cyl_trg_count, get_s3dut_indices, - get_s3dut_media, NULL, cyl_vrtx_count, get_s3dut_position, &ctx) + get_s3dut_media, cyl_vrtx_count, get_s3dut_position, NULL, NULL, &ctx) == RES_OK); } } diff --git a/src/test_senc_many_triangles.c b/src/test_senc_many_triangles.c @@ -104,11 +104,13 @@ main(int argc, char** argv) ASSERT(ctx.data.nvertices < UINT_MAX); cyl_trg_count = (unsigned)ctx.data.nprimitives; cyl_vrtx_count = (unsigned)ctx.data.nvertices; + CHK(senc_scene_reserve(scn, NB_CYL * cyl_vrtx_count, NB_CYL * cyl_trg_count, 0) + == RES_OK); FOR_EACH(i, 0, NB_CYL) { m1 = i; d3(ctx.ctx.offset, 0, 0, i * 10); CHK(senc_scene_add_geometry(scn, cyl_trg_count, get_s3dut_indices, - get_s3dut_media, NULL, cyl_vrtx_count, get_s3dut_position, &ctx) + get_s3dut_media, cyl_vrtx_count, get_s3dut_position, NULL, NULL, &ctx) == RES_OK); } S3DUT(mesh_ref_put(cyl)); diff --git a/src/test_senc_sample_enclosure.c b/src/test_senc_sample_enclosure.c @@ -72,7 +72,7 @@ main(int argc, char** argv) ctx.back_media = medium0; CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, - get_media, NULL, nvertices, get_position, &ctx) == RES_OK); + get_media, nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); diff --git a/src/test_senc_scene.c b/src/test_senc_scene.c @@ -29,9 +29,10 @@ main(int argc, char** argv) struct senc_enclosure* enc = NULL; struct senc_enclosure_header header; struct context ctx; - unsigned medfront[2], medback[2]; + unsigned medfront[2], medback[2], ind[3]; + double vrtx[3]; unsigned count, i, maxm; - enum senc_convention convention; + int convention; (void)argc, (void)argv; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); @@ -51,6 +52,9 @@ main(int argc, char** argv) CHK(senc_scene_create(dev, SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK); + CHK(senc_scene_reserve(NULL, 0, 0, 0) == RES_BAD_ARG); + CHK(senc_scene_reserve(scn, 0, 0, 0) == RES_OK); + CHK(senc_scene_get_convention(NULL, &convention) == RES_BAD_ARG); CHK(senc_scene_get_convention(scn, NULL) == RES_BAD_ARG); CHK(senc_scene_get_convention(NULL, NULL) == RES_BAD_ARG); @@ -81,6 +85,16 @@ main(int argc, char** argv) CHK(senc_scene_get_unique_vertices_count(scn, &count) == RES_OK); CHK(count == 0); + CHK(senc_scene_get_unique_sides_without_medium_count(NULL, &count) + == RES_BAD_ARG); + CHK(senc_scene_get_unique_sides_without_medium_count(scn, NULL) + == RES_BAD_ARG); + CHK(senc_scene_get_unique_sides_without_medium_count(NULL, NULL) + == RES_BAD_ARG); + CHK(senc_scene_get_unique_sides_without_medium_count(scn, &count) + == RES_OK); + CHK(count == 0); + /* A 3D cube. * With this geometry front is inside with NORMAL_BACK convention, * outside with NORMAL_FRONT convention */ @@ -92,22 +106,19 @@ main(int argc, char** argv) d3(ctx.offset, 0, 0, 0); ctx.front_media = medium0; ctx.back_media = medium1; - ctx.global_ids = gid_face; CHK(senc_scene_add_geometry(NULL, ntriangles, get_indices, get_media, - get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG); - CHK(senc_scene_add_geometry(scn, 0, get_indices, get_media, get_global_id, - nvertices, get_position, &ctx) == RES_BAD_ARG); + nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); + CHK(senc_scene_add_geometry(scn, 0, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); CHK(senc_scene_add_geometry(scn, ntriangles, NULL, get_media, - get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG); - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL, - get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG); + nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - get_global_id, 0, get_position, &ctx) == RES_BAD_ARG); + 0, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - get_global_id, nvertices, NULL, &ctx) == RES_BAD_ARG); + nvertices, NULL, NULL, NULL, &ctx) == RES_BAD_ARG); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - get_global_id, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_get_triangles_count(scn, &count) == RES_OK); CHK(count == ntriangles); @@ -118,6 +129,33 @@ main(int argc, char** argv) CHK(senc_scene_get_unique_vertices_count(scn, &count) == RES_OK); CHK(count == nvertices); + CHK(senc_scene_get_unique_triangle(NULL, 0, ind) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(scn, UINT_MAX, ind) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(scn, 0, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(NULL, UINT_MAX, ind) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(NULL, 0, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(scn, UINT_MAX, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(NULL, UINT_MAX, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle(scn, 0, ind) == RES_OK); + + CHK(senc_scene_get_unique_triangle_media(NULL, 0, ind) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(scn, UINT_MAX, ind) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(scn, 0, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(NULL, UINT_MAX, ind) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(NULL, 0, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(scn, UINT_MAX, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(NULL, UINT_MAX, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_triangle_media(scn, 0, ind) == RES_OK); + + CHK(senc_scene_get_unique_vertex(NULL, 0, vrtx) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(scn, UINT_MAX, vrtx) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(scn, 0, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(NULL, UINT_MAX, vrtx) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(NULL, 0, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(scn, UINT_MAX, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(NULL, UINT_MAX, NULL) == RES_BAD_ARG); + CHK(senc_scene_get_unique_vertex(scn, 0, vrtx) == RES_OK); + CHK(senc_scene_analyze(NULL, NULL) == RES_BAD_ARG); CHK(senc_scene_analyze(scn, NULL) == RES_BAD_ARG); CHK(senc_scene_analyze(NULL, &desc) == RES_BAD_ARG); @@ -136,7 +174,7 @@ main(int argc, char** argv) CHK(senc_scene_get_convention(scn, &convention) == RES_OK); CHK(convention == (SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE)); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - get_global_id, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); /* Check that medium 0 is inside */ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK); @@ -144,21 +182,14 @@ main(int argc, char** argv) CHK(!header.is_infinite); CHK(senc_enclosure_ref_put(enc) == RES_OK); - FOR_EACH(i, 0, ntriangles) { - unsigned gid; - CHK(senc_descriptor_get_global_triangle_global_id(desc, i, &gid) == RES_OK); - /* gid has been set to gid_face. */ - CHK(gid == gid_face[i]); - } CHK(senc_descriptor_get_global_triangle_media(desc, 0, medback) == RES_OK); - ctx.front_media = medium1_3; CHK(senc_scene_ref_put(scn) == RES_OK); CHK(senc_descriptor_ref_put(desc) == RES_OK); CHK(senc_scene_create(dev, SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, - get_global_id, nvertices, get_position, &ctx) == RES_OK); + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); /* Medium mismatch between neighbour segments, but OK */ CHK(senc_scene_analyze(scn, &desc) == RES_OK); @@ -179,8 +210,8 @@ main(int argc, char** argv) CHK(senc_descriptor_ref_put(desc) == RES_OK); CHK(senc_scene_create(dev, SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK); - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_analyze(scn, &desc) == RES_OK); /* Check that medium 0 is outside */ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK); @@ -188,46 +219,40 @@ main(int argc, char** argv) CHK(header.is_infinite); CHK(senc_enclosure_ref_put(enc) == RES_OK); - FOR_EACH(i, 0, ntriangles) { - unsigned gid; - CHK(senc_descriptor_get_global_triangle_global_id(desc, i, &gid) == RES_OK); - /* Default gid: triangle rank. */ - CHK(gid == i); - } CHK(senc_descriptor_get_global_triangle_media(desc, 0, medfront) == RES_OK); FOR_EACH(i, 0, 2) CHK(medback[i] == medfront[i]); /* Invalid vertex ID */ - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices - 1, get_position, &ctx) == RES_BAD_ARG); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices - 1, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); /* Incoherent medium on a duplicate triangle */ ctx.back_media = medium1_3; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_BAD_ARG); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_BAD_ARG); /* It is OK add geometry after a failed add */ ctx.back_media = medium1; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); /* Coherent medium on duplicate triangle */ ctx.back_media = medium1; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); /* Coherent medium on duplicate triangle V2 */ ctx.reverse_med = 1; ctx.front_media = medium1; ctx.back_media = medium0; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); /* Coherent medium on duplicate triangle V3 */ ctx.reverse_med = 0; ctx.reverse_vrtx = 1; - CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, - nvertices, get_position, &ctx) == RES_OK); + CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx) == RES_OK); CHK(senc_scene_ref_put(scn) == RES_OK); CHK(senc_device_ref_put(dev) == RES_OK); diff --git a/src/test_senc_undefined_medium.c b/src/test_senc_undefined_medium.c @@ -0,0 +1,277 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "senc.h" +#include "senc_s3d_wrapper.h" +#include "test_senc_utils.h" + +#include <rsys/double3.h> + +static void +test(const int convention) +{ + struct mem_allocator allocator; + struct senc_descriptor* desc = NULL; + struct senc_device* dev = NULL; + struct senc_scene* scn = NULL; + struct senc_enclosure* enclosure; + struct senc_enclosure_header header; + unsigned medium, expected_external_medium, expected_internal_medium; + unsigned gid; + enum senc_side side; + struct context ctx; + unsigned i, t, ecount, vcount, tcount, scount; + unsigned media[12]; + unsigned rev_box_indices[sizeof(box_indices) / sizeof(*box_indices)]; + const int conv_front = (convention & SENC_CONVENTION_NORMAL_FRONT) != 0; + + /* Create a box with reversed triangles */ + FOR_EACH(i, 0, sizeof(rev_box_indices) / sizeof(*rev_box_indices)) { + switch (i % 3) { + case 0: rev_box_indices[i] = box_indices[i]; break; + case 1: rev_box_indices[i] = box_indices[i + 1]; break; + case 2: rev_box_indices[i] = box_indices[i - 1]; break; + } + } + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)); + + OK(senc_scene_create(dev, convention, &scn)); + + /* A 3D cube. + * 2 enclosures (inside, outside) sharing the same triangles, + * but opposite sides */ + ctx.positions = box_vertices; + ctx.indices = box_indices; + ctx.scale = 1; + ctx.reverse_vrtx = 0; + ctx.reverse_med = 0; + d3(ctx.offset, 0, 0, 0); + ctx.front_media = media; + ctx.back_media = medium1; + + /* Can add the same triangles again defined/undefined media in any order */ + + /* Add geometry with no media information on both sides */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = SENC_UNDEFINED_MEDIUM; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 2 * ntriangles); + + /* Add geometry with no media information on the front sides */ + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == ntriangles); + + /* Analyze with undefined media on the front sides */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_get_enclosure_count(desc, &ecount)); + CHK(ecount == 2); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* ee; + struct senc_enclosure_header hh; + unsigned cc; + OK(senc_descriptor_get_enclosure(desc, i, &enclosure)); + OK(senc_enclosure_get_header(enclosure, &header)); + + CHK(header.enclosure_id == i); + CHK(header.enclosed_media_count == 1); + + OK(senc_enclosure_get_medium(enclosure, 0, &medium)); + /* Geometrical normals point outside the cube in input triangles: + * if convention is front, front medium (undef) is outside, + * that is medium 0's enclosure is infinite */ + expected_external_medium = conv_front ? SENC_UNDEFINED_MEDIUM : 1; + expected_internal_medium = conv_front ? 1 :SENC_UNDEFINED_MEDIUM; + + CHK(medium == (header.is_infinite + ? expected_external_medium : expected_internal_medium)); + CHK(header.triangle_count == ntriangles); + CHK(header.unique_triangle_count == ntriangles); + CHK(header.vertices_count == nvertices); + CHK(header.is_infinite == (i == 0)); + + OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc)); + CHK(cc == 1); + OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee)); + OK(senc_enclosure_get_header(ee, &hh)); + CHK(header.enclosure_id == hh.enclosure_id); + OK(senc_enclosure_ref_put(ee)); + + FOR_EACH(t, 0, header.triangle_count) { + unsigned ind[3]; + OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side)); + CHK(gid == t); + CHK(side == (medium == 1) ? SENC_BACK :SENC_FRONT); + OK(senc_enclosure_get_triangle(enclosure, t, ind)); + } + OK(senc_enclosure_ref_put(enclosure)); + } + OK(senc_descriptor_ref_put(desc)); + + /* Same geometry, front media are defined for odd triangles */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = (i % 2) ? 0 : SENC_UNDEFINED_MEDIUM; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == ntriangles / 2); + + /* Analyze with undefined media */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_ref_put(desc)); + + /* Get the deduplicated geometry without (successful) analyze */ + OK(senc_scene_get_unique_vertices_count(scn, &vcount)); + CHK(vcount == nvertices); + OK(senc_scene_get_unique_triangles_count(scn, &tcount)); + CHK(tcount == ntriangles); + FOR_EACH(i, 0, tcount) { + int j; + unsigned med[2], ids[3]; + OK(senc_scene_get_unique_triangle(scn, i, ids)); + OK(senc_scene_get_unique_triangle_media(scn, i, med)); + CHK(med[0] == ((i % 2) ? 0 : SENC_UNDEFINED_MEDIUM) && med[1] == 1); + FOR_EACH(j, 0, 3) { + double pos[3]; + CHK(ids[j] < vcount); + OK(senc_scene_get_unique_vertex(scn, ids[j], pos)); + } + } + + /* Same information again, using a reversed box */ + ctx.indices = rev_box_indices; + SWAP(const unsigned*, ctx.front_media, ctx.back_media); + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == ntriangles / 2); + + /* Analyze with undefined media */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_ref_put(desc)); + + /* Define media for remaining triangles, using reversed box */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = (i % 2) ? SENC_UNDEFINED_MEDIUM : 0; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 0); + + /* Get the deduplicated geometry without (successful) analyze */ + OK(senc_scene_get_unique_vertices_count(scn, &vcount)); + CHK(vcount == nvertices); + OK(senc_scene_get_unique_triangles_count(scn, &tcount)); + CHK(tcount == ntriangles); + FOR_EACH(i, 0, tcount) { + int j; + unsigned med[2], ids[3]; + OK(senc_scene_get_unique_triangle(scn, i, ids)); + OK(senc_scene_get_unique_triangle_media(scn, i, med)); + CHK(med[0] == 0 && med[1] == 1); + FOR_EACH(j, 0, 3) { + double pos[3]; + CHK(ids[j] < vcount); + OK(senc_scene_get_unique_vertex(scn, ids[j], pos)); + } + } + + /* Analyze with all media defined */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_ref_put(desc)); + + /* Define media for all triangles, nothing new here */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = 0; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 0); + + /* Define incoherent media for some triangles */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = (i % 2); + BA(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, NULL, NULL, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 0); + + /* Scene is still OK and can be analyzed */ + OK(senc_scene_analyze(scn, &desc)); + + OK(senc_descriptor_get_global_triangles_count(desc, &tcount)); + CHK(tcount == sizeof(media) / sizeof(*media)); + + OK(senc_descriptor_get_enclosure_count(desc, &ecount)); + CHK(ecount == 2); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* ee; + struct senc_enclosure_header hh; + unsigned cc; + OK(senc_descriptor_get_enclosure(desc, i, &enclosure)); + OK(senc_enclosure_get_header(enclosure, &header)); + + CHK(header.enclosure_id == i); + CHK(header.enclosed_media_count == 1); + OK(senc_enclosure_get_medium(enclosure, 0, &medium)); + /* Geometrical normals point outside the cube in input triangles: + * if convention is front, front medium (0) is outside, + * that is medium 0's enclosure is infinite */ + CHK(conv_front == ((medium == 0) == header.is_infinite)); + CHK(header.triangle_count == ntriangles); + CHK(header.unique_triangle_count == ntriangles); + CHK(header.vertices_count == nvertices); + CHK(header.is_infinite == (i == 0)); + + OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc)); + CHK(cc == 1); + OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee)); + OK(senc_enclosure_get_header(ee, &hh)); + CHK(header.enclosure_id == hh.enclosure_id); + OK(senc_enclosure_ref_put(ee)); + + FOR_EACH(t, 0, header.triangle_count) { + OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side)); + CHK(gid == t); + CHK(side == (medium == 1) ? SENC_BACK : SENC_FRONT); + } + OK(senc_enclosure_ref_put(enclosure)); + } + + SENC(scene_ref_put(scn)); + SENC(device_ref_put(dev)); + SENC(descriptor_ref_put(desc)); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); +} + +int +main(int argc, char** argv) +{ + (void) argc, (void) argv; + test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE); + test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE); + test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE); + test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE); + return 0; +} diff --git a/src/test_senc_undefined_medium_attr.c b/src/test_senc_undefined_medium_attr.c @@ -0,0 +1,366 @@ +/* Copyright (C) |Meso|Star> 2016-2018 (contact@meso-star.com) +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "senc.h" +#include "senc_s3d_wrapper.h" +#include "test_senc_utils.h" + +#include <rsys/double3.h> +#include <limits.h> + +#define INVALID_INTFACE_ID UINT_MAX + +static FINLINE void +set_null_id(struct mem_allocator* alloc, unsigned* data) +{ + ASSERT(data); (void)alloc; + *data = INVALID_INTFACE_ID; +} + +#include <rsys/dynamic_array.h> +#define DARRAY_NAME intface_id +#define DARRAY_FUNCTOR_INIT set_null_id +#define DARRAY_DATA unsigned +#include <rsys/dynamic_array.h> + +/* Manage interface properties */ +struct merge_ctx { + struct darray_intface_id global_interf_data; + const unsigned* current_add_interf_data; +}; + +static res_T +add_trg + (const unsigned global_id, + const unsigned itri, + void* context) +{ + res_T res = RES_OK; + struct context* ctx = context; + struct merge_ctx* merge_ctx; + unsigned interf; + ASSERT(ctx); + merge_ctx = ctx->custom; + /* Get interface information from ctx */ + interf = merge_ctx->current_add_interf_data[itri]; + /* Keep data */ + res = darray_intface_id_resize(&merge_ctx->global_interf_data, global_id + 1); + if(res != RES_OK) return res; + darray_intface_id_data_get(&merge_ctx->global_interf_data)[global_id] = interf; + return res; +} + +static res_T +merge_trg + (const unsigned global_id, + const unsigned itri, + const int reversed_triangle, + void* context) +{ + res_T res = RES_OK; + struct context* ctx = context; + struct merge_ctx* merge_ctx; + int need_merge; + unsigned interf; + unsigned* interf_data; + ASSERT(ctx); (void)reversed_triangle; + merge_ctx = ctx->custom; + res = darray_intface_id_resize(&merge_ctx->global_interf_data, global_id + 1); + if(res != RES_OK) return res; + /* Get interface information from ctx */ + interf = merge_ctx->current_add_interf_data[itri]; + + interf_data = darray_intface_id_data_get(&merge_ctx->global_interf_data); + + need_merge = (interf_data[global_id] != INVALID_INTFACE_ID); + if (need_merge) { + if (interf_data[global_id] != interf) + /* Previous interface id is different: no possible merge */ + return RES_BAD_ARG; + } else { + /* Triangle is known, but without interface information: create */ + interf_data[global_id] = interf; + } + return RES_OK; +} + +static void +test(const int convention) +{ + struct mem_allocator allocator; + struct senc_descriptor* desc = NULL; + struct senc_device* dev = NULL; + struct senc_scene* scn = NULL; + struct senc_enclosure* enclosure; + struct senc_enclosure_header header; + unsigned medium, expected_external_medium, expected_internal_medium; + unsigned gid; + enum senc_side side; + struct context ctx; + unsigned i, t, ecount, vcount, tcount, scount; + unsigned media[12], interface_ids[12] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 }; + unsigned rev_box_indices[sizeof(box_indices) / sizeof(*box_indices)]; + struct merge_ctx merge_ctx; + const int conv_front = (convention & SENC_CONVENTION_NORMAL_FRONT) != 0; + + darray_intface_id_init(&allocator, &merge_ctx.global_interf_data); + merge_ctx.current_add_interf_data = interface_ids; + + /* Create a box with reversed triangles */ + FOR_EACH(i, 0, sizeof(rev_box_indices) / sizeof(*rev_box_indices)) { + switch (i % 3) { + case 0: rev_box_indices[i] = box_indices[i]; break; + case 1: rev_box_indices[i] = box_indices[i + 1]; break; + case 2: rev_box_indices[i] = box_indices[i - 1]; break; + } + } + OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator)); + OK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)); + + OK(senc_scene_create(dev, convention, &scn)); + + /* A 3D cube. + * 2 enclosures (inside, outside) sharing the same triangles, + * but opposite sides */ + ctx.positions = box_vertices; + ctx.indices = box_indices; + ctx.scale = 1; + ctx.reverse_vrtx = 0; + ctx.reverse_med = 0; + d3(ctx.offset, 0, 0, 0); + ctx.front_media = media; + ctx.back_media = medium1; + ctx.custom = &merge_ctx; + + /* Can add the same triangles again defined/undefined media in any order */ + + /* Add geometry with no media information on both sides */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = SENC_UNDEFINED_MEDIUM; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 2 * ntriangles); + + /* If merge fails, add geometry fails */ + interface_ids[0] = 6; + BA(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL, + nvertices, get_position, add_trg, merge_trg, &ctx)); + interface_ids[0] = 0; + + /* Add geometry with no media information on the front sides */ + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == ntriangles); + + /* Analyze with undefined media on the front sides */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_get_enclosure_count(desc, &ecount)); + CHK(ecount == 2); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* ee; + struct senc_enclosure_header hh; + unsigned cc; + OK(senc_descriptor_get_enclosure(desc, i, &enclosure)); + OK(senc_enclosure_get_header(enclosure, &header)); + + CHK(header.enclosure_id == i); + CHK(header.enclosed_media_count == 1); + + OK(senc_enclosure_get_medium(enclosure, 0, &medium)); + /* Geometrical normals point outside the cube in input triangles: + * if convention is front, front medium (undef) is outside, + * that is medium 0's enclosure is infinite */ + expected_external_medium = conv_front ? SENC_UNDEFINED_MEDIUM : 1; + expected_internal_medium = conv_front ? 1 :SENC_UNDEFINED_MEDIUM; + + CHK(medium == (header.is_infinite + ? expected_external_medium : expected_internal_medium)); + CHK(header.triangle_count == ntriangles); + CHK(header.unique_triangle_count == ntriangles); + CHK(header.vertices_count == nvertices); + CHK(header.is_infinite == (i == 0)); + + OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc)); + CHK(cc == 1); + OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee)); + OK(senc_enclosure_get_header(ee, &hh)); + CHK(header.enclosure_id == hh.enclosure_id); + OK(senc_enclosure_ref_put(ee)); + + FOR_EACH(t, 0, header.triangle_count) { + unsigned ind[3]; + OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side)); + CHK(gid == t); + CHK(side == (medium == 1) ? SENC_BACK : SENC_FRONT); + OK(senc_enclosure_get_triangle(enclosure, t, ind)); + } + OK(senc_enclosure_ref_put(enclosure)); + } + OK(senc_descriptor_ref_put(desc)); + + /* Same geometry, front media are defined for odd triangles */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = (i % 2) ? 0 : SENC_UNDEFINED_MEDIUM; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == ntriangles / 2); + + /* Analyze with undefined media */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_ref_put(desc)); + + /* Get the deduplicated geometry without (successful) analyze */ + OK(senc_scene_get_unique_vertices_count(scn, &vcount)); + CHK(vcount == nvertices); + OK(senc_scene_get_unique_triangles_count(scn, &tcount)); + CHK(tcount == ntriangles); + FOR_EACH(i, 0, tcount) { + int j; + unsigned med[2], ids[3]; + OK(senc_scene_get_unique_triangle(scn, i, ids)); + OK(senc_scene_get_unique_triangle_media(scn, i, med)); + CHK(med[0] == ((i % 2) ? 0 : SENC_UNDEFINED_MEDIUM) && med[1] == 1); + FOR_EACH(j, 0, 3) { + double pos[3]; + CHK(ids[j] < vcount); + OK(senc_scene_get_unique_vertex(scn, ids[j], pos)); + } + } + + /* Same information again, using a reversed box */ + ctx.indices = rev_box_indices; + SWAP(const unsigned*, ctx.front_media, ctx.back_media); + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == ntriangles / 2); + + /* Analyze with undefined media */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_ref_put(desc)); + + /* Define media for remaining triangles, using reversed box */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = (i % 2) ? SENC_UNDEFINED_MEDIUM : 0; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 0); + + /* Get the deduplicated geometry without (successful) analyze */ + OK(senc_scene_get_unique_vertices_count(scn, &vcount)); + CHK(vcount == nvertices); + OK(senc_scene_get_unique_triangles_count(scn, &tcount)); + CHK(tcount == ntriangles); + FOR_EACH(i, 0, tcount) { + int j; + unsigned med[2], ids[3]; + OK(senc_scene_get_unique_triangle(scn, i, ids)); + OK(senc_scene_get_unique_triangle_media(scn, i, med)); + CHK(med[0] == 0 && med[1] == 1); + FOR_EACH(j, 0, 3) { + double pos[3]; + CHK(ids[j] < vcount); + OK(senc_scene_get_unique_vertex(scn, ids[j], pos)); + } + } + + /* Analyze with all media defined */ + OK(senc_scene_analyze(scn, &desc)); + OK(senc_descriptor_ref_put(desc)); + + /* Define media for all triangles, nothing new here */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = 0; + OK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 0); + + /* Define incoherent media for some triangles */ + for (i = 0; i < sizeof(media) / sizeof(*media); i++) + media[i] = (i % 2); + BA(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, + nvertices, get_position, add_trg, merge_trg, &ctx)); + OK(senc_scene_get_unique_sides_without_medium_count(scn, &scount)); + CHK(scount == 0); + + /* Scene is still OK and can be analyzed */ + OK(senc_scene_analyze(scn, &desc)); + + OK(senc_descriptor_get_global_triangles_count(desc, &tcount)); + CHK(tcount == sizeof(media) / sizeof(*media)); + + OK(senc_descriptor_get_enclosure_count(desc, &ecount)); + CHK(ecount == 2); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* ee; + struct senc_enclosure_header hh; + unsigned cc; + OK(senc_descriptor_get_enclosure(desc, i, &enclosure)); + OK(senc_enclosure_get_header(enclosure, &header)); + + CHK(header.enclosure_id == i); + CHK(header.enclosed_media_count == 1); + OK(senc_enclosure_get_medium(enclosure, 0, &medium)); + /* Geometrical normals point outside the cube in input triangles: + * if convention is front, front medium (0) is outside, + * that is medium 0's enclosure is infinite */ + CHK(conv_front == ((medium == 0) == header.is_infinite)); + CHK(header.triangle_count == ntriangles); + CHK(header.unique_triangle_count == ntriangles); + CHK(header.vertices_count == nvertices); + CHK(header.is_infinite == (i == 0)); + + OK(senc_descriptor_get_enclosure_count_by_medium(desc, medium, &cc)); + CHK(cc == 1); + OK(senc_descriptor_get_enclosure_by_medium(desc, medium, 0, &ee)); + OK(senc_enclosure_get_header(ee, &hh)); + CHK(header.enclosure_id == hh.enclosure_id); + OK(senc_enclosure_ref_put(ee)); + + FOR_EACH(t, 0, header.triangle_count) { + OK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid, &side)); + CHK(gid == t); + CHK(side == (medium == 1) ? SENC_BACK : SENC_FRONT); + } + OK(senc_enclosure_ref_put(enclosure)); + } + + SENC(scene_ref_put(scn)); + SENC(device_ref_put(dev)); + SENC(descriptor_ref_put(desc)); + darray_intface_id_release(&merge_ctx.global_interf_data); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHK(mem_allocated_size() == 0); +} + +int +main(int argc, char** argv) +{ + (void) argc, (void) argv; + test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE); + test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE); + test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE); + test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE); + return 0; +} diff --git a/src/test_senc_utils.h b/src/test_senc_utils.h @@ -22,6 +22,9 @@ #include <stdio.h> +#define OK(Expr) CHK((Expr) == RES_OK) +#define BA(Expr) CHK((Expr) == RES_BAD_ARG) + /******************************************************************************* * Geometry ******************************************************************************/ @@ -78,7 +81,7 @@ struct context { const unsigned* indices; const unsigned* front_media; const unsigned* back_media; - const unsigned* global_ids; + void* custom; double offset[3]; double scale; char reverse_vrtx, reverse_med; @@ -91,12 +94,10 @@ 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 gid_face[12] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 }; - static INLINE void get_indices(const unsigned itri, unsigned ids[3], void* context) { - struct context* ctx = 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]; @@ -106,7 +107,7 @@ get_indices(const unsigned itri, unsigned ids[3], void* context) static INLINE void get_position(const unsigned ivert, double pos[3], void* context) { - struct context* ctx = 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]; @@ -116,20 +117,12 @@ get_position(const unsigned ivert, double pos[3], void* context) static INLINE void get_media(const unsigned itri, unsigned medium[2], void* context) { - struct context* ctx = context; + const struct context* ctx = context; ASSERT(medium && ctx); medium[ctx->reverse_med ? 1 : 0] = ctx->front_media[itri]; medium[ctx->reverse_med ? 0 : 1] = ctx->back_media[itri]; } -static INLINE void -get_global_id(const unsigned itri, unsigned* gid, void* context) -{ - struct context* ctx = context; - ASSERT(gid && context); - *gid = ctx->global_ids[itri]; -} - /******************************************************************************* * Miscellaneous ******************************************************************************/ @@ -201,7 +194,7 @@ static INLINE void check_memory_allocator(struct mem_allocator* allocator) { if(MEM_ALLOCATED_SIZE(allocator)) { - char dump[128]; + char dump[1024]; MEM_DUMP(allocator, dump, sizeof(dump)); fprintf(stderr, "%s\n", dump); FATAL("Memory leaks.\n");