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 c89e7b3fb6f79bd3ef1661a15ab9d0acb487e54f
parent c95cc1f4a73e7b0fa2ee84378fba4fc4118db209
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Mon, 26 Feb 2018 13:12:56 +0100

Refactoring of the build result step.

Diffstat:
Msrc/senc_device_c.h | 4----
Msrc/senc_enclosure_data.h | 30++++++++++++++++++++++++------
Msrc/senc_internal_types.h | 6++++++
Msrc/senc_scene_analyze.c | 197++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/senc_scene_analyze_c.h | 17+++++++++++++++++
5 files changed, 157 insertions(+), 97 deletions(-)

diff --git a/src/senc_device_c.h b/src/senc_device_c.h @@ -19,10 +19,6 @@ #include <rsys/free_list.h> #include <rsys/ref_count.h> -#define OK(expr)\ - res = expr;\ - if(res != RES_OK) goto error; - struct name { FITEM; }; #define FITEM_TYPE name #include <rsys/free_list.h> diff --git a/src/senc_enclosure_data.h b/src/senc_enclosure_data.h @@ -41,14 +41,23 @@ 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_char side_membership; + /* Number of components involved in this enclosure */ + component_id_t cc_count; + /* Linked list of the components */ + component_id_t first_component; }; static FINLINE void enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) { ASSERT(enc); init_header(&enc->header); + enc->cc_count = 0; + enc->first_component = COMPONENT_NULL__; darray_triangle_in_init(alloc, &enc->sides); darray_vrtx_id_init(alloc, &enc->vertices); + darray_char_init(alloc, &enc->side_membership); } static FINLINE res_T @@ -59,9 +68,13 @@ enclosure_data_copy res_T res = RES_OK; ASSERT(src && dst); dst->header = src->header; - res = darray_triangle_in_copy(&dst->sides, &src->sides); - if(res != RES_OK) return res; - return darray_vrtx_id_copy(&dst->vertices, &src->vertices); + dst->cc_count = src->cc_count; + dst->first_component = src->first_component; + OK(darray_triangle_in_copy(&dst->sides, &src->sides)); + OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices)); + OK(darray_char_copy(&dst->side_membership, &src->side_membership)); +error: + return res; } static FINLINE void @@ -69,6 +82,7 @@ enclosure_data_release(struct enclosure_data* n) { ASSERT(n); darray_triangle_in_release(&n->sides); darray_vrtx_id_release(&n->vertices); + darray_char_release(&n->side_membership); } static FINLINE res_T @@ -79,9 +93,13 @@ enclosure_data_copy_and_release res_T res = RES_OK; ASSERT(src && dst); dst->header = src->header; - res = darray_triangle_in_copy_and_release(&dst->sides, &src->sides); - if(res != RES_OK) return res; - return darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices); + dst->cc_count = src->cc_count; + dst->first_component = src->first_component; + OK(darray_triangle_in_copy_and_release(&dst->sides, &src->sides)); + OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices)); + OK(darray_char_copy(&dst->side_membership, &src->side_membership)); +error: + return res; } #endif /* SENC_ENCLOSURE_DATA_H */ diff --git a/src/senc_internal_types.h b/src/senc_internal_types.h @@ -20,6 +20,12 @@ #include <stdint.h> +/* Utility macro */ +#define OK(expr)\ + res = expr;\ + if(res != RES_OK) goto error; + + /* Side IDs are uint32_t */ typedef uint32_t side_id_t; #define SIDE_MAX__ (UINT32_MAX-1) diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c @@ -35,7 +35,8 @@ #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, CC_GROUP_ROOT_NONE, CC_GROUP_ID_NONE, CC_ID_NONE, TRG_NULL__,\ + TRG_NULL__\ } const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__; @@ -268,6 +269,7 @@ extract_connex_components const side_id_t start_side_id = get_side_not_in_connex_component(scn, trgsides, &first_side_not_in_component); side_id_t crt_side_id = start_side_id; + side_id_t last_side_id = start_side_id; char* side_membership; size_t sz; @@ -280,7 +282,9 @@ extract_connex_components sz = darray_cc_descriptor_size_get(connex_components); OK(darray_cc_descriptor_resize(connex_components, 1+ sz)); current_cc = darray_cc_descriptor_data_get(connex_components) + sz; - /* 1 char per triangle (2 sides) */ + /* 1 char per triangle (2 sides); allow uint64_t* access */ + OK(darray_char_reserve(&current_cc->side_membership, + ((scn->nutris + 7) / 8) * 8)); OK(darray_char_resize(&current_cc->side_membership, scn->nutris)); side_membership = darray_char_data_get(&current_cc->side_membership); memset(side_membership, 0, scn->nutris * sizeof(char)); @@ -288,6 +292,7 @@ extract_connex_components ASSERT(sz <= COMPONENT_MAX__); current_cc->cc_id = (component_id_t)sz; current_cc->medium = m; + current_cc->first_member_id = TRGSIDE_2_TRG(start_side_id); for(;;) { int i; @@ -366,9 +371,11 @@ extract_connex_components if(darray_side_id_size_get(&stack) == 0) break; /* Empty stack => connex component is done! */ crt_side_id = get_side_from_stack(trgsides, &stack); + 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->last_member_id = TRGSIDE_2_TRG(last_side_id); } exit: @@ -449,6 +456,7 @@ group_connex_components side_id_t infinite_medium_first_side = SIDE_MAX__; char infinite_medium_is_known = 0; (void)trgsides; + ASSERT(desc && trgsides && triangles_comp && connex_components); alloc = descriptor_get_allocator(desc); descriptors = darray_cc_descriptor_data_get(connex_components); @@ -583,8 +591,7 @@ group_connex_components } #endif if(hit_trg_in->medium[hit_side] != cc->medium) { - /* Medium mismatch! - * Model topology is broken. */ + /* 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 struct triangle_in* triangles_in @@ -619,9 +626,13 @@ group_connex_components } /* Post-process links to group connex components */ + OK(darray_enclosure_resize(&desc->enclosures, desc->enclosures_count)); FOR_EACH(c, 0, cc_count) { struct cc_descriptor* const cc = descriptors + c; const struct cc_descriptor* other_desc = cc; + struct enclosure_data* enclosures + = darray_enclosure_data_get(&desc->enclosures); + component_id_t fst; while(other_desc->enclosure_id == CC_GROUP_ID_NONE) { other_desc = darray_cc_descriptor_cdata_get(connex_components) @@ -631,6 +642,11 @@ group_connex_components ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE); cc->cc_group_root = other_desc->cc_group_root; cc->enclosure_id = other_desc->enclosure_id; + ++enclosures[cc->enclosure_id].cc_count; + /* Linked list of componnents */ + fst = enclosures[cc->enclosure_id].first_component; + cc->next_component = fst; + enclosures[cc->enclosure_id].first_component = cc->cc_id; } exit: @@ -1084,16 +1100,16 @@ build_result { res_T res = RES_OK; struct mem_allocator* alloc; - const struct cc_descriptor* cc_descriptors; + struct cc_descriptor* cc_descriptors; struct enclosure_data* enclosures; - char* side_membership = NULL; const struct triangle_in* triangles_in; struct triangle_enc* triangles_enc; struct htable_vrtx_id vtable; size_t tmp; - component_id_t cc_count, c; + component_id_t cc_count; enclosure_id_t e; - side_id_t* side_counts = NULL; + trg_id_t fst_ixd = 0; + trg_id_t sgd_ixd; ASSERT(desc && connex_components); @@ -1101,125 +1117,132 @@ build_result tmp = darray_cc_descriptor_size_get(connex_components); ASSERT(tmp < COMPONENT_MAX__); cc_count = (component_id_t)tmp; - cc_descriptors = darray_cc_descriptor_cdata_get(connex_components); - OK(darray_enclosure_resize(&desc->enclosures, desc->enclosures_count)); + cc_descriptors = darray_cc_descriptor_data_get(connex_components); enclosures = darray_enclosure_data_get(&desc->enclosures); triangles_in = darray_triangle_in_cdata_get(&desc->scene->triangles_in); - /* Set some enclosure data */ - side_counts = MEM_CALLOC(alloc, desc->enclosures_count, sizeof(side_id_t)); - if(!side_counts) { - res = RES_MEM_ERR; - goto error; - } - FOR_EACH(e, 0, desc->enclosures_count) { - struct enclosure_data* enc = enclosures + e; - ASSERT(e < UINT_MAX); - enc->header.enclosure_id = (unsigned)e; /* Back to API type */ - enc->header.is_infinite = (e == 0); - } - /* Process components to feed enclosures */ - FOR_EACH(c, 0, cc_count) { - const struct cc_descriptor* cc = cc_descriptors + c; - const enclosure_id_t e_id = cc->enclosure_id; - struct enclosure_data* enc = enclosures + e_id; - ASSERT(enc->header.enclosed_medium == MEDIUM_NULL__ /* Unset */ - || enc->header.enclosed_medium == cc->medium); /* Same medium */ - ASSERT(enc->header.enclosed_medium < UINT_MAX); - enc->header.enclosed_medium = (unsigned)cc->medium; /* Back to API type */ - side_counts[e_id] += cc->side_count; - } - side_membership - = MEM_ALLOC(alloc, desc->scene->nutris * sizeof(*side_membership)); - if(!side_membership) { - res = RES_MEM_ERR; - goto error; - } OK(darray_triangle_enc_resize(&desc->triangles_enc, desc->scene->nutris)); triangles_enc = darray_triangle_enc_data_get(&desc->triangles_enc); htable_vrtx_id_init(alloc, &vtable); + + /* Merge enclosures' membership information */ FOR_EACH(e, 0, desc->enclosures_count) { struct enclosure_data* enc = enclosures + e; + struct cc_descriptor* current = cc_descriptors + enc->first_component; + const char* enc_memb; + uint64_t* enc_memb64; trg_id_t t; - memset(side_membership, 0, desc->scene->nutris * sizeof(*side_membership)); - /* Process all CC enclosures_count times to limit memory footprint. */ - FOR_EACH(c, 0, cc_count) { - const struct cc_descriptor* cc = cc_descriptors + c; - const char* cc_membership - = darray_char_cdata_get(&cc->side_membership); - if(cc->enclosure_id != e) continue; - FOR_EACH(t, 0, desc->scene->nutris) side_membership[t] |= cc_membership[t]; + trg_id_t first_member_id = desc->scene->nutris; + trg_id_t last_member_id = 0; + side_id_t side_count = 0; + ASSERT(enc->cc_count != 0 && enc->cc_count <= cc_count); + ASSERT(enc->first_component <= cc_count); + ASSERT(current != NULL); + enc->header.enclosure_id = (unsigned)e; /* Back to API type */ + 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); + /* Get side_membership information from component */ + darray_char_copy_and_clear(&enc->side_membership, + &current->side_membership); + enc_memb = darray_char_cdata_get(&enc->side_membership); + enc_memb64 = (uint64_t*)enc_memb; + /* Check we can use uint64_t to merge bit vectors */ + ASSERT(darray_char_capacity(&enc->side_membership) + % sizeof(*enc_memb64) == 0); + ASSERT(darray_char_size_get(&enc->side_membership) + == desc->scene->nutris); + for(;;) { + uint64_t* cc_memb64; + trg_id_t t64; + size_t tmin, tmax; + ASSERT(enc->header.enclosed_medium == (unsigned)current->medium); + side_count += current->side_count; + first_member_id = MMIN(first_member_id, current->first_member_id); + last_member_id = MMAX(last_member_id, current->last_member_id); + if(current->next_component == COMPONENT_NULL__) break; + ASSERT(current->next_component <= cc_count); + current = cc_descriptors + current->next_component; + ASSERT(darray_char_size_get(&current->side_membership) + == desc->scene->nutris); + cc_memb64 = (uint64_t*)darray_char_cdata_get(&current->side_membership); + ASSERT(darray_char_capacity(&current->side_membership) + % sizeof(*enc_memb64) == 0); + tmin = current->first_member_id / sizeof(*enc_memb64); + tmax = (darray_char_size_get(&enc->side_membership) + sizeof(*enc_memb64) - 1) + / sizeof(*enc_memb64); + ASSERT(tmin <= tmax); + ASSERT(tmax < TRG_MAX__); + FOR_EACH(t64, (trg_id_t)tmin, (trg_id_t)tmax) { + enc_memb64[t64] |= cc_memb64[t64]; + } + darray_char_purge(&current->side_membership); } - /* Translate membership into a side and vertex lists. */ - OK(darray_triangle_in_reserve(&enc->sides, side_counts[e])); - OK(darray_vrtx_id_reserve(&enc->vertices, side_counts[e] / 2)); + + /* 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)); /* New vertex numbering scheme local to the enclosure */ htable_vrtx_id_clear(&vtable); ASSERT(desc->scene->nutris == darray_triangle_in_size_get(&desc->scene->triangles_in)); - /* Proceed in 2 steps; the second step puts at the end the back-faces - * of triangles that also have front-face in the list. */ - FOR_EACH(t, 0, desc->scene->nutris) { + 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_EACH(t, first_member_id, desc->scene->nutris) { const struct triangle_in* trg_in = triangles_in + t; - struct triangle_in trg; + struct triangle_in* trg; + unsigned vertice_id[3]; int i; - if(!side_membership[t]) continue; + if(!enc_memb[t]) continue; ++enc->header.unique_triangle_count; + FOR_EACH(i, 0, 3) { vrtx_id_t* id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i); if(id) { - trg.vertice_id[i] = *id; /* Known vertex */ + vertice_id[i] = *id; /* Known vertex */ } else { /* Create new association */ tmp = htable_vrtx_id_size_get(&vtable); ASSERT(tmp == darray_vrtx_id_size_get(&enc->vertices)); ASSERT(tmp < VRTX_MAX__); - trg.vertice_id[i] = (vrtx_id_t)tmp; + vertice_id[i] = (vrtx_id_t)tmp; OK(htable_vrtx_id_set(&vtable, trg_in->vertice_id + i, - trg.vertice_id + i)); - OK(darray_vrtx_id_push_back(&enc->vertices, trg_in->vertice_id + i)); + vertice_id + i)); + OK(darray_vrtx_id_push_back(&enc->vertices, vertice_id + i)); ++enc->header.vertices_count; } } - FOR_EACH(i, 0, 2) trg.medium[i] = trg_in->medium[i]; - trg.global_id = trg_in->global_id; - if(side_membership[t] & FLAG_FRONT) { + ASSERT((enc_memb[t] & FLAG_FRONT) || (enc_memb[t] & FLAG_BACK)); + if(enc_memb[t] & FLAG_FRONT) { ++enc->header.triangle_count; - OK(darray_triangle_in_push_back(&enc->sides, &trg)); + trg = darray_triangle_in_data_get(&enc->sides) + fst_ixd++; + + 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; - } else if(side_membership[t] & FLAG_BACK) { + } + if(enc_memb[t] & FLAG_BACK) { ++enc->header.triangle_count; - triangle_in_flip(&trg); - OK(darray_triangle_in_push_back(&enc->sides, &trg)); + trg = darray_triangle_in_data_get(&enc->sides) + + ((enc_memb[t] & FLAG_FRONT) ? --sgd_ixd : fst_ixd++); + + 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; } - FOR_EACH(t, 0, desc->scene->nutris) { - const struct triangle_in* trg_in = triangles_in + t; - struct triangle_in trg; - int i; - if(!((side_membership[t] & FLAG_FRONT) && (side_membership[t] & FLAG_BACK))) - continue; - ++enc->header.triangle_count; - FOR_EACH(i, 0, 3) { - vrtx_id_t* id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i); - ASSERT(id); - trg.vertice_id[2-i] = *id; /* Known vertex */ - } - FOR_EACH(i, 0, 2) trg.medium[1-i] = trg_in->medium[i]; - trg.global_id = trg_in->global_id; - OK(darray_triangle_in_push_back(&enc->sides, &trg)); - ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__); - triangles_enc[t].enclosure[SIDE_BACK] = e; - } - ASSERT(darray_triangle_in_size_get(&enc->sides) == side_counts[e]); + darray_char_purge(&enc->side_membership); } exit: htable_vrtx_id_release(&vtable); - if(side_membership) MEM_RM(alloc, side_membership); - if(side_counts) MEM_RM(alloc, side_counts); return res; error: goto exit; diff --git a/src/senc_scene_analyze_c.h b/src/senc_scene_analyze_c.h @@ -153,8 +153,13 @@ struct cc_descriptor { component_id_t cc_id; component_id_t cc_group_root; enclosure_id_t enclosure_id; + /* To create linked lists of componnents */ + component_id_t next_component; /* TODO: use only 1 bit per side (now 1 char per triangle) */ + trg_id_t first_member_id; + trg_id_t last_member_id; struct darray_char side_membership; + }; extern const struct cc_descriptor CC_DESCRIPTOR_NULL; @@ -185,6 +190,9 @@ cc_descriptor_clear(struct cc_descriptor* data) data->cc_id = CC_DESCRIPTOR_NULL.cc_id; data->cc_group_root = CC_DESCRIPTOR_NULL.cc_group_root; data->enclosure_id = CC_DESCRIPTOR_NULL.enclosure_id; + data->next_component = CC_DESCRIPTOR_NULL.next_component; + data->first_member_id = CC_DESCRIPTOR_NULL.first_member_id; + data->last_member_id = CC_DESCRIPTOR_NULL.last_member_id; darray_char_clear(&data->side_membership); } @@ -200,6 +208,9 @@ cc_descriptor_purge(struct cc_descriptor* data) data->cc_id = CC_DESCRIPTOR_NULL.cc_id; data->cc_group_root = CC_DESCRIPTOR_NULL.cc_group_root; data->enclosure_id = CC_DESCRIPTOR_NULL.enclosure_id; + data->next_component = CC_DESCRIPTOR_NULL.next_component; + data->first_member_id = CC_DESCRIPTOR_NULL.first_member_id; + data->last_member_id = CC_DESCRIPTOR_NULL.last_member_id; darray_char_purge(&data->side_membership); } @@ -216,6 +227,9 @@ cc_descriptor_copy(struct cc_descriptor* dst, const struct cc_descriptor* src) dst->cc_id = src->cc_id; dst->cc_group_root = src->cc_group_root; dst->enclosure_id = src->enclosure_id; + dst->next_component = src->next_component; + dst->first_member_id = src->first_member_id; + dst->last_member_id = src->last_member_id; return darray_char_copy(&dst->side_membership, &src->side_membership); } @@ -234,6 +248,9 @@ cc_descriptor_copy_and_release dst->cc_id = src->cc_id; dst->cc_group_root = src->cc_group_root; dst->enclosure_id = src->enclosure_id; + dst->next_component = src->next_component; + dst->first_member_id = src->first_member_id; + dst->last_member_id = src->last_member_id; return darray_char_copy_and_release(&dst->side_membership, &src->side_membership); }