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 3f864fc7d4d70c571c9474f26bb559ede06b024a
parent 5afa312ad2caffe9cbae56084694848da46223a5
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Tue,  6 Mar 2018 16:10:17 +0100

Remove bit arrays storing side membership information.

Both for components and enclosures.

Diffstat:
Msrc/senc_enclosure_data.h | 18+++++++++++-------
Msrc/senc_scene_analyze.c | 427++++++++++++++++++++++++++++++++++++-------------------------------------------
Msrc/senc_scene_analyze_c.h | 25+++++++++++++++----------
3 files changed, 220 insertions(+), 250 deletions(-)

diff --git a/src/senc_enclosure_data.h b/src/senc_enclosure_data.h @@ -18,7 +18,6 @@ #include <rsys/rsys.h> #include <rsys/ref_count.h> -#include <rsys/dynamic_array_uchar.h> #include "senc.h" #include "senc_scene_c.h" @@ -44,12 +43,14 @@ struct enclosure_data { struct darray_triangle_in sides; /* Index of vertices in scene's unique vertices */ struct darray_vrtx_id vertices; - /* TODO: use only 1 bit per side (now 1 char per triangle) */ - struct darray_uchar side_membership; /* Number of components involved in this enclosure */ component_id_t cc_count; /* Linked list of the components */ component_id_t first_component; + /* Range of triangles member of the enclosure */ + struct side_range side_range; + /* Counts */ + side_id_t side_count; }; static FINLINE void @@ -58,9 +59,11 @@ enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) { init_header(&enc->header); enc->cc_count = 0; enc->first_component = COMPONENT_NULL__; + enc->side_range.first = SIDE_NULL__; + enc->side_range.last = 0; + enc->side_count = 0; darray_triangle_in_init(alloc, &enc->sides); darray_vrtx_id_init(alloc, &enc->vertices); - darray_uchar_init(alloc, &enc->side_membership); } static FINLINE res_T @@ -73,9 +76,10 @@ enclosure_data_copy dst->header = src->header; dst->cc_count = src->cc_count; dst->first_component = src->first_component; + dst->side_range = src->side_range; + dst->side_count = src->side_count; OK(darray_triangle_in_copy(&dst->sides, &src->sides)); OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices)); - OK(darray_uchar_copy(&dst->side_membership, &src->side_membership)); error: return res; } @@ -85,7 +89,6 @@ 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->side_membership); } static FINLINE res_T @@ -98,9 +101,10 @@ enclosure_data_copy_and_release dst->header = src->header; dst->cc_count = src->cc_count; dst->first_component = src->first_component; + dst->side_range = src->side_range; + dst->side_count = src->side_count; OK(darray_triangle_in_copy_and_release(&dst->sides, &src->sides)); OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices)); - OK(darray_uchar_copy(&dst->side_membership, &src->side_membership)); error: return res; } diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -36,7 +36,7 @@ #define CC_DESCRIPTOR_NULL__ {\ {0,0,-DBL_MAX}, -1, SIDE_NULL__, VRTX_NULL__, 0, MEDIUM_NULL__,\ CC_ID_NONE, CC_GROUP_ROOT_NONE, CC_GROUP_ID_NONE, CC_ID_NONE,\ - { TRG_NULL__, 0}, { NULL, 0, 0, NULL }\ + { TRG_NULL__, 0}\ } const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__; @@ -81,92 +81,9 @@ neighbour_cmp(const void* w1, const void* w2) return (a1 > a2) - (a1 < a2); } -static void -find_component_Zmax - (struct senc_scene* scn, - struct darray_triangle_tmp* triangles_tmp_array, - struct cc_descriptor* cc) -{ - trg_id_t trid; - double edge0[3], edge1[3], normal[3], norm, side_nz; - struct triangle_in* triangles_in; - struct triangle_tmp* triangles_tmp; - const union double3* vertices; - const unsigned char* side_membership; - ASSERT(scn && triangles_tmp_array && cc); - - vertices = darray_position_cdata_get(&scn->vertices); - triangles_in = darray_triangle_in_data_get(&scn->triangles_in); - triangles_tmp = darray_triangle_tmp_data_get(triangles_tmp_array); - side_membership = darray_uchar_cdata_get(&cc->side_membership); - - /* Build the sorted list of side ids */ - ASSERT(darray_triangle_tmp_size_get(triangles_tmp_array) - == darray_triangle_in_size_get(&scn->triangles_in)); - ASSERT(scn->nutris - == darray_triangle_in_size_get(&scn->triangles_in)); - FOR_EACH(trid, 0, scn->nutris) { - const unsigned char member = side_membership[trid]; - struct triangle_in* const trg_in = triangles_in + trid; - struct triangle_tmp* const trg_tmp = triangles_tmp + trid; - enum side_id side; - int change = 0; - - if(!member) continue; - - /* Keep track of the appropriate vertex/side of the connex component - * in order to cast a ray at the component grouping step of the algorithm. - * The most appropriate vertex is (the) one with the greater Z coordinate. - * If more than one vertex/side has the same Z, we want the side that most - * faces Z (that is the one with the greater nz). - * This is mandatory to select the correct side when both sides of a triangle - * are candidate. */ - if(cc->max_vrtx[2] > trg_tmp->max_z) - continue; - - d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec, - vertices[trg_in->vertice_id[0]].vec); - d3_sub(edge1, vertices[trg_in->vertice_id[2]].vec, - vertices[trg_in->vertice_id[0]].vec); - d3_cross(normal, edge0, edge1); - norm = d3_normalize(normal, normal); - ASSERT(norm); (void)norm; - - if((member & FLAG_FRONT) && (member & FLAG_BACK)) { - /* Select the side with nz>0 */ - side_nz = fabs(normal[2]); - side = (normal[2] > 0) ? SIDE_FRONT : SIDE_BACK; - } else if(member & FLAG_FRONT) { - side_nz = normal[2]; - side = SIDE_FRONT; - } else { - ASSERT(member & FLAG_BACK); - side_nz = -normal[2]; - side = SIDE_BACK; - } - - if(cc->max_vrtx[2] < trg_tmp->max_z) { - change = 1; /* Try first to improve z */ - } else if(cc->max_z_nz <= 0 && fabs(cc->max_z_nz) < fabs(side_nz)) { - change = 1; /* If nz <= 0, the more negative the better */ - } else if(cc->max_z_nz > 0 && cc->max_z_nz < side_nz) { - change = 1; /* If nz > 0, the more positive the better */ - } - if(change) { - cc->max_z_nz = side_nz; - cc->max_z_side_id = TRGIDxSIDE_2_TRGSIDE(trid, side); - ASSERT(trg_tmp->max_z_vrtx_id < 3); - ASSERT(trg_in->vertice_id[trg_tmp->max_z_vrtx_id] < scn->nverts); - cc->max_z_vrtx_id = trg_in->vertice_id[trg_tmp->max_z_vrtx_id]; - ASSERT(trg_tmp->max_z == vertices[cc->max_z_vrtx_id].pos.z); - d3_set(cc->max_vrtx, vertices[cc->max_z_vrtx_id].vec); - } - } -} - static FINLINE void add_side_to_stack - (struct senc_scene* scn, + (const struct senc_scene* scn, struct darray_side_id* stack, struct trgside* trgsides, const side_id_t side_id) @@ -182,30 +99,30 @@ add_side_to_stack static side_id_t get_side_not_in_connex_component - (struct senc_scene* scn, - struct trgside* trgsides, + (const struct senc_scene* scn, + const struct trgside* trgsides, side_id_t* first_side_not_in_component, - medium_id_t medium) + 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 + while(i <= last_side && (trgsides[i].medium != medium || trgsides[i].list_id != FLAG_LIST_SIDE_LIST)) { ++i; } *first_side_not_in_component = i+1; - if(i == last_side) return SIDE_NULL__; + if(i > last_side) return SIDE_NULL__; return i; } static FINLINE side_id_t get_side_from_stack - (struct trgside* trgsides, + (const struct trgside* trgsides, struct darray_side_id* stack) { side_id_t id; @@ -213,6 +130,7 @@ get_side_from_stack (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); @@ -224,17 +142,18 @@ extract_connex_components (struct senc_descriptor* desc, struct trgside* trgsides, struct darray_ptr_component_descriptor* connex_components, - struct darray_triangle_tmp* triangles_tmp_array, + const struct darray_triangle_tmp* triangles_tmp_array, struct darray_triangle_comp* triangles_comp) { res_T res = RES_OK; - struct senc_scene* scn; + const struct senc_scene* scn; struct mem_allocator* alloc; ATOMIC component_count = 0; int stack_initialised = 0; int mm; #ifndef NDEBUG trg_id_t t; + component_id_t c; #endif ASSERT(trgsides && desc && connex_components && triangles_tmp_array); @@ -248,8 +167,8 @@ extract_connex_components #ifndef NDEBUG FOR_EACH(t, 0, scn->nutris) { - struct triangle_in* trg_in = - darray_triangle_in_data_get(&scn->triangles_in) + t; + const struct triangle_in* trg_in = + darray_triangle_in_cdata_get(&scn->triangles_in) + t; const struct side_range* media_use = darray_side_range_cdata_get(&scn->media_use); FOR_EACH(mm, 0, 2) { @@ -263,87 +182,152 @@ extract_connex_components #pragma omp parallel for firstprivate(stack_initialised) schedule(dynamic) for(mm = 0; mm < scn->nmeds; mm++) { /* Process all media */ const medium_id_t m = (medium_id_t)mm; - struct cc_descriptor* current_cc; + struct cc_descriptor* cc; struct darray_side_id stack; /* Any not-already-used side is used as a starting point */ - side_id_t first_side_not_in_component + side_id_t first_side_not_in_component; + if(res != RES_OK) continue; + first_side_not_in_component = darray_side_range_cdata_get(&scn->media_use)[m].first; - if (first_side_not_in_component == SIDE_NULL__) + if(first_side_not_in_component == SIDE_NULL__) continue; /* Unused medium */ ASSERT(first_side_not_in_component < 2 * scn->nutris); - if(res != RES_OK) continue; if(!stack_initialised) { stack_initialised = 1; darray_side_id_init(alloc, &stack); } ASSERT(darray_side_id_size_get(&stack) == 0); - for(;;) { /* Process all enclosures for this medium */ + 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); side_id_t crt_side_id = start_side_id; side_id_t last_side_id = start_side_id; - unsigned char* side_membership; - ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nutris); if(start_side_id == SIDE_NULL__) { /* start_side_id=SIDE_NULL__ => done! */ if(stack_initialised) { - stack_initialised = 0; + stack_initialised = 0; /* TODO: don't recreate stack for same thread */ darray_side_id_release(&stack); } break; } ASSERT(trgsides[start_side_id].list_id == FLAG_LIST_SIDE_LIST); +#ifndef NDEBUG + { + trg_id_t tid = TRGSIDE_2_TRG(start_side_id); + enum side_flag s = TRGSIDE_2_SIDE(start_side_id); + medium_id_t side_med = darray_triangle_in_data_get(&desc->scene->triangles_in)[tid].medium[s]; + ASSERT(side_med == m); + } +#endif + /* Create and init a new component */ - current_cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor)); - if(!current_cc) { + cc = MEM_ALLOC(alloc, sizeof(struct cc_descriptor)); + if(!cc) { res = RES_MEM_ERR; goto error; } - cc_descriptor_init(alloc, current_cc); - /* 1 uchar per triangle (2 sides); allow uint64_t* access */ - OK(darray_uchar_reserve(&current_cc->side_membership, - ((scn->nutris + 7) / 8) * 8)); - OK(darray_uchar_resize(&current_cc->side_membership, scn->nutris)); - side_membership = darray_uchar_data_get(&current_cc->side_membership); - memset(side_membership, 0, scn->nutris * sizeof(unsigned char)); + cc_descriptor_init(alloc, cc); ASSERT(m == trgsides[start_side_id].medium); - current_cc->cc_id = (component_id_t)(ATOMIC_INCR(&component_count) - 1); - current_cc->medium = m; - current_cc->in_use_membership_range.first = start_side_id; + cc->cc_id = (component_id_t)(ATOMIC_INCR(&component_count) - 1); + cc->medium = m; + cc->side_range.first = start_side_id; - for(;;) { /* Process all sides of this enclosure */ + for(;;) { /* Process all sides of this component */ int i; - /* Pop waiting stack to feed crt_side */ + enum side_flag crt_side_flag = TRGSIDE_2_SIDE(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; + const union double3* vertices = + darray_position_cdata_get(&scn->vertices); ASSERT(crt_trg_id < scn->nutris); ASSERT(trgsides[crt_side_id].medium == m); + /* Record Zmax information + * Keep track of the appropriate vertex/side of the connex component + * in order to cast a ray at the component grouping step of the + * algorithm. + * The most appropriate vertex is (the) one with the greater Z + * coordinate. + * If more than one vertex/side has the same Z, we want the side that + * most faces Z (that is the one with the greater nz). + * This is mandatory to select the correct side when both sides of a + * triangle are candidate. */ + if(cc->max_vrtx[2] <= trg_tmp->max_z) { + /* Can either improve z or nz */ + + if(cc->max_z_side_id == TRGSIDE_OPPOSITE(crt_side_id)) { + /* Both sides are in cc and the opposite side is currently selected + * Just keep the side with nz>0 */ + if(cc->max_z_nz < 0) { + /* Change side! */ + cc->max_z_nz = -cc->max_z_nz; + cc->max_z_side_id = crt_side_id; + } + } else { + double edge0[3], edge1[3], normal[3], norm, side_nz; + int process = 0; + + d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec, + vertices[trg_in->vertice_id[0]].vec); + d3_sub(edge1, vertices[trg_in->vertice_id[2]].vec, + vertices[trg_in->vertice_id[0]].vec); + d3_cross(normal, edge0, edge1); + norm = d3_normalize(normal, normal); + ASSERT(norm); (void) norm; + + if(TRGSIDE_IS_FRONT(crt_side_id)) { + side_nz = normal[2]; + process = 1; + } else { + side_nz = -normal[2]; + process = 1; + } + + if(process) { + int change = 0; + if(cc->max_vrtx[2] < trg_tmp->max_z) { + change = 1; /* Try first to improve z */ + } else if (cc->max_z_nz <= 0 && fabs(cc->max_z_nz) < fabs(side_nz)) { + change = 1; /* If nz <= 0, the more negative the better */ + } else if (cc->max_z_nz > 0 && cc->max_z_nz < side_nz) { + change = 1; /* If nz > 0, the more positive the better */ + } + + if(change) { + cc->max_z_nz = side_nz; + cc->max_z_side_id = crt_side_id; + ASSERT(trg_tmp->max_z_vrtx_id < 3); + ASSERT(trg_in->vertice_id[trg_tmp->max_z_vrtx_id] < scn->nverts); + cc->max_z_vrtx_id = trg_in->vertice_id[trg_tmp->max_z_vrtx_id]; + ASSERT(trg_tmp->max_z == vertices[cc->max_z_vrtx_id].pos.z); + d3_set(cc->max_vrtx, vertices[cc->max_z_vrtx_id].vec); + } + } + } + } + /* Record crt_side both as component and triangle level */ - current_cc->side_count++; + cc->side_count++; trgsides[crt_side_id].list_id = FLAG_LIST_COMPONENT; - if(TRGSIDE_IS_FRONT(crt_side_id)) { - ASSERT(trg_comp->component[SIDE_FRONT] == COMPONENT_NULL__); - trg_comp->component[SIDE_FRONT] = current_cc->cc_id; - ASSERT(!(side_membership[crt_trg_id] & FLAG_FRONT)); - side_membership[crt_trg_id] |= FLAG_FRONT; - } else { - ASSERT(trg_comp->component[SIDE_BACK] == COMPONENT_NULL__); - trg_comp->component[SIDE_BACK] = current_cc->cc_id; - ASSERT(!(side_membership[crt_trg_id] & FLAG_BACK)); - side_membership[crt_trg_id] |= FLAG_BACK; - } + ASSERT(trg_comp->component[crt_side_flag] == COMPONENT_NULL__); + trg_comp->component[crt_side_flag] = cc->cc_id; #ifndef NDEBUG - crt_side->member_of_cc = current_cc->cc_id; + crt_side->member_of_cc = cc->cc_id; #endif + /* 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); - struct trgside* neighbour = trgsides + neighbour_id; + const struct trgside* neighbour = trgsides + neighbour_id; + CHK(m == crt_side->medium); if(neighbour->medium != crt_side->medium) { /* Found medium discontinuity! Model topology is broken. */ const struct triangle_in* triangles_in @@ -377,7 +361,7 @@ extract_connex_components if(neighbour->list_id == FLAG_LIST_COMPONENT) { /* Already processed */ #ifndef NDEBUG - ASSERT(neighbour->member_of_cc == current_cc->cc_id); + ASSERT(neighbour->member_of_cc == cc->cc_id); #endif continue; } @@ -392,22 +376,25 @@ extract_connex_components last_side_id = MMAX(last_side_id, crt_side_id); } /* Keep track of this new connex component */ - find_component_Zmax(scn, triangles_tmp_array, current_cc); - current_cc->in_use_membership_range.last = last_side_id; + cc->side_range.last = last_side_id; /* Need to synchronize connex_components growth as this global structure - * is accessed bay multipe threads */ + * is accessed by multipe threads */ #pragma omp critical { - res_T tmp_res; struct cc_descriptor** components; size_t sz = darray_ptr_component_descriptor_size_get(connex_components); - tmp_res = darray_ptr_component_descriptor_resize(connex_components, - MMAX(sz, 1 + current_cc->cc_id)); - if (tmp_res != RES_OK) res = tmp_res; - components = - darray_ptr_component_descriptor_data_get(connex_components); - ASSERT(components[current_cc->cc_id] == NULL); - components[current_cc->cc_id] = current_cc; + if(sz <= cc->cc_id) { + res_T tmp_res = darray_ptr_component_descriptor_resize(connex_components, + 1 + cc->cc_id); + if(tmp_res != RES_OK) res = tmp_res; + } + if(res == RES_OK) { + /* Don't set the pointer before resize as this can lead to move data */ + components = + darray_ptr_component_descriptor_data_get(connex_components); + ASSERT(components[cc->cc_id] == NULL); + components[cc->cc_id] = cc; + } } } error: @@ -424,6 +411,12 @@ extract_connex_components ASSERT(trg_comp->component[SIDE_FRONT] != COMPONENT_NULL__); ASSERT(trg_comp->component[SIDE_BACK] != COMPONENT_NULL__); } + FOR_EACH(c, 0, component_count) { + struct cc_descriptor** components = + darray_ptr_component_descriptor_data_get(connex_components); + ASSERT(components[c] != NULL && + components[c]->cc_id == c); + } #endif exit: @@ -588,7 +581,7 @@ group_connex_components = darray_position_cdata_get(&desc->scene->vertices); log_err(desc->scene->dev, "Medium mismatch found between triangle %lu %s side and triangle" - " %lu %s side, both facing infinite.\n", + " %lu %s side, both facing infinity.\n", (unsigned long)triangles_in[t1].global_id, TRGSIDE_IS_FRONT(infinite_medium_first_side) ? "front" : "back", (unsigned long)triangles_in[t2].global_id, @@ -634,14 +627,12 @@ group_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]); - ASSERT(darray_uchar_cdata_get(&hit_desc->side_membership)[hit_trg_id] - & TRGSIDE_IS_FRONT(hit_side) ? FLAG_FRONT : FLAG_BACK); } #endif if(hit_trg_in->medium[hit_side] != cc->medium) { /* Medium mismatch! Model topology is broken. */ const trg_id_t t1 = TRGSIDE_2_TRG(hit_side_id); - const trg_id_t t2 = TRGSIDE_2_TRG(hit_side); + const trg_id_t t2 = TRGSIDE_2_TRG(cc->max_z_side_id); const struct triangle_in* triangles_in = darray_triangle_in_cdata_get(&desc->scene->triangles_in); const union double3* positions @@ -668,6 +659,7 @@ group_connex_components log_err(desc->scene->dev, "Media: %lu VS %lu\n", (unsigned long)hit_trg_in->medium[hit_side], (unsigned long)cc->medium); + res = RES_BAD_ARG; goto error; } @@ -695,8 +687,13 @@ group_connex_components ++enclosures[cc->enclosure_id].cc_count; /* Linked list of componnents */ fst = enclosures[cc->enclosure_id].first_component; - cc->next_component = fst; + cc->enclosure_next_component = fst; 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; } exit: @@ -928,43 +925,58 @@ error: static res_T build_result (struct senc_descriptor* desc, - struct darray_ptr_component_descriptor* connex_components) + const struct darray_ptr_component_descriptor* connex_components, + const struct darray_triangle_comp* triangles_comp_array) { res_T res = RES_OK; struct mem_allocator* alloc; - struct cc_descriptor** cc_descriptors; + const struct cc_descriptor* const* cc_descriptors; struct enclosure_data* enclosures; const struct triangle_in* triangles_in; struct triangle_enc* triangles_enc; + const struct triangle_comp* triangles_comp; + int tt; int ee; - ASSERT(desc && connex_components); + ASSERT(desc && connex_components && triangles_comp_array); alloc = descriptor_get_allocator(desc); ASSERT(darray_ptr_component_descriptor_size_get(connex_components) < COMPONENT_MAX__); - cc_descriptors = darray_ptr_component_descriptor_data_get(connex_components); + 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); + triangles_comp = darray_triangle_comp_cdata_get(triangles_comp_array); OK2(darray_triangle_enc_resize(&desc->triangles_enc, desc->scene->nutris), error_); triangles_enc = darray_triangle_enc_data_get(&desc->triangles_enc); + /* Build global enclosure information */ + #pragma omp parallel for + for(tt = 0; tt < (int)desc->scene->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 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; + } + /* Resize/push operations on enclosure's fields are valid in the * openmp block as a given enclosure is processed by a single thread */ #pragma omp parallel for schedule(dynamic) for(ee = 0; ee < (int)desc->enclosures_count; ee++) { const enclosure_id_t e = (enclosure_id_t)ee; struct enclosure_data* enc = enclosures + e; - struct cc_descriptor* current = cc_descriptors[enc->first_component]; - struct htable_vrtx_id vtable; - const unsigned char* enc_memb; - uint64_t* enc_memb64; - trg_id_t fst_ixd = 0; - trg_id_t sgd_ixd; + const struct cc_descriptor* current = cc_descriptors[enc->first_component]; + struct htable_vrtx_id vtable; /* TODO: don't recreate vtable for same thread */ + trg_id_t fst_idx = 0; + trg_id_t sgd_idx = enc->side_count;; trg_id_t t; - side_id_t first_member_side = SIDE_MAX__; - side_id_t last_member_side = 0; - side_id_t side_count = 0; ASSERT(enc->first_component < darray_ptr_component_descriptor_size_get(connex_components)); ASSERT(ee <= ENCLOSURE_MAX__); @@ -978,76 +990,29 @@ build_result enc->header.enclosed_medium = (unsigned)current->medium; /* Back to API type */ ASSERT(enc->header.enclosed_medium < desc->scene->nmeds); - /* Get side_membership information from first component */ - darray_uchar_copy_and_clear(&enc->side_membership, - &current->side_membership); - enc_memb = darray_uchar_cdata_get(&enc->side_membership); - enc_memb64 = (uint64_t*)enc_memb; - /* Check we can use uint64_t to merge bit vectors */ - ASSERT(darray_uchar_capacity(&enc->side_membership) - % sizeof(*enc_memb64) == 0); - ASSERT(darray_uchar_size_get(&enc->side_membership) - == desc->scene->nutris); - /* Merge enclosures' membership information */ - for(;;) { - uint64_t* cc_memb64; - trg_id_t t64, tmin64, tmax64; - size_t tmin, tmax; - ASSERT(enc->header.enclosed_medium == (unsigned)current->medium); - side_count += current->side_count; - first_member_side = MMIN(first_member_side, - current->in_use_membership_range.first); - last_member_side = MMAX(last_member_side, - current->in_use_membership_range.last); - if(current->next_component == COMPONENT_NULL__) break; - ASSERT(current->next_component - < darray_ptr_component_descriptor_size_get(connex_components)); - ASSERT(cc_descriptors[current->next_component]->cc_id == current->next_component); - current = cc_descriptors[current->next_component]; - ASSERT(current->enclosure_id == enc->header.enclosure_id); - ASSERT(darray_uchar_size_get(&current->side_membership) - == desc->scene->nutris); - cc_memb64 = (uint64_t*)darray_uchar_cdata_get(&current->side_membership); - ASSERT(darray_uchar_capacity(&current->side_membership) - % sizeof(*enc_memb64) == 0); - /* Merge only the range where current is defined */ - tmin = TRGSIDE_2_TRG(current->in_use_membership_range.first - / sizeof(*enc_memb64)); - tmax = TRGSIDE_2_TRG((current->in_use_membership_range.last - + sizeof(*enc_memb64) - 1) / sizeof(*enc_memb64)); - ASSERT(tmin <= tmax); - ASSERT(tmax < TRG_MAX__); - tmin64 = (trg_id_t)tmin; - tmax64 = (trg_id_t)tmax; - /* We accept the for loop processes meaningless data, - * but it must be allocated! */ - ASSERT(tmax * sizeof(*enc_memb64) - < darray_uchar_capacity(&enc->side_membership)); - for(t64 = tmin64; t64 <= tmax64; t64++) - enc_memb64[t64] |= cc_memb64[t64]; - darray_uchar_purge(&current->side_membership); - } - /* Translate membership into side and vertex lists. */ - OK(darray_triangle_in_resize(&enc->sides, side_count)); - OK(darray_vrtx_id_reserve(&enc->vertices, side_count / 2)); + /* Build side and vertex lists. */ + OK(darray_triangle_in_resize(&enc->sides, enc->side_count)); + /* Size is just a int */ + OK(darray_vrtx_id_reserve(&enc->vertices, + enc->side_count / 2 + enc->side_count / 8)); /* New vertex numbering scheme local to the enclosure */ htable_vrtx_id_init(alloc, &vtable); ASSERT(desc->scene->nutris == darray_triangle_in_size_get(&desc->scene->triangles_in)); - fst_ixd = 0; - sgd_ixd = side_count; /* Put at the end the back-faces of triangles that also have their * front-face in the list. */ - for(t = TRGSIDE_2_TRG(first_member_side); - t <= TRGSIDE_2_TRG(last_member_side); + for(t = TRGSIDE_2_TRG(enc->side_range.first); + t <= TRGSIDE_2_TRG(enc->side_range.last); t++) { const struct triangle_in* trg_in = triangles_in + t; struct triangle_in* trg; unsigned vertice_id[3]; int i; - if(!enc_memb[t]) continue; + if(triangles_enc[t].enclosure[SIDE_FRONT] != e + && triangles_enc[t].enclosure[SIDE_BACK] != e) + continue; ++enc->header.unique_triangle_count; FOR_EACH(i, 0, 3) { @@ -1066,31 +1031,27 @@ build_result ++enc->header.vertices_count; } } - ASSERT((enc_memb[t] & FLAG_FRONT) || (enc_memb[t] & FLAG_BACK)); - if(enc_memb[t] & FLAG_FRONT) { + ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == e + || triangles_enc[t].enclosure[SIDE_BACK] == e); + if(triangles_enc[t].enclosure[SIDE_FRONT] == e) { ++enc->header.triangle_count; - trg = darray_triangle_in_data_get(&enc->sides) + fst_ixd++; + trg = darray_triangle_in_data_get(&enc->sides) + fst_idx++; FOR_EACH(i, 0, 2) trg->medium[i] = trg_in->medium[i]; trg->global_id = trg_in->global_id; FOR_EACH(i, 0, 3) trg->vertice_id[i] = vertice_id[i]; - ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_FRONT] = e; } - if(enc_memb[t] & FLAG_BACK) { + if(triangles_enc[t].enclosure[SIDE_BACK] == e) { ++enc->header.triangle_count; trg = darray_triangle_in_data_get(&enc->sides) + - ((enc_memb[t] & FLAG_FRONT) ? --sgd_ixd : fst_ixd++); + ((triangles_enc[t].enclosure[SIDE_FRONT] == e) ? --sgd_idx : fst_idx++); FOR_EACH(i, 0, 2) trg->medium[i] = trg_in->medium[1 - i]; trg->global_id = trg_in->global_id; FOR_EACH(i, 0, 3) trg->vertice_id[i] = vertice_id[2 - i]; - ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_BACK] = e; } - if(fst_ixd == sgd_ixd) break; + if(fst_idx == sgd_idx) break; } - darray_uchar_purge(&enc->side_membership); htable_vrtx_id_release(&vtable); error: /* Cannot exit openmp block */ @@ -1185,16 +1146,16 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc) goto error; } - darray_triangle_comp_release(&triangles_comp); - triangles_comp_initialized = 0; - /* Build result. */ - res = build_result(desc, &connex_components); + res = build_result(desc, &connex_components, &triangles_comp); if(res != RES_OK) { log_err(scn->dev, "%s: could not build result.\n", FUNC_NAME); goto error; } + darray_triangle_comp_release(&triangles_comp); + triangles_comp_initialized = 0; + exit: if(connex_components_initialized) { size_t c, cc_count = diff --git a/src/senc_scene_analyze_c.h b/src/senc_scene_analyze_c.h @@ -120,33 +120,38 @@ struct cc_descriptor { component_id_t cc_group_root; enclosure_id_t enclosure_id; /* To create by-medium linked lists of componnents */ - component_id_t next_component; - /* TODO: use only 1 bit per side (now 1 uchar per triangle) */ - struct side_range in_use_membership_range; - struct darray_uchar side_membership; + component_id_t enclosure_next_component; + /* Range of sides member of this component */ + struct side_range side_range; }; extern const struct cc_descriptor CC_DESCRIPTOR_NULL; static FINLINE void -cc_descriptor_init(struct mem_allocator* alloc, struct cc_descriptor* data) +cc_descriptor_init + (struct mem_allocator* alloc, + struct cc_descriptor* data) { ASSERT(data); + (void)alloc; *data = CC_DESCRIPTOR_NULL; - darray_uchar_init(alloc, &data->side_membership); } static FINLINE void -ptr_component_descriptor_init(struct mem_allocator* alloc, struct cc_descriptor** data) { - (void) alloc; +ptr_component_descriptor_init + (struct mem_allocator* alloc, + struct cc_descriptor** data) +{ + (void)alloc; ASSERT(data); *data = NULL; } static FINLINE void -ptr_component_descriptor_release(struct mem_allocator* allocator, struct cc_descriptor** data) +ptr_component_descriptor_release + (struct mem_allocator* allocator, + struct cc_descriptor** data) { ASSERT(allocator && data); - darray_uchar_release(&(*data)->side_membership); MEM_RM(allocator, *data); }