commit 8e023fde7b0b4f0c3c22046d2c83c6e649396713
parent bb7813ddc4ec7b5e5bc58e7a092db4921b4d2159
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 17 Jul 2024 11:15:51 +0200
Merge branch 'release_0.7.2'
Diffstat:
9 files changed, 726 insertions(+), 84 deletions(-)
diff --git a/Makefile b/Makefile
@@ -126,6 +126,8 @@ lint:
################################################################################
TEST_SRC =\
src/test_senc3d_bad_grouping.c\
+ src/test_senc3d_bad_grouping2.c\
+ src/test_senc3d_bad_grouping3.c\
src/test_senc3d_cube_behind_cube.c\
src/test_senc3d_cube_in_cube.c\
src/test_senc3d_cube_on_cube.c\
@@ -213,6 +215,8 @@ $(TEST_OBJ_S3DUT): config.mk senc3d-local.pc
-c $(@:.o=.c) -o $@
test_senc3d_bad_grouping \
+test_senc3d_bad_grouping2 \
+test_senc3d_bad_grouping3 \
test_senc3d_cube_behind_cube \
test_senc3d_cube_in_cube \
test_senc3d_cube_on_cube \
diff --git a/README.md b/README.md
@@ -37,9 +37,17 @@ Edit config.mk as needed, then run:
## Release notes
+### Version 0.7.2
+
+- Another correction in the code that groups connex components to create
+ enclosures.
+- Add function `senc3d_scene_dump_enclosure_obj` which writes an Obj
+ file of a given enclosure geometry.
+
### Version 0.7.1
-- Fixes a bug in the code that groups connex components to create enclosures.
+- Fixes a bug in the code that groups connex components to create
+ enclosures.
### Version 0.7
diff --git a/config.mk b/config.mk
@@ -1,4 +1,4 @@
-VERSION = 0.7.1
+VERSION = 0.7.2
PREFIX = /usr/local
LIB_TYPE = SHARED
diff --git a/src/senc3d.h b/src/senc3d.h
@@ -333,6 +333,13 @@ senc3d_scene_get_overlapping_triangle
const unsigned idx,
unsigned* id);
+/* Dump a given enclosure in an OBJ file */
+SENC3D_API res_T
+senc3d_scene_dump_enclosure_obj
+ (struct senc3d_scene* scn,
+ const unsigned enc,
+ const char* filename);
+
SENC3D_API res_T
senc3d_scene_ref_get
(struct senc3d_scene* scene);
diff --git a/src/senc3d_scene.c b/src/senc3d_scene.c
@@ -319,6 +319,58 @@ senc3d_scene_get_vertex
}
res_T
+senc3d_scene_dump_enclosure_obj
+ (struct senc3d_scene* scn,
+ const unsigned enc,
+ const char* name)
+{
+ struct senc3d_enclosure* enclosure = NULL;
+ struct senc3d_enclosure_header header;
+ FILE* stream = NULL;
+ unsigned count, i;
+ res_T res = RES_OK;
+
+ if(!scn || !name) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ if(enc >= count) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ OK(senc3d_scene_get_enclosure(scn, enc, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+
+ stream = fopen(name, "w");
+ if(!stream) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ FOR_EACH(i, 0, header.vertices_count) {
+ double tmp[3];
+ OK(senc3d_enclosure_get_vertex(enclosure, i, tmp));
+ fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
+ }
+ FOR_EACH(i, 0, header.primitives_count) {
+ unsigned indices[3];
+ OK(senc3d_enclosure_get_triangle(enclosure, i, indices));
+ fprintf(stream, "f %u %u %u\n",
+ 1+indices[0], 1+indices[1], 1+indices[2]);
+ }
+
+exit:
+ if(enclosure) SENC3D(enclosure_ref_put(enclosure));
+ if(stream) fclose(stream);
+ return res;
+error:
+ goto exit;
+}
+
+res_T
senc3d_scene_ref_get(struct senc3d_scene* scn)
{
if(!scn) return RES_BAD_ARG;
diff --git a/src/senc3d_scene_analyze.c b/src/senc3d_scene_analyze.c
@@ -67,12 +67,14 @@ const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
* If ray.normal < threshold we suspect accuracy could be a problem */
#define DOT_THRESHOLD 0.0001f
-struct filter_ctx0 {
- component_id_t origin_component;
- struct darray_triangle_comp* triangles_comp;
+enum ctx_type {
+ CTX0,
+ CTX1,
+ CTX2
};
-struct filter_ctx1 {
+struct filter_ctx {
+ enum ctx_type type;
struct senc3d_scene* scn;
struct s3d_scene_view* view;
component_id_t origin_component;
@@ -80,34 +82,14 @@ struct filter_ctx1 {
struct darray_ptr_component_descriptor* components;
/* Tmp data used across filter calls */
double current_6volume;
+ int cpt;
float s;
- /* Result of hit */
+ /* Result of CTX1 hit */
component_id_t hit_component;
float hit_dir[3], hit_dist;
struct s3d_primitive hit_prim;
};
-struct filter_ctx2 {
- struct darray_triangle_comp* triangles_comp;
- int cpt;
- component_id_t component;
-};
-
-enum fctx_type {
- FCTX0,
- FCTX1,
- FCTX2
-};
-
-struct filter_ctx {
- enum fctx_type type;
- union {
- struct filter_ctx0 ctx0;
- struct filter_ctx1 ctx1;
- struct filter_ctx2 ctx2;
- } c;
-};
-
#define HTABLE_NAME overlap
#define HTABLE_KEY trg_id_t
#define HTABLE_DATA char
@@ -129,7 +111,7 @@ static FINLINE int
is_component_inside
(struct cc_descriptor* cc1,
struct cc_descriptor* cc2,
- struct filter_ctx1* ctx)
+ struct filter_ctx* ctx)
{
int i;
side_id_t side;
@@ -184,13 +166,13 @@ is_component_inside
d3_divd(pt, pt, 3);
f3_set_d3(org, pt);
/* Trace a ray and count intersections with component c */
- ctx2.type = FCTX2;
- ctx2.c.ctx2.triangles_comp = ctx->triangles_comp;
- ctx2.c.ctx2.cpt = 0;
- ctx2.c.ctx2.component = cc1->cc_id;
+ ctx2.type = CTX2;
+ ctx2.triangles_comp = ctx->triangles_comp;
+ ctx2.cpt = 0;
+ ctx2.origin_component = cc1->cc_id;
S3D(scene_view_trace_ray(ctx->view, org, dir, rg, &ctx2, &hit));
/* cc2 is not inside cc1 if cpt is even */
- if(ctx2.c.ctx2.cpt % 2 == 0) return 0;
+ if(ctx2.cpt % 2 == 0) return 0;
return 1;
}
@@ -256,68 +238,204 @@ self_hit_filter
void* ray_data,
void* filter_data)
{
- struct filter_ctx* fctx_ = ray_data;
+ struct filter_ctx* ctx = ray_data;
(void)ray_org; (void)ray_range; (void)filter_data;
- ASSERT(fctx_);
+ ASSERT(ctx);
ASSERT(hit->uv[0] == CLAMP(hit->uv[0], 0, 1));
ASSERT(hit->uv[1] == CLAMP(hit->uv[1], 0, 1));
- switch (fctx_->type) {
+ switch (ctx->type) {
default: FATAL("Invalid");
- case FCTX2: {
+ case CTX2: {
/* The filter is used to count the hits on some component along an
* infinite ray */
- struct filter_ctx2* ctx2 = &fctx_->c.ctx2;
const struct triangle_comp* trg_comp;
const component_id_t* hit_comp;
ASSERT(hit->prim.prim_id
- < darray_triangle_comp_size_get(ctx2->triangles_comp));
- trg_comp = darray_triangle_comp_cdata_get(ctx2->triangles_comp);
+ < darray_triangle_comp_size_get(ctx->triangles_comp));
+ trg_comp = darray_triangle_comp_cdata_get(ctx->triangles_comp);
hit_comp = trg_comp[hit->prim.prim_id].component;
- if(hit_comp[SENC3D_FRONT] == ctx2->component
- || hit_comp[SENC3D_BACK] == ctx2->component)
+ if(hit_comp[SENC3D_FRONT] == ctx->origin_component
+ || hit_comp[SENC3D_BACK] == ctx->origin_component)
{
- ctx2->cpt++;
+ ctx->cpt++;
}
return 1; /* Reject to continue counting */
}
- case FCTX0: {
+ case CTX0: {
/* This filter is called from a closest point query from a point belonging
* to origin_component. The returned hit is used to determine the search
- * radius for FCTX1 main computation. */
- struct filter_ctx0* ctx = &fctx_->c.ctx0;
+ * radius for CTX1 main computation. */
const struct triangle_comp*
trg_comp = darray_triangle_comp_cdata_get(ctx->triangles_comp);
const component_id_t*
hit_comp = trg_comp[hit->prim.prim_id].component;
const component_id_t oc = ctx->origin_component;
+ vrtx_id_t other_id;
+ struct cc_descriptor* const* comp_descriptors
+ = darray_ptr_component_descriptor_cdata_get(ctx->components);
+ size_t compsz = darray_ptr_component_descriptor_size_get(ctx->components);
+ const union double3*
+ vertices = darray_position_cdata_get(&ctx->scn->vertices);
+ const double org_z = vertices[comp_descriptors[oc]->max_z_vrtx_id].pos.z;
+ float s = 0, hit_normal[3], rdir[3];
+ enum senc3d_side hit_side;
+ const int log_components =
+ ctx->scn->convention & SENC3D_LOG_COMPONENTS_INFORMATION;
ASSERT(hit->prim.prim_id
< darray_triangle_comp_size_get(ctx->triangles_comp));
+ ASSERT(hit_comp[SENC3D_FRONT] < compsz);
+ ASSERT(hit_comp[SENC3D_BACK] < compsz);
+ (void)compsz; /* Avoid "unused variable" warning */
+ /* Hit acceptance must be coherent at CTX0 and FTCX1 stages:
+ * the search radius as found at stage CTX0 must include the hit that
+ * stage CTX1 will select using an infinite radius */
if(hit_comp[SENC3D_FRONT] == oc || hit_comp[SENC3D_BACK] == oc) {
- /* Self hit */
- return 1; /* Reject */
+ return 1; /* Self hit, reject */
+ }
+ if(hit->distance == 0) {
+ /* origin component is in contact with some other components
+ * We will need further exploration to know if they should be considered
+ * Accepting hit at distance 0 => radius is definitively 0 */
+ int n;
+
+ /* If same component, process only once */
+ FOR_EACH(n, 0, (hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK] ? 1 : 2)) {
+ const enum senc3d_side sides[2] = { SENC3D_FRONT, SENC3D_BACK };
+ component_id_t c = hit_comp[sides[n]];
+ ASSERT(c < darray_ptr_component_descriptor_size_get(ctx->components));
+ if(comp_descriptors[c]->is_outer_border) {
+ /* The inner component we are trying to link can only be linked to
+ * an outer component if it is inside */
+ if(!is_component_inside(comp_descriptors[c],
+ comp_descriptors[oc], ctx))
+ {
+ continue;
+ }
+
+ if(log_components) {
+ #pragma omp critical
+ printf("Component #%u: decreasing search radius "
+ "(R=%g, n=%g,%g,%g, components: %u, %u)\n",
+ oc, hit->distance, SPLIT3(hit->normal),
+ hit_comp[SENC3D_FRONT], hit_comp[SENC3D_BACK]);
+ }
+ return 0;
+ } else {
+ /* c is an inner component */
+ vrtx_id_t c_z_id;
+ /* The inner component we are trying to link can only be linked to
+ * another inner component if (at least partly) above and not inside */
+ c_z_id = comp_descriptors[c]->max_z_vrtx_id;
+ ASSERT(c_z_id < darray_position_size_get(&ctx->scn->vertices));
+ ASSERT(vertices[c_z_id].pos.z >= org_z);
+ if(vertices[c_z_id].pos.z == org_z) {
+ continue; /* Not above */
+ }
+ if(is_component_inside(comp_descriptors[c],
+ comp_descriptors[oc], ctx))
+ {
+ continue; /* Inside */
+ }
+ if(log_components) {
+ #pragma omp critical
+ printf("Component #%u: decreasing search radius "
+ "(R=%g, n=%g,%g,%g, components: %u, %u)\n",
+ oc, hit->distance, SPLIT3(hit->normal),
+ hit_comp[SENC3D_FRONT], hit_comp[SENC3D_BACK]);
+ }
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ ASSERT(hit->distance > 0);
+ if(hit_comp[SENC3D_FRONT] == hit_comp[SENC3D_BACK]) {
+ /* Hit component is known, check if above */
+ other_id = comp_descriptors[hit_comp[SENC3D_FRONT]]->max_z_vrtx_id;
+ ASSERT(other_id < darray_position_size_get(&ctx->scn->vertices));
+ if(vertices[other_id].pos.z <= org_z) {
+ return 1;
+ }
+ if(log_components) {
+ #pragma omp critical
+ printf("Component #%u: decreasing search radius "
+ "(R=%g, n=%g,%g,%g, components: %u, %u)\n",
+ oc, hit->distance, SPLIT3(hit->normal),
+ hit_comp[SENC3D_FRONT], hit_comp[SENC3D_BACK]);
+ }
+ return 0;
}
- if(hit->distance > 0 && ray_dir[2] <= 0) {
- return 1; /* Not upward */
+ /* Compute hit side */
+ /* For s to be comparable, vectors must be normalized */
+ f3_normalize(hit_normal, hit->normal);
+ f3_normalize(rdir, ray_dir);
+ s = f3_dot(rdir, hit_normal); /* Can be NaN for tiny distances */
+ if(isnan(s)) {
+ /* Try to fix it */
+ f3_divf(rdir, ray_dir, hit->distance);
+ f3_normalize(rdir, rdir);
+ s = f3_dot(rdir, hit_normal);
+ ASSERT(!isnan(s));
}
- return 0; /* Keep*/
+ if(fabsf(s) < DOT_THRESHOLD) {
+ /* We cannot know for sure which side to consider */
+ vrtx_id_t i1 = comp_descriptors[hit_comp[SENC3D_FRONT]]->max_z_vrtx_id;
+ vrtx_id_t i2 = comp_descriptors[hit_comp[SENC3D_BACK]]->max_z_vrtx_id;
+ double possible_z = MMIN(vertices[i1].pos.z, vertices[i2].pos.z);
+ if(possible_z > org_z) {
+ /* Both components are above origin component => keep */
+ if(log_components) {
+ #pragma omp critical
+ printf("Component #%u: decreasing search radius "
+ "(R=%g, n=%g,%g,%g, components: %u, %u)\n",
+ oc, hit->distance, SPLIT3(hit->normal),
+ hit_comp[SENC3D_FRONT], hit_comp[SENC3D_BACK]);
+ }
+ return 0;
+ }
+ /* Cannot be sure => the safest choice is to reject */
+ return 1;
+ }
+ /* Determine which side was hit */
+ hit_side =
+ ((s < 0) /* Facing geometrical normal of hit */
+ == ((ctx->scn->convention & SENC3D_CONVENTION_NORMAL_FRONT) != 0))
+ /* Warning: following Embree 2 convention for geometrical normals,
+ * the Star3D hit normal is left-handed while star-enclosures-3d uses
+ * right-handed convention */
+ ? SENC3D_BACK : SENC3D_FRONT;
+ other_id = comp_descriptors[hit_comp[hit_side]]->max_z_vrtx_id;
+ ASSERT(other_id < darray_position_size_get(&ctx->scn->vertices));
+ if(vertices[other_id].pos.z <= org_z) {
+ return 1;
+ }
+ if(log_components) {
+ #pragma omp critical
+ printf("Component #%u: decreasing search radius "
+ "(R=%g, n=%g,%g,%g, components: %u, %u)\n",
+ oc, hit->distance, SPLIT3(hit->normal),
+ hit_comp[SENC3D_FRONT], hit_comp[SENC3D_BACK]);
+ }
+ return 0;
}
- case FCTX1: {
+ case CTX1: {
/* This filter is called from a closest point query from a point belonging
* to origin_component. The returned hit is used to determine a component
* to which origin_component is linked. At a later stage the algorithm
* process linked components to determine their relative inclusions.
*
* This filter is called with a search distance that has been ajusted in
- * FCTX0 filter. This distance must be left unchanged to ensure visiting
+ * CTX0 filter. This distance must be left unchanged to ensure visiting
* all the surfaces at the determined distance: allways reject hits to
* avoid decreasing search distance.
*
@@ -330,7 +448,6 @@ self_hit_filter
* (greater volume needed), or they can be disjoint, with (at least) ray_org
* as a common vertex (they can also partially intersect, but this is invalid
* and remains undetected by star enclosures). */
- struct filter_ctx1* ctx = &fctx_->c.ctx1;
struct cc_descriptor* const* comp_descriptors
= darray_ptr_component_descriptor_cdata_get(ctx->components);
const struct triangle_comp*
@@ -355,24 +472,33 @@ self_hit_filter
< darray_triangle_comp_size_get(ctx->triangles_comp));
if(log_components) {
+ #pragma omp critical
printf("Component #%u: investigating hit "
"(d=%g, n=%g,%g,%g, components: %u, %u)\n",
oc, hit->distance, SPLIT3(hit->normal),
hit_comp[SENC3D_FRONT], hit_comp[SENC3D_BACK]);
}
+ /* Has CTX1 filter do not reduce search radius, hits can be processed
+ * that are at farther distance than the current best candidate: we need
+ * to reject them here */
if(hit->distance > ctx->hit_dist) {
/* No improvement */
if(log_components) {
+ #pragma omp critical
printf("Component #%u: further away (%g): reject\n",
oc, ctx->hit_dist);
}
return 1;
}
+ /* Hit acceptance must be coherent at CTX0 and FTCX1 stages:
+ * the search radius as found at stage CTX0 must include the hit that
+ * stage CTX1 will select using an infinite radius */
if(hit_comp[SENC3D_FRONT] == oc || hit_comp[SENC3D_BACK] == oc) {
/* Self hit */
if(log_components) {
+ #pragma omp critical
printf("Component #%u: self hit: reject\n", oc);
}
return 1;
@@ -391,6 +517,7 @@ self_hit_filter
if(c == ctx->hit_component) {
/* Cannot change ctx->hit_component */
if(log_components) {
+ #pragma omp critical
printf("Component #%u: hit component #%u and already linked to it:"
" reject\n",
oc, c);
@@ -402,12 +529,14 @@ self_hit_filter
/* The inner component we are trying to link can only be linked to
* an outer component if it is inside */
if(log_components) {
+ #pragma omp critical
printf("Component #%u: hit outer component #%u\n", oc, c);
}
if(!is_component_inside(comp_descriptors[c],
comp_descriptors[oc], ctx))
{
if(log_components) {
+ #pragma omp critical
printf("Component #%u: not inside: reject\n", oc);
}
continue;
@@ -419,7 +548,7 @@ self_hit_filter
* we are looking for is the smallest one (to manage outer component
* inside another outer component). */
if((ctx->hit_component != COMPONENT_NULL__
- && !comp_descriptors[ctx->hit_component]->is_outer_border )
+ && !comp_descriptors[ctx->hit_component]->is_outer_border)
|| v < ctx->current_6volume) {
ctx->hit_component = c;
ctx->current_6volume = v;
@@ -427,10 +556,12 @@ self_hit_filter
ctx->hit_prim = hit->prim;
if(log_components) {
if(v < ctx->current_6volume) {
+ #pragma omp critical
printf("Component #%u: currently the smaller one: "
"keep component #%u\n",
oc, ctx->hit_component);
} else {
+ #pragma omp critical
printf("Component #%u: change from inner to outer: "
"keep component #%u\n",
oc, ctx->hit_component);
@@ -438,6 +569,7 @@ self_hit_filter
}
} else {
if(log_components) {
+ #pragma omp critical
printf("Component #%u: not the smaller one: reject\n", oc);
}
continue;
@@ -449,12 +581,14 @@ self_hit_filter
/* If we've already found a valid outer component, inner components
* should not be considered anymore */
if(log_components) {
+ #pragma omp critical
printf("Component #%u: hit inner component #%u\n", oc, c);
}
if(ctx->hit_component != COMPONENT_NULL__
- && comp_descriptors[ctx->hit_component]->is_outer_border )
+ && comp_descriptors[ctx->hit_component]->is_outer_border)
{
if(log_components) {
+ #pragma omp critical
printf("Component #%u: already in an outer component: reject\n",
oc);
}
@@ -468,6 +602,7 @@ self_hit_filter
ASSERT(vertices[c_z_id].pos.z >= org_z);
if(vertices[c_z_id].pos.z == org_z) {
if(log_components) {
+ #pragma omp critical
printf("Component #%u: not (even in part) above: reject\n", oc);
}
continue; /* Not above */
@@ -476,6 +611,7 @@ self_hit_filter
comp_descriptors[oc], ctx))
{
if(log_components) {
+ #pragma omp critical
printf("Component #%u: not outside: reject\n", oc);
}
continue; /* Inside */
@@ -490,12 +626,14 @@ self_hit_filter
ctx->hit_dist = 0;
ctx->hit_prim = hit->prim;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: currently the bigger one: "
"keep component #%u\n",
oc, ctx->hit_component);
}
} else {
if(log_components) {
+ #pragma omp critical
printf("Component #%u: not the bigger one: reject\n", oc);
}
continue;
@@ -512,8 +650,8 @@ self_hit_filter
ASSERT(other_id < darray_position_size_get(&ctx->scn->vertices));
if(vertices[other_id].pos.z <= org_z) {
if(log_components) {
- printf("Component #%u: 2 sides, not (even in part) above: reject\n",
- oc);
+ #pragma omp critical
+ printf("Component #%u: 2 sides, not above: reject\n", oc);
}
return 1;
}
@@ -523,6 +661,7 @@ self_hit_filter
ctx->hit_dist = hit->distance;
ctx->hit_prim = hit->prim;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: 2 sides with same component: "
"keep component #%u\n",
oc, ctx->hit_component);
@@ -531,7 +670,7 @@ self_hit_filter
}
/* Compute hit side */
- /* For s to be comparable, vectors must be normailzed */
+ /* For s to be comparable, vectors must be normalized */
f3_normalize(hit_normal, hit->normal);
f3_normalize(rdir, ray_dir);
s = f3_dot(rdir, hit_normal); /* Can be NaN for tiny distances */
@@ -542,6 +681,7 @@ self_hit_filter
s = f3_dot(rdir, hit_normal);
ASSERT(!isnan(s));
if(log_components) {
+ #pragma omp critical
printf("Component #%u: had to fix s (was NaN)\n", oc);
}
}
@@ -549,6 +689,7 @@ self_hit_filter
if(ctx->hit_dist == hit->distance && fabsf(ctx->s) >= fabsf(s)) {
/* Same distance with no s improvement: keep the previous hit */
if(log_components) {
+ #pragma omp critical
printf("Component #%u: not improving s (%g VS %g): reject\n",
oc, s, ctx->s);
}
@@ -561,8 +702,10 @@ self_hit_filter
vrtx_id_t i2 = comp_descriptors[hit_comp[SENC3D_BACK]]->max_z_vrtx_id;
double possible_z = MMAX(vertices[i1].pos.z, vertices[i2].pos.z);
if(possible_z <= org_z) {
+ /* None of the components are above origin component => reject */
if(log_components) {
- printf("Component #%u: tiny s, not (even in part) above: reject\n",
+ #pragma omp critical
+ printf("Component #%u: none of the components above: reject\n",
oc);
}
return 1;
@@ -573,6 +716,7 @@ self_hit_filter
ctx->hit_dist = hit->distance;
ctx->hit_prim = hit->prim;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: tiny s (%g): "
"keep but don't know the component\n",
oc, s);
@@ -591,6 +735,7 @@ self_hit_filter
ASSERT(other_id < darray_position_size_get(&ctx->scn->vertices));
if(vertices[other_id].pos.z <= org_z) {
if(log_components) {
+ #pragma omp critical
printf("Component #%u: standard s, not (even in part) above: reject\n",
oc);
}
@@ -602,6 +747,7 @@ self_hit_filter
ctx->hit_dist = hit->distance;
ctx->hit_prim = hit->prim;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: standard s, (%g): keep component #%u\n",
oc, s, ctx->hit_component);
}
@@ -1151,7 +1297,7 @@ group_connex_components
ASSERT(scn->analyze.enclosures_count == 1);
#ifndef NDEBUG
-#pragma omp single
+ #pragma omp single
{
/* Ensure reproducible cc_ids for debugging purpose */
*res = reorder_components(scn, connex_components, triangles_comp);
@@ -1164,6 +1310,7 @@ group_connex_components
cc_count = (component_id_t)tmp;
positions = darray_position_cdata_get(&scn->vertices);
+ #pragma omp single
if(dump_components) {
/* Do it now before any other problem can occur (fingers crossed).
* Do it sequential and not optimized as it is debug code.
@@ -1222,14 +1369,16 @@ group_connex_components
scene_cpt++;
}
-
- ctx0.type = FCTX0;
- ctx0.c.ctx0.triangles_comp = triangles_comp;
- ctx1.type = FCTX1;
- ctx1.c.ctx1.scn = scn;
- ctx1.c.ctx1.view = s3d_view;
- ctx1.c.ctx1.triangles_comp = triangles_comp;
- ctx1.c.ctx1.components = connex_components;
+ ctx0.type = CTX0;
+ ctx0.scn = scn;
+ ctx0.view = s3d_view;
+ ctx0.triangles_comp = triangles_comp;
+ ctx0.components = connex_components;
+ ctx1.type = CTX1;
+ ctx1.scn = scn;
+ ctx1.view = s3d_view;
+ ctx1.triangles_comp = triangles_comp;
+ ctx1.components = connex_components;
*res = s3d_scene_view_get_aabb(s3d_view, lower, upper);
if(*res != RES_OK) goto end;
#pragma omp for schedule(dynamic)
@@ -1255,6 +1404,7 @@ group_connex_components
ASSERT(id <= ENCLOSURE_MAX__);
cc->enclosure_id = (enclosure_id_t)id;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: is outer, not processed\n", c);
}
continue;
@@ -1270,8 +1420,11 @@ group_connex_components
rrr[i] = MMIN(origin[i] - lower[i], upper[i] - origin[i]);
}
rrr[2] = upper[2] - origin[2];
- r = f3_len(rrr) + FLT_EPSILON; /* Ensure r > 0 */
- ctx0.c.ctx0.origin_component = cc->cc_id;
+ r = f3_len(rrr) * (1 + FLT_EPSILON) + FLT_EPSILON; /* Ensure r > 0 */
+ ctx0.origin_component = cc->cc_id;
+ ctx0.current_6volume = DBL_MAX;
+ ctx0.hit_dist = FLT_MAX;
+ ctx0.hit_component = COMPONENT_NULL__;
tmp_res = s3d_scene_view_closest_point(s3d_view, origin, r, &ctx0, &hit);
if(tmp_res != RES_OK) {
*res = tmp_res;
@@ -1282,20 +1435,22 @@ group_connex_components
cc->cc_group_root = CC_GROUP_ROOT_INFINITE;
cc->enclosure_id = 0;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: is part of enclosure #0\n", c);
}
continue;
}
/* Second step is to determine which component faces component #c */
- ctx1.c.ctx1.origin_component = cc->cc_id;
- ctx1.c.ctx1.current_6volume = DBL_MAX;
- ctx1.c.ctx1.hit_dist = FLT_MAX;
- ctx1.c.ctx1.hit_component = COMPONENT_NULL__;
+ ctx1.origin_component = cc->cc_id;
+ ctx1.current_6volume = DBL_MAX;
+ ctx1.hit_dist = FLT_MAX;
+ ctx1.hit_component = COMPONENT_NULL__;
/* New search radius is hit.distance + some margin to cope with numerical
* issues (and r==0 is an error) */
r = hit.distance * (1 + FLT_EPSILON) + FLT_EPSILON;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: starting search for components (R=%g) from %g %g %g\n",
c, r, SPLIT3(origin));
}
@@ -1305,18 +1460,19 @@ group_connex_components
*res = tmp_res;
continue;
}
- /* As FCTX1 filter rejects any hit, do not rely on hit but use result as
+ /* As CTX1 filter rejects any hit, do not rely on hit but use result as
* stored in ctx1 */
/* If no hit is accepted, the component is facing an infinite medium */
- if(ctx1.c.ctx1.hit_dist == FLT_MAX) {
+ if(ctx1.hit_dist == FLT_MAX) {
cc->cc_group_root = CC_GROUP_ROOT_INFINITE;
cc->enclosure_id = 0;
if(log_components) {
+ #pragma omp critical
printf("Component #%u: is part of enclosure #0\n", c);
}
continue;
}
- else if(ctx1.c.ctx1.hit_component == COMPONENT_NULL__) {
+ else if(ctx1.hit_component == COMPONENT_NULL__) {
/* The selected triangle was nearly parallel to the line of sight:
* FRONT/BACK discrimination was not reliable enough and should be done
* differently. */
@@ -1327,9 +1483,10 @@ group_connex_components
continue;
} else {
/* If hit, group this component */
- cc->cc_group_root = ctx1.c.ctx1.hit_component;
+ cc->cc_group_root = ctx1.hit_component;
ASSERT(cc->cc_group_root < cc_count);
if(log_components) {
+ #pragma omp critical
printf("Component #%u: linked to component #%u\n", c, cc->cc_group_root);
}
}
diff --git a/src/test_senc3d_bad_grouping.c b/src/test_senc3d_bad_grouping.c
@@ -580,10 +580,6 @@ main(int argc, char** argv)
OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
- /* Create a scene with the cubes.
- * The enclosures in the small cubes contain medium 0, the external enclosure
- * contains medium 2, the enclosure between the small and big cubes
- * contains medium 1. */
ctx.positions = bat_1_S_glazing_vertices;
ctx.indices = bat_1_S_glazing_triangles;
ctx.properties = bat_1_S_glazing_properties;
diff --git a/src/test_senc3d_bad_grouping2.c b/src/test_senc3d_bad_grouping2.c
@@ -0,0 +1,206 @@
+/* Copyright (C) 2018-2020, 2023, 2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses a star-cad scene that crashed. */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+#include <stdio.h>
+
+/*
+ * +--------------------------+
+ * | |
+ * | +--+ |
+ * | | | |
+ * | | | |
+ * | | | |
+ * | | | ++ |
+ * | | | ++ |
+ * | | | |
+ * | | | |
+ * | +--+ |
+ * | |
+ * +--------------------------+
+*/
+
+static const unsigned bad2_vertices_count = 24;
+static const double bad2_vertices[72] =
+{
+ 0, 10, 10,
+ 0, 0, 0,
+ 0, 0, 10,
+ 0, 10, 0,
+ 10, 10, 10,
+ 10, 0, 10,
+ 10, 0, 0,
+ 10, 10, 0,
+ 1, 9, 9,
+ 1, 1, 1,
+ 1, 1, 9,
+ 1, 9, 1,
+ 2, 9, 9,
+ 2, 1, 9,
+ 2, 1, 1,
+ 2, 9, 1,
+ 3, 5, 5,
+ 3, 4, 4,
+ 3, 4, 5,
+ 3, 5, 4,
+ 4, 5, 5,
+ 4, 4, 5,
+ 4, 4, 4,
+ 4, 5, 4,
+};
+unsigned bad2_triangles_count = 36;
+unsigned bad2_triangles[600] =
+{
+ 0, 1, 2,
+ 0, 3, 1,
+ 4, 5, 6,
+ 4, 6, 7,
+ 6, 2, 1,
+ 5, 2, 6,
+ 7, 3, 0,
+ 4, 7, 0,
+ 3, 6, 1,
+ 7, 6, 3,
+ 0, 2, 5,
+ 4, 0, 5,
+ 8, 9, 10,
+ 8, 11, 9,
+ 12, 13, 14,
+ 12, 14, 15,
+ 14, 10, 9,
+ 13, 10, 14,
+ 15, 11, 8,
+ 12, 15, 8,
+ 11, 14, 9,
+ 15, 14, 11,
+ 8, 10, 13,
+ 12, 8, 13,
+ 16, 17, 18,
+ 16, 19, 17,
+ 20, 21, 22,
+ 20, 22, 23,
+ 22, 18, 17,
+ 21, 18, 22,
+ 23, 19, 16,
+ 20, 23, 16,
+ 19, 22, 17,
+ 23, 22, 19,
+ 16, 18, 21,
+ 20, 16, 21
+};
+unsigned bad2_properties[108] =
+{
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM
+};
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned count, e;
+ const double volumes[] = { -1000, 935, 64, 1};
+ int volume_used[] = {0, 0, 0, 0};
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ ctx.positions = bad2_vertices;
+ ctx.indices = bad2_triangles;
+ ctx.properties = bad2_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE,
+ bad2_triangles_count, get_indices, get_media_from_properties,
+ bad2_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == bad2_vertices_count);
+
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == bad2_triangles_count);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 4);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ size_t i;
+ int found = 0;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ OK(senc3d_enclosure_ref_put(enclosure));
+ for(i = 0; i < sizeof(volumes)/sizeof(*volumes); i++) {
+ if(!volume_used[i] && fabs(volumes[i] - header.volume) < DBL_EPSILON) {
+ volume_used[i] = 1;
+ found = 1;
+ break;
+ }
+ }
+ if(!found) return 1;
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc3d_bad_grouping3.c b/src/test_senc3d_bad_grouping3.c
@@ -0,0 +1,212 @@
+/* Copyright (C) 2018-2020, 2023, 2024 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This test has been created using the sg3_geometry_dump_as_C_code feature
+ * of star-geometry. It uses a star-cad scene that crashed. */
+
+#include "senc3d.h"
+#include "test_senc3d_utils.h"
+
+#include <rsys/double3.h>
+
+#include <stdio.h>
+
+/*
+ * +-------------+
+ * | |
+ * | + |
+ * | /|\ |
+ * | / | \ |
+ * | + | + |
+ * | | | | |
+ * | | | | |
+ * | +--+--+ |
+ * | |
+ * +-------------+
+*/
+
+static const unsigned bad3_vertices_count = 24;
+static const double bad3_vertices[72] =
+{
+ 0, 10, 10,
+ 0, 0, 0,
+ 0, 0, 10,
+ 0, 10, 0,
+ 10, 10, 10,
+ 10, 0, 10,
+ 10, 0, 0,
+ 10, 10, 0,
+
+ 1, 5, 5,
+ 1, 1, 1,
+ 1, 1, 5,
+ 1, 5, 1,
+ 5, 5, 6,
+ 5, 1, 6,
+ 5, 1, 1,
+ 5, 5, 1,
+
+ 5, 5, 6.12, /* Duplicate, use #12 instead */
+ 5, 1, 1.14, /* Duplicate, use #14 instead */
+ 5, 1, 6.13, /* Duplicate, use #13 instead */
+ 5, 5, 1.15, /* Duplicate, use #15 instead */
+ 9, 5, 5,
+ 9, 1, 5,
+ 9, 1, 1,
+ 9, 5, 1
+};
+unsigned bad3_triangles_count = 34;
+unsigned bad3_triangles[582] =
+{
+ 0, 1, 2,
+ 0, 3, 1,
+ 4, 5, 6,
+ 4, 6, 7,
+ 6, 2, 1,
+ 5, 2, 6,
+ 7, 3, 0,
+ 4, 7, 0,
+ 3, 6, 1,
+ 7, 6, 3,
+ 0, 2, 5,
+ 4, 0, 5,
+
+ 8, 9, 10,
+ 8, 11, 9,
+ 12, 13, 14,
+ 12, 14, 15,
+ 14, 10, 9,
+ 13, 10, 14,
+ 15, 11, 8,
+ 12, 15, 8,
+ 11, 14, 9,
+ 15, 14, 11,
+ 8, 10, 13,
+ 12, 8, 13,
+
+ /* 12, 14, 13, */ /* Duplicate */
+ /* 12, 15, 14, */ /* Duplicate */
+ 20, 21, 22,
+ 20, 22, 23,
+ 22, 13, 14,
+ 21, 13, 22,
+ 23, 15, 12,
+ 20, 23, 12,
+ 15, 22, 14,
+ 23, 22, 15,
+ 12, 13, 21,
+ 20, 12, 21
+};
+unsigned bad3_properties[102] =
+{
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ /* SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, */
+ /* SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, */
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM,
+ SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM, SENC3D_UNSPECIFIED_MEDIUM
+};
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc3d_device* dev = NULL;
+ struct senc3d_scene* scn = NULL;
+ struct context ctx = CONTEXT_NULL__;
+ unsigned count, e;
+ const double volumes[] = { -1000, 856, 72, 72};
+ int volume_used[] = {0, 0, 0, 0};
+ (void)argc, (void)argv;
+
+ OK(mem_init_proxy_allocator(&allocator, &mem_default_allocator));
+ OK(senc3d_device_create(NULL, &allocator, SENC3D_NTHREADS_DEFAULT, 1, &dev));
+
+ /* Create a scene with the cubes.
+ * The enclosures in the small cubes contain medium 0, the external enclosure
+ * contains medium 2, the enclosure between the small and big cubes
+ * contains medium 1. */
+ ctx.positions = bad3_vertices;
+ ctx.indices = bad3_triangles;
+ ctx.properties = bad3_properties;
+ OK(senc3d_scene_create(dev,
+ SENC3D_CONVENTION_NORMAL_BACK | SENC3D_CONVENTION_NORMAL_OUTSIDE,
+ bad3_triangles_count, get_indices, get_media_from_properties,
+ bad3_vertices_count, get_position, &ctx, &scn));
+
+ OK(senc3d_scene_get_vertices_count(scn, &count));
+ CHK(count == bad3_vertices_count);
+
+ OK(senc3d_scene_get_triangles_count(scn, &count));
+ CHK(count == bad3_triangles_count);
+
+ OK(senc3d_scene_get_enclosure_count(scn, &count));
+ CHK(count == 4);
+ FOR_EACH(e, 0, count) {
+ struct senc3d_enclosure* enclosure;
+ struct senc3d_enclosure_header header;
+ size_t i;
+ int found = 0;
+ OK(senc3d_scene_get_enclosure(scn, e, &enclosure));
+ OK(senc3d_enclosure_get_header(enclosure, &header));
+ OK(senc3d_enclosure_ref_put(enclosure));
+ for(i = 0; i < sizeof(volumes)/sizeof(*volumes); i++) {
+ if(!volume_used[i] && fabs(volumes[i] - header.volume) < DBL_EPSILON) {
+ volume_used[i] = 1;
+ found = 1;
+ break;
+ }
+ }
+ if(!found) return 1;
+ }
+
+ OK(senc3d_scene_ref_put(scn));
+ OK(senc3d_device_ref_put(dev));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}