commit ae4d27842dfb20c710380de8e840d41959083491
parent cc97338e42269d232fa95417faf30a02bf13d3f9
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 4 Jan 2023 12:11:00 +0100
Merge branch 'release_0.1'
Diffstat:
19 files changed, 615 insertions(+), 556 deletions(-)
diff --git a/README.md b/README.md
@@ -29,7 +29,7 @@ informations on CMake.
## License
-Copyright (C) 2020, 2021 [|Meso|Star>](https://www.meso-star.com)
+Copyright (C) 2020-2023 [|Méso|Star>](https://www.meso-star.com)
(<contact@meso-star.com>). Star-UnstructuredVolumetricMesh is free software
released under the GPL v3+ license: GNU GPL version 3 or later. You are welcome
to redistribute it under certain conditions; refer to the COPYING file for
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+# Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -25,9 +25,9 @@ option(NO_TEST "Do not build tests" OFF)
################################################################################
find_package(Embree 3.6 REQUIRED)
find_package(RCMake 0.4 REQUIRED)
-find_package(RSys 0.12 REQUIRED)
+find_package(RSys 0.13 REQUIRED)
if(NOT NO_TEST)
- find_package(StarTetraHedra)
+ find_package(StarMesh)
endif()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
@@ -44,8 +44,8 @@ endif()
# Configure and define targets
################################################################################
set(VERSION_MAJOR 0)
-set(VERSION_MINOR 0)
-set(VERSION_PATCH 1)
+set(VERSION_MINOR 1)
+set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SUVM_FILES_SRC
@@ -91,7 +91,7 @@ if(NOT NO_TEST)
${SUVM_SOURCE_DIR}/test_suvm_utils.h)
target_link_libraries(${_name} suvm RSys ${ARGN})
endfunction()
-
+
function(new_test _name)
build_test(${_name} ${ARGN})
add_test(${_name} ${_name})
@@ -101,12 +101,12 @@ if(NOT NO_TEST)
new_test(test_suvm_volume)
new_test(test_suvm_primitive_intersection)
- if(StarTetraHedra_FOUND)
- add_executable(suvm_voxelize ${SUVM_SOURCE_DIR}/suvm_voxelize_sth.c)
- target_link_libraries(suvm_voxelize RSys StarTetraHedra suvm)
+ if(StarMesh_FOUND)
+ add_executable(suvm_voxelize ${SUVM_SOURCE_DIR}/suvm_voxelize.c)
+ target_link_libraries(suvm_voxelize RSys StarMesh suvm)
else()
- message(STATUS "Star-TetraHedra was not found. "
- "The suvm_voxelize_sth program will not be build.")
+ message(STATUS "Star-Mesh was not found. "
+ "The program suvm_voxelize will not be built")
endif()
endif()
diff --git a/src/suvm.h b/src/suvm.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -97,6 +97,18 @@ struct suvm_polyhedron {
float upper[3/*#coords*/];
};
+/* Internal copy of the unstructured mesh */
+struct suvm_mesh_desc {
+ const float* positions;
+ const uint32_t* indices;
+ size_t nvertices;
+ size_t nprimitives;
+ unsigned dvertex; /* Dimension of a vertex */
+ unsigned dprimitive; /* Dimension of a primitive */
+};
+#define SUVM_MESH_DESC_NULL__ {NULL, NULL, 0, 0, 0, 0}
+static const struct suvm_mesh_desc SUVM_MESH_DESC_NULL = SUVM_MESH_DESC_NULL__;
+
struct suvm_tetrahedral_mesh_args {
size_t ntetrahedra; /* #tetrahedra */
size_t nvertices; /* #vertices */
@@ -229,6 +241,16 @@ suvm_volume_compute_hash
const int cpnt_mask, /* Combination of suvm_volume_cpnt_flag */
hash256_T hash);
+SUVM_API res_T
+suvm_volume_get_mesh_desc
+ (const struct suvm_volume* volume,
+ struct suvm_mesh_desc* desc);
+
+SUVM_API res_T
+suvm_mesh_desc_compute_hash
+ (const struct suvm_mesh_desc* desc,
+ hash256_T hash);
+
/*******************************************************************************
* Primitive API
******************************************************************************/
diff --git a/src/suvm_c.h b/src/suvm_c.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/suvm_device.c b/src/suvm_device.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/suvm_device.h b/src/suvm_device.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/suvm_primitive.c b/src/suvm_primitive.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/suvm_volume.c b/src/suvm_volume.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,18 +23,6 @@
#include <rsys/dynamic_array_size_t.h>
#include <rsys/ref_count.h>
-struct hash_context {
- struct cpnt {
- const void* mem;
- size_t size; /* Size in bytes */
- size_t chunk_min; /* Inclusive */
- size_t chunk_max; /* Exclusive */
- } cpnts[4];
- int ncpnts;
- int icpnt;
-};
-static const struct hash_context HASH_CONTEXT_NULL;
-
/* Generate the dynamic array of RTCBuildPrimitive */
#define DARRAY_NAME rtc_prim
#define DARRAY_DATA struct RTCBuildPrimitive
@@ -521,40 +509,6 @@ error:
}
static void
-get_chunk(char dst[64], const size_t ichunk, void* context)
-{
- struct hash_context* ctx = context;
- const struct cpnt* cpnt = NULL;
- const char* chunk = NULL;
- size_t cpnt_offset = 0;
- size_t chunk_sz = 0;
- ASSERT(dst && ctx && ctx->icpnt < 4);
-
- /* Fetch the component to handle */
- cpnt = ctx->cpnts + ctx->icpnt;
- ASSERT(cpnt->chunk_min <= ichunk);
- ASSERT(cpnt->chunk_max > ichunk);
-
- /* Compute the offset into the component up to the data to copy */
- cpnt_offset = (ichunk - cpnt->chunk_min) * 64;
-
- /* Fetch the address toward the data to copy and compute the data size */
- chunk = (const char*)cpnt->mem + cpnt_offset;
- chunk_sz = MMIN(cpnt->size - cpnt_offset, 64);
-
- /* Copy the component data toward the chunk */
- memcpy(dst, chunk, chunk_sz);
-
- /* Clean up the chunk from the last written byte to the end of the chunk */
- if(chunk_sz < 64) memset(dst + chunk_sz, 0, 64 - chunk_sz);
-
- /* Progress into the component */
- while(ichunk == ctx->cpnts[ctx->icpnt].chunk_max - 1 && ctx->icpnt < 4) {
- ++ctx->icpnt;
- }
-}
-
-static void
volume_release(ref_T* ref)
{
struct suvm_volume* vol = NULL;
@@ -701,10 +655,7 @@ suvm_volume_compute_hash
const int cpnt_mask,
hash256_T hash)
{
- struct chunked_data_desc chunked_data = CHUNKED_DATA_DESC_NULL;
- struct hash_context ctx = HASH_CONTEXT_NULL;
- size_t sz = 0;
- int i = 0;
+ struct sha256_ctx ctx;
res_T res = RES_OK;
if(!vol || !hash) {
@@ -712,53 +663,80 @@ suvm_volume_compute_hash
goto error;
}
- /* Setup the components to hash */
+ sha256_ctx_init(&ctx);
+
if(cpnt_mask & SUVM_POSITIONS) {
- ctx.cpnts[i].mem = darray_float_cdata_get(&vol->positions);
- ctx.cpnts[i].size = darray_float_size_get(&vol->positions) * sizeof(float);
- ++i;
+ const float* pos = darray_float_cdata_get(&vol->positions);
+ const size_t n = darray_float_size_get(&vol->positions);
+ sha256_ctx_update(&ctx, (const char*)pos, sizeof(*pos)*n);
}
if(cpnt_mask & SUVM_INDICES) {
- ctx.cpnts[i].mem = darray_u32_cdata_get(&vol->indices);
- ctx.cpnts[i].size = darray_u32_size_get(&vol->indices) * sizeof(uint32_t);
- ++i;
+ const uint32_t* ids = darray_u32_cdata_get(&vol->indices);
+ const size_t n = darray_u32_size_get(&vol->indices);
+ sha256_ctx_update(&ctx, (const char*)ids, sizeof(*ids)*n);
}
if(cpnt_mask & SUVM_PRIMITIVE_DATA) {
- ctx.cpnts[i].mem = vol->prim_data.mem;
- ctx.cpnts[i].size = vol->prim_data.size * vol->prim_data.elmt_stride;
- ++i;
+ const size_t sz = vol->prim_data.size * vol->prim_data.elmt_stride;
+ sha256_ctx_update(&ctx, vol->prim_data.mem, sz);
}
if(cpnt_mask & SUVM_VERTEX_DATA) {
- ctx.cpnts[i].mem = vol->vert_data.mem;
- ctx.cpnts[i].size = vol->vert_data.size * vol->vert_data.elmt_stride;
- ++i;
- }
- ctx.ncpnts = i;
-
- /* Precompute the range of chunks overlapped by each component */
- FOR_EACH(i, 0, ctx.ncpnts) {
- const size_t nchunks = (ctx.cpnts[i].size + 63/*ceil*/) / 64;
- sz += nchunks * 64;
- if(i == 0) {
- ctx.cpnts[i].chunk_min = 0;
- ctx.cpnts[i].chunk_max = nchunks;
- } else {
- ctx.cpnts[i].chunk_min = ctx.cpnts[i-1].chunk_max;
- ctx.cpnts[i].chunk_max = ctx.cpnts[i-1].chunk_max + nchunks;
- }
+ const size_t sz = vol->vert_data.size * vol->vert_data.elmt_stride;
+ sha256_ctx_update(&ctx, vol->vert_data.mem, sz);
}
- /* Setup the index of the 1st component to hash */
- ctx.icpnt = 0;
+ sha256_ctx_finalize(&ctx, hash);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+suvm_volume_get_mesh_desc
+ (const struct suvm_volume* vol,
+ struct suvm_mesh_desc* desc)
+{
+ res_T res = RES_OK;
+
+ if(!vol || !desc) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
- /* Hash the volume data */
- chunked_data.get_chunk512 = get_chunk;
- chunked_data.size = sz;
- chunked_data.context = &ctx;
- hash_sha256_chunked_data(&chunked_data, hash);
+ desc->positions = darray_float_cdata_get(&vol->positions);
+ desc->indices = darray_u32_cdata_get(&vol->indices);
+ desc->dvertex = 3;
+ desc->dprimitive = 4;
+ desc->nvertices = darray_float_size_get(&vol->positions) / desc->dvertex;
+ desc->nprimitives = darray_u32_size_get(&vol->indices) / desc->dprimitive;
exit:
return res;
error:
goto exit;
}
+
+res_T
+suvm_mesh_desc_compute_hash(const struct suvm_mesh_desc* desc, hash256_T hash)
+{
+ struct sha256_ctx ctx;
+
+ if(!desc || !hash) return RES_BAD_ARG;
+
+ #define HASH(Var, Nb) \
+ sha256_ctx_update(&ctx, (const char*)(Var), sizeof(*Var)*(Nb));
+
+ sha256_ctx_init(&ctx);
+ HASH(desc->positions, desc->nvertices*desc->dvertex);
+ HASH(desc->indices, desc->nprimitives*desc->dprimitive);
+ HASH(&desc->nvertices, 1);
+ HASH(&desc->nprimitives, 1);
+ HASH(&desc->dvertex, 1);
+ HASH(&desc->dprimitive, 1);
+ sha256_ctx_finalize(&ctx, hash);
+
+ #undef HASH
+
+ return RES_OK;
+}
diff --git a/src/suvm_volume.h b/src/suvm_volume.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/suvm_volume_at.c b/src/suvm_volume_at.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,7 +44,7 @@ intersect_leaf
float n0[3], n1[3], n2[3], n3[3];
float p[3];
float d0, d1, d2, d3;
- float h0, h1, h2, h3;
+ float h1, h2, h3;
size_t itetra;
ASSERT(vol && leaf && pos && bcoords);
ASSERT(leaf->prim_id < volume_get_primitives_count(vol));
@@ -80,7 +80,6 @@ intersect_leaf
v2 = darray_float_cdata_get(&vol->positions) + tetra[2]*3;
/* Distance of tetrahedron corners to their opposite face */
- h0 = f3_dot(n0, f3_sub(p, v3, v0));
h1 = f3_dot(n1, f3_sub(p, v2, v1));
h2 = f3_dot(n2, f3_sub(p, v0, v2));
h3 = f3_dot(n3, f3_sub(p, v1, v3));
@@ -89,7 +88,18 @@ intersect_leaf
bcoords[0] = d2 / h2;
bcoords[1] = d3 / h3;
bcoords[2] = d1 / h1;
- bcoords[3] = d0 / h0;
+
+#if 1
+ /* Do not use d0 and h0 to calculate the last barycentric coordinate but
+ * calculate it from the 3 others. This gets around the numerical imprecision
+ * and ensures that the sum of the bcoords is indeed 1 */
+ bcoords[3] = 1.f - bcoords[0] - bcoords[1] - bcoords[2];
+#else
+ {
+ const float h0 = f3_dot(n0, f3_sub(p, v3, v0));
+ bcoords[3] = d0 / h0;
+ }
+#endif
return 1;
}
diff --git a/src/suvm_volume_intersect_aabb.c b/src/suvm_volume_intersect_aabb.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/suvm_voxelize.c b/src/suvm_voxelize.c
@@ -0,0 +1,438 @@
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#define _POSIX_C_SOURCE 200112L /* getopt/close support */
+
+#include "suvm.h"
+#include <star/smsh.h>
+#include <rsys/clock_time.h>
+#include <rsys/cstr.h>
+#include <rsys/mem_allocator.h>
+
+#include <string.h>
+#include <unistd.h> /* getopt & close functions */
+
+struct args {
+ const char* input_filename;
+ const char* output_filename;
+ unsigned def[3];
+ int precompute_normals;
+ int quit;
+ int verbose;
+};
+
+static const struct args ARGS_DEFAULT = {
+ NULL, /* Input file */
+ NULL, /* Output file */
+ {64, 64, 64}, /* Definition */
+ 0, /* Precompute normals */
+ 0, /* Quit */
+ 0 /* Verbose */
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+print_help(const char* cmd)
+{
+ ASSERT(cmd);
+ printf(
+"Usage: %s [options] [file]\n"
+"Voxelize a smsh(5) file and save result following VTK file format.\n"
+"With no file option, mesh is read from standard input\n",
+ cmd);
+ printf("\n");
+ printf(
+" -d X:Y:Z voxelisation definition along the 3 axes.\n"
+" Default definition is %u:%u:%u.\n",
+ ARGS_DEFAULT.def[0],
+ ARGS_DEFAULT.def[1],
+ ARGS_DEFAULT.def[2]);
+ printf(
+" -h display this help and exit.\n");
+ printf(
+" -n precompute the tetrahedra normals.\n");
+ printf(
+" -o <output> filename of the output VTK file. If not defined, write\n"
+" results to standard ouput\n");
+ printf(
+" -v make the program verobse.\n");
+ printf("\n");
+ printf(
+"Copyright (C) 2020-2023 |Méso|Star> <contact@meso-star.com>.\n"
+"This is free software released under the GNU GPL license, version 3 or\n"
+"later. You are free to change or redistribute it under certain\n"
+"conditions <http://gnu.org.licenses/gpl.html>\n");
+}
+
+static void
+args_release(struct args* args)
+{
+ ASSERT(args);
+ *args = ARGS_DEFAULT;
+}
+
+static res_T
+args_init(struct args* args, const int argc, char** argv)
+{
+ size_t n;
+ int opt;
+ res_T res = RES_OK;
+ ASSERT(args);
+
+ *args = ARGS_DEFAULT;
+
+ while((opt = getopt(argc, argv, "d:hno:v")) != -1) {
+ switch(opt) {
+ case 'd':
+ res = cstr_to_list_uint(optarg, ':', args->def, &n, 3);
+ if(res == RES_OK && n != 3) res = RES_BAD_ARG;
+ if(!args->def[0] || !args->def[1] || !args->def[2]) res = RES_BAD_ARG;
+ break;
+ case 'h':
+ print_help(argv[0]);
+ args_release(args);
+ args->quit = 1;
+ break;
+ case 'n':
+ args->precompute_normals = 1;
+ break;
+ case 'o':
+ args->output_filename = optarg;
+ break;
+ case 'v': args->verbose = 1; break;
+ default: res = RES_BAD_ARG; break;
+ }
+ if(res != RES_OK) {
+ if(optarg) {
+ fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n",
+ argv[0], optarg, opt);
+ }
+ goto error;
+ }
+ }
+
+ if(optind < argc) {
+ args->input_filename = argv[optind];
+ }
+
+exit:
+ optind = 1;
+ return res;
+error:
+ args_release(args);
+ goto exit;
+}
+
+static void
+get_indices(const size_t itetra, size_t ids[4], void* ctx)
+{
+ const uint64_t* ui64;
+ struct smsh_desc* desc = ctx;
+ ASSERT(desc && desc->dcell == 4);
+ ui64 = smsh_desc_get_cell(desc, itetra);
+ ids[0] = (size_t)ui64[0];
+ ids[1] = (size_t)ui64[1];
+ ids[2] = (size_t)ui64[2];
+ ids[3] = (size_t)ui64[3];
+}
+
+static void
+get_position(const size_t ivert, double pos[3], void* ctx)
+{
+ const double* dbl;
+ struct smsh_desc* desc = ctx;
+ ASSERT(desc && desc->dnode == 3);
+ dbl = smsh_desc_get_node(desc, ivert);
+ pos[0] = dbl[0];
+ pos[1] = dbl[1];
+ pos[2] = dbl[2];
+}
+
+static void
+write_voxels
+ (FILE* stream,
+ const int* vxls,
+ const unsigned def[3],
+ const double vxl_sz[3],
+ const double org[3])
+{
+ size_t ix, iy, iz;
+ size_t ivxl;
+ size_t i;
+ ASSERT(stream && vxls && def && def[0] && def[1] && def[2]);
+
+ fprintf(stream, "# vtk DataFile Version 2.0\n");
+ fprintf(stream, "Volumetric grid\n");
+ fprintf(stream, "ASCII\n");
+
+ fprintf(stream, "DATASET RECTILINEAR_GRID\n");
+ fprintf(stream, "DIMENSIONS %u %u %u\n", def[0]+1, def[1]+1, def[2]+1);
+ fprintf(stream, "X_COORDINATES %u float\n", def[0]+1);
+ FOR_EACH(i, 0, def[0]+1) fprintf(stream, "%g ", (double)i*vxl_sz[0] + org[0]);
+ fprintf(stream, "\n");
+ fprintf(stream, "Y_COORDINATES %u float\n", def[1]+1);
+ FOR_EACH(i, 0, def[1]+1) fprintf(stream, "%g ", (double)i*vxl_sz[1] + org[1]);
+ fprintf(stream, "\n");
+ fprintf(stream, "Z_COORDINATES %u float\n", def[2]+1);
+ FOR_EACH(i, 0, def[2]+1) fprintf(stream, "%g ", (double)i*vxl_sz[2] + org[2]);
+ fprintf(stream, "\n");
+
+ fprintf(stream, "CELL_DATA %u\n", def[0]*def[1]*def[2]);
+ fprintf(stream, "SCALARS intersect_type int 1\n");
+ fprintf(stream, "LOOKUP_TABLE default\n");
+
+ ivxl = 0;
+ FOR_EACH(iz, 0, def[2]) {
+ FOR_EACH(iy, 0, def[1]) {
+ FOR_EACH(ix, 0, def[0]) {
+ fprintf(stream, "%i\n", vxls[ivxl]);
+ ++ivxl;
+ }
+ }
+ }
+}
+
+static res_T
+voxelize_suvm_volume
+ (const struct suvm_volume* vol,
+ const unsigned def[3],
+ int* vxls)
+{
+ double low[3], upp[3];
+ double vxl_sz[3];
+ size_t iprim;
+ size_t nprims;
+ int progress = 0;
+ res_T res = RES_OK;
+ ASSERT(vol && def && def[0] && def[1] && def[2] && vxls);
+
+ /* Compute the voxel size */
+ res = suvm_volume_get_aabb(vol, low, upp);
+ if(res != RES_OK) goto error;
+ vxl_sz[0] = (upp[0] - low[0]) / (double)def[0];
+ vxl_sz[1] = (upp[1] - low[1]) / (double)def[1];
+ vxl_sz[2] = (upp[2] - low[2]) / (double)def[2];
+
+ res = suvm_volume_get_primitives_count(vol, &nprims);
+ if(res != RES_OK) goto error;
+
+ FOR_EACH(iprim, 0, nprims) {
+ struct suvm_primitive prim = SUVM_PRIMITIVE_NULL;
+ struct suvm_polyhedron poly;
+ size_t ivxl_low[3];
+ size_t ivxl_upp[3];
+ size_t ivxl[3];
+ size_t i = 0;
+ int pcent;
+
+ CHK(suvm_volume_get_primitive(vol, iprim, &prim) == RES_OK);
+ CHK(suvm_primitive_setup_polyhedron(&prim, &poly) == RES_OK);
+
+ /* Transform the polyhedron AABB in voxel space */
+ ivxl_low[0] = (size_t)((poly.lower[0] - low[0]) / vxl_sz[0]);
+ ivxl_low[1] = (size_t)((poly.lower[1] - low[1]) / vxl_sz[1]);
+ ivxl_low[2] = (size_t)((poly.lower[2] - low[2]) / vxl_sz[2]);
+ ivxl_upp[0] = (size_t)ceil((poly.upper[0] - low[0]) / vxl_sz[0]);
+ ivxl_upp[1] = (size_t)ceil((poly.upper[1] - low[1]) / vxl_sz[1]);
+ ivxl_upp[2] = (size_t)ceil((poly.upper[2] - low[2]) / vxl_sz[2]);
+ CHK(ivxl_low[0] < def[0] && ivxl_upp[0] <= def[0]);
+ CHK(ivxl_low[1] < def[1] && ivxl_upp[1] <= def[1]);
+ CHK(ivxl_low[2] < def[2] && ivxl_upp[2] <= def[2]);
+
+ FOR_EACH(ivxl[2], ivxl_low[2], ivxl_upp[2]) {
+ float vxl_low[3];
+ float vxl_upp[3];
+ vxl_low[0] = (float)low[0];
+ vxl_low[1] = (float)low[1];
+ vxl_low[2] = (float)((double)ivxl[2] * vxl_sz[2] + low[2]);
+ vxl_upp[0] = (float)upp[0];
+ vxl_upp[1] = (float)upp[1];
+ vxl_upp[2] = vxl_low[2] + (float)vxl_sz[2];
+
+ FOR_EACH(ivxl[1], ivxl_low[1], ivxl_upp[1]) {
+ vxl_low[1] = (float)((double)ivxl[1] * vxl_sz[1] + low[1]);
+ vxl_upp[1] = vxl_low[1] + (float)vxl_sz[1];
+ FOR_EACH(ivxl[0], ivxl_low[0], ivxl_upp[0]) {
+ vxl_low[0] = (float)((double)ivxl[0] * vxl_sz[0] + low[0]);
+ vxl_upp[0] = vxl_low[0] + (float)vxl_sz[0];
+
+ i = ivxl[0] + ivxl[1]*def[0] + ivxl[2]*def[0]*def[1];
+ vxls[i] += (int)suvm_polyhedron_intersect_aabb(&poly, vxl_low, vxl_upp);
+ }
+ }
+ }
+ pcent = (int)((double)iprim * 100 / (double)nprims + 0.5/*round*/);
+ if(pcent > progress) {
+ progress = pcent;
+ fprintf(stderr, "Voxelizing: %3d%%\r", progress);
+ fflush(stderr);
+ }
+ }
+
+ fprintf(stderr, "Voxelizing: %3d%%\n", progress);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+/*******************************************************************************
+ * Main functions
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ char dump[128];
+ struct args args = ARGS_DEFAULT;
+ FILE* stream_out = stdout;
+ FILE* stream_in = stdin;
+ const char* stream_out_name = "stdout";
+ const char* stream_in_name = "stdin";
+ struct smsh* smsh = NULL;
+ struct smsh_create_args smsh_args = SMSH_CREATE_ARGS_DEFAULT;
+ struct smsh_desc desc = SMSH_DESC_NULL;
+ struct suvm_device* suvm = NULL;
+ struct suvm_volume* vol = NULL;
+ struct suvm_tetrahedral_mesh_args msh_args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL;
+ struct time t0, t1;
+ int* vxls = NULL;
+ double low[3];
+ double upp[3];
+ double vxl_sz[3];
+ res_T res = RES_OK;
+ int err = 0;
+
+ res = args_init(&args, argc, argv);
+ if(res != RES_OK) goto error;
+ if(args.quit) goto exit;
+
+ /* Setup input stream */
+ if(args.input_filename) {
+ stream_in = fopen(args.input_filename, "r");
+ if(!stream_in) {
+ fprintf(stderr, "Could not open the input file '%s' -- %s.\n",
+ args.input_filename, strerror(errno));
+ goto error;
+ }
+ stream_in_name = args.input_filename;
+ }
+
+ /* Setup output stream */
+ if(args.output_filename) {
+ stream_out = fopen(args.output_filename, "w");
+ if(!stream_out) {
+ fprintf(stderr, "Could not open the output file '%s' -- %s.\n",
+ args.output_filename, strerror(errno));
+ goto error;
+ }
+ stream_out_name = args.output_filename;
+ (void)stream_out_name;
+ }
+
+
+ /* Load the submitted file */
+ smsh_args.verbose = args.verbose;
+ res = smsh_create(&smsh_args, &smsh);
+ if(res != RES_OK) goto error;
+ res = smsh_load_stream(smsh, stream_in, stream_in_name);
+ if(res != RES_OK) goto error;
+ res = smsh_get_desc(smsh, &desc);
+ if(res != RES_OK) goto error;
+ if(desc.dnode != 3 || desc.dcell != 4) {
+ fprintf(stderr, "Only tetrahedrical mesh are supported\n");
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if(args.verbose) {
+ fprintf(stderr, "#nodes: %u; #tetrahedra: %u\n", desc.dnode, desc.dcell);
+ }
+
+ res = suvm_device_create(NULL, NULL, args.verbose, &suvm);
+ if(res != RES_OK) goto error;
+
+ msh_args.nvertices = desc.nnodes;
+ msh_args.ntetrahedra = desc.ncells;
+ msh_args.get_indices = get_indices;
+ msh_args.get_position = get_position;
+ msh_args.context = &desc;
+ msh_args.precompute_normals = args.precompute_normals;
+
+ /* Setup the volume from the loaded data */
+ if(args.verbose) {
+ fprintf(stderr, "Partitionning the tetrahedral mesh '%s'\n", stream_in_name);
+ }
+ time_current(&t0);
+ res = suvm_tetrahedral_mesh_create(suvm, &msh_args, &vol);
+ if(res != RES_OK) goto error;
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump));
+ if(args.verbose) {
+ fprintf(stderr, "Build acceleration structure in %s\n", dump);
+ }
+
+ /* Allocate the list of voxels */
+ vxls = mem_calloc(args.def[0]*args.def[1]*args.def[2], sizeof(*vxls));
+ if(!vxls) {
+ fprintf(stderr, "Could not allocate the list of voxels.\n");
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ /* Voxelize the volume */
+ time_current(&t0);
+ res = voxelize_suvm_volume(vol, args.def, vxls);
+ if(res != RES_OK) goto error;
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump));
+ if(args.verbose) {
+ fprintf(stderr, "Volume voxelized in %s\n", dump);
+ }
+
+ /* Write the voxels */
+ if(args.verbose) {
+ fprintf(stderr, "Writing voxels in '%s'\n", stream_out_name);
+ }
+ SUVM(volume_get_aabb(vol, low, upp));
+ vxl_sz[0] = (upp[0] - low[0]) / (double)args.def[0];
+ vxl_sz[1] = (upp[1] - low[1]) / (double)args.def[1];
+ vxl_sz[2] = (upp[2] - low[2]) / (double)args.def[2];
+ time_current(&t0);
+ write_voxels(stream_out, vxls, args.def, vxl_sz, low);
+ time_sub(&t0, time_current(&t1), &t0);
+ time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump));
+ if(args.verbose) {
+ fprintf(stderr, "Voxels written in %s\n", dump);
+ }
+
+exit:
+ if(stream_out && stream_out != stdout) fclose(stream_out);
+ if(stream_in && stream_in != stdin) fclose(stream_in);
+ if(suvm) SUVM(device_ref_put(suvm));
+ if(vol) SUVM(volume_ref_put(vol));
+ if(smsh) SMSH(ref_put(smsh));
+ if(vxls) mem_rm(vxls);
+ args_release(&args);
+ if(mem_allocated_size() != 0) {
+ fprintf(stderr, "Memory leaks: %lu Bytes.\n",
+ (unsigned long)mem_allocated_size());
+ }
+ return err;
+error:
+ err = -1;
+ goto exit;
+}
diff --git a/src/suvm_voxelize_sth.c b/src/suvm_voxelize_sth.c
@@ -1,431 +0,0 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>. */
-
-#define _POSIX_C_SOURCE 200112L /* getopt/close support */
-
-#include "suvm.h"
-#include <star/sth.h>
-#include <rsys/clock_time.h>
-#include <rsys/cstr.h>
-#include <rsys/mem_allocator.h>
-
-#include <string.h>
-#include <unistd.h> /* getopt & close functions */
-
-struct args {
- const char* input_filename;
- const char* output_filename;
- unsigned def[3];
- int precompute_normals;
- int quit;
- int verbose;
-};
-
-static const struct args ARGS_DEFAULT = {
- NULL, /* Input file */
- NULL, /* Output file */
- {64, 64, 64}, /* Definition */
- 0, /* Precompute normals */
- 0, /* Quit */
- 0 /* Verbose */
-};
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static void
-print_help(const char* cmd)
-{
- ASSERT(cmd);
- printf(
-"Usage: %s [options] [file]\n"
-"Voxelize the submitted Star-TetraHedra geometry and save the result\n"
-"into a VTK file.\n",
- cmd);
- printf("\n");
- printf(
-" -d X:Y:Z voxelisation definition along the 3 axes.\n"
-" The default definition is %u:%u:%u.\n",
- ARGS_DEFAULT.def[0],
- ARGS_DEFAULT.def[1],
- ARGS_DEFAULT.def[2]);
- printf(
-" -h display this help and exit.\n");
- printf(
-" -n precompute the tetrahedra normals.\n");
- printf(
-" -o <output> filename of the output VTK file. If not defined, write\n"
-" results to standard ouput\n");
- printf(
-" -v make the program verobse.\n");
- printf("\n");
- printf(
-"Copyright (C) 2020, 2021 |Meso|Star> <contact@meso-star.com>.\n"
-"This is free software released under the GNU GPL license, version 3 or\n"
-"later. You are free to change or redistribute it under certain\n"
-"conditions <http://gnu.org.licenses/gpl.html>\n");
-}
-
-static void
-args_release(struct args* args)
-{
- ASSERT(args);
- *args = ARGS_DEFAULT;
-}
-
-static res_T
-args_init(struct args* args, const int argc, char** argv)
-{
- size_t n;
- int opt;
- res_T res = RES_OK;
- ASSERT(args);
-
- *args = ARGS_DEFAULT;
-
- while((opt = getopt(argc, argv, "d:hno:v")) != -1) {
- switch(opt) {
- case 'd':
- res = cstr_to_list_uint(optarg, ':', args->def, &n, 3);
- if(res == RES_OK && n != 3) res = RES_BAD_ARG;
- if(!args->def[0] || !args->def[1] || !args->def[2]) res = RES_BAD_ARG;
- break;
- case 'h':
- print_help(argv[0]);
- args_release(args);
- args->quit = 1;
- break;
- case 'n':
- args->precompute_normals = 1;
- break;
- case 'o':
- args->output_filename = optarg;
- break;
- case 'v': args->verbose = 1; break;
- default: res = RES_BAD_ARG; break;
- }
- if(res != RES_OK) {
- if(optarg) {
- fprintf(stderr, "%s: invalid option argument '%s' -- '%c'\n",
- argv[0], optarg, opt);
- }
- goto error;
- }
- }
-
- if(optind < argc) {
- args->input_filename = argv[optind];
- }
-
-exit:
- optind = 1;
- return res;
-error:
- args_release(args);
- goto exit;
-}
-
-static void
-get_indices(const size_t itetra, size_t ids[4], void* ctx)
-{
- const uint64_t* ui64;
- struct sth_desc* desc = ctx;
- ASSERT(desc);
- ui64 = sth_desc_get_tetrahedron_indices(desc, itetra);
- ids[0] = (size_t)ui64[0];
- ids[1] = (size_t)ui64[1];
- ids[2] = (size_t)ui64[2];
- ids[3] = (size_t)ui64[3];
-}
-
-static void
-get_position(const size_t ivert, double pos[3], void* ctx)
-{
- const double* dbl;
- struct sth_desc* desc = ctx;
- ASSERT(desc);
- dbl = sth_desc_get_vertex_position(desc, ivert);
- pos[0] = dbl[0];
- pos[1] = dbl[1];
- pos[2] = dbl[2];
-}
-
-static void
-write_voxels
- (FILE* stream,
- const int* vxls,
- const unsigned def[3],
- const double vxl_sz[3],
- const double org[3])
-{
- size_t ix, iy, iz;
- size_t ivxl;
- size_t i;
- ASSERT(stream && vxls && def && def[0] && def[1] && def[2]);
-
- fprintf(stream, "# vtk DataFile Version 2.0\n");
- fprintf(stream, "Volumetric grid\n");
- fprintf(stream, "ASCII\n");
-
- fprintf(stream, "DATASET RECTILINEAR_GRID\n");
- fprintf(stream, "DIMENSIONS %u %u %u\n", def[0]+1, def[1]+1, def[2]+1);
- fprintf(stream, "X_COORDINATES %u float\n", def[0]+1);
- FOR_EACH(i, 0, def[0]+1) fprintf(stream, "%g ", (double)i*vxl_sz[0] + org[0]);
- fprintf(stream, "\n");
- fprintf(stream, "Y_COORDINATES %u float\n", def[1]+1);
- FOR_EACH(i, 0, def[1]+1) fprintf(stream, "%g ", (double)i*vxl_sz[1] + org[1]);
- fprintf(stream, "\n");
- fprintf(stream, "Z_COORDINATES %u float\n", def[2]+1);
- FOR_EACH(i, 0, def[2]+1) fprintf(stream, "%g ", (double)i*vxl_sz[2] + org[2]);
- fprintf(stream, "\n");
-
- fprintf(stream, "CELL_DATA %u\n", def[0]*def[1]*def[2]);
- fprintf(stream, "SCALARS intersect_type int 1\n");
- fprintf(stream, "LOOKUP_TABLE default\n");
-
- ivxl = 0;
- FOR_EACH(iz, 0, def[2]) {
- FOR_EACH(iy, 0, def[1]) {
- FOR_EACH(ix, 0, def[0]) {
- fprintf(stream, "%i\n", vxls[ivxl]);
- ++ivxl;
- }
- }
- }
-}
-
-static res_T
-voxelize_suvm_volume
- (const struct suvm_volume* vol,
- const unsigned def[3],
- int* vxls)
-{
- double low[3], upp[3];
- double vxl_sz[3];
- size_t iprim;
- size_t nprims;
- int progress = 0;
- res_T res = RES_OK;
- ASSERT(vol && def && def[0] && def[1] && def[2] && vxls);
-
- /* Compute the voxel size */
- res = suvm_volume_get_aabb(vol, low, upp);
- if(res != RES_OK) goto error;
- vxl_sz[0] = (upp[0] - low[0]) / (double)def[0];
- vxl_sz[1] = (upp[1] - low[1]) / (double)def[1];
- vxl_sz[2] = (upp[2] - low[2]) / (double)def[2];
-
- res = suvm_volume_get_primitives_count(vol, &nprims);
- if(res != RES_OK) goto error;
-
- FOR_EACH(iprim, 0, nprims) {
- struct suvm_primitive prim = SUVM_PRIMITIVE_NULL;
- struct suvm_polyhedron poly;
- size_t ivxl_low[3];
- size_t ivxl_upp[3];
- size_t ivxl[3];
- size_t i = 0;
- int pcent;
-
- CHK(suvm_volume_get_primitive(vol, iprim, &prim) == RES_OK);
- CHK(suvm_primitive_setup_polyhedron(&prim, &poly) == RES_OK);
-
- /* Transform the polyhedron AABB in voxel space */
- ivxl_low[0] = (size_t)((poly.lower[0] - low[0]) / vxl_sz[0]);
- ivxl_low[1] = (size_t)((poly.lower[1] - low[1]) / vxl_sz[1]);
- ivxl_low[2] = (size_t)((poly.lower[2] - low[2]) / vxl_sz[2]);
- ivxl_upp[0] = (size_t)ceil((poly.upper[0] - low[0]) / vxl_sz[0]);
- ivxl_upp[1] = (size_t)ceil((poly.upper[1] - low[1]) / vxl_sz[1]);
- ivxl_upp[2] = (size_t)ceil((poly.upper[2] - low[2]) / vxl_sz[2]);
- CHK(ivxl_low[0] < def[0] && ivxl_upp[0] <= def[0]);
- CHK(ivxl_low[1] < def[1] && ivxl_upp[1] <= def[1]);
- CHK(ivxl_low[2] < def[2] && ivxl_upp[2] <= def[2]);
-
- FOR_EACH(ivxl[2], ivxl_low[2], ivxl_upp[2]) {
- float vxl_low[3];
- float vxl_upp[3];
- vxl_low[0] = (float)low[0];
- vxl_low[1] = (float)low[1];
- vxl_low[2] = (float)((double)ivxl[2] * vxl_sz[2] + low[2]);
- vxl_upp[0] = (float)upp[0];
- vxl_upp[1] = (float)upp[1];
- vxl_upp[2] = vxl_low[2] + (float)vxl_sz[2];
-
- FOR_EACH(ivxl[1], ivxl_low[1], ivxl_upp[1]) {
- vxl_low[1] = (float)((double)ivxl[1] * vxl_sz[1] + low[1]);
- vxl_upp[1] = vxl_low[1] + (float)vxl_sz[1];
- FOR_EACH(ivxl[0], ivxl_low[0], ivxl_upp[0]) {
- vxl_low[0] = (float)((double)ivxl[0] * vxl_sz[0] + low[0]);
- vxl_upp[0] = vxl_low[0] + (float)vxl_sz[0];
-
- i = ivxl[0] + ivxl[1]*def[0] + ivxl[2]*def[0]*def[1];
- vxls[i] += (int)suvm_polyhedron_intersect_aabb(&poly, vxl_low, vxl_upp);
- }
- }
- }
- pcent = (int)((double)iprim * 100 / (double)nprims + 0.5/*round*/);
- if(pcent > progress) {
- progress = pcent;
- fprintf(stdout, "Voxelizing: %3d%%\r", progress);
- fflush(stdout);
- }
- }
-
- printf("Voxelizing: %3d%%\n", progress);
-
-exit:
- return res;
-error:
- goto exit;
-}
-
-/*******************************************************************************
- * Main functions
- ******************************************************************************/
-int
-main(int argc, char** argv)
-{
- char dump[128];
- struct args args = ARGS_DEFAULT;
- FILE* stream_out = stdout;
- FILE* stream_in = stdin;
- const char* stream_out_name = "stdout";
- const char* stream_in_name = "stdin";
- struct sth* sth = NULL;
- struct sth_desc desc = STH_DESC_NULL;
- struct suvm_device* suvm = NULL;
- struct suvm_volume* vol = NULL;
- struct suvm_tetrahedral_mesh_args msh_args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL;
- struct time t0, t1;
- int* vxls = NULL;
- double low[3];
- double upp[3];
- double vxl_sz[3];
- res_T res = RES_OK;
- int err = 0;
-
- res = args_init(&args, argc, argv);
- if(res != RES_OK) goto error;
- if(args.quit) goto exit;
-
- /* Setup input stream */
- if(args.input_filename) {
- stream_in = fopen(args.input_filename, "r");
- if(!stream_in) {
- fprintf(stderr, "Could not open the input file '%s' -- %s.\n",
- args.input_filename, strerror(errno));
- goto error;
- }
- stream_in_name = args.input_filename;
- }
-
- /* Setup output stream */
- if(args.output_filename) {
- stream_out = fopen(args.output_filename, "w");
- if(!stream_out) {
- fprintf(stderr, "Could not open the output file '%s' -- %s.\n",
- args.output_filename, strerror(errno));
- goto error;
- }
- stream_out_name = args.output_filename;
- (void)stream_out_name;
- }
-
-
- /* Load the submitted file */
- res = sth_create(NULL, NULL, args.verbose, &sth);
- if(res != RES_OK) goto error;
- res = sth_load_stream(sth, stream_in, stream_in_name);
- if(res != RES_OK) goto error;
- res = sth_get_desc(sth, &desc);
- if(res != RES_OK) goto error;
- if(args.verbose) {
- printf("#nodes: %lu; #tetrahedra: %lu\n", desc.nvertices, desc.ntetrahedra);
- }
-
- res = suvm_device_create(NULL, NULL, args.verbose, &suvm);
- if(res != RES_OK) goto error;
-
- msh_args.nvertices = desc.nvertices;
- msh_args.ntetrahedra = desc.ntetrahedra;
- msh_args.get_indices = get_indices;
- msh_args.get_position = get_position;
- msh_args.context = &desc;
- msh_args.precompute_normals = args.precompute_normals;
-
- /* Setup the volume from the loaded data */
- if(args.verbose) {
- printf("Partitionning the tetrahedral mesh '%s'\n", stream_in_name);
- }
- time_current(&t0);
- res = suvm_tetrahedral_mesh_create(suvm, &msh_args, &vol);
- if(res != RES_OK) goto error;
- time_sub(&t0, time_current(&t1), &t0);
- time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump));
- if(args.verbose) {
- printf("Build acceleration structure in %s\n", dump);
- }
-
- /* Allocate the list of voxels */
- vxls = mem_calloc(args.def[0]*args.def[1]*args.def[2], sizeof(*vxls));
- if(!vxls) {
- fprintf(stderr, "Could not allocate the list of voxels.\n");
- res = RES_MEM_ERR;
- goto error;
- }
-
- /* Voxelize the volume */
- time_current(&t0);
- res = voxelize_suvm_volume(vol, args.def, vxls);
- if(res != RES_OK) goto error;
- time_sub(&t0, time_current(&t1), &t0);
- time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump));
- if(args.verbose) {
- printf("Volume voxelized in %s\n", dump);
- }
-
- /* Write the voxels */
- if(args.verbose) {
- printf("Writing voxels in '%s'\n", stream_out_name);
- }
- SUVM(volume_get_aabb(vol, low, upp));
- vxl_sz[0] = (upp[0] - low[0]) / (double)args.def[0];
- vxl_sz[1] = (upp[1] - low[1]) / (double)args.def[1];
- vxl_sz[2] = (upp[2] - low[2]) / (double)args.def[2];
- time_current(&t0);
- write_voxels(stream_out, vxls, args.def, vxl_sz, low);
- time_sub(&t0, time_current(&t1), &t0);
- time_dump(&t0, TIME_ALL, NULL, dump, sizeof(dump));
- if(args.verbose) {
- printf("Voxels written in %s\n", dump);
- }
-
-exit:
- if(stream_out && stream_out != stdout) fclose(stream_out);
- if(stream_in && stream_in != stdin) fclose(stream_in);
- if(suvm) SUVM(device_ref_put(suvm));
- if(vol) SUVM(volume_ref_put(vol));
- if(sth) STH(ref_put(sth));
- if(vxls) mem_rm(vxls);
- args_release(&args);
- if(mem_allocated_size() != 0) {
- fprintf(stderr, "Memory leaks: %lu Bytes.\n",
- (unsigned long)mem_allocated_size());
- }
- return err;
-error:
- err = -1;
- goto exit;
-}
diff --git a/src/test_suvm_ball.h b/src/test_suvm_ball.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -5329,7 +5329,7 @@ const double ball_vertices[] = {
-1.3397540e-01, -8.3003223e-02, -8.1768147e-02,
1.0188783e-01, -8.7012677e-02, -1.2649865e-01
};
-const size_t ball_nvertices = sizeof(ball_vertices) / sizeof(double[3]);
+const size_t ball_nvertices = sizeof(ball_vertices) / (sizeof(double)*3);
const size_t ball_tetrahedra[] = {
4099, 4031, 278, 4086,
@@ -25032,6 +25032,6 @@ const size_t ball_tetrahedra[] = {
5157, 3404, 3494, 3391,
1380, 1381, 4890, 1429
};
-const size_t ball_ntetrahedra = sizeof(ball_tetrahedra)/sizeof(size_t[4]);
+const size_t ball_ntetrahedra = sizeof(ball_tetrahedra)/(sizeof(size_t)*4);
#endif /* TEST_SUVM_BALL_H */
diff --git a/src/test_suvm_box.h b/src/test_suvm_box.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,7 +27,7 @@ static const double box_vertices[9/*#vertices*/*3/*#coords per vertex*/] = {
1.0, 1.0, 1.0,
0.5, 0.5, 0.5
};
-static const size_t box_nverts = sizeof(box_vertices) / sizeof(double[3]);
+static const size_t box_nverts = sizeof(box_vertices) / (sizeof(double)*3);
/* The following array lists the indices toward the 3D vertices of each
* boundary triangle. The index 8 references the vertex at the center of the
@@ -46,7 +46,6 @@ static const size_t box_indices[12/*#tetras*/*4/*#indices per tetra*/] = {
2, 7, 6, 8, 7, 2, 3, 8, /* +Y */
0, 5, 1, 8, 5, 0, 4, 8 /* -Y */
};
-static const size_t box_ntetras = sizeof(box_indices) / sizeof(size_t[4]);
-
+static const size_t box_ntetras = sizeof(box_indices) / (sizeof(size_t)*4);
#endif /* TEST_SUVM_BOX_H */
diff --git a/src/test_suvm_device.c b/src/test_suvm_device.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/test_suvm_primitive_intersection.c b/src/test_suvm_primitive_intersection.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/test_suvm_utils.h b/src/test_suvm_utils.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/test_suvm_volume.c b/src/test_suvm_volume.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2020, 2021 |Meso|Star> (contact@meso-star.com)
+/* Copyright (C) 2020-2023 |Méso|Star> (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -169,12 +169,38 @@ check_volume_polyhedra(const struct suvm_volume* vol, struct mesh* msh)
}
static void
+check_volume_mesh(const struct suvm_volume* vol, struct mesh* msh)
+{
+ struct suvm_mesh_desc desc = SUVM_MESH_DESC_NULL;
+ size_t i;
+
+ CHK(suvm_volume_get_mesh_desc(vol, &desc) == RES_OK);
+ CHK(desc.nvertices == msh->nvertices);
+ CHK(desc.nprimitives == msh->ntetrahedra);
+ CHK(desc.dvertex == 3);
+ CHK(desc.dprimitive == 4);
+
+ FOR_EACH(i, 0, desc.nvertices) {
+ CHK(desc.positions[i*3+0] == (float)msh->vertices[i*3+0]);
+ CHK(desc.positions[i*3+1] == (float)msh->vertices[i*3+1]);
+ CHK(desc.positions[i*3+2] == (float)msh->vertices[i*3+2]);
+ }
+ FOR_EACH(i, 0, desc.nprimitives) {
+ CHK(desc.indices[i*4+0] == (uint32_t)msh->tetrahedra[i*4+0]);
+ CHK(desc.indices[i*4+1] == (uint32_t)msh->tetrahedra[i*4+1]);
+ CHK(desc.indices[i*4+2] == (uint32_t)msh->tetrahedra[i*4+2]);
+ CHK(desc.indices[i*4+3] == (uint32_t)msh->tetrahedra[i*4+3]);
+ }
+}
+
+static void
test_tetrahedral_mesh_creation(struct suvm_device* dev)
{
struct mesh msh = MESH_NULL;
struct suvm_tetrahedral_mesh_args args = SUVM_TETRAHEDRAL_MESH_ARGS_NULL;
struct suvm_volume* vol = NULL;
struct suvm_primitive prim = SUVM_PRIMITIVE_NULL;
+ struct suvm_mesh_desc desc = SUVM_MESH_DESC_NULL;
struct suvm_polyhedron poly;
size_t nprims;
@@ -272,6 +298,12 @@ test_tetrahedral_mesh_creation(struct suvm_device* dev)
check_volume_polyhedra(vol, &msh);
+ CHK(suvm_volume_get_mesh_desc(NULL, &desc) == RES_BAD_ARG);
+ CHK(suvm_volume_get_mesh_desc(vol, NULL) == RES_BAD_ARG);
+ CHK(suvm_volume_get_mesh_desc(vol, &desc) == RES_OK);
+
+ check_volume_mesh(vol, &msh);
+
CHK(suvm_volume_ref_put(vol) == RES_OK);
}
@@ -485,6 +517,7 @@ check_hash
const int has_prim_data,
const int has_vert_data)
{
+ struct suvm_mesh_desc msh_desc;
void* mem = NULL;
float* pos = NULL;
uint32_t* ids = NULL;
@@ -504,15 +537,23 @@ check_hash
hash_sha256(NULL, 0, hash1);
CHK(hash256_eq(hash0, hash1));
- /* Compute data size to hash. Note that SUVM align the data to hash on 64
- * bytes by padding data with null bytes if necessary */
- sz_pos = ALIGN_SIZE(msh->nvertices*sizeof(float[3]), 64u);
- sz_ids = ALIGN_SIZE(msh->ntetrahedra*sizeof(uint32_t[4]), 64u);
+ msh_desc = SUVM_MESH_DESC_NULL;
+ CHK(suvm_mesh_desc_compute_hash(NULL, hash0) == RES_BAD_ARG);
+ CHK(suvm_mesh_desc_compute_hash(&msh_desc, NULL) == RES_BAD_ARG);
+ CHK(suvm_mesh_desc_compute_hash(&msh_desc, hash0) == RES_OK);
+
+ CHK(suvm_volume_get_mesh_desc(vol, &msh_desc) == RES_OK);
+ CHK(suvm_mesh_desc_compute_hash(&msh_desc, hash1) == RES_OK);
+ CHK(!hash256_eq(hash0, hash1));
+
+ /* Compute data size to hash */
+ sz_pos = msh->nvertices*sizeof(float[3]);
+ sz_ids = msh->ntetrahedra*sizeof(uint32_t[4]);
if(has_prim_data) {
- sz_prims = ALIGN_SIZE(msh->ntetrahedra*sizeof(size_t[4]), 64u);
+ sz_prims = msh->ntetrahedra*sizeof(size_t[4]);
}
if(has_vert_data) {
- sz_verts = ALIGN_SIZE(msh->nvertices*sizeof(double[3]), 64u);
+ sz_verts = msh->nvertices*sizeof(double[3]);
}
mem = mem_calloc(1, sz_pos + sz_ids + sz_prims + sz_verts);
CHK(mem != NULL);
@@ -671,6 +712,7 @@ test_volume_at_cube(struct suvm_device* dev)
msh.vertex_data_alignment = args.vertex_data.alignment;
CHK(suvm_tetrahedral_mesh_create(dev, &args, &vol) == RES_OK);
+ check_volume_mesh(vol, &msh);
pos[0] = 0.25;
pos[1] = 0.4;
@@ -821,6 +863,7 @@ test_volume_at_ball(struct suvm_device* dev)
aabb_sz = d3_len(d3_sub(vec, aabb_upp, aabb_low));
CHK(suvm_tetrahedral_mesh_create(dev, &args, &vol) == RES_OK);
+ check_volume_mesh(vol, &msh);
check_volume_polyhedra(vol, &msh);