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 6eff3fc4983d92db883095405347910a3b1e366a
parent 9af25aa613f4f20c9596409cd40ae808cce0ebb0
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue, 11 Sep 2018 17:10:53 +0200

Merge remote-tracking branch 'origin/feature_multi_mat_enclosures_2' into develop

Diffstat:
Mcmake/CMakeLists.txt | 4++--
Msrc/senc.h | 14++++++++++----
Msrc/senc_descriptor.c | 9++++-----
Msrc/senc_descriptor_c.h | 2+-
Msrc/senc_enclosure.c | 21+++++++++++++++++++--
Msrc/senc_enclosure_c.h | 2+-
Msrc/senc_enclosure_data.h | 85++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/senc_internal_types.h | 9+++++++--
Msrc/senc_scene_analyze.c | 541+++++++++++++++++++++++++++++++++----------------------------------------------
Msrc/senc_scene_analyze_c.h | 34+++++++++++++---------------------
Msrc/test_senc_cube_behind_cube.c | 60+++++++++++++++++++++++++++++++++---------------------------
Msrc/test_senc_cube_in_cube.c | 31++++++++++++++++++++++++++++---
Msrc/test_senc_descriptor.c | 10+++++-----
Msrc/test_senc_enclosure.c | 13+++++++++++--
Msrc/test_senc_many_enclosures.c | 7+++++--
Msrc/test_senc_scene.c | 21+++++++++++++++++----
Msrc/test_senc_utils.h | 37+++++++++++++++++++++++++++++++++++++
17 files changed, 503 insertions(+), 397 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -47,8 +47,8 @@ endif() # Configure and define targets ################################################################################ set(VERSION_MAJOR 0) -set(VERSION_MINOR 1) -set(VERSION_PATCH 1) +set(VERSION_MINOR 2) +set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) set(SENC_FILES_SRC diff --git a/src/senc.h b/src/senc.h @@ -66,8 +66,8 @@ struct senc_enclosure_header { unsigned unique_triangle_count; /* Number of vertices */ unsigned vertices_count; - /* The medium inside the enclosure */ - unsigned enclosed_medium; + /* The number of media inside the enclosure */ + unsigned enclosed_media_count; /* Is the enclosure open/infinite? * Only the outermost enclosure is infinite. */ char is_infinite; @@ -163,7 +163,7 @@ senc_scene_ref_put SENC_API res_T senc_descriptor_get_max_medium (const struct senc_descriptor* descriptor, - unsigned* rank); + unsigned* max_medium_id); SENC_API res_T senc_descriptor_get_enclosure_count @@ -173,7 +173,7 @@ senc_descriptor_get_enclosure_count SENC_API res_T senc_descriptor_get_enclosure_count_by_medium (const struct senc_descriptor* descriptor, - const unsigned imed, + const unsigned imed, /* Must be in [0 max_medium_id] */ unsigned* count); SENC_API res_T @@ -278,6 +278,12 @@ senc_enclosure_get_triangle_global_id unsigned* gid); SENC_API res_T +senc_enclosure_get_medium + (const struct senc_enclosure* enclosure, + const unsigned imed, + unsigned* medium); + +SENC_API res_T senc_enclosure_ref_get (struct senc_enclosure* enclosure); diff --git a/src/senc_descriptor.c b/src/senc_descriptor.c @@ -86,11 +86,11 @@ struct mem_allocator* ******************************************************************************/ res_T senc_descriptor_get_max_medium - (const struct senc_descriptor* desc, unsigned* rank) + (const struct senc_descriptor* desc, unsigned* max_medium_id) { - if(!desc || !rank) return RES_BAD_ARG; + if(!desc || !max_medium_id) return RES_BAD_ARG; ASSERT(desc->scene->nmeds < UINT_MAX); /* API type */ - *rank = (unsigned)desc->scene->nmeds; + *max_medium_id = (unsigned)desc->scene->nmeds - 1; return RES_OK; } @@ -135,8 +135,7 @@ senc_descriptor_get_enclosure struct senc_enclosure* enc; if(!desc || idx >= darray_enclosure_size_get(&desc->enclosures) || !out_enc) return RES_BAD_ARG; - enc = - enclosure_create(desc, darray_enclosure_data_get(&desc->enclosures) + idx); + enc = enclosure_create(desc, idx); if(!enc) return RES_MEM_ERR; *out_enc = enc; return RES_OK; diff --git a/src/senc_descriptor_c.h b/src/senc_descriptor_c.h @@ -45,7 +45,7 @@ triangle_comp_init(struct mem_allocator* alloc, struct triangle_comp* trg) { #include <rsys/dynamic_array.h> struct triangle_enc { - /* The connex component in which each side is. */ + /* The enclosure in which each side is. */ enclosure_id_t enclosure[2]; }; diff --git a/src/senc_enclosure.c b/src/senc_enclosure.c @@ -45,13 +45,15 @@ enclosure_release(ref_T * ref) struct senc_enclosure* enclosure_create (struct senc_descriptor* desc, - const struct enclosure_data* data) + const unsigned idx) { struct senc_enclosure* enc; - ASSERT(desc); + ASSERT(desc && idx < darray_enclosure_size_get(&desc->enclosures)); enc = MEM_CALLOC(descriptor_get_allocator(desc), 1, sizeof(struct senc_enclosure)); if(enc) { + const struct enclosure_data* data + = darray_enclosure_data_get(&desc->enclosures) + idx; SENC(descriptor_ref_get(desc)); enc->desc = desc; enc->data = data; @@ -156,6 +158,21 @@ senc_enclosure_get_triangle_global_id } res_T +senc_enclosure_get_medium + (const struct senc_enclosure* enclosure, + const unsigned imed, + unsigned* medium) +{ + if(!enclosure || !medium + || imed >= enclosure->data->header.enclosed_media_count) + return RES_BAD_ARG; + ASSERT(enclosure->data->header.enclosed_media_count + == darray_media_size_get(&enclosure->data->enclosed_media)); + *medium = darray_media_cdata_get(&enclosure->data->enclosed_media)[imed]; + return RES_OK; +} + +res_T senc_enclosure_ref_get(struct senc_enclosure* enc) { if(!enc) return RES_BAD_ARG; diff --git a/src/senc_enclosure_c.h b/src/senc_enclosure_c.h @@ -32,6 +32,6 @@ struct senc_enclosure { struct senc_enclosure* enclosure_create (struct senc_descriptor* desc, - const struct enclosure_data* data); + const unsigned idx); #endif /* SENC_ENCLOSURE_C_H */ diff --git a/src/senc_enclosure_data.h b/src/senc_enclosure_data.h @@ -18,6 +18,19 @@ #include <rsys/rsys.h> #include <rsys/ref_count.h> +#include <rsys/hash_table.h> +#include <rsys/dynamic_array.h> + +/* unsigned char array with init to zero */ +static FINLINE void +zero_init_uchar + (struct mem_allocator* alloc, unsigned char* data) +{ + ASSERT(data); (void) alloc; + *data = 0; +} +#define DARRAY_FUNCTOR_INIT zero_init_uchar +#include <rsys/dynamic_array_uchar.h> #include "senc.h" #include "senc_scene_c.h" @@ -33,16 +46,77 @@ init_header(struct senc_enclosure_header* header) header->triangle_count = 0; header->unique_triangle_count = 0; header->vertices_count = 0; - header->enclosed_medium = MEDIUM_NULL__; + header->enclosed_media_count = 0; header->is_infinite = CHAR_MAX; } +#define DARRAY_NAME media +#define DARRAY_DATA medium_id_t +#include <rsys/dynamic_array.h> + +static FINLINE res_T +bool_array_of_media_merge + (struct darray_uchar* dst, + const unsigned char* src, + const medium_id_t sz) +{ + res_T res = RES_OK; + medium_id_t i; + unsigned char* data_dst; + + ASSERT(src && dst); + + OK(darray_uchar_resize(dst, sz)); + data_dst = darray_uchar_data_get(dst); + ASSERT(sz <= MEDIUM_MAX__); + if(res != RES_OK) goto error; + FOR_EACH(i, 0, sz) { + if(!src[i]) continue; + data_dst[i] = 1; + } +end: + return res; +error: + goto end; +} + +static FINLINE res_T +bool_array_of_media_to_darray_media + (struct darray_media* dst, + struct darray_uchar* src) +{ + 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__); + darray_media_clear(dst); + if(res != RES_OK) goto error; + FOR_EACH(i, 0, (medium_id_t) sz) { + if(!data[i]) continue; + res = darray_media_push_back(dst, &i); + if(res != RES_OK) goto error; + } +end: + return res; +error: + goto end; +} + struct enclosure_data { struct senc_enclosure_header header; /* Same triangle can appear twice if both sides */ struct darray_triangle_in sides; /* Index of vertices in scene's unique vertices */ struct darray_vrtx_id vertices; + /* List of the enclosed media */ + struct darray_uchar tmp_enclosed_media; + struct darray_media enclosed_media; /* Number of components involved in this enclosure */ component_id_t cc_count; /* Linked list of the components */ @@ -64,6 +138,8 @@ enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) { enc->side_count = 0; darray_triangle_in_init(alloc, &enc->sides); darray_vrtx_id_init(alloc, &enc->vertices); + darray_uchar_init(alloc, &enc->tmp_enclosed_media); + darray_media_init(alloc, &enc->enclosed_media); } static FINLINE res_T @@ -80,6 +156,8 @@ enclosure_data_copy dst->side_count = src->side_count; OK(darray_triangle_in_copy(&dst->sides, &src->sides)); OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices)); + OK(darray_uchar_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media)); + OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media)); error: return res; } @@ -89,6 +167,8 @@ enclosure_data_release(struct enclosure_data* n) { ASSERT(n); darray_triangle_in_release(&n->sides); darray_vrtx_id_release(&n->vertices); + darray_uchar_release(&n->tmp_enclosed_media); + darray_media_release(&n->enclosed_media); } static FINLINE res_T @@ -105,6 +185,9 @@ enclosure_data_copy_and_release dst->side_count = src->side_count; OK(darray_triangle_in_copy_and_release(&dst->sides, &src->sides)); OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices)); + OK(darray_uchar_copy_and_release(&dst->tmp_enclosed_media, + &src->tmp_enclosed_media)); + OK(darray_media_copy_and_release(&dst->enclosed_media, &src->enclosed_media)); error: return res; } diff --git a/src/senc_internal_types.h b/src/senc_internal_types.h @@ -81,8 +81,13 @@ typedef uint32_t enclosure_id_t; /* Component IDs use the same type than enclosure IDs */ typedef enclosure_id_t component_id_t; -#define COMPONENT_MAX__ ENCLOSURE_MAX__ -#define COMPONENT_NULL__ ENCLOSURE_NULL__ +#define COMPONENT_MAX__ (UINT32_MAX - 2) /* To allow special values */ +#define COMPONENT_NULL__ UINT32_MAX +/* Special values */ +#define CC_GROUP_ROOT_NONE UINT32_MAX +#define CC_GROUP_ROOT_INFINITE (UINT32_MAX - 1) +#define CC_GROUP_ID_NONE UINT32_MAX +#define CC_ID_NONE UINT32_MAX /* This one is used as flag */ enum side_flag { diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -26,6 +26,7 @@ #include <rsys/mem_allocator.h> #include <rsys/hash_table.h> #include <rsys/dynamic_array.h> +#include <rsys/dynamic_array_uchar.h> #include <star/s3d.h> @@ -34,46 +35,28 @@ #include <stdlib.h> #define CC_DESCRIPTOR_NULL__ {\ - CHAR_MAX, VRTX_NULL__, 0, MEDIUM_NULL__,\ + CHAR_MAX, VRTX_NULL__, 0,\ CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\ - { TRG_NULL__, 0}\ + { TRG_NULL__, 0},\ + NULL\ } +#ifdef COMPILER_GCC + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__; +#ifdef COMPILER_GCC + #pragma GCC diagnostic pop +#endif #define DARRAY_NAME component_id #define DARRAY_DATA component_id_t #include <rsys/dynamic_array.h> -#define DARRAY_NAME side_id -#define DARRAY_DATA side_id_t -#include <rsys/dynamic_array.h> - /******************************************************************************* * Helper function ******************************************************************************/ static INLINE int -find_side_in_list - (const struct trgside* trgsides, - const struct darray_side_id* side_ids, - const side_id_t side_id, - const enum list_id list_id) -{ - side_id_t i; - size_t tmp; - (void)list_id; - (void)trgsides; - ASSERT(trgsides && side_ids); - tmp = darray_side_id_size_get(side_ids); - ASSERT(tmp <= SIDE_MAX__); - FOR_EACH(i, 0, (side_id_t)tmp) { - const side_id_t id = darray_side_id_cdata_get(side_ids)[i]; - ASSERT(trgsides[id].list_id & list_id); - if(id == side_id) return 1; - } - return 0; -} - -static INLINE int neighbour_cmp(const void* w1, const void* w2) { const double a1 = ((struct neighbour_info*)w1)->angle; @@ -81,60 +64,26 @@ neighbour_cmp(const void* w1, const void* w2) return (a1 > a2) - (a1 < a2); } -static FINLINE res_T -add_side_to_stack - (const struct senc_scene* scn, - struct darray_side_id* stack, - struct trgside* trgsides, - const side_id_t side_id) -{ - (void)scn; - ASSERT(scn && trgsides && stack - && side_id < SIDE_MAX__ && side_id < 2 * scn->nutris); - ASSERT((darray_side_id_size_get(stack) > 128) - || !find_side_in_list(trgsides, stack, side_id, FLAG_WAITING_STACK)); - trgsides[side_id].list_id = FLAG_WAITING_STACK; - return darray_side_id_push_back(stack, &side_id); -} - static side_id_t get_side_not_in_connex_component - (const struct senc_scene* scn, + (const side_id_t last_side, const struct trgside* trgsides, + const unsigned char* processed, side_id_t* first_side_not_in_component, const medium_id_t medium) { - side_id_t i; - const trg_id_t last_side - = darray_side_range_cdata_get(&scn->media_use)[medium].last; - ASSERT(scn && trgsides && first_side_not_in_component); - i = *first_side_not_in_component; - while(i <= last_side - && (trgsides[i].medium != medium - || trgsides[i].list_id != FLAG_LIST_SIDE_LIST)) { - ++i; + ASSERT(trgsides && processed && first_side_not_in_component); + { + side_id_t i = *first_side_not_in_component; + while (i <= last_side + && (trgsides[i].medium != medium + || (processed[TRGSIDE_2_TRG(i)] & TRGSIDE_2_SIDEFLAG(i)))) + ++i; + + *first_side_not_in_component = i + 1; + if(i > last_side) return SIDE_NULL__; + return i; } - - *first_side_not_in_component = i+1; - if(i > last_side) return SIDE_NULL__; - return i; -} - -static FINLINE side_id_t -get_side_from_stack - (const struct trgside* trgsides, - struct darray_side_id* stack) -{ - side_id_t id; - size_t sz; - (void)trgsides; - ASSERT(trgsides && stack); - sz = darray_side_id_size_get(stack); - ASSERT(sz); - id = darray_side_id_cdata_get(stack)[sz - 1]; - ASSERT(trgsides[id].list_id == FLAG_WAITING_STACK); - darray_side_id_pop_back(stack); - return id; } static void @@ -190,12 +139,12 @@ extract_connex_components struct trgside* trgsides, struct darray_ptr_component_descriptor* connex_components, const struct darray_triangle_tmp* triangles_tmp_array, - struct darray_triangle_comp* triangles_comp, + struct darray_triangle_comp* triangles_comp_array, struct s3d_scene_view** s3d_view, ATOMIC* component_count, /* Shared error status. * We accept to overwritte an error with a different error */ - res_T* res) + res_T* p_res) { /* This function is called from an omp parallel block and executed * concurrently. */ @@ -205,67 +154,87 @@ extract_connex_components struct darray_side_id stack; struct darray_side_id ids_of_sides_around_max_z_vertex; const union double3* positions; + const struct triangle_tmp* triangles_tmp; + struct triangle_comp* triangles_comp; + /* An array to flag sides when processed */ + unsigned char* processed; + /* An array to store the component being processed */ + struct darray_side_id current_component; + /* A bool array to store media of the component being processed */ + unsigned char* current_media = NULL; size_t sz, ii; -#ifndef NDEBUG - trg_id_t t; - component_id_t c; -#endif ASSERT(trgsides && desc && connex_components && triangles_tmp_array - && component_count && res); + && triangles_comp_array && s3d_view && component_count && p_res); alloc = descriptor_get_allocator(desc); scn = desc->scene; positions = darray_position_cdata_get(&scn->vertices); + triangles_tmp = darray_triangle_tmp_cdata_get(triangles_tmp_array); + triangles_comp = darray_triangle_comp_data_get(triangles_comp_array); darray_side_id_init(alloc, &stack); darray_side_id_init(alloc, &ids_of_sides_around_max_z_vertex); + darray_side_id_init(alloc, &current_component); + processed = MEM_CALLOC(alloc, scn->nutris, sizeof(unsigned char)); + if(!processed) { + *p_res = RES_MEM_ERR; + return; + } #ifndef NDEBUG #pragma omp single { + trg_id_t t_; ASSERT(darray_ptr_component_descriptor_size_get(connex_components) == 0); - FOR_EACH(t, 0, scn->nutris) { + FOR_EACH(t_, 0, scn->nutris) { const struct triangle_in* trg_in = - darray_triangle_in_cdata_get(&scn->triangles_in) + t; + darray_triangle_in_cdata_get(&scn->triangles_in) + t_; const struct side_range* media_use = darray_side_range_cdata_get(&scn->media_use); FOR_EACH(mm, 0, 2) { - const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t, mm); + const side_id_t side = TRGIDxSIDE_2_TRGSIDE(t_, mm); const medium_id_t medium = trg_in->medium[mm]; ASSERT(media_use[medium].first <= side && side <= media_use[medium].last); } } - } + } /* Implicit barrier here */ #endif + /* We loop on sides to build connex components. */ #pragma omp for schedule(dynamic) nowait for(mm = 0; mm < (int64_t)scn->nmeds; mm++) { /* Process all media */ const medium_id_t m = (medium_id_t)mm; - struct cc_descriptor* cc; /* Any not-already-used side is used as a starting point */ - side_id_t first_side_not_in_component; + const struct side_range* media_use = + darray_side_range_cdata_get(&scn->media_use) + m; + side_id_t first_side_not_in_component = media_use->first; double max_z_nz; + const side_id_t last_side = media_use->last; + int component_canceled = 0; + res_T tmp_res = RES_OK; + ATOMIC id; - if(*res != RES_OK) continue; - first_side_not_in_component - = darray_side_range_cdata_get(&scn->media_use)[m].first; + if(*p_res != RES_OK) continue; if(first_side_not_in_component == SIDE_NULL__) continue; /* Unused medium */ ASSERT(first_side_not_in_component < 2 * scn->nutris); ASSERT(darray_side_id_size_get(&stack) == 0); + ASSERT(darray_side_id_size_get(&current_component) == 0); for(;;) { /* Process all components for this medium */ - const side_id_t start_side_id = get_side_not_in_connex_component(scn, - trgsides, &first_side_not_in_component, m); + const side_id_t start_side_id = get_side_not_in_connex_component + (last_side, trgsides, processed, &first_side_not_in_component, m); side_id_t crt_side_id = start_side_id; side_id_t last_side_id = start_side_id; + vrtx_id_t max_z_vrtx_id = VRTX_NULL__; + struct cc_descriptor *cc; double max_z = -DBL_MAX; ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nutris); + darray_side_id_clear(&current_component); - if(*res != RES_OK) break; + if(*p_res != RES_OK) break; if(start_side_id == SIDE_NULL__) - break; /* start_side_id=SIDE_NULL__ => done! */ - ASSERT(trgsides[start_side_id].list_id == FLAG_LIST_SIDE_LIST); + break; /* start_side_id=SIDE_NULL__ => component done! */ #ifndef NDEBUG { @@ -277,36 +246,32 @@ extract_connex_components } #endif - /* Create and init a new component */ - cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor)); - if(!cc) { - *res = RES_MEM_ERR; - continue; + /* Reuse array if possible, or create a new one */ + if(current_media) { + memset(current_media, 0, scn->nmeds); + } else { + current_media = MEM_CALLOC(alloc, scn->nmeds, sizeof(unsigned char)); + if(!current_media) { + *p_res = RES_MEM_ERR; + continue; + } } - cc_descriptor_init(alloc, cc); - ASSERT(m == trgsides[start_side_id].medium); - cc->cc_id = (component_id_t)(ATOMIC_INCR(component_count) - 1); - cc->medium = m; - cc->side_range.first = start_side_id; - + current_media[m] = 1; for(;;) { /* Process all sides of this component */ int i; - enum side_id s = TRGSIDE_2_SIDE(crt_side_id); + enum side_flag crt_side_flag = TRGSIDE_2_SIDEFLAG(crt_side_id); struct trgside* crt_side = trgsides + crt_side_id; const trg_id_t crt_trg_id = TRGSIDE_2_TRG(crt_side_id); const struct triangle_in* trg_in = darray_triangle_in_cdata_get(&scn->triangles_in) + crt_trg_id; - struct triangle_comp* trg_comp = - darray_triangle_comp_data_get(triangles_comp) + crt_trg_id; - const struct triangle_tmp* const trg_tmp = - darray_triangle_tmp_cdata_get(triangles_tmp_array) + crt_trg_id; + unsigned char* trg_used = processed + crt_trg_id; + const struct triangle_tmp* const trg_tmp = triangles_tmp + crt_trg_id; ASSERT(crt_trg_id < scn->nutris); - ASSERT(trgsides[crt_side_id].medium == m); - if(*res != RES_OK) break; + if(*p_res != RES_OK) break; /* Record Zmax information - * Keep track of the appropriate vertex of the connex component in order + * Keep track of the appropriate vertex of the component in order * to cast a ray at the component grouping step of the algorithm. * The most appropriate vertex is (the) one with the greater Z * coordinate. */ @@ -316,99 +281,96 @@ extract_connex_components /* New vertex: reset list of sides */ darray_side_id_clear(&ids_of_sides_around_max_z_vertex); - /* Select one vertex with z == max_z */ + /* Select a vertex with z == max_z */ FOR_EACH(i, 0, 3) { if(max_z == positions[trg_in->vertice_id[i]].pos.z) { - cc->max_z_vrtx_id = trg_in->vertice_id[i]; + max_z_vrtx_id = trg_in->vertice_id[i]; break; } } ASSERT(i < 3); /* Found one */ /* List of sides using the vertex */ - *res = darray_side_id_push_back(&ids_of_sides_around_max_z_vertex, - &crt_side_id); + OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex, + &crt_side_id)); } else if(max_z == trg_tmp->max_z) { /* Does this triangle use the currently selected max_z vertex? */ FOR_EACH(i, 0, 3) { - if(cc->max_z_vrtx_id == trg_in->vertice_id[i]) { + if(max_z_vrtx_id == trg_in->vertice_id[i]) { /* List of sides using the vertex */ - *res = darray_side_id_push_back(&ids_of_sides_around_max_z_vertex, - &crt_side_id); + OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex, + &crt_side_id)); break; } } } - if(*res != RES_OK) break; /* Record crt_side both as component and triangle level */ - cc->side_count++; - trgsides[crt_side_id].list_id = FLAG_LIST_COMPONENT; - ASSERT(trg_comp->component[s] == COMPONENT_NULL__); - trg_comp->component[s] = cc->cc_id; -#ifndef NDEBUG - crt_side->member_of_cc = cc->cc_id; -#endif + 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; + } - /* Store neighbour sides in a waiting stack */ + /* Store neighbour' sides in a waiting stack */ FOR_EACH(i, 0, 3) { side_id_t neighbour_id = crt_side->facing_side_id[i]; trg_id_t nbour_trg_id = TRGSIDE_2_TRG(neighbour_id); + enum side_flag nbour_side_id = TRGSIDE_2_SIDEFLAG(neighbour_id); + unsigned char* nbour_used = processed + nbour_trg_id; const struct trgside* neighbour = trgsides + neighbour_id; - ASSERT(m == crt_side->medium); - if(neighbour->medium != crt_side->medium) { - /* Found medium discontinuity! Model topology is broken. */ - const struct triangle_in* triangles_in - = darray_triangle_in_cdata_get(&scn->triangles_in); - log_err(scn->dev, - "Medium mismatch found between neighbour triangles %lu %s" - " side and %u %s side.\n", - (unsigned long)triangles_in[crt_trg_id].global_id, - TRGSIDE_IS_FRONT(crt_side_id) ? "front" : "back", - triangles_in[nbour_trg_id].global_id, - TRGSIDE_IS_FRONT(neighbour_id) ? "front" : "back"); - log_err(scn->dev, - "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n", - (unsigned long)triangles_in[crt_trg_id].global_id, - SPLIT3(positions[triangles_in[crt_trg_id].vertice_id[0]].vec), - SPLIT3(positions[triangles_in[crt_trg_id].vertice_id[1]].vec), - SPLIT3(positions[triangles_in[crt_trg_id].vertice_id[2]].vec)); - log_err(scn->dev, - "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n", - (unsigned long)triangles_in[nbour_trg_id].global_id, - SPLIT3(positions[triangles_in[nbour_trg_id].vertice_id[0]].vec), - SPLIT3(positions[triangles_in[nbour_trg_id].vertice_id[1]].vec), - SPLIT3(positions[triangles_in[nbour_trg_id].vertice_id[2]].vec)); - log_err(desc->scene->dev, "Media: %lu VS %lu\n", - (unsigned long)neighbour->medium, (unsigned long)crt_side->medium); - *res = RES_BAD_ARG; - break; - } - if(neighbour->list_id == FLAG_LIST_COMPONENT) { - /* Already processed */ -#ifndef NDEBUG - ASSERT(neighbour->member_of_cc == cc->cc_id); -#endif - continue; + if(*nbour_used & nbour_side_id) continue; /* Already processed */ + if(neighbour->medium < m) { + /* Not the same medium. + * Neighbour's medium id is less than current medium: the whole + * component is to be processed by another thread (possibly the one + * associated with neighbour's medium). */ + component_canceled = 1; + goto canceled; } - if(neighbour->list_id == FLAG_WAITING_STACK) { - continue; /* Already processed */ - } - *res = add_side_to_stack(scn, &stack, trgsides, neighbour_id); - if(*res != RES_OK) break; + /* Mark neighbour as processed and stack it */ + *nbour_used |= (unsigned char)nbour_side_id; + OK2(darray_side_id_push_back(&stack, &neighbour_id)); + OK2(darray_side_id_push_back(&current_component, &neighbour_id)); + current_media[neighbour->medium] = 1; } - if(*res != RES_OK) break; - if(darray_side_id_size_get(&stack) == 0) - break; /* Empty stack => connex component is done! */ - crt_side_id = get_side_from_stack(trgsides, &stack); + sz = darray_side_id_size_get(&stack); + if(sz == 0) break; /* Empty stack => component is done! */ + crt_side_id = darray_side_id_cdata_get(&stack)[sz - 1]; + darray_side_id_pop_back(&stack); last_side_id = MMAX(last_side_id, crt_side_id); } - if(*res != RES_OK) { - MEM_RM(alloc, cc); - cc = NULL; - break; - } - /* Keep track of this new connex component */ + canceled: + if(component_canceled) continue; + + /* Register the new component and get it initialized */ + cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor)); + if(!cc) *p_res = RES_MEM_ERR; + if(*p_res != RES_OK) break; + + ASSERT(m == trgsides[start_side_id].medium); + ASSERT(max_z_vrtx_id != VRTX_NULL__); + cc_descriptor_init(alloc, cc); + id = ATOMIC_INCR(component_count) - 1; + ASSERT(id <= COMPONENT_MAX__); + cc->cc_id = (component_id_t)id; + sz = darray_side_id_size_get(&current_component); + ASSERT(sz <= SIDE_MAX__); + cc->side_count = (side_id_t)sz; + cc->side_range.first = start_side_id; cc->side_range.last = last_side_id; + cc->max_z_vrtx_id = max_z_vrtx_id; + /* Tranfer ownership of the array to component */ + ASSERT(!cc->media && current_media); + cc->media = current_media; + current_media = NULL; + + /* Write component membership in the global structure + * No need for sync here as an unique thread write a given side */ + STATIC_ASSERT(sizeof(cc->cc_id) >= 4, Cannot_write_IDs_sync_free); + ASSERT(IS_ALIGNED(triangles_comp->component, sizeof(cc->cc_id))); + FOR_EACH(ii, 0, sz) { + const side_id_t s = darray_side_id_cdata_get(&current_component)[ii]; + triangles_comp[TRGSIDE_2_TRG(s)].component[TRGSIDE_2_SIDE(s)] = cc->cc_id; + } /* Compute the normal at the max_z vertex. */ max_z_nz = 0; @@ -419,8 +381,7 @@ extract_connex_components const trg_id_t trg_id = TRGSIDE_2_TRG(side_id); const struct triangle_in* trg_in = darray_triangle_in_cdata_get(&scn->triangles_in) + trg_id; - const struct triangle_comp* trg_comp = - darray_triangle_comp_cdata_get(triangles_comp) + trg_id; + const struct triangle_comp* trg_comp = triangles_comp + trg_id; const union double3* vertices = darray_position_cdata_get(&scn->vertices); double edge0[3], edge1[3], normal[3], norm; @@ -430,7 +391,7 @@ extract_connex_components * contribute (remember than x + y - x - y can be non-zero). */ ASSERT(trg_comp->component[SIDE_FRONT] == cc->cc_id || trg_comp->component[SIDE_BACK] == cc->cc_id); - if (trg_comp->component[SIDE_FRONT] == trg_comp->component[SIDE_BACK]) + if(trg_comp->component[SIDE_FRONT] == trg_comp->component[SIDE_BACK]) continue; d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec, @@ -442,14 +403,12 @@ extract_connex_components ASSERT(norm); (void) norm; /* Geometrical normal points toward the front side */ - if (TRGSIDE_IS_FRONT(side_id)) { + if(TRGSIDE_IS_FRONT(side_id)) { max_z_nz += normal[2]; - } - else { + } else { max_z_nz -= normal[2]; } } - if(*res != RES_OK) break; cc->is_outer_border = (max_z_nz < 0); /* Need to synchronize connex_components growth as this global structure @@ -459,12 +418,11 @@ extract_connex_components struct cc_descriptor** components; sz = darray_ptr_component_descriptor_size_get(connex_components); if(sz <= cc->cc_id) { - res_T tmp_res = - darray_ptr_component_descriptor_resize(connex_components, + tmp_res = darray_ptr_component_descriptor_resize(connex_components, 1 + cc->cc_id); - if(tmp_res != RES_OK) *res = tmp_res; + if(tmp_res != RES_OK) *p_res = tmp_res; } - if(*res == RES_OK) { + if(*p_res == RES_OK) { /* Don't set the pointer before resize as this can lead to move data */ components = darray_ptr_component_descriptor_data_get(connex_components); @@ -473,15 +431,20 @@ extract_connex_components } } } + tmp_error: + if(tmp_res != RES_OK) *p_res = tmp_res; } /* No barrier here */ + MEM_RM(alloc, processed); + MEM_RM(alloc, current_media); + darray_side_id_release(&current_component); darray_side_id_release(&stack); darray_side_id_release(&ids_of_sides_around_max_z_vertex); /* The first thread here creates the s3d view */ #pragma omp single nowait - if(*res == RES_OK) { - res_T tmp_res = RES_OK; + if(*p_res == RES_OK) { + res_T res = RES_OK; struct s3d_device* s3d = NULL; struct s3d_scene* s3d_scn = NULL; struct s3d_shape* s3d_shp = NULL; @@ -492,21 +455,22 @@ extract_connex_components attribs.get = get_scn_position; /* Put geometry in a 3D view */ - OK2(s3d_device_create(desc->scene->dev->logger, alloc, 0, &s3d)); - OK2(s3d_scene_create(s3d, &s3d_scn)); - OK2(s3d_shape_create_mesh(s3d, &s3d_shp)); + OK(s3d_device_create(desc->scene->dev->logger, alloc, 0, &s3d)); + OK(s3d_scene_create(s3d, &s3d_scn)); + OK(s3d_shape_create_mesh(s3d, &s3d_shp)); /* Back to API type for ntris and nverts */ ASSERT(desc->scene->nutris < UINT_MAX); ASSERT(desc->scene->nuverts < UINT_MAX); - OK2(s3d_mesh_setup_indexed_vertices(s3d_shp, + OK(s3d_mesh_setup_indexed_vertices(s3d_shp, (unsigned)desc->scene->nutris, get_scn_indices, (unsigned)desc->scene->nuverts, &attribs, 1, desc->scene)); - s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter, triangles_comp); - OK2(s3d_scene_attach_shape(s3d_scn, s3d_shp)); - OK2(s3d_scene_view_create(s3d_scn, S3D_TRACE, s3d_view)); - tmp_error: - if(tmp_res != RES_OK) *res = tmp_res; + s3d_mesh_set_hit_filter_function(s3d_shp, self_hit_filter, + triangles_comp_array); + OK(s3d_scene_attach_shape(s3d_scn, s3d_shp)); + OK(s3d_scene_view_create(s3d_scn, S3D_TRACE, s3d_view)); + error: + if(res != RES_OK) *p_res = res; if(s3d) S3D(device_ref_put(s3d)); if(s3d_scn) S3D(scene_ref_put(s3d_scn)); if(s3d_shp) S3D(shape_ref_put(s3d_shp)); @@ -515,24 +479,26 @@ extract_connex_components #ifndef NDEBUG /* Need to wait for all threads done to be able to check stuff */ #pragma omp barrier - if(*res != RES_OK) return; + if(*p_res != RES_OK) return; #pragma omp single { + trg_id_t t_; + component_id_t c; ASSERT(ATOMIC_GET(component_count) == (int)darray_ptr_component_descriptor_size_get(connex_components)); - FOR_EACH(t, 0, scn->nutris) { + FOR_EACH(t_, 0, scn->nutris) { struct triangle_comp* trg_comp = - darray_triangle_comp_data_get(triangles_comp) + t; + 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__); } FOR_EACH(c, 0, ATOMIC_GET(component_count)) { struct cc_descriptor** components = darray_ptr_component_descriptor_data_get(connex_components); - ASSERT(components[c] != NULL && - components[c]->cc_id == c); + ASSERT(components[c] != NULL && components[c]->cc_id == c); } - } + ASSERT(desc->triangle_count == scn->nutris); + } /* Implicit barrier here */ #endif } @@ -544,7 +510,6 @@ group_connex_components struct darray_ptr_component_descriptor* connex_components, struct s3d_scene_view* s3d_view, ATOMIC* next_enclosure_id, - ATOMIC* infinity_first_cc, /* Shared error status. * We accept to overwritte an error with a different error */ res_T* res) @@ -559,7 +524,7 @@ group_connex_components (void)trgsides; ASSERT(desc && trgsides && triangles_comp && connex_components - && s3d_view && next_enclosure_id &&infinity_first_cc && res); + && s3d_view && next_enclosure_id && res); ASSERT(desc->enclosures_count == 1); descriptors = darray_ptr_component_descriptor_data_get(connex_components); @@ -579,18 +544,20 @@ group_connex_components const float range[2] = { 0, FLT_MAX }; struct cc_descriptor* const cc = descriptors[c]; component_id_t self_hit_component = cc->cc_id; - const double* max_vrtx = positions[cc->max_z_vrtx_id].vec; + const double* max_vrtx; if(*res != RES_OK) continue; ASSERT(cc->cc_id == c); ASSERT(cc->cc_group_root == CC_GROUP_ID_NONE); + ASSERT(cc->max_z_vrtx_id < desc->scene->nverts); + max_vrtx = positions[cc->max_z_vrtx_id].vec; if(cc->is_outer_border) { - int64_t id; + ATOMIC id; /* Don't need to cast a ray */ cc->cc_group_root = cc->cc_id; /* New group with self as root */ id = ATOMIC_INCR(next_enclosure_id) - 1; - ASSERT(id < ENCLOSURE_MAX__); + ASSERT(id <= ENCLOSURE_MAX__); cc->enclosure_id = (enclosure_id_t)id; continue; } @@ -605,85 +572,20 @@ group_connex_components } /* If no hit, the component is facing an infinite medium */ if(S3D_HIT_NONE(&hit)) { - struct cc_descriptor* inf_first_cc; cc->cc_group_root = CC_GROUP_ROOT_INFINITE; cc->enclosure_id = 0; - /* Keep track of the first component facing infinity */ - ATOMIC_CAS(infinity_first_cc, (ATOMIC)cc, (ATOMIC)NULL); - inf_first_cc = (struct cc_descriptor*)ATOMIC_GET(infinity_first_cc); - if(inf_first_cc->medium != cc->medium) { - /* Medium mismatch! Model topology is broken. */ - const double* infinity_max_vrtx = - positions[inf_first_cc->max_z_vrtx_id].vec; - log_err(desc->scene->dev, - "Medium mismatch found between vertex %lu and vertex %lu," - " both facing infinity.\n", - (unsigned long)inf_first_cc->max_z_vrtx_id, - (unsigned long)cc->max_z_vrtx_id); - log_err(desc->scene->dev, - "Vertex %lu: (%g %g %g)\n", - (unsigned long)inf_first_cc->max_z_vrtx_id, - SPLIT3(infinity_max_vrtx)); - log_err(desc->scene->dev, - "Vertex %lu: (%g %g %g)\n", - (unsigned long)cc->max_z_vrtx_id, - SPLIT3(max_vrtx)); - log_err(desc->scene->dev, "Media: %lu VS %lu\n", - (unsigned long)inf_first_cc->medium, (unsigned long)cc->medium); - *res = RES_BAD_ARG; - } - /* Same medium as previous members of the group: OK */ - continue; } else { /* If hit, group this component */ const trg_id_t hit_trg_id = (trg_id_t)hit.prim.prim_id; - const struct triangle_in* hit_trg_in = - darray_triangle_in_cdata_get(&desc->scene->triangles_in) + hit_trg_id; const struct triangle_comp* hit_trg_comp = darray_triangle_comp_cdata_get(triangles_comp) + hit_trg_id; enum side_id hit_side = (hit.normal[2] > 0) ? SIDE_FRONT : SIDE_BACK; - const side_id_t hit_side_id = TRGIDxSIDE_2_TRGSIDE(hit_trg_id, hit_side); ASSERT(hit_trg_id < desc->scene->nutris); /* Not really the root until following links */ cc->cc_group_root = hit_trg_comp->component[hit_side]; -#ifndef NDEBUG - { - const struct cc_descriptor* hit_desc; - ASSERT(cc->cc_group_root - < darray_ptr_component_descriptor_size_get(connex_components)); - hit_desc = *(darray_ptr_component_descriptor_cdata_get(connex_components) - + cc->cc_group_root); - ASSERT(hit_desc->medium == hit_trg_in->medium[hit_side]); - } -#endif - if(hit_trg_in->medium[hit_side] != cc->medium) { - /* Medium mismatch! Model topology is broken. */ - const trg_id_t tr = TRGSIDE_2_TRG(hit_side_id); - const struct triangle_in* triangles_in - = darray_triangle_in_cdata_get(&desc->scene->triangles_in); - log_err(desc->scene->dev, - "Medium mismatch found between vertex %lu and triangle" - " %lu %s side facing each other.\n", - (unsigned long)cc->max_z_vrtx_id, - (unsigned long)triangles_in[tr].global_id, - TRGSIDE_IS_FRONT(hit_side_id) ? "front" : "back"); - log_err(desc->scene->dev, - "Vertex %lu: (%g %g %g)\n", - (unsigned long)cc->max_z_vrtx_id, - SPLIT3(max_vrtx)); - log_err(desc->scene->dev, - "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n", - (unsigned long)triangles_in[tr].global_id, - SPLIT3(positions[triangles_in[tr].vertice_id[0]].vec), - SPLIT3(positions[triangles_in[tr].vertice_id[1]].vec), - SPLIT3(positions[triangles_in[tr].vertice_id[2]].vec)); - log_err(desc->scene->dev, "Media: %lu VS %lu\n", - (unsigned long)cc->medium, - (unsigned long)hit_trg_in->medium[hit_side]); - *res = RES_BAD_ARG; - } + ASSERT(cc->cc_group_root < cc_count); } } /* Implicit barrier here */ @@ -699,12 +601,13 @@ group_connex_components if(tmp_res != RES_OK) { *res = tmp_res; } else { + struct enclosure_data* enclosures + = darray_enclosure_data_get(&desc->enclosures); FOR_EACH(ccc, 0, cc_count) { component_id_t c = (component_id_t)ccc; struct cc_descriptor* const cc = descriptors[c]; const struct cc_descriptor* other_desc = cc; - struct enclosure_data* enclosures - = darray_enclosure_data_get(&desc->enclosures); + struct enclosure_data* enc; while(other_desc->enclosure_id == CC_GROUP_ID_NONE) { other_desc = *(darray_ptr_component_descriptor_cdata_get(connex_components) @@ -712,17 +615,21 @@ group_connex_components } ASSERT(other_desc->cc_group_root != CC_GROUP_ROOT_NONE); ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE); - ASSERT(cc->medium == other_desc->medium); cc->cc_group_root = other_desc->cc_group_root; cc->enclosure_id = other_desc->enclosure_id; - ++enclosures[cc->enclosure_id].cc_count; + enc = enclosures + cc->enclosure_id; + ++enc->cc_count; /* Linked list of componnents */ - enclosures[cc->enclosure_id].first_component = cc->cc_id; - enclosures[cc->enclosure_id].side_range.first - = MMIN(enclosures[cc->enclosure_id].side_range.first, cc->side_range.first); - enclosures[cc->enclosure_id].side_range.last - = MMAX(enclosures[cc->enclosure_id].side_range.last, cc->side_range.last); - enclosures[cc->enclosure_id].side_count += cc->side_count; + enc->first_component = cc->cc_id; + enc->side_range.first = MMIN(enc->side_range.first, cc->side_range.first); + enc->side_range.last = MMAX(enc->side_range.last, cc->side_range.last); + enc->side_count += cc->side_count; + tmp_res = bool_array_of_media_merge(&enc->tmp_enclosed_media, cc->media, + desc->scene->nmeds); + if(tmp_res != RES_OK) { + *res = tmp_res; + break; + } } } } @@ -914,8 +821,6 @@ collect_and_link_neighbours 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); - p_crt_side->list_id = FLAG_LIST_SIDE_LIST; - p_ccw_side->list_id = FLAG_LIST_SIDE_LIST; } } tmp_error: @@ -950,7 +855,7 @@ build_result alloc = descriptor_get_allocator(desc); ASSERT(darray_ptr_component_descriptor_size_get(connex_components) - < COMPONENT_MAX__); + <= COMPONENT_MAX__); cc_descriptors = darray_ptr_component_descriptor_cdata_get(connex_components); enclosures = darray_enclosure_data_get(&desc->enclosures); triangles_in = darray_triangle_in_cdata_get(&desc->scene->triangles_in); @@ -991,33 +896,45 @@ build_result for(ee = 0; ee < (int64_t)desc->enclosures_count; ee++) { const enclosure_id_t e = (enclosure_id_t)ee; struct enclosure_data* enc = enclosures + e; - const struct cc_descriptor* current = cc_descriptors[enc->first_component]; - struct darray_enc_id* enc_ids_by_medium; trg_id_t fst_idx = 0; trg_id_t sgd_idx = enc->side_count; trg_id_t t; + medium_id_t m; res_T tmp_res = RES_OK; ASSERT(enc->first_component < darray_ptr_component_descriptor_size_get(connex_components)); - ASSERT(current->cc_id == enc->first_component); + ASSERT(cc_descriptors[enc->first_component]->cc_id + == enc->first_component); if(*res != RES_OK) continue; ASSERT(e <= UINT_MAX); enc->header.enclosure_id = (unsigned)e; /* Back to API type */ - ASSERT(current->enclosure_id == enc->header.enclosure_id); + ASSERT(cc_descriptors[enc->first_component]->enclosure_id + == enc->header.enclosure_id); enc->header.is_infinite = (e == 0); - enc->header.enclosed_medium - = (unsigned)current->medium; /* Back to API type */ - ASSERT(enc->header.enclosed_medium < desc->scene->nmeds); - - enc_ids_by_medium = - darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) - + current->medium; - #pragma omp critical - { - tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e); + + ASSERT(darray_uchar_size_get(&enc->tmp_enclosed_media) <= UINT_MAX); + ASSERT(enc->header.enclosed_media_count <= desc->scene->nmeds); + OK2(bool_array_of_media_to_darray_media + (&enc->enclosed_media, &enc->tmp_enclosed_media)); + enc->header.enclosed_media_count + = (unsigned)darray_media_size_get(&enc->enclosed_media); + darray_uchar_purge(&enc->tmp_enclosed_media); + + /* Add this enclosure in relevant by-medium lists */ + FOR_EACH(m, 0, enc->header.enclosed_media_count) { + medium_id_t medium = darray_media_data_get(&enc->enclosed_media)[m]; + struct darray_enc_id* enc_ids_by_medium = + darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + medium; + #pragma omp critical + { + tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e); + } + if(tmp_res != RES_OK) { + *res = tmp_res; + break; + } } - if(tmp_res != RES_OK) *res = tmp_res; if(*res != RES_OK) continue; /* Build side and vertex lists. */ @@ -1112,10 +1029,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; - /* Used as args to have shared vars between threads in functions */ - static_assert(sizeof(intptr_t) == sizeof(ATOMIC), - "Cannot use ATOMIC to store pointers"); - ATOMIC infinity_first_cc = (ATOMIC)NULL; res_T res = RES_OK; res_T res2 = RES_OK; @@ -1211,8 +1124,7 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) /* Step 3: group components */ group_connex_components(desc, trgsides, &triangles_comp, - &connex_components, s3d_view, &next_enclosure_id, &infinity_first_cc, - &res); + &connex_components, s3d_view, &next_enclosure_id, &res); /* Barrier at the end of step 3: data used in step 3 can be released / * data produced by step 3 can be used */ @@ -1255,7 +1167,6 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) { #pragma omp section { - ASSERT(connex_components_initialized); custom_darray_ptr_component_descriptor_release(&connex_components); connex_components_initialized = 0; } diff --git a/src/senc_scene_analyze_c.h b/src/senc_scene_analyze_c.h @@ -20,18 +20,9 @@ #include "senc_internal_types.h" #include <rsys/mem_allocator.h> -#include <rsys/dynamic_array_uchar.h> #include <rsys/hash_table.h> #include <rsys/double3.h> -enum list_id { - FLAG_NO_LIST = 0, - FLAG_LIST_SIDE_LIST = BIT(1), - FLAG_LIST_COMPONENT = BIT(2), - FLAG_WAITING_STACK = BIT(3), - FLAG_ANY_LIST = 0xFF -}; - /* Triangle edge struct and basic functions */ struct trg_edge { vrtx_id_t vrtx0, vrtx1; @@ -87,32 +78,29 @@ struct trgside { * - side * This is due to the memory layout of the elt darray: * front(trg_0), back(trg_0), front(trg_1), back(trg_1), ... */ - -#ifndef NDEBUG - component_id_t member_of_cc; -#endif }; +#define DARRAY_NAME side_id +#define DARRAY_DATA side_id_t +#include <rsys/dynamic_array.h> + /* Descriptors for connex component. * Define lists of trg sides starting from a given head. * Also keeps the maximum z info of the component - * along with the associated triangle and vertex ids */ -#define CC_ID_NONE COMPONENT_MAX__ -#define CC_GROUP_ROOT_NONE COMPONENT_MAX__ -#define CC_GROUP_ROOT_INFINITE (COMPONENT_MAX__-1) -#define CC_GROUP_ID_NONE COMPONENT_MAX__ + * and the list of media found */ struct cc_descriptor { /* Does this component is an outer border of an enclosure or an inner one? */ char is_outer_border; - vrtx_id_t max_z_vrtx_id; + vrtx_id_t max_z_vrtx_id; /* id of the vrtx with max z value */ side_id_t side_count; - medium_id_t medium; /* Used when grouping components to form enclosures */ component_id_t cc_id; component_id_t cc_group_root; enclosure_id_t enclosure_id; /* Range of sides member of this component */ struct side_range side_range; + /* Media used by this component */ + unsigned char* media; }; extern const struct cc_descriptor CC_DESCRIPTOR_NULL; @@ -152,7 +140,11 @@ custom_darray_ptr_component_descriptor_release if(!array) return; cc_count = darray_ptr_component_descriptor_size_get(array); components = darray_ptr_component_descriptor_data_get(array); - FOR_EACH(c, 0, cc_count) MEM_RM(array->allocator, components[c]); + FOR_EACH(c, 0, cc_count) { + if(!components[c]) continue; + MEM_RM(array->allocator, components[c]->media); + MEM_RM(array->allocator, components[c]); + } darray_ptr_component_descriptor_release(array); } diff --git a/src/test_senc_cube_behind_cube.c b/src/test_senc_cube_behind_cube.c @@ -18,30 +18,6 @@ #include <rsys/double3.h> -void check_desc(struct senc_descriptor* desc) { - unsigned mcount, ecount, i; - CHK(senc_descriptor_get_max_medium(desc, &mcount) == RES_OK); - CHK(mcount == 2); - CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK); - FOR_EACH(i, 0, mcount) { - unsigned j, ecount_bym; - unsigned found = 0; - senc_descriptor_get_enclosure_count_by_medium(desc, i, &ecount_bym); - FOR_EACH(j, 0, ecount_bym) { - struct senc_enclosure* enc; - struct senc_enclosure_header h; - CHK(senc_descriptor_get_enclosure_by_medium(desc, i, j, &enc) == RES_OK); - CHK(senc_enclosure_get_header(enc, &h) == RES_OK); - found += (h.enclosed_medium == i); - CHK(senc_enclosure_ref_put(enc) == RES_OK); - } - ASSERT(found == ecount_bym); /* All the enclosures enclose medim i */ - ASSERT(ecount_bym); - ecount -= ecount_bym; - } - ASSERT(ecount == 0); -} - int main(int argc, char** argv) { @@ -50,6 +26,7 @@ main(int argc, char** argv) struct senc_device* dev = NULL; struct senc_scene* scn = NULL; struct context ctx; + unsigned i, ecount, maxm; (void)argc, (void)argv; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); @@ -83,13 +60,26 @@ main(int argc, char** argv) CHK(senc_scene_analyze(scn, &desc) == RES_OK); + CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK); + CHK(ecount == 3); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* enclosure; + struct senc_enclosure_header header; + CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK); + CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); + ASSERT(header.enclosed_media_count == 1); + CHK(senc_enclosure_ref_put(enclosure) == RES_OK); + } + + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); + CHK(maxm == 1); check_desc(desc); /* Even further in +Z, even bigger */ d3(ctx.offset, -3, -3, 30); ctx.scale = 7; - /* Front/back media have been exchanged: external enclosure shows 2 media - * analyze will fail */ + /* Front/back media have been exchanged: external enclosure shows 2 media */ ctx.front_media = medium1; ctx.back_media = medium0; @@ -99,7 +89,23 @@ main(int argc, char** argv) if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); desc = NULL; - CHK(senc_scene_analyze(scn, &desc) == RES_BAD_ARG); + CHK(senc_scene_analyze(scn, &desc) == RES_OK); + + CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK); + CHK(ecount == 4); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* enclosure; + struct senc_enclosure_header header; + CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK); + CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); + ASSERT(header.enclosed_media_count == (header.is_infinite ? 2u : 1u)); + CHK(senc_enclosure_ref_put(enclosure) == RES_OK); + } + + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); + CHK(maxm == 1); + check_desc(desc); CHK(senc_scene_ref_put(scn) == RES_OK); CHK(senc_device_ref_put(dev) == RES_OK); diff --git a/src/test_senc_cube_in_cube.c b/src/test_senc_cube_in_cube.c @@ -26,6 +26,7 @@ main(int argc, char** argv) struct senc_device* dev = NULL; struct senc_scene* scn = NULL; struct context ctx; + unsigned i, ecount, maxm; (void)argc, (void)argv; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); @@ -62,14 +63,31 @@ main(int argc, char** argv) CHK(senc_scene_analyze(scn, &desc) == RES_OK); + CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK); + CHK(ecount == 3); + + FOR_EACH(i, 0, ecount) { + struct senc_enclosure* enclosure; + struct senc_enclosure_header header; + CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK); + CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); + ASSERT(header.enclosed_media_count == 1); + CHK(senc_enclosure_ref_put(enclosure) == RES_OK); + } + + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); + CHK(maxm == 1); + check_desc(desc); + d3(ctx.offset, -4, -4, -4); ctx.scale = 10; ctx.reverse_vrtx = 1; ctx.reverse_med = 1; /* Biggest cube exterior is medium 1 */ ctx.front_media = medium1; - /* Biggest cube interior is medium 0 */ - ctx.back_media = medium0; /* mismatch with cube 2 */ + /* Biggest cube interior is medium 0 + * interior/exterior media have been exchanged: external enclosure shows 2 media */ + ctx.back_media = medium0; /* Third cube */ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, @@ -77,7 +95,14 @@ main(int argc, char** argv) if(desc) CHK(senc_descriptor_ref_put(desc) == RES_OK); desc = NULL; - CHK(senc_scene_analyze(scn, &desc) == RES_BAD_ARG); + CHK(senc_scene_analyze(scn, &desc) == RES_OK); + + CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK); + CHK(ecount == 4); + + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); + CHK(maxm == 1); + check_desc(desc); CHK(senc_scene_ref_put(scn) == RES_OK); CHK(senc_device_ref_put(dev) == RES_OK); diff --git a/src/test_senc_descriptor.c b/src/test_senc_descriptor.c @@ -28,7 +28,7 @@ main(int argc, char** argv) struct senc_descriptor* desc = NULL; struct senc_enclosure* enc = NULL; struct context ctx; - unsigned count; + unsigned count, maxm; unsigned indices[3]; double coord[3]; unsigned media[2]; @@ -61,12 +61,12 @@ main(int argc, char** argv) CHK(senc_descriptor_ref_put(NULL) == RES_BAD_ARG); CHK(senc_descriptor_ref_put(desc) == RES_OK); - CHK(senc_descriptor_get_max_medium(NULL, &count) == RES_BAD_ARG); + CHK(senc_descriptor_get_max_medium(NULL, &maxm) == RES_BAD_ARG); CHK(senc_descriptor_get_max_medium(desc, NULL) == RES_BAD_ARG); - CHK(senc_descriptor_get_enclosure_count(NULL, NULL) == RES_BAD_ARG); - CHK(senc_descriptor_get_max_medium(desc, &count) == RES_OK); + CHK(senc_descriptor_get_max_medium(NULL, NULL) == RES_BAD_ARG); + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); - CHK(count == 2); + CHK(maxm == 1); CHK(senc_descriptor_get_enclosure_count(NULL, &count) == RES_BAD_ARG); CHK(senc_descriptor_get_enclosure_count(desc, NULL) == RES_BAD_ARG); diff --git a/src/test_senc_enclosure.c b/src/test_senc_enclosure.c @@ -133,6 +133,15 @@ main(int argc, char** argv) == RES_BAD_ARG); CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, &gid) == RES_OK); + CHK(senc_enclosure_get_medium(NULL, 0, medium) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(enclosure, 2, medium) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(enclosure, 0, NULL) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(NULL, 2, medium) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(NULL, 0, NULL) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(enclosure, 2, NULL) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(NULL, 2, NULL) == RES_BAD_ARG); + CHK(senc_enclosure_get_medium(enclosure, 0, medium) == RES_OK); + CHK(senc_enclosure_ref_put(enclosure) == RES_OK); FOR_EACH(i, 0, ecount) { @@ -144,7 +153,7 @@ main(int argc, char** argv) CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); CHK(header.enclosure_id == i); - CHK(header.enclosed_medium == (i == 0 ? 0U : 1U)); + CHK(header.enclosed_media_count == 1); CHK(header.triangle_count == ntriangles); CHK(header.unique_triangle_count == ntriangles); CHK(header.vertices_count == nvertices); @@ -205,7 +214,7 @@ main(int argc, char** argv) CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); CHK(header.enclosure_id == 0); - CHK(header.enclosed_medium == 0); + CHK(header.enclosed_media_count == 1); CHK(header.triangle_count == 2 * header.unique_triangle_count); CHK(header.unique_triangle_count == ntriangles - 1); CHK(header.vertices_count == nvertices); diff --git a/src/test_senc_many_enclosures.c b/src/test_senc_many_enclosures.c @@ -146,12 +146,15 @@ main(int argc, char** argv) FOR_EACH(e, 0, count) { struct senc_enclosure* enclosure; struct senc_enclosure_header header; + unsigned m; CHK(senc_descriptor_get_enclosure(desc, e, &enclosure) == RES_OK); CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK); + CHK(header.enclosed_media_count == 1); + CHK(senc_enclosure_get_medium(enclosure, 0, &m) == RES_OK); CHK(header.triangle_count == - (e == 0 /* Outermost enclosure: NB_CYL_1*NB_CYL_1 cylinders */ + (header.is_infinite /* Outermost enclosure: NB_CYL_1*NB_CYL_1 cylinders */ ? NB_CYL_1 * NB_CYL_1 * cyl_trg_count - : (header.enclosed_medium == 0 + : (m == 0 ? cyl_trg_count /* Innermost enclosures: 1 cylinder */ : 2 * cyl_trg_count))); /* Other enclosures: 2 cylinders */ CHK(senc_enclosure_ref_put(enclosure) == RES_OK); diff --git a/src/test_senc_scene.c b/src/test_senc_scene.c @@ -27,7 +27,7 @@ main(int argc, char** argv) struct senc_scene* scn = NULL; struct senc_descriptor* desc = NULL; struct context ctx; - unsigned count, i; + unsigned count, i, maxm; (void)argc, (void)argv; CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); @@ -129,11 +129,24 @@ main(int argc, char** argv) CHK(senc_scene_create(dev, &scn) == RES_OK); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, get_global_id, nvertices, get_position, &ctx) == RES_OK); - /* Medium mismatch between neighbour segments */ - CHK(senc_scene_analyze(scn, &desc) == RES_BAD_ARG); + /* Medium mismatch between neighbour segments, but OK */ + CHK(senc_scene_analyze(scn, &desc) == RES_OK); + + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); + CHK(maxm == 3); + CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 0, &count) == RES_OK); + CHK(count == 0); /* Medium 0 unused */ + CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 1, &count) == RES_OK); + CHK(count == 2); /* Medium 1 used twice */ + CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 2, &count) == RES_OK); + CHK(count == 0); /* Medium 2 unused */ + CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 3, &count) == RES_OK); + CHK(count == 1); /* Medium 3 used */ + check_desc(desc); + ctx.front_media = medium0; - CHK(senc_scene_ref_put(scn) == RES_OK); + CHK(senc_descriptor_ref_put(desc) == RES_OK); CHK(senc_scene_create(dev, &scn) == RES_OK); CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL, nvertices, get_position, &ctx) == RES_OK); diff --git a/src/test_senc_utils.h b/src/test_senc_utils.h @@ -207,5 +207,42 @@ check_memory_allocator(struct mem_allocator* allocator) } } +/******************************************************************************* + * Check functions + ******************************************************************************/ +static INLINE void check_desc(struct senc_descriptor* desc) +{ + unsigned maxm, ecount, i; + size_t e_cpt = 0; + CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK); + CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK); + for(i = 0; i <= maxm; i++) { + unsigned j, ecount_bym; + unsigned found = 0; + CHK(senc_descriptor_get_enclosure_count_by_medium(desc, i, &ecount_bym) == RES_OK); + /* Can be 0 if media numbering is not compact */ + FOR_EACH(j, 0, ecount_bym) { + struct senc_enclosure* enc; + struct senc_enclosure_header h; + unsigned k; + int f = 0; + CHK(senc_descriptor_get_enclosure_by_medium(desc, i, j, &enc) == RES_OK); + CHK(senc_enclosure_get_header(enc, &h) == RES_OK); + ASSERT(h.enclosed_media_count); + FOR_EACH(k, 0, h.enclosed_media_count) { + unsigned m; + CHK(senc_enclosure_get_medium(enc, k, &m) == RES_OK); + found += (m == i); + f += (m == i); + } + ASSERT(f == 1); /* Single reference expected */ + CHK(senc_enclosure_ref_put(enc) == RES_OK); + } + ASSERT(found == ecount_bym); /* All the enclosures enclose medim i */ + e_cpt += ecount_bym; + } + ASSERT(e_cpt >= ecount); /* Every enc has been visited at least once */ +} + #endif /* TEST_UTILS_H */