commit 478a65339f787d29f0942f25e842cf349dc75882
parent 6173ec407affbda1fde1c2f1637835816e9105db
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 5 Oct 2018 12:19:50 +0200
Merge branch 'release_0.2'
Diffstat:
28 files changed, 2680 insertions(+), 1392 deletions(-)
diff --git a/README.md b/README.md
@@ -1,29 +1,54 @@
-# StarEnclosures
+StarEnclosures
+==============
-The purpose of this library is to extract enclosures from raw geometry. An
-enclosure is a set of triangles enclosing a given volume. The library manages
-vertices and triangles duplicates, easing the scene definition process. It also
-checks some coherency properties, most noticeably the enclosed medium unicity.
+Overview
+--------
-## How to build
+The purpose of Star-enclosures is to extract enclosures from raw
+geometry. An enclosure is a set of triangles enclosing a given volume.
+The enclosure notion extends to open enclosures for which there is no
+inside or outside. For every detected enclosure, the library provides
+the set of involved triangle sides as well as the set of involved media
+and a few metrics (number of triangles, ...).
+
+The library allows geometry to be added by subsets of triangles and
+manages vertices and triangles duplicates as long as the duplicate
+information is coherent, easing the scene definition process.
+
+Also the convention regarding FRONT/BACK sides for input triangles as
+well as the convention regarding normals' orientation for output
+triangles can be set.
+
+How to build
+------------
StarEnclosures relies on the [CMake](http://www.cmake.org) and the
-[RCMake](https://gitlab.com/vaplv/rcmake/) package to build. It also depends on
-the [RSys](https://gitlab.com/vaplv/rsys/) and
-[Star-3D](https://gitlab.com/meso-star/star-3d/) and
-[Star-SP](https://gitlab.com/meso-star/star-sp/) libraries, the later being
-necessary only when building tests.
+[RCMake](https://gitlab.com/vaplv/rcmake/) package to build. It also
+depends on the [RSys](https://gitlab.com/vaplv/rsys/) and
+[Star-3D](https://gitlab.com/meso-star/star-3d/) libraries. Additionaly,
+two more libraries are needed to build tests:
+[Star-SP](https://gitlab.com/meso-star/star-sp/) and
+[Star-3DUT](https://gitlab.com/meso-star/star-3dut/).
+
+First ensure that CMake and a C compiler that implements the OpenMP 1.2
+are installed on your system. Then install the RCMake package as well as
+all the aforementioned prerequisites. Finally generate the project from
+the `cmake/CMakeLists.txt` file by appending to the `CMAKE_PREFIX_PATH`
+variable the install directories of its dependencies.
+
+Release notes
+-------------
-First ensure that CMake and a C compiler are installed on your system. Then
-install the RCMake package as well as all the aforementioned prerequisites.
-Finally generate the project from the `cmake/CMakeLists.txt` file by appending
-to the `CMAKE_PREFIX_PATH` variable the install directories of its
-dependencies.
+### Version 0.2
-## License
+- Add the support of enclosures with multiple media.
+- Allow to set the FRONT/BACK convention for input triangles.
+- Allow to set the normal convention for output triangles.
-StarEnclosures is Copyright (C) |Meso|Star> 2018 (<contact@meso-star.com>).
-It is free software released under the GPLv3+ license. You are welcome to
-redistribute it under certain conditions; refer to the COPYING files for
-details.
+License
+-------
+StarEnclosures is Copyright (C) |Meso|Star> 2018
+(<contact@meso-star.com>). It is free software released under the GPLv3+
+license. You are welcome to redistribute it under certain conditions;
+refer to the COPYING files for details.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -26,6 +26,7 @@ option(NO_TEST "Do not build tests" OFF)
find_package(RCMake 0.4 REQUIRED)
find_package(Star3D 0.5 REQUIRED)
find_package(RSys 0.6.1 REQUIRED)
+find_package(OpenMP 2.0 REQUIRED)
if(NOT NO_TEST)
find_package(StarSP 0.7 REQUIRED)
@@ -36,11 +37,17 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
include(rcmake_runtime)
+if(NO_TEST)
+rcmake_append_runtime_dirs(_runtime_dirs RSys Star3D)
+else()
+rcmake_append_runtime_dirs(_runtime_dirs RSys StarSP Star3DUT Star3D)
+endif()
+
################################################################################
# Configure and define targets
################################################################################
set(VERSION_MAJOR 0)
-set(VERSION_MINOR 1)
+set(VERSION_MINOR 2)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
@@ -81,14 +88,16 @@ target_link_libraries(senc RSys Star3D)
set_target_properties(senc PROPERTIES
DEFINE_SYMBOL SENC_SHARED_BUILD
VERSION ${VERSION}
+ COMPILE_FLAGS ${OpenMP_C_FLAGS}
SOVERSION ${VERSION_MAJOR})
rcmake_copy_runtime_libraries(senc)
if(CMAKE_COMPILER_IS_GNUCC)
- set_target_properties(senc PROPERTIES LINK_FLAGS "-lm")
+ set_target_properties(senc PROPERTIES LINK_FLAGS "${OpenMP_C_FLAGS}")
+ target_link_libraries(senc m)
endif()
-rcmake_setup_devel(senc StarEnc ${VERSION} senc_version.h)
+rcmake_setup_devel(senc StarEnc ${VERSION} star/senc_version.h)
################################################################################
# Add tests
@@ -117,11 +126,14 @@ if(NOT NO_TEST)
new_test(test_senc_descriptor)
new_test(test_senc_device)
new_test(test_senc_enclosure)
+ new_test(test_senc_inconsistant_cube)
+ new_test(test_senc_many_enclosures)
new_test(test_senc_many_triangles)
new_test(test_senc_sample_enclosure)
new_test(test_senc_scene)
target_link_libraries(test_senc_sample_enclosure StarSP)
+ target_link_libraries(test_senc_many_enclosures Star3DUT)
target_link_libraries(test_senc_many_triangles Star3DUT)
rcmake_copy_runtime_libraries(test_senc_sample_enclosure)
rcmake_copy_runtime_libraries(test_senc_many_triangles)
@@ -134,5 +146,5 @@ install(TARGETS senc
ARCHIVE DESTINATION bin
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
-install(FILES ${SENC_FILES_INC_API} DESTINATION include/)
+install(FILES ${SENC_FILES_INC_API} DESTINATION include/star)
install(FILES ${SENC_FILES_DOC} DESTINATION share/doc/star-enc)
diff --git a/src/senc.h b/src/senc.h
@@ -57,7 +57,7 @@ struct senc_scene;
struct senc_enclosure;
/* Enclosure header type */
-struct enclosure_header {
+struct senc_enclosure_header {
/* The ID of the enclosure; 0, 1, ... */
unsigned enclosure_id;
/* Number of triangles; a triangle can be accounted for twice, once by side */
@@ -66,24 +66,69 @@ struct 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;
};
+/* We consider the geometrical normal Ng to a triangle V0 V1 V2
+ * that verifies "(V0, V0V1, V0V2, Ng) is a direct system"
+ * (right-handed system).
+ *
+ * The user can set the convention used to determine which side of
+ * a triangle is to be considered front/back by using the flags :
+ * SENC_CONVENTION_NORMAL_FRONT => Ng points toward the front side,
+ * SENC_CONVENTION_NORMAL_BACK => Ng points toward the back side.
+ *
+ * Additionaly the user can set the convention used to output enclosures
+ * so that Ng points toward the enclosure or on the opposite direction
+ * (for a closed enclosure Ng points toward the inside or toward the outside)
+ * by using the flags :
+ * SENC_CONVENTION_NORMAL_INSIDE => Ng points toward the enclosure,
+ * SENC_CONVENTION_NORMAL_OUTSIDE => Ng points to the opposite of the enclosure.
+ *
+ * Note that normals in output data can be opposite to normals in input data
+ * (vertices are then given in reverse order).
+ *
+ * Also note that both sides of a triangle can be part of the same enclosure;
+ * in this case the 2 sides will be given with opposite Ng (meaning they
+ * will be given with opposite vertices order).
+ */
+enum senc_convention {
+ /*
+ * Convention regarding FRONT/BACK sides in input data
+ */
+
+ /* Geometrical normals point toward the front side */
+ SENC_CONVENTION_NORMAL_FRONT = BIT(0),
+ /* Geometrical normals point toward the back side */
+ SENC_CONVENTION_NORMAL_BACK = BIT(1),
+
+ /*
+ * Convention regarding geometrical normals in output data
+ */
+
+ /* Geometrical normals point toward the enclosure */
+ SENC_CONVENTION_NORMAL_INSIDE = BIT(2),
+ /* Geometrical normals point to the opposite of the enclosure */
+ SENC_CONVENTION_NORMAL_OUTSIDE = BIT(3)
+};
+
BEGIN_DECLS
/*******************************************************************************
* StarEnclosures device. It is an handle toward the StarEnc library.
* It manages the lib resources.
+ * If provided, the allocator has to be suitable for parallel high frequency
+ * allocations. As a consequence, a rsys proxy allocator should be avoided.
******************************************************************************/
SENC_API res_T
senc_device_create
(struct logger* logger, /* May be NULL <=> use default logger */
struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
- const unsigned nthreads_hint, /* UNUSED */
+ const unsigned nthreads_hint,
const int verbose,
struct senc_device** device);
@@ -102,19 +147,23 @@ senc_device_ref_put
SENC_API res_T
senc_scene_create
(struct senc_device* device,
- const unsigned media_count,
+ const enum senc_convention convention,
struct senc_scene** scene);
/* Add a new set of vertices and triangles to the scene.
* Vertices can be duplicates and are deduplicated on the fly.
* Triangles can be duplicates as long as they constantly define the same
- * medium on both sides (or an error will be reported) and are deduplicated. */
+ * medium on both sides (or an error will be reported) and are deduplicated.
+ * When deduplicating triangles, the first occurence is kept (with it original
+ * global_id). */
SENC_API res_T
senc_scene_add_geometry
(struct senc_scene* scene,
const unsigned triangles_count,
void(*indices)(const unsigned itri, unsigned ids[3], void* context),
void(*media)(const unsigned itri, unsigned med[2], void* context),
+ void(*global_id) /* May be NULL <=> use triangle rank */
+ (const unsigned itri, unsigned* gid, void* context),
const unsigned vertices_count,
void(*position)(const unsigned ivert, double pos[3], void* context),
void* context);
@@ -125,6 +174,31 @@ senc_scene_analyze
struct senc_descriptor** descriptor);
SENC_API res_T
+senc_scene_get_convention
+ (const struct senc_scene* scene,
+ enum senc_convention* convention);
+
+SENC_API res_T
+senc_scene_get_triangles_count
+ (const struct senc_scene* scene,
+ unsigned* count);
+
+SENC_API res_T
+senc_scene_get_unique_triangles_count
+ (const struct senc_scene* scene,
+ unsigned* count);
+
+SENC_API res_T
+senc_scene_get_vertices_count
+ (const struct senc_scene* scene,
+ unsigned* count);
+
+SENC_API res_T
+senc_scene_get_unique_vertices_count
+ (const struct senc_scene* scene,
+ unsigned* count);
+
+SENC_API res_T
senc_scene_ref_get
(struct senc_scene* scene);
@@ -136,17 +210,35 @@ senc_scene_ref_put
* StarEnclosures descriptor. It is an handle toward an analyze result.
******************************************************************************/
SENC_API res_T
+senc_descriptor_get_max_medium
+ (const struct senc_descriptor* descriptor,
+ unsigned* max_medium_id);
+
+SENC_API res_T
senc_descriptor_get_enclosure_count
(const struct senc_descriptor* descriptor,
unsigned* count);
SENC_API res_T
+senc_descriptor_get_enclosure_count_by_medium
+ (const struct senc_descriptor* descriptor,
+ const unsigned imed, /* Must be in [0 max_medium_id] */
+ unsigned* count);
+
+SENC_API res_T
senc_descriptor_get_enclosure
(struct senc_descriptor* descriptor,
const unsigned idx,
struct senc_enclosure** enclosure);
SENC_API res_T
+senc_descriptor_get_enclosure_by_medium
+ (struct senc_descriptor* descriptor,
+ const unsigned imed,
+ const unsigned idx,
+ struct senc_enclosure** enclosure);
+
+SENC_API res_T
senc_descriptor_get_global_triangles_count
(const struct senc_descriptor* descriptor,
unsigned* count); /* Number of unique triangles. */
@@ -181,6 +273,12 @@ senc_descriptor_get_global_triangle_enclosures
unsigned enclosures[2]);
SENC_API res_T
+senc_descriptor_get_global_triangle_global_id
+ (const struct senc_descriptor* descriptor,
+ const unsigned itri,
+ unsigned* gid);
+
+SENC_API res_T
senc_descriptor_ref_get
(struct senc_descriptor* descriptor);
@@ -196,13 +294,13 @@ senc_descriptor_ref_put
* case the 2 occurences of the triangle have reversed vertices order and
* unique_triangle_count and triangle_count differ.
* By-index API accesses of triangles (or properties) visit unique triangles
- * for indexes in the [0 unique_triangle_count[ and back-faces of the
+ * for indexes in the [0 unique_triangle_count[ range and back-faces of the
* doubly-listed triangles in the [unique_triangle_count triangle_count[ range.
******************************************************************************/
SENC_API res_T
senc_enclosure_get_header
(const struct senc_enclosure* enclosure,
- const struct enclosure_header** header);
+ struct senc_enclosure_header* header);
SENC_API res_T
senc_enclosure_get_triangle
@@ -223,6 +321,18 @@ senc_enclosure_get_triangle_media
unsigned medium[2]);
SENC_API res_T
+senc_enclosure_get_triangle_global_id
+ (const struct senc_enclosure* enclosure,
+ const unsigned itri,
+ 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
@@ -36,6 +36,7 @@ descriptor_release(ref_T * ref)
scn = desc->scene;
darray_triangle_enc_release(&desc->triangles_enc);
darray_enclosure_release(&desc->enclosures);
+ darray_enc_ids_array_release(&desc->enc_ids_array_by_medium);
MEM_RM(scn->dev->allocator, desc);
SENC(scene_ref_put(scn));
@@ -48,21 +49,29 @@ struct senc_descriptor*
descriptor_create(struct senc_scene* scn)
{
struct senc_descriptor* desc;
+ res_T res = RES_OK;
ASSERT(scn);
desc = MEM_CALLOC(scn->dev->allocator, 1, sizeof(struct senc_descriptor));
if(desc) {
desc->scene = scn;
SENC(scene_ref_get(desc->scene));
+ ref_init(&desc->ref);
darray_triangle_enc_init(scn->dev->allocator, &desc->triangles_enc);
- /* Enclosure 0 is always defined for infinite */
darray_enclosure_init(scn->dev->allocator, &desc->enclosures);
- darray_enclosure_resize(&desc->enclosures, 1);
+ darray_enc_ids_array_init(scn->dev->allocator,
+ &desc->enc_ids_array_by_medium);
+ OK(darray_enc_ids_array_resize(&desc->enc_ids_array_by_medium, scn->nmeds));
+ /* Enclosure 0 is always defined for infinite */
+ OK(darray_enclosure_resize(&desc->enclosures, 1));
desc->enclosures_count = 1;
desc->triangle_count = scn->nutris;
desc->vertices_count = scn->nuverts;
- ref_init(&desc->ref);
}
+end:
return desc;
+error:
+ if(desc) SENC(descriptor_ref_put(desc));
+ goto end;
}
struct mem_allocator*
@@ -76,6 +85,16 @@ struct mem_allocator*
* Exported functions
******************************************************************************/
res_T
+senc_descriptor_get_max_medium
+ (const struct senc_descriptor* desc, unsigned* max_medium_id)
+{
+ if(!desc || !max_medium_id) return RES_BAD_ARG;
+ ASSERT(desc->scene->nmeds < UINT_MAX); /* API type */
+ *max_medium_id = (unsigned)desc->scene->nmeds - 1;
+ return RES_OK;
+}
+
+res_T
senc_descriptor_get_enclosure_count
(const struct senc_descriptor* desc, unsigned* count)
{
@@ -83,11 +102,31 @@ senc_descriptor_get_enclosure_count
if(!desc || !count) return RES_BAD_ARG;
tmp = darray_enclosure_size_get(&desc->enclosures);
ASSERT(tmp < UINT_MAX); /* API type */
+ ASSERT(desc->enclosures_count == tmp);
*count = (unsigned)tmp;
return RES_OK;
}
res_T
+senc_descriptor_get_enclosure_count_by_medium
+ (const struct senc_descriptor* desc,
+ const unsigned imed,
+ unsigned* count)
+{
+ size_t tmp;
+ const struct darray_enc_id* enc_ids;
+ if(!desc || !count || imed >= desc->scene->nmeds)
+ return RES_BAD_ARG;
+ ASSERT(darray_enc_ids_array_size_get(&desc->enc_ids_array_by_medium)
+ == desc->scene->nmeds);
+ enc_ids = darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + imed;
+ tmp = darray_enc_id_size_get(enc_ids);
+ ASSERT(tmp < UINT_MAX); /* API type */
+ *count = (unsigned)tmp;
+ return RES_OK;
+}
+
+FINLINE res_T
senc_descriptor_get_enclosure
(struct senc_descriptor* desc,
const unsigned idx,
@@ -96,14 +135,30 @@ 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;
}
res_T
+senc_descriptor_get_enclosure_by_medium
+ (struct senc_descriptor* desc,
+ const unsigned imed,
+ const unsigned idx,
+ struct senc_enclosure** out_enc)
+{
+ const struct darray_enc_id* enc_ids;
+ unsigned index;
+ if(!desc || imed >= desc->scene->nmeds || !out_enc) return RES_BAD_ARG;
+ enc_ids =
+ darray_enc_ids_array_cdata_get(&desc->enc_ids_array_by_medium) + imed;
+ if(idx >= darray_enc_id_size_get(enc_ids)) return RES_BAD_ARG;
+ index = darray_enc_id_cdata_get(enc_ids)[idx];
+ return senc_descriptor_get_enclosure(desc, index, out_enc);
+}
+
+res_T
senc_descriptor_get_global_triangles_count
(const struct senc_descriptor* desc,
unsigned* count)
@@ -175,7 +230,9 @@ senc_descriptor_get_global_triangle_media
return RES_BAD_ARG;
trg = darray_triangle_in_cdata_get(&desc->scene->triangles_in) + itri;
FOR_EACH(i, 0, 2) {
+#if (UINT_MAX < MEDIUM_MAX__)
ASSERT(trg->medium[i] < UINT_MAX);
+#endif
media[i] = (unsigned)trg->medium[i]; /* Back to API type */
}
return RES_OK;
@@ -194,13 +251,30 @@ senc_descriptor_get_global_triangle_enclosures
return RES_BAD_ARG;
trg = darray_triangle_enc_cdata_get(&desc->triangles_enc) + itri;
FOR_EACH(i, 0, 2) {
+#if (UINT_MAX < ENCLOSURE_MAX__)
ASSERT(trg->enclosure[i] < UINT_MAX);
+#endif
enclosures[i] = (unsigned)trg->enclosure[i]; /* Back to API type */
}
return RES_OK;
}
res_T
+senc_descriptor_get_global_triangle_global_id
+ (const struct senc_descriptor* desc,
+ const unsigned itri,
+ unsigned* gid)
+{
+ const struct triangle_in* trg;
+ if(!gid || !desc
+ || itri >= darray_triangle_in_size_get(&desc->scene->triangles_in))
+ return RES_BAD_ARG;
+ trg = darray_triangle_in_cdata_get(&desc->scene->triangles_in) + itri;
+ *gid = trg->global_id;
+ return RES_OK;
+}
+
+res_T
senc_descriptor_ref_get(struct senc_descriptor* desc)
{
if(!desc) return RES_BAD_ARG;
diff --git a/src/senc_descriptor_c.h b/src/senc_descriptor_c.h
@@ -31,7 +31,6 @@ struct triangle_comp {
component_id_t component[2];
};
-#ifndef NDEBUG
static void
triangle_comp_init(struct mem_allocator* alloc, struct triangle_comp* trg) {
int i;
@@ -39,15 +38,14 @@ triangle_comp_init(struct mem_allocator* alloc, struct triangle_comp* trg) {
ASSERT(trg);
FOR_EACH(i, 0, 2) trg->component[i] = COMPONENT_NULL__;
}
-#define DARRAY_FUNCTOR_INIT triangle_comp_init
-#endif
#define DARRAY_NAME triangle_comp
#define DARRAY_DATA struct triangle_comp
+#define DARRAY_FUNCTOR_INIT triangle_comp_init
#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];
};
@@ -55,7 +53,7 @@ struct triangle_enc {
static void
triangle_enc_init(struct mem_allocator* alloc, struct triangle_enc* trg) {
int i;
- (void) alloc;
+ (void)alloc;
ASSERT(trg);
FOR_EACH(i, 0, 2) trg->enclosure[i] = ENCLOSURE_NULL__;
}
@@ -74,6 +72,18 @@ triangle_enc_init(struct mem_allocator* alloc, struct triangle_enc* trg) {
#define DARRAY_FUNCTOR_COPY_AND_RELEASE enclosure_data_copy_and_release
#include <rsys/dynamic_array.h>
+#define DARRAY_NAME enc_id
+#define DARRAY_DATA enclosure_id_t
+#include <rsys/dynamic_array.h>
+
+#define DARRAY_NAME enc_ids_array
+#define DARRAY_DATA struct darray_enc_id
+#define DARRAY_FUNCTOR_INIT darray_enc_id_init
+#define DARRAY_FUNCTOR_COPY darray_enc_id_copy
+#define DARRAY_FUNCTOR_RELEASE darray_enc_id_release
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_enc_id_copy_and_release
+#include <rsys/dynamic_array.h>
+
struct senc_descriptor {
struct senc_scene* scene;
enclosure_id_t enclosures_count;
@@ -81,6 +91,7 @@ struct senc_descriptor {
struct darray_triangle_enc triangles_enc;
/* Store enclosures */
struct darray_enclosure enclosures;
+ struct darray_enc_ids_array enc_ids_array_by_medium;
trg_id_t triangle_count;
vrtx_id_t vertices_count;
diff --git a/src/senc_device.c b/src/senc_device.c
@@ -19,6 +19,8 @@
#include <rsys/logger.h>
#include <rsys/mem_allocator.h>
+#include <omp.h>
+
/*******************************************************************************
* Helper functions
******************************************************************************/
@@ -104,6 +106,8 @@ senc_device_create
dev->logger = log;
dev->allocator = allocator;
dev->verbose = verbose;
+ /* Cannot use int args for MMIN here as default is -1 */
+ dev->nthreads = (int)MMIN(nthreads_hint, (unsigned)omp_get_num_procs());
ref_init(&dev->ref);
exit:
diff --git a/src/senc_device_c.h b/src/senc_device_c.h
@@ -19,10 +19,6 @@
#include <rsys/free_list.h>
#include <rsys/ref_count.h>
-#define OK(expr)\
- res = expr;\
- if(res != RES_OK) goto error;
-
struct name { FITEM; };
#define FITEM_TYPE name
#include <rsys/free_list.h>
@@ -31,6 +27,7 @@ struct senc_device {
struct logger* logger;
struct mem_allocator* allocator;
int verbose;
+ int nthreads;
ref_T ref;
};
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;
@@ -66,10 +68,10 @@ enclosure_create
res_T
senc_enclosure_get_header
(const struct senc_enclosure* enclosure,
- const struct enclosure_header** header)
+ struct senc_enclosure_header* header)
{
if(!enclosure || !header) return RES_BAD_ARG;
- *header = &enclosure->data->header;
+ *header = enclosure->data->header;
return RES_OK;
}
@@ -100,15 +102,19 @@ senc_enclosure_get_vertex
const unsigned ivert,
double coord[3])
{
- const union double3* positions;
if(!enclosure || !coord
- || ivert >= enclosure->data->header.vertices_count)
+ || ivert >= enclosure->data->header.vertices_count) {
return RES_BAD_ARG;
- ASSERT(darray_position_size_get(&enclosure->data->vertices)
- == enclosure->data->header.vertices_count);
- positions = darray_position_cdata_get(&enclosure->data->vertices);
- d3_set(coord, positions[ivert].vec);
- return RES_OK;
+ } else {
+ const vrtx_id_t idx
+ = darray_vrtx_id_cdata_get(&enclosure->data->vertices)[ivert];
+ const union double3* positions
+ = darray_position_cdata_get(&enclosure->desc->scene->vertices);
+ ASSERT(darray_vrtx_id_size_get(&enclosure->data->vertices)
+ == enclosure->data->header.vertices_count);
+ d3_set(coord, positions[idx].vec);
+ return RES_OK;
+ }
}
res_T
@@ -126,13 +132,47 @@ senc_enclosure_get_triangle_media
== enclosure->data->header.triangle_count);
triangle = darray_triangle_in_cdata_get(&enclosure->data->sides) + itri;
FOR_EACH(i, 0, 2) {
+#if (UINT_MAX < MEDIUM_MAX__)
ASSERT(triangle->medium[i] < UINT_MAX);
+#endif
medium[i] = (unsigned)triangle->medium[i]; /* Back to API type */
}
return RES_OK;
}
res_T
+senc_enclosure_get_triangle_global_id
+ (const struct senc_enclosure* enclosure,
+ const unsigned itri,
+ unsigned* gid)
+{
+ const struct triangle_in* triangle;
+ if(!enclosure || !gid
+ || itri >= enclosure->data->header.triangle_count)
+ return RES_BAD_ARG;
+ ASSERT(darray_triangle_in_size_get(&enclosure->data->sides)
+ == enclosure->data->header.triangle_count);
+ triangle = darray_triangle_in_cdata_get(&enclosure->data->sides) + itri;
+ *gid = triangle->global_id;
+ return RES_OK;
+}
+
+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,68 +18,178 @@
#include <rsys/rsys.h>
#include <rsys/ref_count.h>
+#include <rsys/hash_table.h>
+#include <rsys/dynamic_array.h>
+
+/* unsigned char array with init to zero */
+static FINLINE void
+zero_init_uchar
+ (struct mem_allocator* alloc, unsigned char* data)
+{
+ ASSERT(data); (void) alloc;
+ *data = 0;
+}
+#define DARRAY_FUNCTOR_INIT zero_init_uchar
+#include <rsys/dynamic_array_uchar.h>
#include "senc.h"
#include "senc_scene_c.h"
+#include "senc_internal_types.h"
+
+#include <limits.h>
static void
-init_header(struct enclosure_header* header)
+init_header(struct senc_enclosure_header* header)
{
ASSERT(header);
header->enclosure_id = ENCLOSURE_NULL__;
header->triangle_count = 0;
header->unique_triangle_count = 0;
header->vertices_count = 0;
- header->enclosed_medium = MEDIUM_NULL__;
+ header->enclosed_media_count = 0;
header->is_infinite = CHAR_MAX;
}
+#define DARRAY_NAME media
+#define DARRAY_DATA medium_id_t
+#include <rsys/dynamic_array.h>
+
+static FINLINE res_T
+bool_array_of_media_merge
+ (struct darray_uchar* dst,
+ const unsigned char* src,
+ const medium_id_t sz)
+{
+ res_T res = RES_OK;
+ medium_id_t i;
+ unsigned char* data_dst;
+
+ ASSERT(src && dst);
+
+ OK(darray_uchar_resize(dst, sz));
+ data_dst = darray_uchar_data_get(dst);
+ ASSERT(sz <= MEDIUM_MAX__);
+ if(res != RES_OK) goto error;
+ FOR_EACH(i, 0, sz) {
+ if(!src[i]) continue;
+ data_dst[i] = 1;
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
+static FINLINE res_T
+bool_array_of_media_to_darray_media
+ (struct darray_media* dst,
+ struct darray_uchar* src)
+{
+ res_T res = RES_OK;
+ medium_id_t i;
+ size_t sz;
+ const unsigned char* data;
+
+ ASSERT(src && dst);
+
+ data = darray_uchar_cdata_get(src);
+ sz = darray_uchar_size_get(src);
+ ASSERT(sz <= MEDIUM_MAX__);
+ darray_media_clear(dst);
+ if(res != RES_OK) goto error;
+ FOR_EACH(i, 0, (medium_id_t) sz) {
+ if(!data[i]) continue;
+ res = darray_media_push_back(dst, &i);
+ if(res != RES_OK) goto error;
+ }
+end:
+ return res;
+error:
+ goto end;
+}
+
struct enclosure_data {
- struct enclosure_header header;
+ struct senc_enclosure_header header;
/* Same triangle can appear twice if both sides */
struct darray_triangle_in sides;
- struct darray_position vertices;
+ /* Index of vertices in scene's unique vertices */
+ struct darray_vrtx_id vertices;
+ /* List of the enclosed media */
+ struct darray_uchar tmp_enclosed_media;
+ struct darray_media enclosed_media;
+ /* Number of components involved in this enclosure */
+ component_id_t cc_count;
+ /* Linked list of the components */
+ component_id_t first_component;
+ /* Range of triangles member of the enclosure */
+ struct side_range side_range;
+ /* Counts */
+ side_id_t side_count;
};
static FINLINE void
enclosure_data_init(struct mem_allocator* alloc, struct enclosure_data* enc) {
ASSERT(enc);
init_header(&enc->header);
+ enc->cc_count = 0;
+ enc->first_component = COMPONENT_NULL__;
+ enc->side_range.first = SIDE_NULL__;
+ enc->side_range.last = 0;
+ enc->side_count = 0;
darray_triangle_in_init(alloc, &enc->sides);
- darray_position_init(alloc, &enc->vertices);
+ darray_vrtx_id_init(alloc, &enc->vertices);
+ darray_uchar_init(alloc, &enc->tmp_enclosed_media);
+ darray_media_init(alloc, &enc->enclosed_media);
}
static FINLINE res_T
enclosure_data_copy
-(struct enclosure_data* dst,
- const struct enclosure_data* src)
+ (struct enclosure_data* dst,
+ const struct enclosure_data* src)
{
res_T res = RES_OK;
ASSERT(src && dst);
dst->header = src->header;
- res = darray_triangle_in_copy(&dst->sides, &src->sides);
- if(res != RES_OK) return res;
- return darray_position_copy(&dst->vertices, &src->vertices);
+ dst->cc_count = src->cc_count;
+ dst->first_component = src->first_component;
+ dst->side_range = src->side_range;
+ dst->side_count = src->side_count;
+ OK(darray_triangle_in_copy(&dst->sides, &src->sides));
+ OK(darray_vrtx_id_copy(&dst->vertices, &src->vertices));
+ OK(darray_uchar_copy(&dst->tmp_enclosed_media, &src->tmp_enclosed_media));
+ OK(darray_media_copy(&dst->enclosed_media, &src->enclosed_media));
+error:
+ return res;
}
static FINLINE void
enclosure_data_release(struct enclosure_data* n) {
ASSERT(n);
darray_triangle_in_release(&n->sides);
- darray_position_release(&n->vertices);
+ darray_vrtx_id_release(&n->vertices);
+ darray_uchar_release(&n->tmp_enclosed_media);
+ darray_media_release(&n->enclosed_media);
}
static FINLINE res_T
enclosure_data_copy_and_release
-(struct enclosure_data* dst,
- struct enclosure_data* src)
+ (struct enclosure_data* dst,
+ struct enclosure_data* src)
{
res_T res = RES_OK;
ASSERT(src && dst);
dst->header = src->header;
- res = darray_triangle_in_copy_and_release(&dst->sides, &src->sides);
- if(res != RES_OK) return res;
- return darray_position_copy_and_release(&dst->vertices, &src->vertices);
+ dst->cc_count = src->cc_count;
+ dst->first_component = src->first_component;
+ dst->side_range = src->side_range;
+ dst->side_count = src->side_count;
+ OK(darray_triangle_in_copy_and_release(&dst->sides, &src->sides));
+ OK(darray_vrtx_id_copy_and_release(&dst->vertices, &src->vertices));
+ OK(darray_uchar_copy_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;
}
#endif /* SENC_ENCLOSURE_DATA_H */
diff --git a/src/senc_internal_types.h b/src/senc_internal_types.h
@@ -20,6 +20,29 @@
#include <stdint.h>
+/* Utility macros */
+#ifdef NDEBUG
+#define OK2(Expr)\
+ if((tmp_res = (Expr)) != RES_OK) goto tmp_error;
+
+#define OK(Expr)\
+ if((res = (Expr)) != RES_OK) goto error;
+#else
+#define OK2(Expr)\
+ if((tmp_res = (Expr)) != RES_OK) {\
+ fprintf(stderr, "%s: error code set to %d at line %d\n", FUNC_NAME,\
+ tmp_res, __LINE__);\
+ goto tmp_error;\
+ }
+
+#define OK(Expr)\
+ if((res = (Expr)) != RES_OK) {\
+ fprintf(stderr, "%s: error code set to %d at line %d\n", FUNC_NAME,\
+ res, __LINE__);\
+ goto error;\
+ }
+#endif
+
/* Side IDs are uint32_t */
typedef uint32_t side_id_t;
#define SIDE_MAX__ (UINT32_MAX-1)
@@ -44,21 +67,73 @@ typedef vrtx_id_t edge_id_t;
#define EDGE_MAX__ VRTX_MAX__
#define EDGE_NULL__ VRTX_NULL__
-/* Medium IDs are internally uint16_t */
+/* Medium IDs are internally uint32_t */
/* Should nnot be larger than unsigned, as the API uses it. */
-typedef uint16_t medium_id_t;
-#define MEDIUM_MAX__ (UINT16_MAX-1)
-#define MEDIUM_NULL__ UINT16_MAX
+typedef uint32_t medium_id_t;
+#define MEDIUM_MAX__ INT32_MAX
+#define MEDIUM_NULL__ UINT32_MAX
-/* Enclosure IDs are internally uint16_t */
+/* Enclosure IDs are internally uint32_t */
/* Cannot be larger than unsigned, as the API uses it. */
-typedef uint16_t enclosure_id_t;
-#define ENCLOSURE_MAX__ (UINT16_MAX-1)
-#define ENCLOSURE_NULL__ UINT16_MAX
+typedef uint32_t enclosure_id_t;
+#define ENCLOSURE_MAX__ UINT32_MAX
+#define ENCLOSURE_NULL__ UINT32_MAX
/* 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 {
+ FLAG_FRONT = BIT(0),
+ FLAG_BACK = BIT(1)
+};
+
+/* This one is used as an index to arrays */
+enum side_id {
+ SIDE_FRONT = 0,
+ SIDE_BACK = 1
+};
+
+/* Utility macros */
+static FINLINE trg_id_t
+TRGSIDE_2_TRG(side_id_t s) {
+ ASSERT(((size_t)s >> 1) <= TRG_MAX__);
+ return s >> 1;
+}
+
+static FINLINE int
+TRGSIDE_IS_FRONT(side_id_t s) {
+ return (s & 1) == 0;
+}
+
+static FINLINE enum side_id
+TRGSIDE_2_SIDE(side_id_t s) {
+ return (s & 1) ? SIDE_BACK : SIDE_FRONT;
+}
+
+static FINLINE enum side_flag
+TRGSIDE_2_SIDEFLAG(side_id_t s) {
+ return (s & 1) ? FLAG_BACK : FLAG_FRONT;
+}
+
+static FINLINE side_id_t
+TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum side_id i) {
+ ASSERT((((size_t)t << 1) | (i == SIDE_BACK)) < SIDE_MAX__);
+ ASSERT(i == SIDE_FRONT || i == SIDE_BACK);
+ return (side_id_t)((t << 1) | (i == SIDE_BACK));
+}
+
+static FINLINE side_id_t
+TRGSIDE_OPPOSITE(side_id_t s) {
+ return TRGIDxSIDE_2_TRGSIDE(TRGSIDE_2_TRG(s),
+ TRGSIDE_IS_FRONT(s) ? SIDE_BACK : SIDE_FRONT);
+}
#endif /* SENC_INTERNAL_TYPES_H */
diff --git a/src/senc_s3d_wrapper.h b/src/senc_s3d_wrapper.h
@@ -21,7 +21,7 @@
#include <rsys/rsys.h>
#include <rsys/float3.h>
-void FINLINE
+FINLINE void
senc_descriptor_get_global_indices__
(const unsigned itri,
unsigned indices[3],
@@ -31,10 +31,10 @@ senc_descriptor_get_global_indices__
res_T r;
ASSERT(indices && ctx);
r = senc_descriptor_get_global_triangle(descriptor, itri, indices);
- ASSERT(r == RES_OK);
+ ASSERT(r == RES_OK); (void)r;
}
-void FINLINE
+static FINLINE void
senc_descriptor_get_global_vertices__
(const unsigned ivert,
float coord[3],
@@ -45,11 +45,11 @@ senc_descriptor_get_global_vertices__
res_T r;
ASSERT(coord && ctx);
r = senc_descriptor_get_global_vertex(descriptor, ivert, tmp);
- ASSERT(r == RES_OK);
+ ASSERT(r == RES_OK); (void)r;
f3_set_d3(coord, tmp);
}
-void FINLINE
+FINLINE void
senc_enclosure_get_triangle__
(const unsigned itri,
unsigned indices[3],
@@ -59,10 +59,10 @@ senc_enclosure_get_triangle__
res_T r;
ASSERT(indices && ctx);
r = senc_enclosure_get_triangle(enclosure, itri, indices);
- ASSERT(r == RES_OK);
+ ASSERT(r == RES_OK); (void)r;
}
-void FINLINE
+static FINLINE void
senc_enclosure_get_vertex__
(const unsigned ivert,
float coord[3],
@@ -73,7 +73,7 @@ senc_enclosure_get_vertex__
res_T r;
ASSERT(coord && ctx);
r = senc_enclosure_get_vertex(enclosure, ivert, tmp);
- ASSERT(r == RES_OK);
+ ASSERT(r == RES_OK); (void)r;
f3_set_d3(coord, tmp);
}
diff --git a/src/senc_scene.c b/src/senc_scene.c
@@ -37,6 +37,7 @@ scene_release(ref_T * ref)
darray_position_release(&scn->vertices);
htable_vrtx_release(&scn->unique_vertices);
htable_trg_release(&scn->unique_triangles);
+ darray_side_range_release(&scn->media_use);
MEM_RM(dev->allocator, scn);
SENC(device_ref_put(dev));
}
@@ -47,13 +48,16 @@ scene_release(ref_T * ref)
res_T
senc_scene_create
(struct senc_device* dev,
- const unsigned nmeds,
+ const enum senc_convention conv,
struct senc_scene** out_scn)
{
struct senc_scene* scn = NULL;
res_T res = RES_OK;
- if(!dev || !out_scn || !nmeds || nmeds > MEDIUM_MAX__)
+ if(!dev || !out_scn
+ /* Convention must be set both regarding FRONT/BACK and INSIDE/OUTSIDE */
+ || !(conv & (SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_BACK))
+ || !(conv & (SENC_CONVENTION_NORMAL_INSIDE | SENC_CONVENTION_NORMAL_OUTSIDE)))
return RES_BAD_ARG;
scn = MEM_CALLOC(dev->allocator, 1, sizeof(struct senc_scene));
@@ -65,16 +69,18 @@ senc_scene_create
ref_init(&scn->ref);
SENC(device_ref_get(dev));
scn->dev = dev;
+ scn->convention = conv;
scn->ngeoms = 0;
scn->ntris = 0;
scn->nutris = 0;
- scn->nmeds = (medium_id_t)nmeds;
+ scn->nmeds = 0;
scn->nverts = 0;
scn->nuverts = 0;
darray_triangle_in_init(dev->allocator, &scn->triangles_in);
darray_position_init(dev->allocator, &scn->vertices);
htable_vrtx_init(dev->allocator, &scn->unique_vertices);
htable_trg_init(dev->allocator, &scn->unique_triangles);
+ darray_side_range_init(dev->allocator, &scn->media_use);
exit:
if(scn) *out_scn = scn;
@@ -93,6 +99,7 @@ senc_scene_add_geometry
const unsigned ntris,
void(*indices)(const unsigned itri, unsigned ids[3], void* ctx),
void(*media)(const unsigned itri, unsigned med[2], void* ctx),
+ void(*global_id)(const unsigned itri, unsigned* gid, void* context),
const unsigned nverts,
void(*position)(const unsigned ivert, double pos[3], void* ctx),
void* ctx)
@@ -132,17 +139,20 @@ senc_scene_add_geometry
p_vrtx = htable_vrtx_find(&scn->unique_vertices, &tmp);
if(p_vrtx) {
/* Duplicate vertex */
+ log_warn(scn->dev, "%s: vertex %lu is a duplicate of unique vertex %lu.\n",
+ FUNC_NAME, (unsigned long)(scn->nverts + i), (unsigned long)*p_vrtx);
+ log_warn(scn->dev, "%s: vertex %lu: (%g %g %g).\n",
+ FUNC_NAME, (unsigned long)(scn->nverts + i), SPLIT3(tmp.vec));
unique_v = *p_vrtx;
} else {
/* New vertex */
unique_v = scn->nuverts + actual_nuverts;
- res = darray_position_push_back(&scn->vertices, &tmp);
- if(res != RES_OK) goto error;
+ OK(darray_position_push_back(&scn->vertices, &tmp));
ASSERT(unique_v == htable_vrtx_size_get(&scn->unique_vertices));
OK(htable_vrtx_set(&scn->unique_vertices, &tmp, &unique_v));
++actual_nuverts;
}
- /* The unique ID for vertex v is u */
+ /* The unique ID for vertex i is unique_v */
ASSERT(i == darray_vrtx_id_size_get(&unique_vertice_ids));
OK(darray_vrtx_id_push_back(&unique_vertice_ids, &unique_v));
++actual_nverts;
@@ -155,8 +165,12 @@ senc_scene_add_geometry
union vrtx_id3 trg_key;
struct triangle_in tmp;
trg_id_t* p_trg;
- trg_id_t tr;
char reversed;
+ if(global_id) {
+ global_id(i, &tmp.global_id, ctx);
+ } else {
+ tmp.global_id = (unsigned)(scn->ntris + i);
+ }
indices(i, ind, ctx); /* API: indices needs an unsigned */
FOR_EACH(j, 0, 3) {
if(ind[j] >= nverts) {
@@ -173,7 +187,7 @@ senc_scene_add_geometry
const union double3* positions
= darray_position_cdata_get(&scn->vertices);
log_err(scn->dev, "%s: triangle %lu is degenerate.\n",
- FUNC_NAME, (unsigned long)i);
+ FUNC_NAME, (unsigned long)tmp.global_id);
log_err(scn->dev, " (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
SPLIT3(positions[trg[i].vertice_id[0]].vec),
SPLIT3(positions[trg[i].vertice_id[1]].vec),
@@ -183,17 +197,11 @@ senc_scene_add_geometry
}
/* Get media */
media(i, med, ctx); /* API: media needs an unsigned */
- ASSERT(scn->nmeds <= MEDIUM_MAX__);
FOR_EACH(j, 0, 2) {
if(med[j] >= scn->nmeds) {
- log_err(scn->dev,
- "%s: triangle %lu %s side references invalid medium: %lu.\n",
- FUNC_NAME,
- (unsigned long)i,
- (j ? "back" : "front"),
- (unsigned long)med[j]);
- res = RES_BAD_ARG;
- goto error;
+ ASSERT(med[j] <= MEDIUM_MAX__);
+ scn->nmeds = med[j] + 1;
+ darray_side_range_resize(&scn->media_use, scn->nmeds);
}
tmp.medium[j] = (medium_id_t)med[j];
}
@@ -213,35 +221,52 @@ senc_scene_add_geometry
/* Same triangles with different media: invalid! */
const union double3* positions
= darray_position_cdata_get(&scn->vertices);
- log_err(scn->dev, "%s: triangle %lu is a duplicate with incoherent media.\n",
- FUNC_NAME, (unsigned long)*p_trg);
- log_err(scn->dev, "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
- (unsigned long)*p_trg,
+ log_err(scn->dev, "%s: triangle %lu is a duplicate"
+ " of triangle %lu with incoherent media.\n",
+ FUNC_NAME, (unsigned long)tmp.global_id,
+ (unsigned long)trg[*p_trg].global_id);
+ log_err(scn->dev,
+ "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
+ (unsigned long)trg[*p_trg].global_id,
SPLIT3(positions[trg[*p_trg].vertice_id[0]].vec),
SPLIT3(positions[trg[*p_trg].vertice_id[1]].vec),
SPLIT3(positions[trg[*p_trg].vertice_id[2]].vec));
log_err(scn->dev, "Media: (%lu, %lu) VS (%lu, %lu)\n",
- umed[ureversed? 1 : 0], umed[ureversed ? 0 : 1],
- med[reversed ? 1 : 0], med[reversed ? 0 : 1]);
+ (unsigned long)umed[ureversed? 1 : 0],
+ (unsigned long)umed[ureversed ? 0 : 1],
+ (unsigned long)med[reversed ? 1 : 0],
+ (unsigned long)med[reversed ? 0 : 1]);
res = RES_BAD_ARG;
goto error;
} else {
+ /* Legit duplicate */
+ log_warn(scn->dev, "%s: triangle %lu is a duplicate of triangle %lu.\n",
+ FUNC_NAME, (unsigned long)tmp.global_id,
+ (unsigned long)trg[*p_trg].global_id);
if(!same) {
FOR_EACH(j, 0, 2) {
- tmp.medium[j] = (medium_id_t) med[1-j];
+ tmp.medium[j] = (medium_id_t)med[1-j];
}
}
}
- }
- else {
+ } else {
/* New triangle */
trg_id_t u = scn->nutris + actual_nutris;
+ struct side_range* media_use;
ASSERT(u == htable_trg_size_get(&scn->unique_triangles));
OK(htable_trg_set(&scn->unique_triangles, &trg_key, &u));
OK(darray_triangle_in_push_back(&scn->triangles_in, &tmp));
+ FOR_EACH(j, 0, 2) {
+ ASSERT(tmp.medium[j] < scn->nmeds);
+ media_use = darray_side_range_data_get(&scn->media_use) + tmp.medium[j];
+ media_use->first = MMIN(media_use->first, TRGIDxSIDE_2_TRGSIDE(u, j));
+ ASSERT(media_use->first < 2 * (scn->nutris + actual_nutris + 1));
+ media_use->last = MMAX(media_use->last, TRGIDxSIDE_2_TRGSIDE(u, j));
+ ASSERT(media_use->last < 2 * (scn->nutris + actual_nutris + 1));
+ ASSERT(media_use->first <= media_use->last);
+ }
++actual_nutris;
}
- tr = scn->nutris + i;
++actual_ntris;
}
@@ -261,6 +286,57 @@ error:
}
res_T
+senc_scene_get_convention
+ (const struct senc_scene* scn,
+ enum senc_convention* convention)
+{
+ if(!scn || !convention) return RES_BAD_ARG;
+ *convention = scn->convention;
+ return RES_OK;
+
+}
+
+res_T
+senc_scene_get_triangles_count
+ (const struct senc_scene* scn,
+ unsigned* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ *count = scn->ntris;
+ return RES_OK;
+}
+
+res_T
+senc_scene_get_unique_triangles_count
+ (const struct senc_scene* scn,
+ unsigned* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ *count = scn->nutris;
+ return RES_OK;
+}
+
+res_T
+senc_scene_get_vertices_count
+ (const struct senc_scene* scn,
+ unsigned* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ *count = scn->nverts;
+ return RES_OK;
+}
+
+res_T
+senc_scene_get_unique_vertices_count
+ (const struct senc_scene* scn,
+ unsigned* count)
+{
+ if(!scn || !count) return RES_BAD_ARG;
+ *count = scn->nuverts;
+ return RES_OK;
+}
+
+res_T
senc_scene_ref_get(struct senc_scene* scn)
{
if(!scn) return RES_BAD_ARG;
diff --git a/src/senc_scene_analyze.c b/src/senc_scene_analyze.c
@@ -26,82 +26,36 @@
#include <rsys/mem_allocator.h>
#include <rsys/hash_table.h>
#include <rsys/dynamic_array.h>
-#include <rsys/dynamic_array_uint.h>
+#include <rsys/dynamic_array_uchar.h>
#include <star/s3d.h>
+#include <omp.h>
#include <limits.h>
#include <stdlib.h>
#define CC_DESCRIPTOR_NULL__ {\
- {0,0,-DBL_MAX}, -1, SIDE_NULL__, VRTX_NULL__, 0, MEDIUM_NULL__,\
- CC_ID_NONE, CC_GROUP_ROOT_NONE, CC_GROUP_ID_NONE\
+ CHAR_MAX, VRTX_NULL__, 0,\
+ CC_ID_NONE, CC_GROUP_ROOT_NONE, ENCLOSURE_NULL__,\
+ { TRG_NULL__, 0},\
+ NULL\
}
+#ifdef COMPILER_GCC
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#endif
const struct cc_descriptor CC_DESCRIPTOR_NULL = CC_DESCRIPTOR_NULL__;
+#ifdef COMPILER_GCC
+ #pragma GCC diagnostic pop
+#endif
#define DARRAY_NAME component_id
#define DARRAY_DATA component_id_t
#include <rsys/dynamic_array.h>
-#define DARRAY_NAME side_id
-#define DARRAY_DATA side_id_t
-#include <rsys/dynamic_array.h>
-
-#define HTABLE_NAME vrtx_id
-#define HTABLE_KEY vrtx_id_t
-#define HTABLE_DATA vrtx_id_t
-#include <rsys/hash_table.h>
-
/*******************************************************************************
* Helper function
******************************************************************************/
-static void
-dumplist
- (const struct trgside* trgsides,
- const struct darray_side_id* side_ids,
- const enum list_id list_id)
-{
- side_id_t i;
- size_t tmp;
- (void)list_id;
- ASSERT(trgsides && side_ids);
- printf("\n");
- 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];
- const struct trgside* const side = trgsides + id;
- printf("Side %lu (%lu %lu %lu)\n",
- (unsigned long)id,
- (unsigned long)side->facing_side_id[0],
- (unsigned long)side->facing_side_id[1],
- (unsigned long)side->facing_side_id[2]);
- ASSERT(side->list_id & list_id);
- }
-}
-
-static 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)
{
@@ -110,345 +64,29 @@ neighbour_cmp(const void* w1, const void* w2)
return (a1 > a2) - (a1 < a2);
}
-static void
-find_component_Zmax
- (struct senc_scene* scn,
- struct darray_triangle_tmp* triangles_tmp_array,
- struct cc_descriptor* cc)
-{
- trg_id_t trid;
- double edge0[3], edge1[3], normal[3], norm, side_nz;
- struct triangle_in* triangles_in;
- struct triangle_tmp* triangles_tmp;
- const union double3* vertices;
- const char* side_membership;
- ASSERT(scn && triangles_tmp_array && cc);
-
- vertices = darray_position_cdata_get(&scn->vertices);
- triangles_in = darray_triangle_in_data_get(&scn->triangles_in);
- triangles_tmp = darray_triangle_tmp_data_get(triangles_tmp_array);
- side_membership = darray_char_cdata_get(&cc->side_membership);
-
- /* Build the sorted list of side ids */
- ASSERT(darray_triangle_tmp_size_get(triangles_tmp_array)
- == darray_triangle_in_size_get(&scn->triangles_in));
- ASSERT(scn->nutris
- == darray_triangle_in_size_get(&scn->triangles_in));
- FOR_EACH(trid, 0, scn->nutris) {
- const char member = side_membership[trid];
- struct triangle_in* const trg_in = triangles_in + trid;
- struct triangle_tmp* const trg_tmp = triangles_tmp + trid;
- enum side_id side;
- int change = 0;
-
- if(!member) continue;
-
- /* Keep track of the appropriate vertex/side of the connex component
- * in order to cast a ray at the component grouping step of the algorithm.
- * The most appropriate vertex is (the) one with the greater Z coordinate.
- * If more than one vertex/side has the same Z, we want the side that most
- * faces Z (that is the one with the greater nz).
- * This is mandatory to select the correct side when both sides of a triangle
- * are candidate. */
- if(cc->max_vrtx[2] > trg_tmp->max_z)
- continue;
-
- d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec,
- vertices[trg_in->vertice_id[0]].vec);
- d3_sub(edge1, vertices[trg_in->vertice_id[2]].vec,
- vertices[trg_in->vertice_id[0]].vec);
- d3_cross(normal, edge0, edge1);
- norm = d3_normalize(normal, normal);
- ASSERT(norm);
-
- if((member & FLAG_FRONT) && (member & FLAG_BACK)) {
- /* Select the side with nz>0 */
- side_nz = fabs(normal[2]);
- side = (normal[2] > 0) ? SIDE_FRONT : SIDE_BACK;
- } else if(member & FLAG_FRONT) {
- side_nz = normal[2];
- side = SIDE_FRONT;
- } else {
- ASSERT(member & FLAG_BACK);
- side_nz = -normal[2];
- side = SIDE_BACK;
- }
-
- if(cc->max_vrtx[2] < trg_tmp->max_z) {
- change = 1; /* Try first to improve z */
- }
- else if(cc->max_z_nz <= 0 && fabs(cc->max_z_nz) < fabs(side_nz)) {
- change = 1; /* If nz <= 0, the more negative the better */
- }
- else if(cc->max_z_nz > 0 && cc->max_z_nz < side_nz) {
- change = 1; /* If nz > 0, the more positive the better */
- }
- if(change) {
- cc->max_z_nz = side_nz;
- cc->max_z_side_id = TRGIDxSIDE_2_TRGSIDE(trid, side);
- ASSERT(trg_tmp->max_z_vrtx_id < 3);
- ASSERT(trg_in->vertice_id[trg_tmp->max_z_vrtx_id] < scn->nverts);
- cc->max_z_vrtx_id = trg_in->vertice_id[trg_tmp->max_z_vrtx_id];
- ASSERT(trg_tmp->max_z == vertices[cc->max_z_vrtx_id].pos.z);
- d3_set(cc->max_vrtx, vertices[cc->max_z_vrtx_id].vec);
- }
- }
-}
-
-static FINLINE void
-add_side_to_stack
- (struct senc_scene* scn,
- 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(!find_side_in_list(trgsides, stack, side_id, FLAG_WAITING_STACK));
- darray_side_id_push_back(stack, &side_id);
- trgsides[side_id].list_id = FLAG_WAITING_STACK;
-}
-
-static FINLINE void
-add_side_to_medium_list
- (struct senc_scene* scn,
- struct darray_side_id* side_ids_by_medium,
- struct trgside* trgsides,
- const side_id_t side_id)
-{
- (void)scn;
- ASSERT(scn && side_ids_by_medium && trgsides
- && side_id < 2 * scn->nutris);
- if(trgsides[side_id].list_id == FLAG_LIST_BY_MEDIUM) {
- ASSERT(find_side_in_list(trgsides, side_ids_by_medium, side_id,
- FLAG_LIST_BY_MEDIUM));
- return;
- }
- ASSERT(!find_side_in_list(trgsides, side_ids_by_medium, side_id,
- FLAG_LIST_BY_MEDIUM));
- darray_side_id_push_back(side_ids_by_medium, &side_id);
- trgsides[side_id].list_id = FLAG_LIST_BY_MEDIUM;
-}
-
static side_id_t
-get_side_from_medium_list_not_in_connex_component
- (struct senc_scene* scn,
- struct trgside* trgsides,
- side_id_t* first_side_by_medium_not_in_component,
- const struct darray_side_id* side_ids_by_medium)
-{
- side_id_t i, sz;
- size_t tmp;
- const side_id_t* ids;
- (void)scn;
- ASSERT(scn && trgsides && first_side_by_medium_not_in_component
- && side_ids_by_medium);
- tmp = darray_side_id_size_get(side_ids_by_medium);
- ids = darray_side_id_cdata_get(side_ids_by_medium);
- ASSERT(tmp <= SIDE_MAX__);
- sz = (side_id_t)tmp;
- i = *first_side_by_medium_not_in_component;
- while(i < sz && trgsides[ids[i]].list_id != FLAG_LIST_BY_MEDIUM) ++i;
-
- *first_side_by_medium_not_in_component = i+1;
- if(i == sz) return SIDE_NULL__;
- ASSERT(trgsides[ids[i]].list_id == FLAG_LIST_BY_MEDIUM);
- return ids[i];
-}
-
-static FINLINE side_id_t
-get_side_from_stack
- (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);
- 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 res_T
-extract_connex_components
- (struct senc_descriptor* desc,
- struct trgside* trgsides,
- struct darray_cc_descriptor* connex_components,
- struct darray_triangle_tmp* triangles_tmp_array,
- struct darray_triangle_comp* triangles_comp,
- struct darray_side_id* side_ids_by_medium)
+get_side_not_in_connex_component
+ (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)
{
- res_T res = RES_OK;
- medium_id_t m;
- size_t tmp;
- struct senc_scene* scn;
- struct mem_allocator* alloc;
- struct darray_side_id stack;
- /* Arrays of cc_descriptor ids, organized by medium. */
- struct darray_component_id* component_ids_by_medium = NULL;
-
- ASSERT(trgsides && desc && connex_components && triangles_tmp_array
- && side_ids_by_medium);
-
- alloc = descriptor_get_allocator(desc);
- scn = desc->scene;
-
- /* Init data structures */
- darray_side_id_init(alloc, &stack);
- component_ids_by_medium
- = MEM_ALLOC(alloc, scn->nmeds * sizeof(struct darray_uint));
- if(!component_ids_by_medium) {
- res = RES_MEM_ERR;
- goto error;
- }
- FOR_EACH(m, 0, scn->nmeds) {
- struct darray_component_id* const cc = component_ids_by_medium + m;
- darray_component_id_init(alloc, cc);
- }
-
- /* For each medium extract connex components */
- FOR_EACH(m, 0, scn->nmeds) {
- struct darray_component_id* const cc_ids_by_medium
- = component_ids_by_medium + m;
- struct cc_descriptor current_cc;
- /* Id of the first trgside not already in a connex component */
- side_id_t first_side_by_medium_not_in_component = 0;
- /* Init current component */
- cc_descriptor_init(alloc, ¤t_cc);
-
- for(;;) {
- /* Any not-already-used side by medium is used as a starting point */
- const side_id_t start_side_id =
- get_side_from_medium_list_not_in_connex_component(scn, trgsides,
- &first_side_by_medium_not_in_component, side_ids_by_medium + m);
- side_id_t crt_side_id = start_side_id;
- char* side_membership;
-
- ASSERT(start_side_id == SIDE_NULL__ || start_side_id < 2 * scn->nutris);
- if(start_side_id == SIDE_NULL__)
- break; /* start_side_id=SIDE_NULL__ => medium done! */
- ASSERT(trgsides[start_side_id].list_id == FLAG_LIST_BY_MEDIUM);
-
- /* Reset CC data for a new CC */
- tmp = darray_cc_descriptor_size_get(connex_components);
- ASSERT(tmp <= COMPONENT_MAX__);
- cc_descriptor_clear(¤t_cc);
- /* 1 char per triangle (2 sides) */
- darray_char_resize(¤t_cc.side_membership, scn->nutris);
- side_membership = darray_char_data_get(¤t_cc.side_membership);
- memset(side_membership, 0, scn->nutris * sizeof(char));
- current_cc.cc_id = (component_id_t)tmp;
- current_cc.medium = m;
-
- for(;;) {
- int i;
- /* Pop waiting stack to feed crt_side */
- struct trgside* crt_side = trgsides + crt_side_id;
- const trg_id_t crt_trg_id = TRGSIDE_2_TRG(crt_side_id);
- struct triangle_comp* trg_comp =
- darray_triangle_comp_data_get(triangles_comp) + crt_trg_id;
- ASSERT(crt_trg_id < scn->nutris);
- ASSERT(trgsides[crt_side_id].medium == m);
-
- /* Record crt_side both as component and triangle level */
- current_cc.side_count++;
- trgsides[crt_side_id].list_id = FLAG_LIST_COMPONENT;
- if(TRGSIDE_IS_FRONT(crt_side_id)) {
- ASSERT(trg_comp->component[SIDE_FRONT] == USHRT_MAX);
- trg_comp->component[SIDE_FRONT] = current_cc.cc_id;
- ASSERT(!(side_membership[crt_trg_id] & FLAG_FRONT));
- side_membership[crt_trg_id] |= FLAG_FRONT;
- } else {
- ASSERT(trg_comp->component[SIDE_BACK] == USHRT_MAX);
- trg_comp->component[SIDE_BACK] = current_cc.cc_id;
- ASSERT(!(side_membership[crt_trg_id] & FLAG_BACK));
- side_membership[crt_trg_id] |= FLAG_BACK;
- }
-#ifndef NDEBUG
- crt_side->member_of_cc = current_cc.cc_id;
-#endif
- /* Store neighbour sides in a waiting stack */
- FOR_EACH(i, 0, 3) {
- side_id_t neighbour_id = crt_side->facing_side_id[i];
- struct trgside* neighbour = trgsides + neighbour_id;
- 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);
- const union double3* positions
- = darray_position_cdata_get(&scn->vertices);
- log_err(scn->dev,
- "Medium mismatch found between triangle %lu %s"
- " side and triangle %u %s side.\n",
- (unsigned long)crt_trg_id,
- TRGSIDE_IS_FRONT(crt_side_id) ? "front": "back",
- TRGSIDE_2_TRG(neighbour_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)crt_trg_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)neighbour_id,
- SPLIT3(positions[triangles_in[neighbour_id].vertice_id[0]].vec),
- SPLIT3(positions[triangles_in[neighbour_id].vertice_id[1]].vec),
- SPLIT3(positions[triangles_in[neighbour_id].vertice_id[2]].vec));
- log_err(desc->scene->dev, "Media: %lu VS %lu\n",
- neighbour->medium, crt_side->medium);
- res = RES_BAD_ARG;
- cc_descriptor_release(¤t_cc);
- goto error;
- }
- if(neighbour->list_id == FLAG_LIST_COMPONENT) {
- /* Already processed */
-#ifndef NDEBUG
- ASSERT(neighbour->member_of_cc == current_cc.cc_id);
-#endif
- continue;
- }
- if(neighbour->list_id == FLAG_WAITING_STACK) {
- continue; /* Already processed */
- }
- add_side_to_stack(scn, &stack, trgsides, neighbour_id);
- }
- if(darray_side_id_size_get(&stack) == 0)
- break; /* Empty stack => connex component is done! */
- crt_side_id = get_side_from_stack(trgsides, &stack);
- }
- /* Keep track of this new connex component */
- darray_component_id_push_back(cc_ids_by_medium, ¤t_cc.cc_id);
- find_component_Zmax(scn, triangles_tmp_array, ¤t_cc);
- darray_cc_descriptor_push_back(connex_components, ¤t_cc);
- }
- cc_descriptor_release(¤t_cc);
- }
-
-exit:
- if(component_ids_by_medium) {
- FOR_EACH(m, 0, scn->nmeds) {
- struct darray_component_id* cc = component_ids_by_medium + m;
- darray_component_id_release(cc);
- }
- MEM_RM(scn->dev->allocator, component_ids_by_medium);
+ 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;
}
- darray_side_id_release(&stack);
- ASSERT(desc->triangle_count
- == darray_triangle_comp_size_get(triangles_comp));
- /* triangles_enc is still unused: no size to assert */
- return res;
-error:
- goto exit;
}
-void
+static void
get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) {
int i;
const struct senc_scene* scene = ctx;
@@ -460,7 +98,7 @@ get_scn_indices(const unsigned itri, unsigned ids[3], void* ctx) {
}
}
-void
+static void
get_scn_position(const unsigned ivert, float pos[3], void* ctx) {
const struct senc_scene* scene = ctx;
const union double3* pt =
@@ -495,391 +133,682 @@ self_hit_filter
return (hit_component == *origin_component);
}
-static res_T
-group_connex_components
+static void
+extract_connex_components
(struct senc_descriptor* desc,
struct trgside* trgsides,
- struct darray_triangle_comp* triangles_comp,
- struct darray_cc_descriptor* connex_components)
+ struct darray_ptr_component_descriptor* connex_components,
+ const struct darray_triangle_tmp* triangles_tmp_array,
+ 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* p_res)
{
- res_T res = RES_OK;
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ const struct senc_scene* scn;
struct mem_allocator* alloc;
- struct cc_descriptor* descriptors;
- struct s3d_device* s3d = NULL;
- struct s3d_scene* s3d_scn = NULL;
- struct s3d_shape* s3d_shp = NULL;
- struct s3d_scene_view* s3d_view = NULL;
- struct s3d_vertex_data attribs;
- size_t tmp;
- component_id_t cc_count, c;
- medium_id_t infinite_medium = MEDIUM_NULL__;
- side_id_t infinite_medium_first_side = SIDE_MAX__;
- char infinite_medium_is_known = 0;
- (void)trgsides;
+ int64_t mm;
+ struct darray_side_id stack;
+ struct darray_side_id ids_of_sides_around_max_z_vertex;
+ const union double3* positions;
+ const struct triangle_tmp* triangles_tmp;
+ struct triangle_comp* triangles_comp;
+ /* An array to flag sides when processed */
+ unsigned char* processed;
+ /* An array to store the component being processed */
+ struct darray_side_id current_component;
+ /* A bool array to store media of the component being processed */
+ unsigned char* current_media = NULL;
+ size_t sz, ii;
+ ASSERT(trgsides && desc && connex_components && triangles_tmp_array
+ && triangles_comp_array && s3d_view && component_count && p_res);
alloc = descriptor_get_allocator(desc);
- descriptors = darray_cc_descriptor_data_get(connex_components);
- tmp = darray_cc_descriptor_size_get(connex_components);
- ASSERT(tmp <= COMPONENT_MAX__);
- cc_count = (component_id_t)tmp;
+ 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);
+ processed = MEM_CALLOC(alloc, scn->nutris, sizeof(unsigned char));
+ if(!processed) {
+ *p_res = RES_MEM_ERR;
+ return;
+ }
+
+#ifndef NDEBUG
+ #pragma omp single
+ {
+ trg_id_t t_;
+ ASSERT(darray_ptr_component_descriptor_size_get(connex_components) == 0);
+ FOR_EACH(t_, 0, scn->nutris) {
+ const struct triangle_in* trg_in =
+ darray_triangle_in_cdata_get(&scn->triangles_in) + t_;
+ const struct side_range* media_use
+ = darray_side_range_cdata_get(&scn->media_use);
+ FOR_EACH(mm, 0, 2) {
+ 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
- if(!cc_count) return RES_OK; /* No component to group */
+ /* 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;
+ /* Any not-already-used side is used as a starting point */
+ const struct side_range* media_use =
+ darray_side_range_cdata_get(&scn->media_use) + m;
+ side_id_t first_side_not_in_component = media_use->first;
+ double max_z_nz;
+ const side_id_t last_side = media_use->last;
+ int component_canceled = 0;
+ res_T tmp_res = RES_OK;
+ ATOMIC id;
+
+ if(*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
+ (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);
+
+ if(*p_res != RES_OK) break;
+ if(start_side_id == SIDE_NULL__)
+ break; /* start_side_id=SIDE_NULL__ => component done! */
+
+#ifndef NDEBUG
+ {
+ trg_id_t tid = TRGSIDE_2_TRG(start_side_id);
+ enum side_id s = TRGSIDE_2_SIDE(start_side_id);
+ medium_id_t side_med
+ = darray_triangle_in_data_get(&desc->scene->triangles_in)[tid].medium[s];
+ ASSERT(side_med == m);
+ }
+#endif
+
+ /* Reuse array if possible, or create a new one */
+ if(current_media) {
+ memset(current_media, 0, scn->nmeds);
+ } else {
+ current_media = MEM_CALLOC(alloc, scn->nmeds, sizeof(unsigned char));
+ if(!current_media) {
+ *p_res = RES_MEM_ERR;
+ continue;
+ }
+ }
+ current_media[m] = 1;
+ for(;;) { /* Process all sides of this component */
+ int i;
+ 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;
+ 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);
+
+ if(*p_res != RES_OK) break;
+
+ /* Record Zmax information
+ * 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. */
+ if(max_z < trg_tmp->max_z) {
+ /* New best vertex */
+ max_z = trg_tmp->max_z;
+ /* New vertex: reset list of sides */
+ darray_side_id_clear(&ids_of_sides_around_max_z_vertex);
+
+ /* Select a vertex with z == max_z */
+ FOR_EACH(i, 0, 3) {
+ if(max_z == positions[trg_in->vertice_id[i]].pos.z) {
+ max_z_vrtx_id = trg_in->vertice_id[i];
+ break;
+ }
+ }
+ ASSERT(i < 3); /* Found one */
+ /* List of sides using the vertex */
+ 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(max_z_vrtx_id == trg_in->vertice_id[i]) {
+ /* List of sides using the vertex */
+ OK2(darray_side_id_push_back(&ids_of_sides_around_max_z_vertex,
+ &crt_side_id));
+ break;
+ }
+ }
+ }
+
+ /* Record crt_side both as component and triangle level */
+ if((*trg_used & crt_side_flag) == 0) {
+ OK2(darray_side_id_push_back(¤t_component, &crt_side_id));
+ *trg_used |= (unsigned char)crt_side_flag;
+ }
+
+ /* 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;
+ 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;
+ }
+ /* Mark neighbour as processed and stack it */
+ *nbour_used |= (unsigned char)nbour_side_id;
+ OK2(darray_side_id_push_back(&stack, &neighbour_id));
+ OK2(darray_side_id_push_back(¤t_component, &neighbour_id));
+ current_media[neighbour->medium] = 1;
+ }
+ 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);
+ }
+ 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;
+ /* Tranfer ownership of the array to component */
+ ASSERT(!cc->media && current_media);
+ cc->media = current_media;
+ current_media = NULL;
+
+ /* Write component membership in the global structure
+ * No need for sync here as an unique thread write a given side */
+ STATIC_ASSERT(sizeof(cc->cc_id) >= 4, Cannot_write_IDs_sync_free);
+ ASSERT(IS_ALIGNED(triangles_comp->component, sizeof(cc->cc_id)));
+ FOR_EACH(ii, 0, sz) {
+ const side_id_t s = darray_side_id_cdata_get(¤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;
+ sz = darray_side_id_size_get(&ids_of_sides_around_max_z_vertex);
+ FOR_EACH(ii, 0, sz) {
+ const side_id_t side_id =
+ darray_side_id_cdata_get(&ids_of_sides_around_max_z_vertex)[ii];
+ 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 = triangles_comp + trg_id;
+ const union double3* vertices =
+ darray_position_cdata_get(&scn->vertices);
+ double edge0[3], edge1[3], normal[3], norm;
+
+ /* To garanty that triangles with 2 sides in the component total to 0
+ * regardless of numeric accuracy, we need to prevent them to
+ * contribute (remember than x + y - y == 0 can be false). */
+ 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])
+ continue;
+
+ d3_sub(edge0, vertices[trg_in->vertice_id[1]].vec,
+ vertices[trg_in->vertice_id[0]].vec);
+ d3_sub(edge1, vertices[trg_in->vertice_id[2]].vec,
+ vertices[trg_in->vertice_id[0]].vec);
+ d3_cross(normal, edge0, edge1);
+ norm = d3_normalize(normal, normal);
+ ASSERT(norm); (void)norm;
+
+ /* Orient the geometrical normal according to the convention */
+ if(TRGSIDE_IS_FRONT(side_id)
+ == ((scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0)) {
+ max_z_nz += normal[2];
+ } else {
+ max_z_nz -= normal[2];
+ }
+ }
+ cc->is_outer_border = (max_z_nz < 0);
+
+ /* Need to synchronize connex_components growth as this global structure
+ * is accessed by multipe threads */
+ #pragma omp critical
+ {
+ struct cc_descriptor** components;
+ sz = darray_ptr_component_descriptor_size_get(connex_components);
+ if(sz <= cc->cc_id) {
+ tmp_res = darray_ptr_component_descriptor_resize(connex_components,
+ 1 + cc->cc_id);
+ if(tmp_res != RES_OK) *p_res = tmp_res;
+ }
+ 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);
+ ASSERT(components[cc->cc_id] == NULL);
+ components[cc->cc_id] = cc;
+ }
+ }
+ }
+ tmp_error:
+ if(tmp_res != RES_OK) *p_res = tmp_res;
+ } /* No barrier here */
+
+ MEM_RM(alloc, processed);
+ MEM_RM(alloc, current_media);
+ darray_side_id_release(¤t_component);
+ darray_side_id_release(&stack);
+ darray_side_id_release(&ids_of_sides_around_max_z_vertex);
+
+ /* The first thread here creates the s3d view */
+ #pragma omp single nowait
+ if(*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;
+ struct s3d_vertex_data attribs;
+
+ attribs.type = S3D_FLOAT3;
+ attribs.usage = S3D_POSITION;
+ attribs.get = get_scn_position;
+
+ /* Put geometry in a 3D view */
+ 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);
+ 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_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));
+ }
+
+#ifndef NDEBUG
+ /* Need to wait for all threads done to be able to check stuff */
+ #pragma omp barrier
+ 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) {
+ struct triangle_comp* trg_comp =
+ 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(desc->triangle_count == scn->nutris);
+ } /* Implicit barrier here */
+#endif
+}
- attribs.type = S3D_FLOAT3;
- attribs.usage = S3D_POSITION;
- attribs.get = get_scn_position;
+static void
+group_connex_components
+ (struct senc_descriptor* desc,
+ struct trgside* trgsides,
+ struct darray_triangle_comp* triangles_comp,
+ struct darray_ptr_component_descriptor* connex_components,
+ struct s3d_scene_view* s3d_view,
+ ATOMIC* next_enclosure_id,
+ /* Shared error status.
+ * We accept to overwritte an error with a different error */
+ res_T* res)
+{
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ struct cc_descriptor** descriptors;
+ const union double3* positions;
+ size_t tmp;
+ component_id_t cc_count;
+ int64_t ccc;
- /* Put geometry in a 3D view */
- 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));
+ (void)trgsides;
+ ASSERT(desc && trgsides && triangles_comp && connex_components
+ && s3d_view && next_enclosure_id && res);
+ ASSERT(desc->enclosures_count == 1);
- /* Back to API type for ntris and nverts */
- ASSERT(desc->scene->nutris < UINT_MAX);
- ASSERT(desc->scene->nuverts < UINT_MAX);
- 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);
- OK(s3d_scene_attach_shape(s3d_scn, s3d_shp));
- OK(s3d_scene_view_create(s3d_scn, S3D_TRACE, &s3d_view));
+ descriptors = darray_ptr_component_descriptor_data_get(connex_components);
+ tmp = darray_ptr_component_descriptor_size_get(connex_components);
+ ASSERT(tmp <= COMPONENT_MAX__);
+ cc_count = (component_id_t)tmp;
+ positions = darray_position_cdata_get(&desc->scene->vertices);
/* Cast rays to find links between connex components */
- FOR_EACH(c, 0, cc_count) {
+ #pragma omp for
+ for(ccc = 0; ccc < (int64_t)cc_count; ccc++) {
+ res_T tmp_res = RES_OK;
+ component_id_t c = (component_id_t)ccc;
struct s3d_hit hit = S3D_HIT_NULL;
float origin[3];
const float dir[3] = { 0, 0, 1 };
const float range[2] = { 0, FLT_MAX };
- struct cc_descriptor* const cc = descriptors + c;
- const struct triangle_comp* origin_trg =
- darray_triangle_comp_cdata_get(triangles_comp) + cc->max_z_vrtx_id;
- component_id_t self_hit_component
- = origin_trg->component[1 - TRGSIDE_2_SIDE(cc->max_z_side_id)];
+ struct cc_descriptor* const cc = descriptors[c];
+ component_id_t self_hit_component = cc->cc_id;
+ 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);
- if(cc->max_z_nz < 0) {
+ max_vrtx = positions[cc->max_z_vrtx_id].vec;
+ if(cc->is_outer_border) {
+ ATOMIC id;
/* Don't need to cast a ray */
- cc->cc_group_root = c; /* New group with self as root */
- ASSERT(desc->enclosures_count < USHRT_MAX);
- cc->enclosure_id = desc->enclosures_count++;
+ cc->cc_group_root = cc->cc_id; /* New group with self as root */
+ id = ATOMIC_INCR(next_enclosure_id) - 1;
+ ASSERT(id <= ENCLOSURE_MAX__);
+ cc->enclosure_id = (enclosure_id_t)id;
continue;
}
- ASSERT(cc->max_z_nz != 0
- /* The only situation with nz==0 we can think of is this one: */
- || (trgsides[cc->max_z_side_id].medium
- == trgsides[TRGSIDE_OPPOSITE(cc->max_z_side_id)].medium
- && (trgsides[cc->max_z_side_id].facing_side_id[0]
- == TRGSIDE_OPPOSITE(cc->max_z_side_id)
- || trgsides[cc->max_z_side_id].facing_side_id[1]
- == TRGSIDE_OPPOSITE(cc->max_z_side_id)
- || trgsides[cc->max_z_side_id].facing_side_id[2]
- == TRGSIDE_OPPOSITE(cc->max_z_side_id))));
- f3_set_d3(origin, cc->max_vrtx);
+ f3_set_d3(origin, max_vrtx);
/* Self-hit data: self hit if hit this component "on the other side" */
- OK(s3d_scene_view_trace_ray(s3d_view, origin, dir, range,
- &self_hit_component, &hit));
+ tmp_res = s3d_scene_view_trace_ray(s3d_view, origin, dir, range,
+ &self_hit_component, &hit);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ continue;
+ }
/* If no hit, the component is facing an infinite medium */
if(S3D_HIT_NONE(&hit)) {
cc->cc_group_root = CC_GROUP_ROOT_INFINITE;
cc->enclosure_id = 0;
- if(!infinite_medium_is_known) {
- infinite_medium_is_known = 1;
- infinite_medium = cc->medium;
- infinite_medium_first_side = cc->max_z_side_id;
- continue;
- }
- if(infinite_medium != cc->medium) {
- /* Medium mismatch! Model topology is broken. */
- const trg_id_t t1 = TRGSIDE_2_TRG(infinite_medium_first_side);
- const trg_id_t t2 = TRGSIDE_2_TRG(cc->max_z_side_id);
- const struct triangle_in* triangles_in
- = darray_triangle_in_cdata_get(&desc->scene->triangles_in);
- const union double3* positions
- = darray_position_cdata_get(&desc->scene->vertices);
- log_err(desc->scene->dev,
- "Medium mismatch found between triangle %lu %s side and triangle"
- " %lu %s side, both facing infinite.\n",
- t1,
- TRGSIDE_IS_FRONT(infinite_medium_first_side) ? "front" : "back",
- TRGSIDE_2_TRG(cc->max_z_side_id),
- TRGSIDE_IS_FRONT(cc->max_z_side_id) ? "front" : "back");
- log_err(desc->scene->dev,
- "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
- (unsigned long)t1,
- SPLIT3(positions[triangles_in[t1].vertice_id[0]].vec),
- SPLIT3(positions[triangles_in[t1].vertice_id[1]].vec),
- SPLIT3(positions[triangles_in[t1].vertice_id[2]].vec));
- log_err(desc->scene->dev,
- "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
- (unsigned long)t2,
- SPLIT3(positions[triangles_in[t2].vertice_id[0]].vec),
- SPLIT3(positions[triangles_in[t2].vertice_id[1]].vec),
- SPLIT3(positions[triangles_in[t2].vertice_id[2]].vec));
- log_err(desc->scene->dev, "Media: %lu VS %lu\n",
- infinite_medium, cc->medium);
- res = RES_BAD_ARG;
- goto error;
- }
- /* 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_cc_descriptor_size_get(connex_components));
- hit_desc = darray_cc_descriptor_cdata_get(connex_components)
- + cc->cc_group_root;
- ASSERT(hit_desc->medium == hit_trg_in->medium[hit_side]);
- ASSERT(darray_char_cdata_get(&hit_desc->side_membership)[hit_trg_id]
- & TRGSIDE_IS_FRONT(hit_side) ? FLAG_FRONT : FLAG_BACK);
- }
-#endif
- if(hit_trg_in->medium[hit_side] != cc->medium) {
- /* Medium mismatch!
- * Model topology is broken. */
- const trg_id_t t1 = TRGSIDE_2_TRG(hit_side_id);
- const trg_id_t t2 = TRGSIDE_2_TRG(hit_side);
- const struct triangle_in* triangles_in
- = darray_triangle_in_cdata_get(&desc->scene->triangles_in);
- const union double3* positions
- = darray_position_cdata_get(&desc->scene->vertices);
- log_err(desc->scene->dev,
- "Medium mismatch found between triangle %lu %s side and triangle"
- " %u %s side facing each other.\n",
- (unsigned long)t1,
- TRGSIDE_IS_FRONT(hit_side) ? "front" : "back",
- (unsigned long)t2,
- TRGSIDE_IS_FRONT(cc->max_z_side_id) ? "front" : "back");
- log_err(desc->scene->dev,
- "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
- (unsigned long)t1,
- SPLIT3(positions[triangles_in[t1].vertice_id[0]].vec),
- SPLIT3(positions[triangles_in[t1].vertice_id[1]].vec),
- SPLIT3(positions[triangles_in[t1].vertice_id[2]].vec));
- log_err(desc->scene->dev,
- "Triangle %lu:\n (%g %g %g)\n (%g %g %g)\n (%g %g %g)\n",
- (unsigned long)t2,
- SPLIT3(positions[triangles_in[t2].vertice_id[0]].vec),
- SPLIT3(positions[triangles_in[t2].vertice_id[1]].vec),
- SPLIT3(positions[triangles_in[t2].vertice_id[2]].vec));
- log_err(desc->scene->dev, "Media: %lu VS %lu\n",
- hit_trg_in->medium[hit_side], cc->medium);
- res = RES_BAD_ARG;
- goto error;
- }
+ ASSERT(cc->cc_group_root < cc_count);
}
}
-
- /* Post-process links to group connex components */
- printf("\n");
- FOR_EACH(c, 0, cc_count) {
- struct cc_descriptor* const cc = descriptors + c;
- const struct cc_descriptor* other_desc = cc;
-
- while(other_desc->enclosure_id == CC_GROUP_ID_NONE) {
- other_desc = darray_cc_descriptor_cdata_get(connex_components)
- + other_desc->cc_group_root;
+ /* Implicit barrier here */
+ ASSERT(ATOMIC_GET(next_enclosure_id) < ENCLOSURE_MAX__);
+ if(*res != RES_OK) return;
+
+ /* One thread post-processes links to group connex components */
+ #pragma omp single
+ {
+ res_T tmp_res = RES_OK;
+ desc->enclosures_count = (enclosure_id_t)ATOMIC_GET(next_enclosure_id);
+ tmp_res = darray_enclosure_resize(&desc->enclosures, desc->enclosures_count);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ } else {
+ struct enclosure_data* enclosures
+ = darray_enclosure_data_get(&desc->enclosures);
+ FOR_EACH(ccc, 0, cc_count) {
+ component_id_t c = (component_id_t)ccc;
+ struct cc_descriptor* const cc = descriptors[c];
+ const struct cc_descriptor* other_desc = cc;
+ struct enclosure_data* enc;
+
+ while(other_desc->enclosure_id == CC_GROUP_ID_NONE) {
+ other_desc = *(darray_ptr_component_descriptor_cdata_get(connex_components)
+ + other_desc->cc_group_root);
+ }
+ ASSERT(other_desc->cc_group_root != CC_GROUP_ROOT_NONE);
+ ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE);
+ cc->cc_group_root = other_desc->cc_group_root;
+ cc->enclosure_id = other_desc->enclosure_id;
+ enc = enclosures + cc->enclosure_id;
+ ++enc->cc_count;
+ /* Linked list of componnents */
+ enc->first_component = cc->cc_id;
+ enc->side_range.first = MMIN(enc->side_range.first, cc->side_range.first);
+ enc->side_range.last = MMAX(enc->side_range.last, cc->side_range.last);
+ enc->side_count += cc->side_count;
+ tmp_res = bool_array_of_media_merge(&enc->tmp_enclosed_media, cc->media,
+ desc->scene->nmeds);
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
+ }
}
- ASSERT(other_desc->cc_group_root != CC_GROUP_ROOT_NONE);
- ASSERT(other_desc->enclosure_id != CC_GROUP_ID_NONE);
- cc->cc_group_root = other_desc->cc_group_root;
- cc->enclosure_id = other_desc->enclosure_id;
}
-
-exit:
- /* Local Star3D stuff is no longer useful */
- 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));
- if(s3d_view) S3D(scene_view_ref_put(s3d_view));
- return res;
-error:
- goto exit;
+ /* Implicit barrier here */
}
-static res_T
-scan_edges
+static void
+collect_and_link_neighbours
(struct senc_scene* scn,
- struct darray_neighbourhood* neighbourhood_by_edge,
- struct darray_triangle_tmp* triangles_tmp_array)
+ struct trgside* trgsides,
+ struct darray_triangle_tmp* triangles_tmp_array,
+ /* Shared error status.
+ * We accept to overwritte an error with a different error */
+ res_T* res)
{
- trg_id_t t;
- struct triangle_in *triangles_in;
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
+ const struct triangle_in *triangles_in;
struct triangle_tmp *triangles_tmp;
- edge_id_t max_nbedges;
+ const union double3* vertices;
+ const int thread_count = omp_get_num_threads();
+ const int rank = omp_get_thread_num();
/* Htable used to give an id to edges */
struct htable_edge_id edge_ids;
- res_T res = RES_OK;
+ /* Array to keep neighbourhood of edges
+ * Resize/Push operations on neighbourhood_by_edge are valid in the
+ * openmp block because a given neighbourhood is only processed
+ * by a single thread */
+ struct darray_neighbourhood neighbourhood_by_edge;
+ edge_id_t edge_count;
+ edge_id_t nbedges_guess;
+ edge_id_t e;
+ trg_id_t t;
+ size_t sz;
+ res_T tmp_res;
- ASSERT(scn && neighbourhood_by_edge && triangles_tmp_array);
+ ASSERT(scn && trgsides && triangles_tmp_array && res);
ASSERT((size_t)scn->nuverts + (size_t)scn->nutris + 2 <= EDGE_MAX__);
- /* Make some room for edges. */
- max_nbedges = (edge_id_t)(scn->nuverts + scn->nutris + 2);
htable_edge_id_init(scn->dev->allocator, &edge_ids);
- OK(htable_edge_id_reserve(&edge_ids, max_nbedges));
- OK(darray_neighbourhood_reserve(neighbourhood_by_edge, max_nbedges));
- OK(darray_triangle_tmp_resize(triangles_tmp_array, scn->nutris));
+ darray_neighbourhood_init(scn->dev->allocator, &neighbourhood_by_edge);
- /* Loop on triangles to register edges. */
- triangles_in = darray_triangle_in_data_get(&scn->triangles_in);
+ triangles_in = darray_triangle_in_cdata_get(&scn->triangles_in);
triangles_tmp = darray_triangle_tmp_data_get(triangles_tmp_array);
+ vertices = darray_position_cdata_get(&scn->vertices);
+
+ ASSERT(scn->nutris == darray_triangle_tmp_size_get(triangles_tmp_array));
+
+ /* Make some room for edges. */
+ nbedges_guess = 4 + (thread_count == 1
+ ? (edge_id_t)(scn->nuverts + scn->nutris)
+ : (edge_id_t)((scn->nuverts + scn->nutris) / (0.75 * thread_count)));
+ OK2(darray_neighbourhood_reserve(&neighbourhood_by_edge, nbedges_guess));
+ OK2(htable_edge_id_reserve(&edge_ids, nbedges_guess));
+
+ /* Loop on triangles to register edges.
+ * All threads considering all the edges and processing some */
FOR_EACH(t, 0, scn->nutris) {
- struct darray_neighbour* neighbour_list;
- struct neighbour_info neighbour;
- struct edge_neighbourhood neighbourhood;
- char e;
- FOR_EACH(e, 0, 3) {
+ struct trg_edge edge;
+ unsigned char ee;
+ FOR_EACH(ee, 0, 3) {
edge_id_t* p_id;
- edge_id_t id;
-
+ size_t n_sz;
+ struct edge_neighbourhood* neighbourhood;
+ struct neighbour_info* info;
+ const vrtx_id_t v0 = triangles_in[t].vertice_id[ee];
+ const vrtx_id_t v1 = triangles_in[t].vertice_id[(ee + 1) % 3];
+ /* Process only "my" edges! */
+ const int64_t h =
+ /* v0,v1 and v1,v0 must give the same hash!!! */
+ v0 + v1 + (int64_t)MMIN(v0, v1);
+ if(h % thread_count != rank) continue;
/* Create edge. */
- set_edge(triangles_in[t].vertice_id[e],
- triangles_in[t].vertice_id[(e + 1) % 3],
- &neighbourhood.edge, &triangles_tmp[t].reversed_edge[e]);
+ set_edge(v0, v1, &edge, &triangles_tmp[t].reversed_edge[ee]);
/* Find edge id; create it if not already done. */
- p_id = htable_edge_id_find(&edge_ids, &neighbourhood.edge);
-
+ p_id = htable_edge_id_find(&edge_ids, &edge);
if(p_id) {
- id = *p_id;
+ neighbourhood =
+ darray_neighbourhood_data_get(&neighbourhood_by_edge) + *p_id;
+ ASSERT(neighbourhood->edge.vrtx0 == edge.vrtx0
+ && neighbourhood->edge.vrtx1 == edge.vrtx1);
} else {
/* Create id */
- size_t tmp;
- tmp = htable_edge_id_size_get(&edge_ids);
- ASSERT(tmp <= EDGE_MAX__);
- id = (edge_id_t)tmp;
- OK(htable_edge_id_set(&edge_ids, &neighbourhood.edge, &id));
- darray_neighbour_init(scn->dev->allocator, &neighbourhood.neighbours);
- OK(darray_neighbourhood_push_back(neighbourhood_by_edge,
- &neighbourhood));
+ edge_id_t id;
+ sz = htable_edge_id_size_get(&edge_ids);
+ ASSERT(sz <= EDGE_MAX__);
+ id = (edge_id_t)sz;
+ ASSERT(htable_edge_id_size_get(&edge_ids)
+ == darray_neighbourhood_size_get(&neighbourhood_by_edge));
+ OK2(htable_edge_id_set(&edge_ids, &edge, &id));
+ OK2(darray_neighbourhood_resize(&neighbourhood_by_edge, 1 + sz));
+ neighbourhood = darray_neighbourhood_data_get(&neighbourhood_by_edge) + sz;
+ /* Add neighbour info to a newly created edge's neighbour list */
+ neighbourhood->edge = edge;
+ ASSERT(darray_neighbour_size_get(&neighbourhood->neighbours) == 0);
+ /* Just a guess: few edges will have less than 2 neighbours */
+ OK2(darray_neighbour_reserve(&neighbourhood->neighbours, 2));
}
- /* Add neighbour info to edge's neighbour list */
- neighbour_list
- = &darray_neighbourhood_data_get(neighbourhood_by_edge)[id].neighbours;
- neighbour.trg_id = t;
- neighbour.edge_rank = e;
- darray_neighbour_push_back(neighbour_list, &neighbour);
+ /* Add neighbour info to neighbourhood */
+ n_sz = darray_neighbour_size_get(&neighbourhood->neighbours);
+ OK2(darray_neighbour_resize(&neighbourhood->neighbours, 1 + n_sz));
+ info = darray_neighbour_data_get(&neighbourhood->neighbours) + n_sz;
+ info->trg_id = t;
+ info->common_edge_rank = ee;
}
- }
-
-exit:
- htable_edge_id_release(&edge_ids);
- return res;
-error:
- goto exit;
-}
+ } /* No barrier here. */
-static res_T
-link_neighbours
- (struct senc_scene* scn,
- struct trgside* trgsides,
- struct darray_neighbourhood* neighbourhood_by_edge,
- struct darray_triangle_tmp* triangles_tmp_array,
- struct darray_side_id* side_ids_by_medium)
-{
- edge_id_t e, edge_count;
- struct triangle_in *triangles_in;
- struct triangle_tmp *triangles_tmp;
- const union double3* vertices;
- size_t tmp;
- res_T res = RES_OK;
-
- ASSERT(scn && neighbourhood_by_edge && triangles_tmp_array
- && side_ids_by_medium);
-
- /* Loop on edges.
+ /* Loop on collected edges.
* For each edge sort triangle sides by rotation angle
* and connect neighbours. */
- triangles_in = darray_triangle_in_data_get(&scn->triangles_in);
- triangles_tmp = darray_triangle_tmp_data_get(triangles_tmp_array);
- vertices = darray_position_cdata_get(&scn->vertices);
- tmp = darray_neighbourhood_size_get(neighbourhood_by_edge);
- ASSERT(tmp <= EDGE_MAX__);
- edge_count = (edge_id_t)tmp;
-
+ sz = darray_neighbourhood_size_get(&neighbourhood_by_edge);
+ ASSERT(sz <= EDGE_MAX__);
+ edge_count = (edge_id_t)sz;
FOR_EACH(e, 0, edge_count) {
- double edge[3], common_edge[3], basis[9], norm, mz, mz_edge;
+ double edge[3], common_edge[3], basis[9], norm, max_z, maxz_edge;
vrtx_id_t v0, v1, v2;
struct edge_neighbourhood* neighbourhood
- = darray_neighbourhood_data_get(neighbourhood_by_edge) + e;
+ = darray_neighbourhood_data_get(&neighbourhood_by_edge) + e;
struct darray_neighbour* neighbour_list = &neighbourhood->neighbours;
side_id_t i, neighbour_count;
- char mz_vid, mz_vid_edge;
- tmp = darray_neighbour_size_get(neighbour_list);
- ASSERT(tmp <= SIDE_MAX__);
- neighbour_count = (side_id_t)tmp;
+ sz = darray_neighbour_size_get(neighbour_list);
+ ASSERT(sz <= SIDE_MAX__);
+ neighbour_count = (side_id_t)sz;
ASSERT(neighbour_count);
v0 = neighbourhood->edge.vrtx0;
v1 = neighbourhood->edge.vrtx1;
d3_sub(common_edge, vertices[v1].vec, vertices[v0].vec);
- if(vertices[v0].pos.z > vertices[v1].pos.z) {
- mz_edge = vertices[v0].pos.z;
- mz_vid_edge = 0;
- } else {
- mz_edge = vertices[v1].pos.z;
- mz_vid_edge = 1;
- }
+ maxz_edge = MMAX(vertices[v0].pos.z, vertices[v1].pos.z);
norm = d3_normalize(common_edge, common_edge);
- ASSERT(norm);
+ ASSERT(norm); (void)norm;
d33_basis(basis, common_edge);
d33_inverse(basis, basis);
FOR_EACH(i, 0, neighbour_count) {
struct neighbour_info* neighbour_info
= darray_neighbour_data_get(neighbour_list) + i;
- struct triangle_in *trg_in = triangles_in + neighbour_info->trg_id;
- struct triangle_tmp *neighbour = triangles_tmp + neighbour_info->trg_id;
- char actual_vid;
- v2 = trg_in->vertice_id[(neighbour_info->edge_rank + 2) % 3];
- if(vertices[v2].pos.z > mz_edge) {
- mz = vertices[v2].pos.z;
- mz_vid = 2;
- } else {
- mz = mz_edge;
- mz_vid = mz_vid_edge;
- }
- /* Compute the actual vertex id
- * as vertices are not in the v0 v1 v2 order in the actual triangle */
- if (mz_vid == 2) {
- actual_vid = (2 + neighbour_info->edge_rank) % 3;
- }
- else {
- int is_r = neighbour->reversed_edge[neighbour_info->edge_rank];
- ASSERT(mz_vid == 0 || mz_vid == 1);
- actual_vid = ((is_r ? 1 - mz_vid : mz_vid) + neighbour_info->edge_rank) % 3;
- }
-
- ASSERT(neighbour->max_z <= mz);
- neighbour->max_z = mz;
- ASSERT(0 <= actual_vid && actual_vid <= 2);
- neighbour->max_z_vrtx_id = actual_vid;
+ const trg_id_t crt_id = neighbour_info->trg_id;
+ const unsigned char crt_edge = neighbour_info->common_edge_rank;
+ const struct triangle_in* trg_in = triangles_in + crt_id;
+ struct triangle_tmp* neighbour = triangles_tmp + crt_id;
+ union double3 n; /* Geometrical normal to neighbour triangle */
+ const int is_reversed = neighbour->reversed_edge[crt_edge];
+ v2 = trg_in->vertice_id[(crt_edge + 2) % 3];
+ max_z = MMAX(vertices[v2].pos.z, maxz_edge);
+ ASSERT(neighbour->max_z <= max_z);
+ neighbour->max_z = max_z;
/* Compute rotation angle around common edge */
d3_sub(edge, vertices[v2].vec, vertices[v0].vec);
d33_muld3(edge, basis, edge);
ASSERT(d3_len(edge) && (edge[0] || edge[1]));
neighbour_info->angle = atan2(edge[1], edge[0]);
+ if(is_reversed)
+ d3(n.vec, +edge[1], -edge[0], 0);
+ else
+ d3(n.vec, -edge[1], +edge[0], 0);
if(neighbour_info->angle < 0) neighbour_info->angle += 2 * PI;
- /* Due to catastrophic cancelation, -eps+2pi translates to 2pi */
- ASSERT(0 <= neighbour_info->angle && neighbour_info->angle <= 2 * PI);
+
+ /* Normal orientation calculation. */
+ if(neighbour_info->angle <= PI / 4) {
+ ASSERT(n.pos.y);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
+ } else if (neighbour_info->angle <= 3 * PI / 4) {
+ ASSERT(n.pos.x);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.x < 0);
+ } else if (neighbour_info->angle <= 5 * PI / 4) {
+ ASSERT(n.pos.y);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y < 0);
+ } else if (neighbour_info->angle <= 7 * PI / 4) {
+ ASSERT(n.pos.x);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.x > 0);
+ } else {
+ ASSERT(n.pos.y);
+ neighbour_info->normal_toward_next_neighbour = (n.pos.y > 0);
+ }
}
/* Sort triangles by rotation angle */
qsort(darray_neighbour_data_get(neighbour_list), neighbour_count,
sizeof(struct neighbour_info), neighbour_cmp);
- /* Link sides.
+ /* Link sides.
* Create cycles of sides by neighbourhood around common edge. */
FOR_EACH(i, 0, neighbour_count) {
/* Neighbourhood info for current pair of triangles */
@@ -888,16 +817,21 @@ link_neighbours
const struct neighbour_info* ccw_neighbour
= darray_neighbour_cdata_get(neighbour_list) + (i + 1) % neighbour_count;
/* Rank of the edge of interest in triangles */
- const char crt_edge = current->edge_rank;
- const char ccw_edge = ccw_neighbour->edge_rank;
+ const unsigned char crt_edge = current->common_edge_rank;
+ /* Here ccw refers to the rotation around the common edge
+ * and has nothing to do with vertices order in triangle definition
+ * nor Front/Back side convention */
+ const unsigned char ccw_edge = ccw_neighbour->common_edge_rank;
/* User id of current triangles */
const trg_id_t crt_id = current->trg_id;
const trg_id_t ccw_id = ccw_neighbour->trg_id;
/* Facing sides of triangles */
+ const int front = ((scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0);
const enum side_id crt_side
- = triangles_tmp[crt_id].reversed_edge[crt_edge] ? SIDE_BACK : SIDE_FRONT;
+ = current->normal_toward_next_neighbour == front ? SIDE_FRONT : SIDE_BACK;
const enum side_id ccw_side
- = triangles_tmp[ccw_id].reversed_edge[ccw_edge] ? SIDE_FRONT : SIDE_BACK;
+ = ccw_neighbour->normal_toward_next_neighbour == front ?
+ SIDE_BACK : SIDE_FRONT;
/* Index of sides in trgsides */
const side_id_t crt_side_idx = TRGIDxSIDE_2_TRGSIDE(crt_id, crt_side);
const side_id_t ccw_side_idx = TRGIDxSIDE_2_TRGSIDE(ccw_id, ccw_side);
@@ -907,168 +841,219 @@ link_neighbours
/* Link sides */
p_crt_side->facing_side_id[crt_edge] = ccw_side_idx;
p_ccw_side->facing_side_id[ccw_edge] = crt_side_idx;
- /* Record sides by medium */
+
+ /* Record media */
p_crt_side->medium = triangles_in[crt_id].medium[crt_side];
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);
- add_side_to_medium_list(scn, side_ids_by_medium + p_crt_side->medium,
- trgsides, crt_side_idx);
- add_side_to_medium_list(scn, side_ids_by_medium + p_ccw_side->medium,
- trgsides, ccw_side_idx);
}
}
- return res;
+tmp_error:
+ if(tmp_res != RES_OK) *res = tmp_res;
+ /* Threads are allowed to return whitout sync. */
+ htable_edge_id_release(&edge_ids);
+ darray_neighbourhood_release(&neighbourhood_by_edge);
}
-static res_T
+static void
build_result
(struct senc_descriptor* desc,
- struct darray_cc_descriptor* connex_components)
+ const struct darray_ptr_component_descriptor* connex_components,
+ const struct darray_triangle_comp* triangles_comp_array,
+ /* Shared error status.
+ * We accept to overwritte an error with a different error */
+ res_T* res)
{
- res_T res = RES_OK;
+ /* This function is called from an omp parallel block and executed
+ * concurrently. */
struct mem_allocator* alloc;
- const struct cc_descriptor* cc_descriptors;
+ struct cc_descriptor* const* cc_descriptors;
struct enclosure_data* enclosures;
- char* side_membership = NULL;
const struct triangle_in* triangles_in;
struct triangle_enc* triangles_enc;
- const union double3* positions;
+ const struct triangle_comp* triangles_comp;
struct htable_vrtx_id vtable;
- size_t tmp;
- component_id_t cc_count, c;
- enclosure_id_t e;
- side_id_t* side_counts;
+ struct senc_scene* scn;
+ int output_normal_in, normals_front, normals_back;
+ int64_t tt;
+ int64_t ee;
- ASSERT(desc && connex_components);
+ ASSERT(desc && connex_components && triangles_comp_array);
alloc = descriptor_get_allocator(desc);
- tmp = darray_cc_descriptor_size_get(connex_components);
- ASSERT(tmp < COMPONENT_MAX__);
- cc_count = (component_id_t)tmp;
- cc_descriptors = darray_cc_descriptor_cdata_get(connex_components);
- darray_enclosure_resize(&desc->enclosures, desc->enclosures_count);
+ scn = desc->scene;
+ output_normal_in = (scn->convention & SENC_CONVENTION_NORMAL_INSIDE) != 0;
+ normals_front = (scn->convention & SENC_CONVENTION_NORMAL_FRONT) != 0;
+ normals_back = (scn->convention & SENC_CONVENTION_NORMAL_BACK) != 0;
+ ASSERT(normals_back != normals_front);
+ ASSERT(output_normal_in != ((scn->convention & SENC_CONVENTION_NORMAL_OUTSIDE) != 0));
+ ASSERT(darray_ptr_component_descriptor_size_get(connex_components)
+ <= 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);
- positions = darray_position_cdata_get(&desc->scene->vertices);
- /* Set some enclosure data */
- side_counts = MEM_CALLOC(alloc, desc->enclosures_count, sizeof(side_id_t));
- if(!side_counts) {
- res = RES_MEM_ERR;
- goto error;
- }
- FOR_EACH(e, 0, desc->enclosures_count) {
- struct enclosure_data* enc = enclosures + e;
- ASSERT(e < UINT_MAX);
- enc->header.enclosure_id = (unsigned)e; /* Back to API type */
- enc->header.is_infinite = (e == 0);
- }
- /* Process components to feed enclosures */
- FOR_EACH(c, 0, cc_count) {
- const struct cc_descriptor* cc = cc_descriptors + c;
- const enclosure_id_t e_id = cc->enclosure_id;
- struct enclosure_data* enc = enclosures + e_id;
- ASSERT(enc->header.enclosed_medium == MEDIUM_NULL__ /* Unset */
- || enc->header.enclosed_medium == cc->medium); /* Same medium */
- ASSERT(enc->header.enclosed_medium < UINT_MAX);
- enc->header.enclosed_medium = (unsigned)cc->medium; /* Back to API type */
- side_counts[e_id] += cc->side_count;
- }
- side_membership
- = MEM_ALLOC(alloc, desc->scene->nutris * sizeof(*side_membership));
- if(!side_membership) {
- res = RES_MEM_ERR;
- goto error;
- }
- res = darray_triangle_enc_resize(&desc->triangles_enc, desc->scene->nutris);
- if(res != RES_OK) goto error;
+ triangles_in = darray_triangle_in_cdata_get(&scn->triangles_in);
+ triangles_comp = darray_triangle_comp_cdata_get(triangles_comp_array);
+
+ #pragma omp single
+ {
+ res_T tmp_res =
+ darray_triangle_enc_resize(&desc->triangles_enc, scn->nutris);
+ if(tmp_res != RES_OK) *res = tmp_res;
+ }/* Implicit barrier here. */
+ if(*res != RES_OK) return;
triangles_enc = darray_triangle_enc_data_get(&desc->triangles_enc);
+
+ /* Build global enclosure information */
+ #pragma omp for
+ for(tt = 0; tt < (int64_t) scn->nutris; tt++) {
+ trg_id_t t = (trg_id_t)tt;
+ const component_id_t cf_id = triangles_comp[t].component[SIDE_FRONT];
+ const component_id_t cb_id = triangles_comp[t].component[SIDE_BACK];
+ const struct cc_descriptor* cf = cc_descriptors[cf_id];
+ const struct cc_descriptor* cb = cc_descriptors[cb_id];
+ const enclosure_id_t ef_id = cf->enclosure_id;
+ const enclosure_id_t eb_id = cb->enclosure_id;
+ ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == ENCLOSURE_NULL__);
+ triangles_enc[t].enclosure[SIDE_FRONT] = ef_id;
+ ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__);
+ triangles_enc[t].enclosure[SIDE_BACK] = eb_id;
+ }
+ /* Implicit barrier here */
+
+ /* Resize/push operations on enclosure's fields are valid in the
+ * openmp block as a given enclosure is processed by a single thread */
htable_vrtx_id_init(alloc, &vtable);
- FOR_EACH(e, 0, desc->enclosures_count) {
+
+ ASSERT(desc->enclosures_count <= ENCLOSURE_MAX__);
+ #pragma omp for schedule(dynamic) nowait
+ 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;
+ trg_id_t fst_idx = 0;
+ trg_id_t sgd_idx = enc->side_count;
trg_id_t t;
- memset(side_membership, 0, desc->scene->nutris * sizeof(*side_membership));
- /* Process all CC enclosures_count times to limit memory footprint. */
- FOR_EACH(c, 0, cc_count) {
- const struct cc_descriptor* cc = cc_descriptors + c;
- const char* cc_membership
- = darray_char_cdata_get(&cc->side_membership);
- if(cc->enclosure_id != e) continue;
- FOR_EACH(t, 0, desc->scene->nutris) side_membership[t] |= cc_membership[t];
+ medium_id_t m;
+ res_T tmp_res = RES_OK;
+ ASSERT(enc->first_component
+ < darray_ptr_component_descriptor_size_get(connex_components));
+ 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(cc_descriptors[enc->first_component]->enclosure_id
+ == enc->header.enclosure_id);
+ enc->header.is_infinite = (e == 0);
+
+ ASSERT(darray_uchar_size_get(&enc->tmp_enclosed_media) <= UINT_MAX);
+ ASSERT(enc->header.enclosed_media_count <= scn->nmeds);
+ OK2(bool_array_of_media_to_darray_media
+ (&enc->enclosed_media, &enc->tmp_enclosed_media));
+ enc->header.enclosed_media_count
+ = (unsigned)darray_media_size_get(&enc->enclosed_media);
+ darray_uchar_purge(&enc->tmp_enclosed_media);
+
+ /* Add this enclosure in relevant by-medium lists */
+ FOR_EACH(m, 0, enc->header.enclosed_media_count) {
+ medium_id_t medium = darray_media_data_get(&enc->enclosed_media)[m];
+ struct darray_enc_id* enc_ids_by_medium =
+ darray_enc_ids_array_data_get(&desc->enc_ids_array_by_medium) + medium;
+ #pragma omp critical
+ {
+ tmp_res = darray_enc_id_push_back(enc_ids_by_medium, &e);
+ }
+ if(tmp_res != RES_OK) {
+ *res = tmp_res;
+ break;
+ }
}
- /* Translate membership into a side and vertex lists. */
- OK(darray_triangle_in_reserve(&enc->sides, side_counts[e]));
- OK(darray_position_reserve(&enc->vertices, side_counts[e] / 2));
+ if(*res != RES_OK) continue;
+
+ /* Build side and vertex lists. */
+ OK2(darray_triangle_in_resize(&enc->sides, enc->side_count));
+ /* Size is just a int */
+ OK2(darray_vrtx_id_reserve(&enc->vertices,
+ (size_t)(enc->side_count * 0.6)));
/* New vertex numbering scheme local to the enclosure */
htable_vrtx_id_clear(&vtable);
- ASSERT(desc->scene->nutris
- == darray_triangle_in_size_get(&desc->scene->triangles_in));
- /* Proceed in 2 steps; the second step puts at the end the back-faces
- * of triangles that also have front-face in the list. */
- FOR_EACH(t, 0, desc->scene->nutris) {
+ ASSERT(scn->nutris == darray_triangle_in_size_get(&scn->triangles_in));
+ /* Put at the end the back-faces of triangles that also have their
+ * front-face in the list. */
+ for(t = TRGSIDE_2_TRG(enc->side_range.first);
+ t <= TRGSIDE_2_TRG(enc->side_range.last);
+ t++)
+ {
const struct triangle_in* trg_in = triangles_in + t;
- struct triangle_in trg;
+ struct triangle_in* trg;
+ unsigned vertice_id[3];
int i;
- if(!side_membership[t]) continue;
+ if(triangles_enc[t].enclosure[SIDE_FRONT] != e
+ && triangles_enc[t].enclosure[SIDE_BACK] != e)
+ continue;
++enc->header.unique_triangle_count;
+
FOR_EACH(i, 0, 3) {
- vrtx_id_t* id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i);
- if(id) {
- trg.vertice_id[i] = *id; /* Known vertex */
+ vrtx_id_t* p_id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i);
+ if(p_id) {
+ vertice_id[i] = *p_id; /* Known vertex */
} else {
/* Create new association */
- tmp = htable_vrtx_id_size_get(&vtable);
- ASSERT(tmp == darray_position_size_get(&enc->vertices));
+ size_t tmp = htable_vrtx_id_size_get(&vtable);
+ ASSERT(tmp == darray_vrtx_id_size_get(&enc->vertices));
ASSERT(tmp < VRTX_MAX__);
- trg.vertice_id[i] = (vrtx_id_t)tmp;
- OK(htable_vrtx_id_set(&vtable, trg_in->vertice_id + i,
- trg.vertice_id + i));
- OK(darray_position_push_back(&enc->vertices,
- positions + trg_in->vertice_id[i]));
+ vertice_id[i] = (vrtx_id_t)tmp;
+ OK2(htable_vrtx_id_set(&vtable, trg_in->vertice_id + i,
+ vertice_id + i));
+ OK2(darray_vrtx_id_push_back(&enc->vertices, trg_in->vertice_id + i));
++enc->header.vertices_count;
}
}
- FOR_EACH(i, 0, 2) trg.medium[i] = trg_in->medium[i];
- if(side_membership[t] & FLAG_FRONT) {
- ++enc->header.triangle_count;
- OK(darray_triangle_in_push_back(&enc->sides, &trg));
- ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == ENCLOSURE_NULL__);
- triangles_enc[t].enclosure[SIDE_FRONT] = e;
- } else if(side_membership[t] & FLAG_BACK) {
+ ASSERT(triangles_enc[t].enclosure[SIDE_FRONT] == e
+ || triangles_enc[t].enclosure[SIDE_BACK] == e);
+ if(triangles_enc[t].enclosure[SIDE_FRONT] == e) {
+ /* Front side of the original triangle is member of the enclosure */
+ int input_normal_in = normals_front;
+ int revert_triangle = (input_normal_in != output_normal_in);
++enc->header.triangle_count;
- triangle_in_flip(&trg);
- OK(darray_triangle_in_push_back(&enc->sides, &trg));
- ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__);
- triangles_enc[t].enclosure[SIDE_BACK] = e;
+ trg = darray_triangle_in_data_get(&enc->sides) + fst_idx++;
+ FOR_EACH(i, 0, 2) {
+ int ii = revert_triangle ? 1 - i : i;
+ trg->medium[i] = trg_in->medium[ii];
+ }
+ trg->global_id = trg_in->global_id;
+ FOR_EACH(i, 0, 3) {
+ int ii = revert_triangle ? 2 - i : i;
+ trg->vertice_id[i] = vertice_id[ii];
+ }
}
- }
- FOR_EACH(t, 0, desc->scene->nutris) {
- const struct triangle_in* trg_in = triangles_in + t;
- struct triangle_in trg;
- int i;
- if(!((side_membership[t] & FLAG_FRONT) && (side_membership[t] & FLAG_BACK)))
- continue;
- ++enc->header.triangle_count;
- FOR_EACH(i, 0, 3) {
- vrtx_id_t* id = htable_vrtx_id_find(&vtable, trg_in->vertice_id + i);
- ASSERT(id);
- trg.vertice_id[2-i] = *id; /* Known vertex */
+ if(triangles_enc[t].enclosure[SIDE_BACK] == e) {
+ /* Back side of the original triangle is member of the enclosure */
+ int input_normal_in = normals_back;
+ int revert_triangle = (input_normal_in != output_normal_in);
+ ++enc->header.triangle_count;
+ /* If both sides are in the enclosure, put the second side at the end */
+ trg = darray_triangle_in_data_get(&enc->sides) +
+ ((triangles_enc[t].enclosure[SIDE_FRONT] == e) ? --sgd_idx : fst_idx++);
+ FOR_EACH(i, 0, 2) {
+ int ii = revert_triangle ? 1 - i : i;
+ trg->medium[i] = trg_in->medium[ii];
+ }
+ trg->global_id = trg_in->global_id;
+ FOR_EACH(i, 0, 3) {
+ int ii = revert_triangle ? 2 - i : i;
+ trg->vertice_id[i] = vertice_id[ii];
+ }
}
- FOR_EACH(i, 0, 2) trg.medium[1-i] = trg_in->medium[i];
- OK(darray_triangle_in_push_back(&enc->sides, &trg));
- ASSERT(triangles_enc[t].enclosure[SIDE_BACK] == ENCLOSURE_NULL__);
- triangles_enc[t].enclosure[SIDE_BACK] = e;
+ if(fst_idx == sgd_idx) break;
}
- ASSERT(darray_triangle_in_size_get(&enc->sides) == side_counts[e]);
- }
-
-exit:
+ continue;
+ tmp_error:
+ ASSERT(tmp_res != RES_OK);
+ *res = tmp_res;
+ } /* No barrier here */
htable_vrtx_id_release(&vtable);
- if(side_membership) MEM_RM(alloc, side_membership);
- if(side_counts) MEM_RM(alloc, side_counts);
- return res;
-error:
- goto exit;
}
/*******************************************************************************
@@ -1077,26 +1062,25 @@ error:
res_T
senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc)
{
- res_T res = RES_OK;
- unsigned m;
struct senc_descriptor* desc = NULL;
/* By triangle tmp data */
struct darray_triangle_tmp triangles_tmp;
char triangles_tmp_initialized = 0;
- /* Arrays of trgside ids, organized by medium */
- struct darray_side_id* side_ids_by_medium = NULL;
/* Array of connex components.
* They are refered to by arrays of ids. */
- struct darray_cc_descriptor connex_components;
+ struct darray_ptr_component_descriptor connex_components;
char connex_components_initialized = 0;
- /* Triangle neighbourhood by edge. */
- struct darray_neighbourhood neighbourhood_by_edge;
- char neighbourhood_by_edge_initialized = 0;
/* Store by-triangle components */
struct darray_triangle_comp triangles_comp;
char triangles_comp_initialized = 0;
/* Array of triangle sides. */
struct trgside* trgsides = NULL;
+ struct s3d_scene_view* s3d_view = NULL;
+ /* Atomic counters to share beetwen threads */
+ ATOMIC component_count = 0;
+ ATOMIC next_enclosure_id = 1;
+ res_T res = RES_OK;
+ res_T res2 = RES_OK;
if(!scn || !out_desc) return RES_BAD_ARG;
@@ -1110,26 +1094,8 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc)
darray_triangle_tmp_init(scn->dev->allocator, &triangles_tmp);
triangles_tmp_initialized = 1;
- darray_neighbourhood_init(scn->dev->allocator, &neighbourhood_by_edge);
- neighbourhood_by_edge_initialized = 1;
-
- /* Step 1: list edges and connect triangles to edges */
- res = scan_edges(scn, &neighbourhood_by_edge, &triangles_tmp);
- if(res != RES_OK) {
- log_err(scn->dev, "%s: could not scan edges.\n", FUNC_NAME);
- goto error;
- }
- side_ids_by_medium
- = MEM_ALLOC(scn->dev->allocator, scn->nmeds * sizeof(struct darray_uint));
- if(!side_ids_by_medium) {
- res = RES_MEM_ERR;
- goto error;
- }
- FOR_EACH(m, 0, scn->nmeds) {
- struct darray_side_id* const s = side_ids_by_medium + m;
- darray_side_id_init(scn->dev->allocator, s);
- }
+ OK(darray_triangle_tmp_resize(&triangles_tmp, scn->nutris));
trgsides
= MEM_CALLOC(scn->dev->allocator, 2 * scn->nutris, sizeof(struct trgside));
if(!trgsides) {
@@ -1137,77 +1103,143 @@ senc_scene_analyze(struct senc_scene* scn, struct senc_descriptor** out_desc)
goto error;
}
- /* Step 2: link triangles by neighbourhood */
- res = link_neighbours(scn, trgsides, &neighbourhood_by_edge,
- &triangles_tmp, side_ids_by_medium);
- if(res != RES_OK) {
- log_err(scn->dev, "%s: could not link neighbours.\n", FUNC_NAME);
- goto error;
- }
+ /* The end of the analyze is multithreaded */
+ ASSERT(scn->dev->nthreads > 0);
+ #pragma omp parallel num_threads(scn->dev->nthreads)
+ {
+ /* Step 1: build neighbourhoods */
+ collect_and_link_neighbours(scn, trgsides, &triangles_tmp, &res);
+ /* No barrier at the end of step 1: data used in step 1 cannot be
+ * released / data produced by step 1 cannot be used
+ * until next sync point */
+
+ /* The first thread here allocates some data.
+ * Barrier needed at the end to ensure data created before any use. */
+ #pragma omp single
+ {
+ res_T tmp_res = RES_OK;
+ darray_ptr_component_descriptor_init(scn->dev->allocator,
+ &connex_components);
+ connex_components_initialized = 1;
+ /* Just a hint; to limit contention */
+ OK2(darray_ptr_component_descriptor_reserve(&connex_components,
+ 2 * scn->nmeds));
+ darray_triangle_comp_init(scn->dev->allocator, &triangles_comp);
+ triangles_comp_initialized = 1;
+ OK2(darray_triangle_comp_resize(&triangles_comp, scn->nutris));
+ tmp_error:
+ if(tmp_res != RES_OK) res2 = tmp_res;
+ }
+ /* Implicit barrier here: constraints on step 1 data are now met */
- darray_neighbourhood_release(&neighbourhood_by_edge);
- neighbourhood_by_edge_initialized = 0;
- darray_cc_descriptor_init(scn->dev->allocator, &connex_components);
- connex_components_initialized = 1;
- darray_triangle_comp_init(scn->dev->allocator, &triangles_comp);
- triangles_comp_initialized = 1;
- OK(darray_triangle_comp_resize(&triangles_comp, scn->nutris));
-
- /* Step 3: extract triangle connex components */
- res = extract_connex_components(desc, trgsides, &connex_components,
- &triangles_tmp, &triangles_comp, side_ids_by_medium);
- if(res != RES_OK) {
- log_err(scn->dev,
- "%s: could not extract connex components from scene.\n", FUNC_NAME);
- goto error;
- }
+ if(res != RES_OK || res2 != RES_OK) {
+ #pragma omp single nowait
+ {
+ if(res != RES_OK) {
+ log_err(scn->dev,
+ "%s: could not build neighbourhoods from scene.\n", FUNC_NAME);
+ } else {
+ res = res2;
+ }
+ }
+ goto error_;
+ }
+
+ /* Step 2: extract triangle connex components */
+ extract_connex_components(desc, trgsides, &connex_components,
+ &triangles_tmp, &triangles_comp, &s3d_view, &component_count, &res);
+ /* No barrier at the end of step 2: data used in step 2 cannot be
+ * released / data produced by step 2 cannot be used
+ * until next sync point */
- darray_triangle_tmp_release(&triangles_tmp);
- triangles_tmp_initialized = 0;
- if(side_ids_by_medium) {
- FOR_EACH(m, 0, scn->nmeds) {
- struct darray_side_id* cc = side_ids_by_medium + m;
- darray_side_id_release(cc);
+ #pragma omp barrier
+ /* Constraints on step 2 data are now met */
+
+ if(res != RES_OK) {
+ #pragma omp single nowait
+ {
+ log_err(scn->dev,
+ "%s: could not extract connex components from scene.\n", FUNC_NAME);
+ } /* No barrier here */
+ goto error_;
}
- MEM_RM(scn->dev->allocator, side_ids_by_medium);
- }
- side_ids_by_medium = NULL;
-
- /* Step 4: group components */
- res = group_connex_components(desc, trgsides, &triangles_comp,
- &connex_components);
- if(res != RES_OK) {
- log_err(scn->dev,
- "%s: could not group connex components from scene.\n", FUNC_NAME);
- goto error;
- }
- darray_triangle_comp_release(&triangles_comp);
- triangles_comp_initialized = 0;
+ /* One thread releases some data before going to step 3,
+ * the others go to step 3 without sync */
+ #pragma omp single nowait
+ {
+ darray_triangle_tmp_release(&triangles_tmp);
+ triangles_tmp_initialized = 0;
+ } /* No barrier here */
+
+ /* Step 3: group components */
+ group_connex_components(desc, trgsides, &triangles_comp,
+ &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 */
+
+ if(res != RES_OK) {
+ #pragma omp single nowait
+ {
+ log_err(scn->dev,
+ "%s: could not group connex components from scene.\n", FUNC_NAME);
+ }
+ goto error_;
+ }
- /* Build result. */
- res = build_result(desc, &connex_components);
- if(res != RES_OK) {
- log_err(scn->dev, "%s: could not build result.\n", FUNC_NAME);
- goto error;
- }
+ /* One thread releases some data before going to step 4,
+ * the others go to step 4 without sync */
+ #pragma omp single nowait
+ {
+ if(s3d_view) S3D(scene_view_ref_put(s3d_view));
+ s3d_view = NULL;
+ } /* No barrier here */
+
+ /* Step 4: Build result */
+ build_result(desc, &connex_components, &triangles_comp, &res);
+ /* No barrier at the end of step 4: data used in step 4 cannot be
+ * released / data produced by step 4 cannot be used
+ * until next sync point */
+
+ #pragma omp barrier
+ /* Constraints on step 4 data are now met */
+
+ if(res != RES_OK) {
+ #pragma omp single nowait
+ {
+ log_err(scn->dev, "%s: could not build result.\n", FUNC_NAME);
+ }
+ goto error_;
+ }
+
+ /* Some threads release data */
+ #pragma omp sections nowait
+ {
+ #pragma omp section
+ {
+ custom_darray_ptr_component_descriptor_release(&connex_components);
+ connex_components_initialized = 0;
+ }
+ #pragma omp section
+ {
+ darray_triangle_comp_release(&triangles_comp);
+ triangles_comp_initialized = 0;
+ }
+ } /* No barrier here */
+error_:
+ ;
+ } /* Implicit barrier here */
+ if(res != RES_OK) goto error;
exit:
if(connex_components_initialized)
- darray_cc_descriptor_release(&connex_components);
- if(neighbourhood_by_edge_initialized)
- darray_neighbourhood_release(&neighbourhood_by_edge);
+ custom_darray_ptr_component_descriptor_release(&connex_components);
+ if(s3d_view) S3D(scene_view_ref_put(s3d_view));
if(triangles_tmp_initialized) darray_triangle_tmp_release(&triangles_tmp);
if(triangles_comp_initialized) darray_triangle_comp_release(&triangles_comp);
- if(side_ids_by_medium) {
- FOR_EACH(m, 0, scn->nmeds) {
- struct darray_side_id* cc = side_ids_by_medium + m;
- darray_side_id_release(cc);
- }
- MEM_RM(scn->dev->allocator, side_ids_by_medium);
- }
if(trgsides) MEM_RM(scn->dev->allocator, trgsides);
if(desc) *out_desc = desc;
+
return res;
error:
if(desc) SENC(descriptor_ref_put(desc));
diff --git a/src/senc_scene_analyze_c.h b/src/senc_scene_analyze_c.h
@@ -20,31 +20,9 @@
#include "senc_internal_types.h"
#include <rsys/mem_allocator.h>
-#include <rsys/dynamic_array_char.h>
#include <rsys/hash_table.h>
#include <rsys/double3.h>
-
-/* This one is used as an index to arrays */
-enum side_id {
- SIDE_FRONT = 0,
- SIDE_BACK = 1
-};
-
-/* This one is used as flag */
-enum side_flag {
- FLAG_FRONT = BIT(0),
- FLAG_BACK = BIT(1)
-};
-
-enum list_id {
- FLAG_NO_LIST = 0,
- FLAG_LIST_BY_MEDIUM = 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;
@@ -63,10 +41,10 @@ set_edge
(const vrtx_id_t vrtx0,
const vrtx_id_t vrtx1,
struct trg_edge* edge,
- char* reversed)
+ unsigned char* reversed)
{
ASSERT(edge && reversed && vrtx0 != vrtx1);
- ASSERT(*reversed == CHAR_MAX); /* Should not be already set. */
+ ASSERT(*reversed == UCHAR_MAX); /* Should not be already set. */
if(vrtx0 < vrtx1) {
edge->vrtx0 = vrtx0;
edge->vrtx1 = vrtx1;
@@ -93,159 +71,83 @@ struct trgside {
/* Id of this trgside's medium */
medium_id_t medium;
/* The list containing the trgside; made of enum list_id flags */
- char list_id;
+ unsigned char list_id;
/* Implicit information that we don't need to store:
* - triangle_id
* - 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
};
-static FINLINE trg_id_t
-TRGSIDE_2_TRG(side_id_t s) {
- ASSERT(((size_t)s >> 1) <= TRG_MAX__);
- return s >> 1; }
-
-static FINLINE int
-TRGSIDE_IS_FRONT(side_id_t s) {
- return (s & 1) == 0;
-}
-
-static FINLINE enum side_id
-TRGSIDE_2_SIDE(side_id_t s) {
- return (s & 1) ? SIDE_BACK : SIDE_FRONT;
-}
-
-static FINLINE side_id_t
-TRGIDxSIDE_2_TRGSIDE(trg_id_t t, enum side_id i) {
- ASSERT((((size_t)t << 1) | (i == SIDE_BACK)) < SIDE_MAX__);
- ASSERT(i == SIDE_FRONT || i == SIDE_BACK);
- return (side_id_t)((t << 1) | (i == SIDE_BACK));
-}
-
-static FINLINE side_id_t
-TRGSIDE_OPPOSITE(side_id_t s) {
- return TRGIDxSIDE_2_TRGSIDE(TRGSIDE_2_TRG(s),
- TRGSIDE_IS_FRONT(s) ? SIDE_BACK : SIDE_FRONT);
-}
+#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 id,
- * a star3D id */
-#define CC_ID_NONE USHRT_MAX
-#define CC_GROUP_ROOT_NONE USHRT_MAX
-#define CC_GROUP_ROOT_INFINITE (USHRT_MAX-1)
-#define CC_GROUP_ID_NONE USHRT_MAX
+ * and the list of media found */
struct cc_descriptor {
- double max_vrtx[3];
- double max_z_nz;
- side_id_t max_z_side_id;
- vrtx_id_t max_z_vrtx_id;
+ /* 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; /* 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;
- /* TODO: use only 1 bit per side (now 1 char per triangle) */
- struct darray_char side_membership;
+ /* Range of sides member of this component */
+ struct side_range side_range;
+ /* Media used by this component */
+ unsigned char* media;
};
extern const struct cc_descriptor CC_DESCRIPTOR_NULL;
static FINLINE void
-cc_descriptor_init(struct mem_allocator* alloc, struct cc_descriptor* data)
+cc_descriptor_init
+ (struct mem_allocator* alloc,
+ struct cc_descriptor* data)
{
ASSERT(data);
+ (void)alloc;
*data = CC_DESCRIPTOR_NULL;
- darray_char_init(alloc, &data->side_membership);
}
static FINLINE void
-cc_descriptor_release(struct cc_descriptor* data)
+ptr_component_descriptor_init
+ (struct mem_allocator* alloc,
+ struct cc_descriptor** data)
{
+ (void)alloc;
ASSERT(data);
- darray_char_release(&data->side_membership);
+ *data = NULL;
}
-static FINLINE void
-cc_descriptor_clear(struct cc_descriptor* data)
-{
- d3_set(data->max_vrtx, CC_DESCRIPTOR_NULL.max_vrtx);
- data->max_z_nz = CC_DESCRIPTOR_NULL.max_z_nz;
- data->max_z_side_id = CC_DESCRIPTOR_NULL.max_z_side_id;
- data->max_z_vrtx_id = CC_DESCRIPTOR_NULL.max_z_vrtx_id;
- data->side_count = CC_DESCRIPTOR_NULL.side_count;
- data->medium = CC_DESCRIPTOR_NULL.medium;
- data->cc_id = CC_DESCRIPTOR_NULL.cc_id;
- data->cc_group_root = CC_DESCRIPTOR_NULL.cc_group_root;
- data->enclosure_id = CC_DESCRIPTOR_NULL.enclosure_id;
- darray_char_clear(&data->side_membership);
-}
+#define DARRAY_NAME ptr_component_descriptor
+#define DARRAY_DATA struct cc_descriptor*
+#define DARRAY_FUNCTOR_INIT ptr_component_descriptor_init
+#include <rsys/dynamic_array.h>
+/* Need allocator to free array elts: cannot rely on standard
+ * darray release stuff */
static FINLINE void
-cc_descriptor_purge(struct cc_descriptor* data)
-{
- d3_set(data->max_vrtx, CC_DESCRIPTOR_NULL.max_vrtx);
- data->max_z_nz = CC_DESCRIPTOR_NULL.max_z_nz;
- data->max_z_side_id = CC_DESCRIPTOR_NULL.max_z_side_id;
- data->max_z_vrtx_id = CC_DESCRIPTOR_NULL.max_z_vrtx_id;
- data->side_count = CC_DESCRIPTOR_NULL.side_count;
- data->medium = CC_DESCRIPTOR_NULL.medium;
- data->cc_id = CC_DESCRIPTOR_NULL.cc_id;
- data->cc_group_root = CC_DESCRIPTOR_NULL.cc_group_root;
- data->enclosure_id = CC_DESCRIPTOR_NULL.enclosure_id;
- darray_char_purge(&data->side_membership);
-}
-
-static FINLINE res_T
-cc_descriptor_copy(struct cc_descriptor* dst, const struct cc_descriptor* src)
+custom_darray_ptr_component_descriptor_release
+ (struct darray_ptr_component_descriptor* array)
{
- ASSERT(dst && src);
- d3_set(dst->max_vrtx, src->max_vrtx);
- dst->max_z_nz = src->max_z_nz;
- dst->max_z_side_id = src->max_z_side_id;
- dst->max_z_vrtx_id = src->max_z_vrtx_id;
- dst->side_count = src->side_count;
- dst->medium = src->medium;
- dst->cc_id = src->cc_id;
- dst->cc_group_root = src->cc_group_root;
- dst->enclosure_id = src->enclosure_id;
- return darray_char_copy(&dst->side_membership, &src->side_membership);
-}
-
-static FINLINE res_T
-cc_descriptor_copy_and_release
- (struct cc_descriptor* dst,
- struct cc_descriptor* src)
-{
- ASSERT(dst && src);
- d3_set(dst->max_vrtx, src->max_vrtx);
- dst->max_z_nz = src->max_z_nz;
- dst->max_z_side_id = src->max_z_side_id;
- dst->max_z_vrtx_id = src->max_z_vrtx_id;
- dst->side_count = src->side_count;
- dst->medium = src->medium;
- dst->cc_id = src->cc_id;
- dst->cc_group_root = src->cc_group_root;
- dst->enclosure_id = src->enclosure_id;
- return darray_char_copy_and_release(&dst->side_membership,
- &src->side_membership);
+ size_t c, cc_count;
+ struct cc_descriptor** components;
+ 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) {
+ if(!components[c]) continue;
+ MEM_RM(array->allocator, components[c]->media);
+ MEM_RM(array->allocator, components[c]);
+ }
+ darray_ptr_component_descriptor_release(array);
}
-#define DARRAY_NAME cc_descriptor
-#define DARRAY_DATA struct cc_descriptor
-#define DARRAY_FUNCTOR_INIT cc_descriptor_init
-#define DARRAY_FUNCTOR_RELEASE cc_descriptor_release
-#define DARRAY_FUNCTOR_COPY cc_descriptor_copy
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE cc_descriptor_copy_and_release
-#include <rsys/dynamic_array.h>
-
/* Triangle information.
* Depending on lifespan, information is kept in different places:
* - triangle_in for user provided information (kept in scene)
@@ -257,9 +159,7 @@ cc_descriptor_copy_and_release
struct triangle_tmp {
/* Are the edges of the triangle defined in the same order than
* the edges they are linked to? */
- char reversed_edge[3];
- /* tmp data used to find the +Z-most vertex of components */
- char max_z_vrtx_id;
+ unsigned char reversed_edge[3];
double max_z;
};
@@ -267,10 +167,9 @@ struct triangle_tmp {
static FINLINE void
triangle_tmp_init(struct mem_allocator* alloc, struct triangle_tmp* trg) {
int i;
- (void) alloc;
+ (void)alloc;
ASSERT(trg);
- FOR_EACH(i, 0, 3) trg->reversed_edge[i] = CHAR_MAX;
- trg->max_z_vrtx_id = CHAR_MAX;
+ FOR_EACH(i, 0, 3) trg->reversed_edge[i] = UCHAR_MAX;
trg->max_z = -DBL_MAX;
}
#define DARRAY_FUNCTOR_INIT triangle_tmp_init
@@ -287,10 +186,13 @@ triangle_tmp_init(struct mem_allocator* alloc, struct triangle_tmp* trg) {
#include <rsys/hash_table.h>
struct neighbour_info {
+ double angle;
trg_id_t trg_id;
/* Rank of the edge in the triangle (in [0 2]) */
- char edge_rank;
- double angle;
+ unsigned char common_edge_rank;
+ /* Does the geometrical normal point towards the next neighbour
+ * (if not, it points towards the previous one)? */
+ unsigned char normal_toward_next_neighbour;
};
#define DARRAY_NAME neighbour
#define DARRAY_DATA struct neighbour_info
diff --git a/src/senc_scene_c.h b/src/senc_scene_c.h
@@ -24,6 +24,11 @@
struct mem_allocator;
+#define HTABLE_NAME vrtx_id
+#define HTABLE_KEY vrtx_id_t
+#define HTABLE_DATA vrtx_id_t
+#include <rsys/hash_table.h>
+
union double3 {
struct {
double x, y, z;
@@ -43,16 +48,19 @@ struct triangle_in {
vrtx_id_t vertice_id[3];
/* Ids of this triangle's media */
medium_id_t medium[2];
+ /* Triangle index in user world (that is regardless of deduplication). */
+ unsigned global_id;
};
#ifndef NDEBUG
static FINLINE void
triangle_in_init(struct mem_allocator* alloc, struct triangle_in* trg) {
int i;
- (void) alloc;
+ (void)alloc;
ASSERT(trg);
FOR_EACH(i, 0, 3) trg->vertice_id[i] = VRTX_NULL__;
FOR_EACH(i, 0, 2) trg->medium[i] = MEDIUM_NULL__;
+ trg->global_id = 0;
}
#define DARRAY_FUNCTOR_INIT triangle_in_init
#endif
@@ -74,7 +82,7 @@ triangle_in_flip(struct triangle_in* trg) {
trg->medium[1] = m;
}
-FINLINE int
+static FINLINE int
vrtx_eq(const union double3* v1, const union double3* v2)
{
ASSERT(v1 && v2);
@@ -100,7 +108,7 @@ union vrtx_id3 {
vrtx_id_t vec[3];
};
-FINLINE char /* Return 1 if reversed */
+static FINLINE char /* Return 1 if reversed */
trg_make_key(union vrtx_id3* k, const vrtx_id_t t[3])
{
ASSERT(t);
@@ -135,21 +143,18 @@ trg_make_key(union vrtx_id3* k, const vrtx_id_t t[3])
k->vec[1] = t[0];
k->vec[2] = t[1];
return 0;
- }
- else {
+ } else {
k->vec[1] = t[1];
k->vec[2] = t[0];
return 1;
}
- }
- else {
+ } else {
k->vec[0] = t[1];
if(t[0] < t[2]) {
k->vec[1] = t[0];
k->vec[2] = t[2];
return 1;
- }
- else {
+ } else {
k->vec[1] = t[2];
k->vec[2] = t[0];
return 0;
@@ -157,7 +162,7 @@ trg_make_key(union vrtx_id3* k, const vrtx_id_t t[3])
}
}
-FINLINE int
+static FINLINE int
trg_key_eq(const union vrtx_id3* k1, const union vrtx_id3* k2)
{
ASSERT(k1 && k2);
@@ -174,7 +179,26 @@ trg_key_eq(const union vrtx_id3* k1, const union vrtx_id3* k2)
#define HTABLE_KEY_FUNCTOR_EQ trg_key_eq
#include <rsys/hash_table.h>
+struct side_range {
+ side_id_t first, last;
+};
+static FINLINE void
+side_range_init(struct mem_allocator* alloc, struct side_range* data)
+{
+ ASSERT(data);
+ (void)alloc;
+ data->first = SIDE_NULL__;
+ data->last = 0;
+}
+#define DARRAY_NAME side_range
+#define DARRAY_DATA struct side_range
+#define DARRAY_FUNCTOR_INIT side_range_init
+#include <rsys/dynamic_array.h>
+
struct senc_scene {
+ /* Front / Back sides convention */
+ enum senc_convention convention;
+
/* Triangle information as given by user; no duplicates here */
struct darray_triangle_in triangles_in;
@@ -196,6 +220,7 @@ struct senc_scene {
trg_id_t ntris, nutris; /* Trg count, unique trg count */
vrtx_id_t nverts, nuverts; /* Vrtx count, unique vrtx count */
medium_id_t nmeds;
+ struct darray_side_range media_use;
ref_T ref;
struct senc_device* dev;
diff --git a/src/test_senc_cube_behind_cube.c b/src/test_senc_cube_behind_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);
@@ -33,7 +34,8 @@ main(int argc, char** argv)
(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
/* Create the scene */
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
ctx.positions = box_vertices;
ctx.indices = box_indices;
@@ -45,8 +47,8 @@ main(int argc, char** argv)
ctx.back_media = medium1;
/* First cube */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
/* +Z from the first cube,
* big enough to prevent rays from the first cube to miss this one */
@@ -54,24 +56,57 @@ main(int argc, char** argv)
ctx.scale = 5;
/* Second cube */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
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 */
ctx.front_media = medium1;
ctx.back_media = medium0;
/* Third cube */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
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);
@@ -33,7 +34,8 @@ main(int argc, char** argv)
(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
/* Create the scene */
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
ctx.positions = box_vertices;
ctx.indices = box_indices;
@@ -47,8 +49,8 @@ main(int argc, char** argv)
ctx.back_media = medium1;
/* First cube */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
d3(ctx.offset, -1, -1, -1);
ctx.scale = 3;
@@ -57,27 +59,51 @@ main(int argc, char** argv)
ctx.reverse_vrtx = 1;
/* Second cube */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
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, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
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_cube_on_cube.c b/src/test_senc_cube_on_cube.c
@@ -13,11 +13,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#define _POSIX_C_SOURCE 200112L /* snprintf */
+
#include "senc.h"
#include "test_senc_utils.h"
#include <rsys/double3.h>
+#include <stdio.h>
+
/*
Z
^
@@ -53,9 +57,10 @@ main(int argc, char** argv)
(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
/* Create the scene */
- CHK(senc_scene_create(dev, 3, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
- ctx.positions = box_vertices;
+ ctx.positions = cube_vertices; /* Need true cubes for cubes #1 and #2 */
ctx.indices = box_indices;
ctx.scale = 1;
ctx.reverse_vrtx = 0;
@@ -68,8 +73,8 @@ main(int argc, char** argv)
ctx.back_media = medium0;
/* Add cube #1 */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx) == RES_OK);
d3(ctx.offset, 1, 1, 1);
ctx.scale = 1;
@@ -80,9 +85,10 @@ main(int argc, char** argv)
ctx.back_media = medium0;
/* Add cube #2 (has a duplicate face with cube #1) */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx) == RES_OK);
+ ctx.positions = box_vertices; /* Can use distorded cube for cube #3 */
d3(ctx.offset, 0, 0, 0);
ctx.scale = 4;
ctx.reverse_vrtx = 1;
@@ -93,8 +99,8 @@ main(int argc, char** argv)
ctx.back_media = medium1;
/* Add cube #3 */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
diff --git a/src/test_senc_descriptor.c b/src/test_senc_descriptor.c
@@ -19,8 +19,6 @@
#include <rsys/float3.h>
#include <rsys/double3.h>
-#include <star/s3d.h>
-
int
main(int argc, char** argv)
{
@@ -30,18 +28,19 @@ 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];
unsigned enclosures[2];
- (void) argc, (void) argv;
+ (void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
== RES_OK);
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
/* A 3D cube */
ctx.positions = box_vertices;
@@ -53,8 +52,8 @@ main(int argc, char** argv)
ctx.front_media = medium0;
ctx.back_media = medium1;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
@@ -63,6 +62,13 @@ 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, &maxm) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_max_medium(desc, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_max_medium(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_max_medium(desc, &maxm) == RES_OK);
+
+ 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);
CHK(senc_descriptor_get_enclosure_count(NULL, NULL) == RES_BAD_ARG);
@@ -70,27 +76,57 @@ main(int argc, char** argv)
CHK(count == 2);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 0, &count) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 9, &count) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 9, &count) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(NULL, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_count_by_medium(desc, 0, &count) == RES_OK);
+
+ CHK(count == 1);
+
CHK(senc_descriptor_get_enclosure(NULL, 0, &enc) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(desc, count, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure(desc, 9, &enc) == RES_BAD_ARG);
CHK(senc_descriptor_get_enclosure(desc, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(NULL, count, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure(NULL, 9, &enc) == RES_BAD_ARG);
CHK(senc_descriptor_get_enclosure(NULL, 0, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(desc, count, NULL) == RES_BAD_ARG);
- CHK(senc_descriptor_get_enclosure(NULL, count, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure(desc, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure(NULL, 9, NULL) == RES_BAD_ARG);
CHK(senc_descriptor_get_enclosure(desc, 0, &enc) == RES_OK);
+ CHK(senc_enclosure_ref_put(enc) == RES_OK);
+
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 9, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 0, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 9, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 9, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 0, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 9, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 0, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 0, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 9, &enc) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(NULL, 9, 9, NULL) == RES_BAD_ARG);
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK);
+
CHK(senc_descriptor_get_global_vertices_count(NULL, &count) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_vertices_count(desc, NULL) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
- CHK(count == box_nvertices);
+ CHK(count == nvertices);
CHK(senc_descriptor_get_global_triangles_count(NULL, &count) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangles_count(desc, NULL) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
- CHK(count == box_ntriangles);
+ CHK(count == ntriangles);
CHK(senc_descriptor_get_global_triangle(NULL, 0, indices) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle(NULL, box_ntriangles, indices)
+ CHK(senc_descriptor_get_global_triangle(NULL, ntriangles, indices)
== RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangle(desc, 0, NULL) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangle(desc, 0, indices) == RES_OK);
@@ -99,7 +135,7 @@ main(int argc, char** argv)
&& indices[2] == box_indices[2]);
CHK(senc_descriptor_get_global_vertex(NULL, 0, coord) == RES_BAD_ARG);
- CHK(senc_descriptor_get_global_vertex(NULL, box_nvertices, coord)
+ CHK(senc_descriptor_get_global_vertex(NULL, nvertices, coord)
== RES_BAD_ARG);
CHK(senc_descriptor_get_global_vertex(desc, 0, NULL) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_vertex(desc, 0, coord) == RES_OK);
@@ -109,7 +145,7 @@ main(int argc, char** argv)
CHK(senc_descriptor_get_global_triangle_media(NULL, 0, media)
== RES_BAD_ARG);
- CHK(senc_descriptor_get_global_triangle_media(NULL, box_nvertices, media)
+ CHK(senc_descriptor_get_global_triangle_media(NULL, nvertices, media)
== RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangle_media(desc, 0, NULL)
== RES_BAD_ARG);
@@ -120,7 +156,7 @@ main(int argc, char** argv)
CHK(senc_descriptor_get_global_triangle_enclosures(
NULL, 0, enclosures) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangle_enclosures(
- NULL, box_nvertices, enclosures) == RES_BAD_ARG);
+ NULL, nvertices, enclosures) == RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangle_enclosures(desc, 0, NULL)
== RES_BAD_ARG);
CHK(senc_descriptor_get_global_triangle_enclosures(desc, 0, enclosures)
@@ -131,25 +167,25 @@ main(int argc, char** argv)
/* Add valid duplicate geometry */
CHK(senc_descriptor_ref_put(desc) == RES_OK);
desc = NULL;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
/* Duplicate vertices have been replaced */
- CHK(count == box_nvertices);
+ CHK(count == nvertices);
CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
/* Duplicate triangles have been replaced */
- CHK(count == box_ntriangles);
+ CHK(count == ntriangles);
/* Add invalid duplicate geometry */
CHK(senc_descriptor_ref_put(desc) == RES_OK);
desc = NULL;
ctx.front_media = medium1;
ctx.back_media = medium0;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_BAD_ARG);
CHK(senc_scene_ref_put(scn) == RES_OK);
CHK(senc_device_ref_put(dev) == RES_OK);
diff --git a/src/test_senc_device.c b/src/test_senc_device.c
@@ -22,7 +22,7 @@ static INLINE void
log_stream(const char* msg, void* ctx)
{
ASSERT(msg);
- (void) msg, (void) ctx;
+ (void)msg, (void)ctx;
printf("%s\n", msg);
}
diff --git a/src/test_senc_enclosure.c b/src/test_senc_enclosure.c
@@ -17,13 +17,12 @@
#include "senc_s3d_wrapper.h"
#include "test_senc_utils.h"
-#include <rsys/float3.h>
#include <rsys/double3.h>
#include <star/s3d.h>
-int
-main(int argc, char** argv)
+static void
+test(enum senc_convention convention)
{
struct mem_allocator allocator;
struct senc_descriptor* desc = NULL;
@@ -31,20 +30,30 @@ main(int argc, char** argv)
struct senc_scene* scn = NULL;
struct senc_enclosure* enclosures[2] = { NULL, NULL };
struct senc_enclosure* enclosure;
- const struct enclosure_header* header;
+ struct senc_enclosure_header header;
struct s3d_device* s3d = NULL;
struct s3d_scene* s3d_scn = NULL;
struct s3d_shape* s3d_shp = NULL;
struct s3d_vertex_data s3d_attribs;
+ unsigned indices[2][3];
+ unsigned medium, media[2];
+ unsigned gid;
+ double vrtx[3];
struct context ctx;
- unsigned i, n, count;
- (void) argc, (void) argv;
+ unsigned i, n, t, ecount;
+ enum senc_convention conv;
+ int is_front, is_in;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
== RES_OK);
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev, convention, &scn) == RES_OK);
+
+ CHK(senc_scene_get_convention(scn, &conv) == RES_OK);
+ CHK(conv == convention);
+ is_front = (conv & SENC_CONVENTION_NORMAL_FRONT) != 0;
+ is_in = (conv & SENC_CONVENTION_NORMAL_INSIDE) != 0;
s3d_attribs.type = S3D_FLOAT3;
s3d_attribs.usage = S3D_POSITION;
@@ -55,7 +64,8 @@ main(int argc, char** argv)
CHK(s3d_scene_create(s3d, &s3d_scn) == RES_OK);
/* A 3D cube.
- * 2 enclosures (inside, outside) sharing the same triangles, but opposite sides */
+ * 2 enclosures (inside, outside) sharing the same triangles,
+ * but opposite sides */
ctx.positions = box_vertices;
ctx.indices = box_indices;
ctx.scale = 1;
@@ -65,15 +75,82 @@ main(int argc, char** argv)
ctx.front_media = medium0;
ctx.back_media = medium1;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
- CHK(count == 2);
+ CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 2);
- FOR_EACH(i, 0, count) {
+ CHK(senc_descriptor_get_enclosure(desc, 0, &enclosure) == RES_OK);
+ CHK(senc_enclosure_ref_get(NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_ref_get(enclosure) == RES_OK);
+ CHK(senc_enclosure_ref_put(NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
+
+ CHK(senc_enclosure_get_triangle(NULL, 0, indices[0]) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(enclosure, ntriangles, indices[0])
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(enclosure, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(NULL, ntriangles, indices[0])
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(enclosure, ntriangles, NULL)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(NULL, ntriangles, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle(enclosure, 0, indices[0]) == RES_OK);
+
+ CHK(senc_enclosure_get_vertex(NULL, 0, vrtx) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(enclosure, nvertices, vrtx)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(enclosure, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(NULL, nvertices, vrtx) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(enclosure, nvertices, NULL)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(NULL, nvertices, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_vertex(enclosure, 0, vrtx) == RES_OK);
+
+ CHK(senc_enclosure_get_triangle_media(NULL, 0, media) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(enclosure, ntriangles, media)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(enclosure, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(NULL, ntriangles, media)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(enclosure, ntriangles, NULL)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(NULL, ntriangles, NULL)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_media(enclosure, 0, media) == RES_OK);
+
+ CHK(senc_enclosure_get_triangle_global_id(NULL, 0, &gid) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, &gid)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_global_id(enclosure, 0, NULL)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, &gid)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_global_id(NULL, 0, NULL) == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_global_id(enclosure, ntriangles, NULL)
+ == RES_BAD_ARG);
+ CHK(senc_enclosure_get_triangle_global_id(NULL, ntriangles, NULL)
+ == 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) {
CHK(senc_descriptor_get_enclosure(desc, i, &enclosure) == RES_OK);
CHK(senc_enclosure_get_header(NULL, &header) == RES_BAD_ARG);
@@ -81,27 +158,43 @@ main(int argc, char** argv)
CHK(senc_enclosure_get_header(NULL, NULL) == RES_BAD_ARG);
CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- CHK(header->enclosure_id == i);
- CHK(header->enclosed_medium == (i == 0 ? 0U : 1U));
- CHK(header->triangle_count == box_ntriangles);
- CHK(header->unique_triangle_count == box_ntriangles);
- CHK(header->vertices_count == box_nvertices);
- CHK(header->is_infinite == (i == 0));
+ CHK(header.enclosure_id == i);
+ CHK(header.enclosed_media_count == 1);
+ CHK(senc_enclosure_get_medium(enclosure, 0, &medium) == RES_OK);
+ /* Geometrical normals point outside the cube in input triangles:
+ * if convention is front, front medium (0) is outside,
+ * that is medium 0's enclosure is infinite */
+ CHK(is_front == ((medium == 0) == header.is_infinite));
+ CHK(header.triangle_count == ntriangles);
+ CHK(header.unique_triangle_count == ntriangles);
+ CHK(header.vertices_count == nvertices);
+ CHK(header.is_infinite == (i == 0));
+
+ FOR_EACH(t, 0, header.triangle_count) {
+ CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid) == RES_OK);
+ CHK(gid == t);
+ }
CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
}
FOR_EACH(i, 0, 2)
CHK(senc_descriptor_get_enclosure(desc, i, enclosures + i) == RES_OK);
- FOR_EACH(n, 0, box_ntriangles) {
- unsigned indices[2][3];
+ FOR_EACH(n, 0, ntriangles) {
+ int same, reversed;
/* Read same triangles in both enclosures */
FOR_EACH(i, 0, 2)
CHK(senc_enclosure_get_triangle(enclosures[i], n, indices[i]) == RES_OK);
- /* Same triangles, opposite sides */
- CHK(indices[0][0] == indices[1][0]);
- CHK(indices[0][1] == indices[1][2]);
- CHK(indices[0][2] == indices[1][1]);
+ /* Same triangles and opposite sides for the 2 enclosures */
+ FOR_EACH(i, 0, 3) CHK(indices[0][i] == indices[1][2 - i]);
+ /* Enclosure 0 is outside (and contains medium 0 if convention is front).
+ * Geometrical normals in output data point in the same direction that those
+ * of input triangles for enclosure 0 iff convention is inside.
+ * The opposite holds for enclosure 1. */
+ cmp_trg(n, enclosures[0], box_indices + 3 * n, box_vertices, &same, &reversed);
+ CHK((same && !reversed) == is_in);
+ cmp_trg(n, enclosures[1], box_indices + 3 * n, box_vertices, &same, &reversed);
+ CHK(same && reversed == is_in);
}
FOR_EACH(i, 0, 2)
CHK(senc_enclosure_ref_put(enclosures[i]) == RES_OK);
@@ -112,7 +205,8 @@ main(int argc, char** argv)
/* Same 3D cube, but with a hole (incomplete).
* 1 single enclosure including both sides of triangles */
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
ctx.positions = box_vertices;
ctx.indices = box_indices;
@@ -121,13 +215,13 @@ main(int argc, char** argv)
ctx.front_media = medium0;
ctx.back_media = medium0;
- CHK(senc_scene_add_geometry(scn, box_ntriangles - 1, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices, get_media,
+ NULL, nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
- CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
- CHK(count == 1);
+ CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 1);
dump_enclosure(desc, 0, "test_enclosure_hole.obj");
@@ -138,29 +232,26 @@ main(int argc, char** argv)
CHK(senc_enclosure_get_header(NULL, NULL) == RES_BAD_ARG);
CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
- CHK(header->enclosure_id == 0);
- CHK(header->enclosed_medium == 0);
- CHK(header->triangle_count == 2 * header->unique_triangle_count);
- CHK(header->unique_triangle_count == box_ntriangles - 1);
- CHK(header->vertices_count == box_nvertices);
- CHK(header->is_infinite == 1);
-
- FOR_EACH(n, 0, header->unique_triangle_count) {
- unsigned indices[2][3];
- /* Read 2 consecutive triangles in the enclosure */
- FOR_EACH(i, 0, 2) /* Triangle n VS 2n */
- CHK(senc_enclosure_get_triangle(enclosure,
- n + i * header->unique_triangle_count, indices[i]) == RES_OK);
- /* Same triangles, opposite sides */
- CHK(indices[0][0] == indices[1][2]);
- CHK(indices[0][1] == indices[1][1]);
- CHK(indices[0][2] == indices[1][0]);
+ CHK(header.enclosure_id == 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);
+ CHK(header.is_infinite == 1);
+
+ FOR_EACH(t, 0, header.unique_triangle_count) {
+ /* The first unique_triangle_count triangles of an enclosure
+ * are unique triangles */
+ CHK(senc_enclosure_get_triangle_global_id(enclosure, t, &gid) == RES_OK);
+ CHK(gid == t);
+ }
+ FOR_EACH(n, 0, header.unique_triangle_count) {
/* Put geometry in a 3D view */
CHK(s3d_shape_create_mesh(s3d, &s3d_shp) == RES_OK);
- CHK(s3d_mesh_setup_indexed_vertices(s3d_shp, header->triangle_count,
- senc_enclosure_get_triangle__, header->vertices_count, &s3d_attribs,
+ CHK(s3d_mesh_setup_indexed_vertices(s3d_shp, header.triangle_count,
+ senc_enclosure_get_triangle__, header.vertices_count, &s3d_attribs,
1, enclosure)
== RES_OK);
@@ -179,6 +270,15 @@ main(int argc, char** argv)
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHK(mem_allocated_size() == 0);
+}
+int
+main(int argc, char** argv)
+{
+ (void) argc, (void) argv;
+ test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE);
+ test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE);
+ test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE);
+ test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE);
return 0;
}
diff --git a/src/test_senc_inconsistant_cube.c b/src/test_senc_inconsistant_cube.c
@@ -0,0 +1,156 @@
+/* Copyright (C) |Meso|Star> 2016-2018 (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/>. */
+
+#include "senc.h"
+#include "senc_s3d_wrapper.h"
+#include "test_senc_utils.h"
+
+#include <rsys/double3.h>
+
+/* The following array lists the indices toward the 3D vertices of each
+* triangle.
+* ,6---,7 ,6----7
+* ,' | ,'/| ,' | \ | Y Z
+* 2----3' / | 2', | \ | | ,'
+* |', | / ,5 | ',4---,5 0----X
+* | ',|/,' | ,' | ,'
+* 0----1' 0----1'
+* Front, right Back, left and
+* and Top faces bottom faces */
+/* Triangle #1 rotation order is not consistant with other triangles */
+static unsigned
+inconsistant_box_indices[12/*#triangles*/ * 3/*#indices per triangle*/] = {
+ 0, 1, 2, 1, 2, 3, /* Front face */
+ 0, 4, 2, 2, 4, 6, /* Left face*/
+ 4, 5, 6, 6, 5, 7, /* Back face */
+ 3, 7, 1, 1, 7, 5, /* Right face */
+ 2, 6, 3, 3, 6, 7, /* Top face */
+ 0, 1, 4, 4, 1, 5 /* Bottom face */
+};
+static const unsigned inconsistant_box_ntriangles
+= sizeof(inconsistant_box_indices) / (3 * sizeof(*inconsistant_box_indices));
+
+/* Media definitions reflect triangle #1 inconsistancy */
+static const unsigned
+inconsistant_medium_front[12] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+static const unsigned
+inconsistant_medium_back[12] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+
+static void
+test(enum senc_convention convention)
+{
+ struct mem_allocator allocator;
+ struct senc_descriptor* desc = NULL;
+ struct senc_device* dev = NULL;
+ struct senc_scene* scn = NULL;
+ struct senc_enclosure* enclosure;
+ struct senc_enclosure_header header;
+ enum senc_convention conv;
+ int conv_front, conv_in;
+ struct context ctx;
+ unsigned i, e, ecount;
+
+ CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
+ CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
+ == RES_OK);
+
+ CHK(senc_scene_create(dev, convention, &scn) == RES_OK);
+
+ /* A 3D cube.
+ * 2 enclosures (inside, outside) sharing the same triangles,
+ * but opposite sides.
+ * What differs in this test is that triangle #0 vertices are given
+ * in the opposite rotation order. */
+ ctx.positions = box_vertices;
+ ctx.indices = inconsistant_box_indices;
+ ctx.scale = 1;
+ ctx.reverse_vrtx = 0;
+ ctx.reverse_med = 0;
+ d3(ctx.offset, 0, 0, 0);
+ ctx.front_media = inconsistant_medium_front;
+ ctx.back_media = inconsistant_medium_back;
+
+ CHK(senc_scene_add_geometry(scn, inconsistant_box_ntriangles, get_indices,
+ get_media, NULL, nvertices, get_position, &ctx) == RES_OK);
+
+ CHK(senc_scene_analyze(scn, &desc) == RES_OK);
+
+ CHK(senc_descriptor_get_enclosure_count(desc, &ecount) == RES_OK);
+ CHK(ecount == 2);
+
+ CHK(senc_scene_get_convention(scn, &conv) == RES_OK);
+ CHK(conv == convention);
+ conv_front = (conv & SENC_CONVENTION_NORMAL_FRONT) != 0;
+ conv_in = (conv & SENC_CONVENTION_NORMAL_INSIDE) != 0;
+
+ FOR_EACH(e, 0, ecount) {
+ unsigned medium, expected_external_medium, expected_medium;
+ char name[128];
+ int front_inside;
+ int expected_side;
+ 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, &medium) == RES_OK);
+ /* If NORMAL_FRONT the external enclosure's medium should be 0,
+ * 1 if NORMAL_BACK */
+ expected_external_medium = conv_front ? 0 : 1;
+ expected_medium = (header.is_infinite ?
+ expected_external_medium : !expected_external_medium);
+ CHK(medium == expected_medium);
+ /* Common media, for non input triangles */
+ front_inside = (conv_front == conv_in);
+ expected_side = front_inside ? 0 : 1;
+
+ sprintf(name, "test_inconsistant_cube_%s_%s_%u.obj",
+ conv_front ? "front" : "back", conv_in ? "in" : "out", e);
+ dump_enclosure(desc, e, name);
+
+ FOR_EACH(i, 0, header.triangle_count) {
+ int same, reversed, fst_reversed;
+ unsigned med[2];
+ fst_reversed = (e == 0) == conv_in;
+ CHK(senc_enclosure_get_triangle_media(enclosure, i, med) == RES_OK);
+ CHK(med[expected_side] == medium);
+ cmp_trg(i, enclosure,
+ inconsistant_box_indices + (3 * i), box_vertices,
+ &same, &reversed);
+ /* Should be made of the same triangles */
+ CHK(same);
+ CHK(i ? reversed != fst_reversed : reversed == fst_reversed);
+ }
+ SENC(enclosure_ref_put(enclosure));
+ }
+
+ SENC(scene_ref_put(scn));
+ SENC(device_ref_put(dev));
+ SENC(descriptor_ref_put(desc));
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+}
+
+int main(int argc, char** argv)
+{
+ (void) argc, (void) argv;
+
+ test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE);
+ test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE);
+ test(SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_OUTSIDE);
+ test(SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_OUTSIDE);
+
+ return 0;
+}
diff --git a/src/test_senc_many_enclosures.c b/src/test_senc_many_enclosures.c
@@ -0,0 +1,172 @@
+/* Copyright (C) |Meso|Star> 2016-2018 (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/>. */
+
+#include "senc.h"
+#include "test_senc_utils.h"
+
+#include <star/s3dut.h>
+#include <rsys/double3.h>
+#include <rsys/clock_time.h>
+
+#include <limits.h>
+
+struct s3dut_context {
+ struct s3dut_mesh_data data;
+ struct context ctx;
+};
+
+static void
+get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context)
+{
+ struct s3dut_context* ctx = context;
+ ASSERT(ids && ctx);
+ ASSERT(itri < ctx->data.nprimitives);
+ ASSERT(ctx->data.indices[itri * 3 + 0] < UINT_MAX
+ && ctx->data.indices[itri * 3 + 1] < UINT_MAX
+ && ctx->data.indices[itri * 3 + 2] < UINT_MAX);
+ ids[0] = (unsigned)ctx->data.indices[itri * 3 + 0];
+ ids[ctx->ctx.reverse_vrtx ? 2 : 1] = (unsigned)ctx->data.indices[itri * 3 + 1];
+ ids[ctx->ctx.reverse_vrtx ? 1 : 2] = (unsigned)ctx->data.indices[itri * 3 + 2];
+}
+
+static void
+get_s3dut_position(const unsigned ivert, double pos[3], void* context)
+{
+ struct s3dut_context* ctx = context;
+ ASSERT(pos && ctx);
+ ASSERT(ivert < ctx->data.nvertices);
+ pos[0]
+ = ctx->data.positions[ivert * 3 + 0] * ctx->ctx.scale + ctx->ctx.offset[0];
+ pos[1]
+ = ctx->data.positions[ivert * 3 + 1] * ctx->ctx.scale + ctx->ctx.offset[1];
+ pos[2]
+ = ctx->data.positions[ivert * 3 + 2] * ctx->ctx.scale + ctx->ctx.offset[2];
+}
+
+static void
+get_s3dut_media(const unsigned itri, unsigned medium[2], void* context)
+{
+ struct s3dut_context* ctx = context;
+ (void)itri;
+ ASSERT(medium && ctx);
+ medium[ctx->ctx.reverse_med ? 1 : 0] = *ctx->ctx.front_media;
+ medium[ctx->ctx.reverse_med ? 0 : 1] = *ctx->ctx.back_media;
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct senc_descriptor* desc = NULL;
+ struct senc_device* dev = NULL;
+ struct senc_scene* scn = NULL;
+ struct s3dut_mesh* cyl = NULL;
+ struct s3dut_context ctx;
+ unsigned m_in, m_out;
+ unsigned count;
+ unsigned cyl_trg_count, cyl_vrtx_count, e;
+ int i, j, k;
+ char dump[64];
+ struct time t0, t1;
+ (void)argc, (void)argv;
+
+ CHK(mem_init_regular_allocator(&allocator) == RES_OK);
+ CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
+ == RES_OK);
+
+#define NB_CYL_1 64
+ /* 64^3 = 262144 cylinders */
+#define NB_CYL (NB_CYL_1 * NB_CYL_1 * NB_CYL_1)
+ /* Create the scene */
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
+
+ ctx.ctx.positions = NULL;
+ ctx.ctx.indices = NULL;
+ ctx.ctx.reverse_vrtx = 0;
+ ctx.ctx.reverse_med = 0;
+ ctx.ctx.front_media = &m_in;
+ ctx.ctx.back_media = &m_out;
+ /* A 20 triangles 12 vertices cylinder template */
+ S3DUT(create_cylinder(&allocator, 1, 1, 5, 1, &cyl));
+ S3DUT(mesh_get_data(cyl, &ctx.data));
+ ASSERT(ctx.data.nprimitives < UINT_MAX);
+ ASSERT(ctx.data.nvertices < UINT_MAX);
+ cyl_trg_count = (unsigned)ctx.data.nprimitives;
+ cyl_vrtx_count = (unsigned)ctx.data.nvertices;
+ FOR_EACH(i, 0, NB_CYL_1) {
+ double center_x = 2 * (1 + NB_CYL_1) * (i - NB_CYL_1 / 2);
+ FOR_EACH(j, 0, NB_CYL_1) {
+ double misalignment = 0.01;
+ FOR_EACH(k, 0, NB_CYL_1) {
+ double center_y = 2 * (1 + NB_CYL_1) * (j - NB_CYL_1 / 2);
+ m_in = (unsigned)k;
+ m_out = (unsigned)(k + 1);
+ ctx.ctx.scale = k + 1;
+ /* Mitigate Embree issue #181
+ * We cannot keep perfect alignment of cylinders
+ * or some hits are missed */
+ misalignment *= -1;
+ d3(ctx.ctx.offset, center_x + misalignment, center_y + misalignment, 0);
+ CHK(senc_scene_add_geometry(scn, cyl_trg_count, get_s3dut_indices,
+ get_s3dut_media, NULL, cyl_vrtx_count, get_s3dut_position, &ctx)
+ == RES_OK);
+ }
+ }
+ }
+ S3DUT(mesh_ref_put(cyl));
+
+ time_current(&t0);
+ CHK(senc_scene_analyze(scn, &desc) == RES_OK);
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump));
+ printf("Scene analyzed in: %s\n", dump);
+
+ /* dump_global(desc, "test_many_enclosures.obj"); */
+
+ CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
+ CHK(count == NB_CYL * cyl_vrtx_count);
+ CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
+ CHK(count == NB_CYL * cyl_trg_count);
+
+ CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
+ CHK(count == 1 + NB_CYL);
+
+ 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 ==
+ (header.is_infinite /* Outermost enclosure: NB_CYL_1*NB_CYL_1 cylinders */
+ ? NB_CYL_1 * NB_CYL_1 * cyl_trg_count
+ : (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);
+ }
+
+ CHK(senc_scene_ref_put(scn) == RES_OK);
+ CHK(senc_device_ref_put(dev) == RES_OK);
+ CHK(senc_descriptor_ref_put(desc) == RES_OK);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_regular_allocator(&allocator);
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}
diff --git a/src/test_senc_many_triangles.c b/src/test_senc_many_triangles.c
@@ -17,8 +17,10 @@
#include "test_senc_utils.h"
#include <star/s3dut.h>
-
#include <rsys/double3.h>
+#include <rsys/clock_time.h>
+
+#include <limits.h>
struct s3dut_context {
struct s3dut_mesh_data data;
@@ -34,9 +36,9 @@ get_s3dut_indices(const unsigned itri, unsigned ids[3], void* context)
ASSERT(ctx->data.indices[itri * 3 + 0] < UINT_MAX
&& ctx->data.indices[itri * 3 + 1] < UINT_MAX
&& ctx->data.indices[itri * 3 + 2] < UINT_MAX);
- ids[0] = (unsigned) ctx->data.indices[itri * 3 + 0];
- ids[ctx->ctx.reverse_vrtx ? 2 : 1] = (unsigned) ctx->data.indices[itri * 3 + 1];
- ids[ctx->ctx.reverse_vrtx ? 1 : 2] = (unsigned) ctx->data.indices[itri * 3 + 2];
+ ids[0] = (unsigned)ctx->data.indices[itri * 3 + 0];
+ ids[ctx->ctx.reverse_vrtx ? 2 : 1] = (unsigned)ctx->data.indices[itri * 3 + 1];
+ ids[ctx->ctx.reverse_vrtx ? 1 : 2] = (unsigned)ctx->data.indices[itri * 3 + 2];
}
static void
@@ -45,19 +47,22 @@ get_s3dut_position(const unsigned ivert, double pos[3], void* context)
struct s3dut_context* ctx = context;
ASSERT(pos && ctx);
ASSERT(ivert < ctx->data.nvertices);
- pos[0] = ctx->data.positions[ivert * 3 + 0] * ctx->ctx.scale + ctx->ctx.offset[0];
- pos[1] = ctx->data.positions[ivert * 3 + 1] * ctx->ctx.scale + ctx->ctx.offset[1];
- pos[2] = ctx->data.positions[ivert * 3 + 2] * ctx->ctx.scale + ctx->ctx.offset[2];
+ pos[0]
+ = ctx->data.positions[ivert * 3 + 0] * ctx->ctx.scale + ctx->ctx.offset[0];
+ pos[1]
+ = ctx->data.positions[ivert * 3 + 1] * ctx->ctx.scale + ctx->ctx.offset[1];
+ pos[2]
+ = ctx->data.positions[ivert * 3 + 2] * ctx->ctx.scale + ctx->ctx.offset[2];
}
static void
get_s3dut_media(const unsigned itri, unsigned medium[2], void* context)
{
struct s3dut_context* ctx = context;
- (void) itri;
+ (void)itri;
ASSERT(medium && ctx);
- medium[ctx->ctx.reverse_med ? 1 : 0] = ctx->ctx.front_media[0];
- medium[ctx->ctx.reverse_med ? 0 : 1] = ctx->ctx.back_media[1];
+ medium[ctx->ctx.reverse_med ? 1 : 0] = *ctx->ctx.front_media;
+ medium[ctx->ctx.reverse_med ? 0 : 1] = *ctx->ctx.back_media;
}
int
@@ -69,52 +74,76 @@ main(int argc, char** argv)
struct senc_scene* scn = NULL;
struct s3dut_mesh* cyl = NULL;
struct s3dut_context ctx;
+ unsigned m0 = 0, m1;
unsigned count;
- unsigned cyl_trg_count, cyl_vrtx_count;
- int i;
- (void) argc, (void) argv;
+ unsigned cyl_trg_count, cyl_vrtx_count, i;
+ char dump[64];
+ struct time t0, t1;
+ (void)argc, (void)argv;
- CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
- CHK(senc_device_create
- (NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev) == RES_OK);
+ CHK(mem_init_regular_allocator(&allocator) == RES_OK);
+ CHK(senc_device_create (NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
+ == RES_OK);
+#define NB_CYL 4
/* Create the scene */
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
ctx.ctx.positions = NULL;
ctx.ctx.indices = NULL;
ctx.ctx.scale = 1;
ctx.ctx.reverse_vrtx = 0;
ctx.ctx.reverse_med = 0;
- ctx.ctx.front_media = medium0;
- ctx.ctx.back_media = medium1;
- /* Create a cylinder (320 K trg, 160 K vrtx). */
- CHK(s3dut_create_cylinder(&allocator, 1, 2, 400, 400, &cyl) == RES_OK);
+ ctx.ctx.back_media = &m0;
+ ctx.ctx.front_media = &m1;
+ /* A 2,562,560 triangles 1,281,282 vertices cylinder template */
+ S3DUT(create_cylinder(&allocator, 1, 2, 1280, 1000, &cyl));
S3DUT(mesh_get_data(cyl, &ctx.data));
ASSERT(ctx.data.nprimitives < UINT_MAX);
ASSERT(ctx.data.nvertices < UINT_MAX);
cyl_trg_count = (unsigned)ctx.data.nprimitives;
cyl_vrtx_count = (unsigned)ctx.data.nvertices;
-#define NB_CYL 10
FOR_EACH(i, 0, NB_CYL) {
+ m1 = i;
d3(ctx.ctx.offset, 0, 0, i * 10);
CHK(senc_scene_add_geometry(scn, cyl_trg_count, get_s3dut_indices,
- get_s3dut_media, cyl_vrtx_count, get_s3dut_position, &ctx) == RES_OK);
+ get_s3dut_media, NULL, cyl_vrtx_count, get_s3dut_position, &ctx)
+ == RES_OK);
}
S3DUT(mesh_ref_put(cyl));
+
+ time_current(&t0);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_MSEC | TIME_SEC | TIME_MIN, NULL, dump, sizeof(dump));
+ printf("Scene analyzed in: %s\n", dump);
+
+ /* dump_global(desc, "test_many_triangles.obj"); */
CHK(senc_descriptor_get_global_vertices_count(desc, &count) == RES_OK);
CHK(count == NB_CYL * cyl_vrtx_count);
CHK(senc_descriptor_get_global_triangles_count(desc, &count) == RES_OK);
CHK(count == NB_CYL * cyl_trg_count);
+ CHK(senc_descriptor_get_enclosure_count(desc, &count) == RES_OK);
+ CHK(count == 1 + NB_CYL);
+ FOR_EACH(i, 0, count) {
+ 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);
+ CHK(header.triangle_count ==
+ i ? cyl_trg_count : NB_CYL * cyl_trg_count);
+ CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
+ }
+
CHK(senc_scene_ref_put(scn) == RES_OK);
CHK(senc_device_ref_put(dev) == RES_OK);
CHK(senc_descriptor_ref_put(desc) == RES_OK);
check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
+ mem_shutdown_regular_allocator(&allocator);
CHK(mem_allocated_size() == 0);
return 0;
}
diff --git a/src/test_senc_sample_enclosure.c b/src/test_senc_sample_enclosure.c
@@ -31,7 +31,7 @@ main(int argc, char** argv)
struct senc_device* dev = NULL;
struct senc_scene* scn = NULL;
struct senc_enclosure* enclosure = NULL;
- const struct enclosure_header* header = NULL;
+ struct senc_enclosure_header header;
struct s3d_device* s3d = NULL;
struct s3d_scene* s3d_scn = NULL;
struct s3d_scene_view* s3d_view = NULL;
@@ -42,26 +42,27 @@ main(int argc, char** argv)
struct context ctx;
int i;
float st[2];
- (void) argc, (void) argv;
+ (void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
== RES_OK);
- CHK(senc_scene_create(dev, 2, &scn) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
vrtx_get.type = S3D_FLOAT3;
vrtx_get.usage = S3D_POSITION;
vrtx_get.get = senc_enclosure_get_vertex__;
- CHK(s3d_device_create(NULL, &allocator, 0, &s3d) == RES_OK);
+ S3D(device_create(NULL, &allocator, 0, &s3d));
- CHK(s3d_scene_create(s3d, &s3d_scn) == RES_OK);
+ S3D(scene_create(s3d, &s3d_scn));
/* A 3D cube, but with a hole (incomplete).
* 1 single enclosure including both sides of triangles */
- ctx.positions = box_vertices;
+ ctx.positions = cube_vertices; /* Need a true cube */
ctx.indices = box_indices;
ctx.scale = 1;
ctx.reverse_vrtx = 0;
@@ -70,8 +71,8 @@ main(int argc, char** argv)
ctx.front_media = medium0;
ctx.back_media = medium0;
- CHK(senc_scene_add_geometry(scn, box_ntriangles - 1, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles - 1, get_indices,
+ get_media, NULL, nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_analyze(scn, &desc) == RES_OK);
@@ -79,14 +80,14 @@ main(int argc, char** argv)
CHK(senc_enclosure_get_header(enclosure, &header) == RES_OK);
/* Put enclosure in a 3D view... */
- CHK(s3d_shape_create_mesh(s3d, &s3d_shp) == RES_OK);
- CHK(s3d_mesh_setup_indexed_vertices(s3d_shp, header->triangle_count,
- senc_enclosure_get_triangle__, header->vertices_count, &vrtx_get, 1, enclosure)
- == RES_OK);
+ S3D(shape_create_mesh(s3d, &s3d_shp));
+ S3D(mesh_setup_indexed_vertices(s3d_shp, header.triangle_count,
+ senc_enclosure_get_triangle__, header.vertices_count, &vrtx_get, 1,
+ enclosure));
- CHK(s3d_scene_attach_shape(s3d_scn, s3d_shp) == RES_OK);
+ S3D(scene_attach_shape(s3d_scn, s3d_shp));
- CHK(s3d_scene_view_create(s3d_scn, S3D_SAMPLE, &s3d_view) == RES_OK);
+ S3D(scene_view_create(s3d_scn, S3D_SAMPLE, &s3d_view));
/* ... and sample it. */
CHK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng) == RES_OK);
@@ -104,19 +105,19 @@ main(int argc, char** argv)
if(eq_eps(attrib.value[n], 0, FLT_EPSILON)
|| eq_eps(attrib.value[n], 1, FLT_EPSILON))
c++;
- ASSERT(c == 1);
+ CHK(c == 1);
S3D(primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, st, &attrib));
c = 0;
FOR_EACH(n, 0, 3)
if(eq_eps(attrib.value[n], -1, FLT_EPSILON)
|| eq_eps(attrib.value[n], 1, FLT_EPSILON))
c++;
- ASSERT(c == 1);
+ CHK(c == 1);
c = 0;
FOR_EACH(n, 0, 3)
if(eq_eps(attrib.value[n], 0, FLT_EPSILON))
c++;
- ASSERT(c == 2);
+ CHK(c == 2);
}
SENC(enclosure_ref_put(enclosure));
diff --git a/src/test_senc_scene.c b/src/test_senc_scene.c
@@ -19,8 +19,6 @@
#include <rsys/float3.h>
#include <rsys/double3.h>
-#include <star/s3d.h>
-
int
main(int argc, char** argv)
{
@@ -28,24 +26,64 @@ main(int argc, char** argv)
struct senc_device* dev = NULL;
struct senc_scene* scn = NULL;
struct senc_descriptor* desc = NULL;
+ struct senc_enclosure* enc = NULL;
+ struct senc_enclosure_header header;
struct context ctx;
+ unsigned medfront[2], medback[2];
+ unsigned count, i, maxm;
+ enum senc_convention convention;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
CHK(senc_device_create(NULL, &allocator, SENC_NTHREADS_DEFAULT, 1, &dev)
== RES_OK);
- CHK(senc_scene_create(NULL, 2, &scn) == RES_BAD_ARG);
+ CHK(senc_scene_create(NULL,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_BAD_ARG);
CHK(senc_scene_create(dev, 0, &scn) == RES_BAD_ARG);
- CHK(senc_scene_create(dev, 2, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, NULL) == RES_BAD_ARG);
CHK(senc_scene_create(NULL, 0, &scn) == RES_BAD_ARG);
- CHK(senc_scene_create(NULL, 2, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_create(NULL,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, NULL) == RES_BAD_ARG);
CHK(senc_scene_create(dev, 0, NULL) == RES_BAD_ARG);
CHK(senc_scene_create(NULL, 0, NULL) == RES_BAD_ARG);
- /* It is valid to have unused media */
- CHK(senc_scene_create(dev, 4, &scn) == RES_OK);
-
- /* A 3D cube */
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
+
+ CHK(senc_scene_get_convention(NULL, &convention) == RES_BAD_ARG);
+ CHK(senc_scene_get_convention(scn, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_convention(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_convention(scn, &convention) == RES_OK);
+ CHK(convention == (SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE));
+
+ CHK(senc_scene_get_triangles_count(NULL, &count) == RES_BAD_ARG);
+ CHK(senc_scene_get_triangles_count(scn, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_triangles_count(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_triangles_count(scn, &count) == RES_OK);
+ CHK(count == 0);
+
+ CHK(senc_scene_get_unique_triangles_count(NULL, &count) == RES_BAD_ARG);
+ CHK(senc_scene_get_unique_triangles_count(scn, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_unique_triangles_count(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_unique_triangles_count(scn, &count) == RES_OK);
+ CHK(count == 0);
+
+ CHK(senc_scene_get_vertices_count(NULL, &count) == RES_BAD_ARG);
+ CHK(senc_scene_get_vertices_count(scn, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_vertices_count(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_vertices_count(scn, &count) == RES_OK);
+ CHK(count == 0);
+
+ CHK(senc_scene_get_unique_vertices_count(NULL, &count) == RES_BAD_ARG);
+ CHK(senc_scene_get_unique_vertices_count(scn, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_unique_vertices_count(NULL, NULL) == RES_BAD_ARG);
+ CHK(senc_scene_get_unique_vertices_count(scn, &count) == RES_OK);
+ CHK(count == 0);
+
+ /* A 3D cube.
+ * With this geometry front is inside with NORMAL_BACK convention,
+ * outside with NORMAL_FRONT convention */
ctx.positions = box_vertices;
ctx.indices = box_indices;
ctx.scale = 1;
@@ -54,21 +92,31 @@ main(int argc, char** argv)
d3(ctx.offset, 0, 0, 0);
ctx.front_media = medium0;
ctx.back_media = medium1;
-
- CHK(senc_scene_add_geometry(NULL, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, 0, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, box_ntriangles, NULL, get_media,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, NULL,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- 0, get_position, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, NULL, &ctx) == RES_BAD_ARG);
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ ctx.global_ids = gid_face;
+
+ CHK(senc_scene_add_geometry(NULL, ntriangles, get_indices, get_media,
+ get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, 0, get_indices, get_media, get_global_id,
+ nvertices, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, NULL, get_media,
+ get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, NULL,
+ get_global_id, nvertices, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ get_global_id, 0, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ get_global_id, nvertices, NULL, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ get_global_id, nvertices, get_position, &ctx) == RES_OK);
+
+ CHK(senc_scene_get_triangles_count(scn, &count) == RES_OK);
+ CHK(count == ntriangles);
+ CHK(senc_scene_get_unique_triangles_count(scn, &count) == RES_OK);
+ CHK(count == ntriangles);
+ CHK(senc_scene_get_vertices_count(scn, &count) == RES_OK);
+ CHK(count == nvertices);
+ CHK(senc_scene_get_unique_vertices_count(scn, &count) == RES_OK);
+ CHK(count == nvertices);
CHK(senc_scene_analyze(NULL, NULL) == RES_BAD_ARG);
CHK(senc_scene_analyze(scn, NULL) == RES_BAD_ARG);
@@ -81,43 +129,105 @@ main(int argc, char** argv)
CHK(senc_scene_ref_put(NULL) == RES_BAD_ARG);
CHK(senc_scene_ref_put(scn) == RES_OK);
- /* Invalid medium ID */
- ctx.back_media = medium1_12;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
- ctx.back_media = medium1;
+ CHK(senc_scene_ref_put(scn) == RES_OK);
+ CHK(senc_descriptor_ref_put(desc) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
+ CHK(senc_scene_get_convention(scn, &convention) == RES_OK);
+ CHK(convention == (SENC_CONVENTION_NORMAL_BACK | SENC_CONVENTION_NORMAL_INSIDE));
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media,
+ get_global_id, nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_analyze(scn, &desc) == RES_OK);
+ /* Check that medium 0 is inside */
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK);
+ CHK(senc_enclosure_get_header(enc, &header) == RES_OK);
+ CHK(!header.is_infinite);
+ CHK(senc_enclosure_ref_put(enc) == RES_OK);
+
+ FOR_EACH(i, 0, ntriangles) {
+ unsigned gid;
+ CHK(senc_descriptor_get_global_triangle_global_id(desc, i, &gid) == RES_OK);
+ /* gid has been set to gid_face. */
+ CHK(gid == gid_face[i]);
+ }
+ CHK(senc_descriptor_get_global_triangle_media(desc, 0, medback) == RES_OK);
+
+ ctx.front_media = medium1_3;
+ CHK(senc_scene_ref_put(scn) == RES_OK);
+ CHK(senc_descriptor_ref_put(desc) == RES_OK);
+ CHK(senc_scene_create(dev,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &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, 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,
+ SENC_CONVENTION_NORMAL_FRONT | SENC_CONVENTION_NORMAL_INSIDE, &scn) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_analyze(scn, &desc) == RES_OK);
+ /* Check that medium 0 is outside */
+ CHK(senc_descriptor_get_enclosure_by_medium(desc, 0, 0, &enc) == RES_OK);
+ CHK(senc_enclosure_get_header(enc, &header) == RES_OK);
+ CHK(header.is_infinite);
+ CHK(senc_enclosure_ref_put(enc) == RES_OK);
+
+ FOR_EACH(i, 0, ntriangles) {
+ unsigned gid;
+ CHK(senc_descriptor_get_global_triangle_global_id(desc, i, &gid) == RES_OK);
+ /* Default gid: triangle rank. */
+ CHK(gid == i);
+ }
+ CHK(senc_descriptor_get_global_triangle_media(desc, 0, medfront) == RES_OK);
+ FOR_EACH(i, 0, 2) CHK(medback[i] == medfront[i]);
/* Invalid vertex ID */
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices - 1, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices - 1, get_position, &ctx) == RES_BAD_ARG);
/* Incoherent medium on a duplicate triangle */
ctx.back_media = medium1_3;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_BAD_ARG);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_BAD_ARG);
/* It is OK dd geometry after a failed add */
ctx.back_media = medium1;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
/* Coherent medium on duplicate triangle */
ctx.back_media = medium1;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
/* Coherent medium on duplicate triangle V2 */
ctx.reverse_med = 1;
ctx.front_media = medium1;
ctx.back_media = medium0;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
/* Coherent medium on duplicate triangle V3 */
ctx.reverse_med = 0;
ctx.reverse_vrtx = 1;
- CHK(senc_scene_add_geometry(scn, box_ntriangles, get_indices, get_media,
- box_nvertices, get_position, &ctx) == RES_OK);
+ CHK(senc_scene_add_geometry(scn, ntriangles, get_indices, get_media, NULL,
+ nvertices, get_position, &ctx) == RES_OK);
CHK(senc_scene_ref_put(scn) == RES_OK);
CHK(senc_device_ref_put(dev) == RES_OK);
diff --git a/src/test_senc_utils.h b/src/test_senc_utils.h
@@ -16,13 +16,28 @@
#ifndef TEST_UTILS_H
#define TEST_UTILS_H
+#include <rsys/rsys.h>
#include <rsys/mem_allocator.h>
+#include <rsys/double3.h>
+
#include <stdio.h>
/*******************************************************************************
* Geometry
******************************************************************************/
+/* Distorded cube */
static const double box_vertices[8/*#vertices*/*3/*#coords per vertex*/] = {
+ 0.1, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 1.0, 0.0,
+ 0.0, 0.0, 1.1,
+ 1.0, 0.0, 1.0,
+ 0.0, 1.0, 1.0,
+ 1.0, 1.1, 1.0
+};
+/* Need a true cube for some tests */
+static const double cube_vertices[8/*#vertices*/ * 3/*#coords per vertex*/] = {
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
@@ -32,19 +47,22 @@ static const double box_vertices[8/*#vertices*/*3/*#coords per vertex*/] = {
0.0, 1.0, 1.0,
1.0, 1.0, 1.0
};
-static const unsigned box_nvertices = sizeof(box_vertices) / sizeof(double[3]);
+static const unsigned nvertices = sizeof(box_vertices) / sizeof(double[3]);
+STATIC_ASSERT(sizeof(box_vertices) == sizeof(cube_vertices),
+ The_2_geometries_must_have_the_same_number_of_vertices);
/* The following array lists the indices toward the 3D vertices of each
* triangle.
- * ,6---,7 ,6----7
- * ,' | ,'/| ,' | \ | Y Z
- * 2----3' / | 2', | \ | | ,'
- * |', | / ,5 | ',4---,5 0----X
- * | ',|/,' | ,' | ,'
- * 0----1' 0----1'
- * Front, right Back, left and
+ * ,2---,3 ,2----3
+ * ,' | ,'/| ,'/| \ |
+ * 6----7' / | 6' / | \ | Y
+ * |', | / ,1 | / ,0---,1 |
+ * | ',|/,' |/,' | ,' o--X
+ * 4----5' 4----5' /
+ * Front, right Back, left and Z
* and Top faces bottom faces */
-static const unsigned box_indices[12/*#triangles*/*3/*#indices per triangle*/] = {
+static const unsigned
+box_indices[12/*#triangles*/*3/*#indices per triangle*/] = {
0, 2, 1, 1, 2, 3, /* Front face */
0, 4, 2, 2, 4, 6, /* Left face*/
4, 5, 6, 6, 5, 7, /* Back face */
@@ -52,13 +70,15 @@ static const unsigned box_indices[12/*#triangles*/*3/*#indices per triangle*/] =
2, 6, 3, 3, 6, 7, /* Top face */
0, 1, 4, 4, 1, 5 /* Bottom face */
};
-static const unsigned box_ntriangles = sizeof(box_indices) / (3 * sizeof(*box_indices));
+static const unsigned
+ntriangles = sizeof(box_indices) / (3 * sizeof(*box_indices));
struct context {
const double* positions;
const unsigned* indices;
const unsigned* front_media;
const unsigned* back_media;
+ const unsigned* global_ids;
double offset[3];
double scale;
char reverse_vrtx, reverse_med;
@@ -68,11 +88,12 @@ static const unsigned medium0[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static const unsigned medium1[12] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
static const unsigned medium2[12] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
static const unsigned medium1_3[12] = { 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1 };
-static const unsigned medium1_12[12] = { 1, 1, 1, 1, 1, 1, 1, 1, 12, 1, 1, 1 };
static const unsigned medium1_back0[12] = { 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1 };
static const unsigned medium1_front0[12] = { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-static void
+static const unsigned gid_face[12] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 };
+
+static INLINE void
get_indices(const unsigned itri, unsigned ids[3], void* context)
{
struct context* ctx = context;
@@ -82,7 +103,7 @@ get_indices(const unsigned itri, unsigned ids[3], void* context)
ids[ctx->reverse_vrtx ? 1 : 2] = ctx->indices[itri * 3 + 2];
}
-static void
+static INLINE void
get_position(const unsigned ivert, double pos[3], void* context)
{
struct context* ctx = context;
@@ -92,7 +113,7 @@ get_position(const unsigned ivert, double pos[3], void* context)
pos[2] = ctx->positions[ivert * 3 + 2] * ctx->scale + ctx->offset[2];
}
-static void
+static INLINE void
get_media(const unsigned itri, unsigned medium[2], void* context)
{
struct context* ctx = context;
@@ -101,39 +122,54 @@ get_media(const unsigned itri, unsigned medium[2], void* context)
medium[ctx->reverse_med ? 0 : 1] = ctx->back_media[itri];
}
+static INLINE void
+get_global_id(const unsigned itri, unsigned* gid, void* context)
+{
+ struct context* ctx = context;
+ ASSERT(gid && context);
+ *gid = ctx->global_ids[itri];
+}
+
/*******************************************************************************
* Miscellaneous
******************************************************************************/
static INLINE void
-dump_mesh
- (FILE* stream,
- const double* pos,
- const size_t npos,
- const size_t* ids,
- const size_t nids)
+dump_global
+ (struct senc_descriptor* desc,
+ const char* name)
{
- size_t i;
- CHK(pos != NULL && npos != 0);
- CHK(ids != NULL && nids != 0);
- FOR_EACH(i, 0, npos) {
- fprintf(stream, "v %g %g %g\n", SPLIT3(pos+i*3));
+ FILE* stream;
+ unsigned triangles_count, vertices_count, i;
+
+ ASSERT(desc && name);
+
+ CHK(senc_descriptor_get_global_vertices_count(desc, &vertices_count) == RES_OK);
+ CHK(senc_descriptor_get_global_triangles_count(desc, &triangles_count) == RES_OK);
+
+ stream = fopen(name, "w");
+ CHK(stream);
+ FOR_EACH(i, 0, vertices_count) {
+ double tmp[3];
+ CHK(senc_descriptor_get_global_vertex(desc, i, tmp) == RES_OK);
+ fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
}
- FOR_EACH(i, 0, nids) {
- fprintf(stream, "f %lu %lu %lu\n",
- (unsigned long)(ids[i*3+0] + 1),
- (unsigned long)(ids[i*3+1] + 1),
- (unsigned long)(ids[i*3+2] + 1));
+ FOR_EACH(i, 0, triangles_count) {
+ unsigned indices[3];
+ CHK(senc_descriptor_get_global_triangle(desc, i, indices) == RES_OK);
+ fprintf(stream, "f %lu %lu %lu\n", (unsigned long)(1 + indices[0]),
+ (unsigned long)(1 + indices[1]), (unsigned long)(1 + indices[2]));
}
+ fclose(stream);
}
-static void
+static INLINE void
dump_enclosure
(struct senc_descriptor* desc,
const unsigned enc,
const char* name)
{
struct senc_enclosure* enclosure;
- const struct enclosure_header* header;
+ struct senc_enclosure_header header;
FILE* stream;
unsigned count, i;
@@ -146,16 +182,16 @@ dump_enclosure
stream = fopen(name, "w");
CHK(stream);
- FOR_EACH(i, 0, header->vertices_count) {
+ FOR_EACH(i, 0, header.vertices_count) {
double tmp[3];
CHK(senc_enclosure_get_vertex(enclosure, i, tmp) == RES_OK);
fprintf(stream, "v %g %g %g\n", SPLIT3(tmp));
}
- FOR_EACH(i, 0, header->triangle_count) {
+ FOR_EACH(i, 0, header.triangle_count) {
unsigned indices[3];
CHK(senc_enclosure_get_triangle(enclosure, i, indices) == RES_OK);
- fprintf(stream, "f %lu %lu %lu\n",
- 1+indices[0], 1+indices[1], 1+indices[2]);
+ fprintf(stream, "f %lu %lu %lu\n", (unsigned long)(1+indices[0]),
+ (unsigned long)(1+indices[1]), (unsigned long)(1+indices[2]));
}
CHK(senc_enclosure_ref_put(enclosure) == RES_OK);
fclose(stream);
@@ -172,5 +208,93 @@ 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 */
+}
+
+/* Compare the itri-th triangle of enclosure with a triangle described by trg2 & vertices2 */
+static INLINE void
+cmp_trg
+ (const unsigned itri,
+ const struct senc_enclosure* enclosure,
+ const unsigned trg2[3],
+ const double* vertices2,
+ int* trg_eq,
+ int* trg_reversed)
+{
+ unsigned trg1[3];
+ double t1[3][3];
+ double t2[3][3];
+ unsigned trg1_eq[3] = { 3, 3, 3 };
+ unsigned i, j, fst_vrtx = 3;
+
+ ASSERT(enclosure && trg2 && vertices2 && trg_eq && trg_reversed);
+
+ CHK(senc_enclosure_get_triangle(enclosure, itri, trg1) == RES_OK);
+ FOR_EACH(i, 0, 3) {
+ CHK(senc_enclosure_get_vertex(enclosure, trg1[i], t1[i]) == RES_OK);
+ d3_set(t2[i], vertices2 + (3 * trg2[i]));
+ }
+ FOR_EACH(i, 0, 3) {
+ FOR_EACH(j, 0, 3) {
+ if (d3_eq(t1[i], t2[j])) {
+ trg1_eq[i] = j;
+ if (i == 0) fst_vrtx = j;
+ break;
+ }
+ }
+ }
+ FOR_EACH(i, 0, 3) {
+ if (trg1_eq[i] == 3) {
+ *trg_eq = 0;
+ return;
+ }
+ if (trg1_eq[i] == trg1_eq[(i + 1) % 3]
+ || trg1_eq[i] == trg1_eq[(i + 2) % 3]) {
+ *trg_eq = 0;
+ return;
+ }
+ }
+ /* Same 3 vertices */
+ ASSERT(fst_vrtx != 3);
+ *trg_eq = 1;
+
+ *trg_reversed = (trg1_eq[1] != (fst_vrtx + 1) % 3);
+ ASSERT(*trg_reversed != (trg1_eq[1] != (fst_vrtx + 2) % 3));
+}
+
#endif /* TEST_UTILS_H */