commit fdb6da45dcdf8fadf5284c3e93fd51684f233392
parent 9af25aa613f4f20c9596409cd40ae808cce0ebb0
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 21 Aug 2018 11:31:52 +0200
An enclosure can now be made of more than 1 medium.
Diffstat:
17 files changed, 468 insertions(+), 388 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,8 @@
#include <rsys/rsys.h>
#include <rsys/ref_count.h>
+#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
#include "senc.h"
#include "senc_scene_c.h"
@@ -33,16 +35,78 @@ 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 HTABLE_NAME media
+#define HTABLE_KEY medium_id_t
+#define HTABLE_DATA char
+#include <rsys/hash_table.h>
+
+static FINLINE res_T
+htable_media_merge
+ (struct htable_media* dst,
+ struct htable_media* src)
+{
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ struct htable_media_iterator it, end;
+ char one = 1;
+
+ htable_media_begin(src, &it);
+ htable_media_end(src, &end);
+ while(!htable_media_iterator_eq(&it, &end)) {
+ medium_id_t* k = htable_media_iterator_key_get(&it);
+ res = htable_media_set(dst, k, &one);
+ if(res != RES_OK) goto error;
+ htable_media_iterator_next(&it);
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+#define DARRAY_NAME media
+#define DARRAY_DATA medium_id_t
+#include <rsys/dynamic_array.h>
+
+static FINLINE res_T
+htable_media_to_darray_media
+ (struct darray_media* dst,
+ struct htable_media* src)
+{
+ res_T res = RES_OK;
+ ASSERT(src && dst);
+ struct htable_media_iterator it, end;
+
+ darray_media_clear(dst);
+ res = darray_media_reserve(dst, htable_media_size_get(src));
+ if(res != RES_OK) goto error;
+ htable_media_begin(src, &it);
+ htable_media_end(src, &end);
+ while(!htable_media_iterator_eq(&it, &end)) {
+ medium_id_t* k = htable_media_iterator_key_get(&it);
+ res = darray_media_push_back(dst, k);
+ if(res != RES_OK) goto error;
+ htable_media_iterator_next(&it);
+ }
+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 htable_media 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 +128,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);
+ htable_media_init(alloc, &enc->tmp_enclosed_media);
+ darray_media_init(alloc, &enc->enclosed_media);
}
static FINLINE res_T
@@ -80,6 +146,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(htable_media_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media));
+ OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media));
error:
return res;
}
@@ -89,6 +157,8 @@ enclosure_data_release(struct enclosure_data* n) {
ASSERT(n);
darray_triangle_in_release(&n->sides);
darray_vrtx_id_release(&n->vertices);
+ htable_media_release(&n->tmp_enclosed_media);
+ darray_media_release(&n->enclosed_media);
}
static FINLINE res_T
@@ -105,6 +175,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(htable_media_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,7 +35,7 @@
#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}\
}
@@ -44,36 +45,10 @@ const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
#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 +56,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 +131,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. */
@@ -204,68 +145,90 @@ extract_connex_components
int64_t mm;
struct darray_side_id stack;
struct darray_side_id ids_of_sides_around_max_z_vertex;
+ struct htable_media tmp_media;
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;
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, ¤t_component);
+ htable_media_init(alloc, &tmp_media);
+ processed = calloc(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;
+ char one = 1;
+ 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(¤t_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(¤t_component);
+ htable_media_clear(&tmp_media);
- 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 +240,22 @@ 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;
- }
- 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;
-
+ OK2(htable_media_set(&tmp_media, &m, &one));
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 +265,95 @@ 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(¤t_component, &crt_side_id));
+ *trg_used |= 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(neighbour->list_id == FLAG_WAITING_STACK) {
- continue; /* Already processed */
+ 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;
}
- *res = add_side_to_stack(scn, &stack, trgsides, neighbour_id);
- if(*res != RES_OK) break;
+ /* Mark neighbour as processed and stack it */
+ *nbour_used |= nbour_side_id;
+ OK2(darray_side_id_push_back(&stack, &neighbour_id));
+ OK2(darray_side_id_push_back(¤t_component, &neighbour_id));
+ if(neighbour->medium != m) /* Can be a new medium */
+ htable_media_set(&tmp_media, &neighbour->medium, &one);
}
- 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(¤t_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;
+ /* First medium of the component */
+ htable_media_copy_and_clear(&cc->media, &tmp_media);
+
+ /* 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(¤t_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 +364,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 +374,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 +386,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 +401,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 +414,20 @@ extract_connex_components
}
}
}
+ tmp_error:
+ if(tmp_res != RES_OK) *p_res = tmp_res;
} /* No barrier here */
+ free(processed);
+ darray_side_id_release(¤t_component);
darray_side_id_release(&stack);
darray_side_id_release(&ids_of_sides_around_max_z_vertex);
+ htable_media_release(&tmp_media);
/* 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 +438,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 +462,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 +493,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 +507,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 +527,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 +555,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 */
@@ -712,7 +597,6 @@ 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;
@@ -723,6 +607,12 @@ group_connex_components
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;
+ tmp_res = htable_media_merge(
+ &enclosures[cc->enclosure_id].tmp_enclosed_media, &cc->media);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
}
}
}
@@ -914,8 +804,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 +838,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 +879,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(htable_media_size_get(&enc->tmp_enclosed_media) <= UINT_MAX);
+ enc->header.enclosed_media_count
+ = (unsigned)htable_media_size_get(&enc->tmp_enclosed_media);
+ ASSERT(enc->header.enclosed_media_count <= desc->scene->nmeds);
+ OK2(htable_media_to_darray_media
+ (&enc->enclosed_media, &enc->tmp_enclosed_media));
+ htable_media_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 +1012,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 +1107,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 +1150,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 */
+ struct htable_media media;
};
extern const struct cc_descriptor CC_DESCRIPTOR_NULL;
@@ -124,6 +112,7 @@ cc_descriptor_init
ASSERT(data);
(void)alloc;
*data = CC_DESCRIPTOR_NULL;
+ htable_media_init(alloc, &data->media);
}
static FINLINE void
@@ -152,7 +141,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;
+ htable_media_release(&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 */