commit 51affe8d794d8cb51bb6878c6065fec392f16bfc
parent 695d9c868c1efa18fa18b1aa35dd7ecf574533cf
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 6 Feb 2018 09:56:37 +0100
Add and test the htvox_scene_for_each_voxel function
Diffstat:
4 files changed, 163 insertions(+), 22 deletions(-)
diff --git a/src/htvox.h b/src/htvox.h
@@ -103,6 +103,13 @@ htvox_scene_get_aabb
double upper[3]);
HTVOX_API res_T
+htvox_scene_for_each_voxel
+ (struct htvox_scene* scn,
+ void (*functor)
+ (const double val, const double low[3], const double upp[3], void* ctx),
+ void* context);
+
+HTVOX_API res_T
htvox_scene_trace_ray
(struct htvox_scene* scn,
const double ray_origin[3],
diff --git a/src/htvox_scene.c b/src/htvox_scene.c
@@ -163,7 +163,7 @@ stack_write
size_t offset = SIZE_MAX;
if(node->data == VOXEL_EMPTY_DATA) {
- xnodes[inode].offset |= OCTREE_XNODE_FLAG_EMPTY;
+ xnodes[inode].offset = OCTREE_XNODE_FLAG_EMPTY;
} else {
if(node->is_leaf) {
double* leaf;
@@ -193,7 +193,6 @@ stack_write
* rewrite the whole stacked nodes in a new page. */
res = octree_buffer_alloc_far_index(buffer, &index);
if(res != RES_OK) {
- printf("Hop\n");
break;
}
far_id = octree_buffer_get_far_index(buffer, index);
@@ -457,9 +456,9 @@ htvox_scene_create
morton_xyz_decode_u21(mcode, ui3);
/* Out of bound voxels */
- if(ui3[0] > nvoxels[0]
- || ui3[1] > nvoxels[1]
- || ui3[2] > nvoxels[2]) {
+ if(ui3[0] >= nvoxels[0]
+ || ui3[1] >= nvoxels[1]
+ || ui3[2] >= nvoxels[2]) {
vox.data = VOXEL_EMPTY_DATA;
} else {
/* Retrieve the voxel data from the caller */
@@ -485,6 +484,10 @@ htvox_scene_create
d3_set(scn->lower, lower);
d3_set(scn->upper, upper);
+ d3_set(scn->oclow, lower);
+ scn->ocupp[0] = (double)scn->definition * vox_sz[0];
+ scn->ocupp[1] = (double)scn->definition * vox_sz[1];
+ scn->ocupp[2] = (double)scn->definition * vox_sz[2];
exit:
if(out_scn) *out_scn = scn;
@@ -515,7 +518,7 @@ htvox_scene_ref_put(struct htvox_scene* scn)
res_T
htvox_scene_get_aabb
- (const struct htvox_scene* scn,
+ (const struct htvox_scene* scn,
double lower[3],
double upper[3])
{
@@ -524,3 +527,81 @@ htvox_scene_get_aabb
d3_set(upper, scn->upper);
return RES_OK;
}
+
+res_T
+htvox_scene_for_each_voxel
+ (struct htvox_scene* scn,
+ void (*func)
+ (const double val, const double low[3], const double upp[3], void* ctx),
+ void* ctx)
+{
+ struct stack_entry {
+ struct octree_index inode;
+ double low[3];
+ double upp[3];
+ } stack[OCTREE_DEPTH_MAX*8];
+ int istack;
+
+ if(!scn || !func) return RES_BAD_ARG;
+
+ stack[0].inode = scn->root;
+ stack[0].low[0] = scn->oclow[0];
+ stack[0].low[1] = scn->oclow[1];
+ stack[0].low[2] = scn->oclow[2];
+ stack[0].upp[0] = scn->ocupp[0];
+ stack[0].upp[1] = scn->ocupp[1];
+ stack[0].upp[2] = scn->ocupp[2];
+ istack = 1;
+
+ do {
+ const struct stack_entry entry = stack[--istack];
+ struct octree_xnode* node;
+
+ node = octree_buffer_get_node(&scn->buffer, entry.inode);
+
+ if(OCTREE_XNODE_IS_LEAF(node)) {
+ double val;
+ struct octree_index ileaf;
+
+ ileaf = octree_buffer_get_child_index(&scn->buffer, entry.inode, 0);
+ val = *octree_buffer_get_leaf(&scn->buffer, ileaf);
+
+ ASSERT(entry.upp[0] <= scn->upper[0]);
+ ASSERT(entry.upp[1] <= scn->upper[1]);
+ ASSERT(entry.upp[2] <= scn->upper[2]);
+ ASSERT(entry.low[0] >= scn->lower[0]);
+ ASSERT(entry.low[1] >= scn->lower[1]);
+ ASSERT(entry.low[2] >= scn->lower[2]);
+
+ func(val, entry.low, entry.upp, ctx);
+
+ } else if(!OCTREE_XNODE_IS_EMPTY(node)) {
+ double half_sz[3]; /* Half size of the current node */
+ double mid[3]; /* Middle point of the current node */
+ int i;
+
+ half_sz[0] = (entry.upp[0] - entry.low[0])*0.5;
+ half_sz[1] = (entry.upp[1] - entry.low[1])*0.5;
+ half_sz[2] = (entry.upp[2] - entry.low[2])*0.5;
+ mid[0] = entry.low[0] + half_sz[0];
+ mid[1] = entry.low[1] + half_sz[1];
+ mid[2] = entry.low[2] + half_sz[2];
+
+ /* Push the children */
+ FOR_EACH(i, 0, 8) {
+ struct stack_entry* top = stack + istack;
+ top->inode = octree_buffer_get_child_index(&scn->buffer, entry.inode, i);
+ top->low[0] = i&4 ? mid[0] : entry.low[0];
+ top->low[1] = i&2 ? mid[1] : entry.low[1];
+ top->low[2] = i&1 ? mid[2] : entry.low[2];
+ top->upp[0] = top->low[0] + half_sz[0];
+ top->upp[1] = top->low[1] + half_sz[1];
+ top->upp[2] = top->low[2] + half_sz[2];
+ ++istack;
+ }
+ }
+ } while(istack);
+
+ return RES_OK;
+}
+
diff --git a/src/htvox_scene.h b/src/htvox_scene.h
@@ -23,7 +23,8 @@ struct htvox_scene {
double vox_scale[3]; /* Scale factor of the octree */
size_t definition; /* Definition of the octree */
- double lower[3], upper[3]; /* World space AABB */
+ double lower[3], upper[3]; /* World space AABB of the scene */
+ double oclow[3], ocupp[3]; /* World space AABB of the octree */
struct octree_buffer buffer;
struct octree_index root; /* Index toward the root node of the octree */
diff --git a/src/test_htvox_scene.c b/src/test_htvox_scene.c
@@ -19,11 +19,18 @@
#include <rsys/double3.h>
+struct context {
+ double* lower;
+ double* upper;
+ size_t* nvoxels;
+};
+
static int
merge(const double min_val, const double max_val, void* ctx)
{
+ (void)min_val, (void)max_val;
CHK((intptr_t)ctx == 0xDECAFBAD);
- return (max_val - min_val) < 0.5;
+ return 0; /* Merge nothing */
}
static void
@@ -40,7 +47,45 @@ get(const size_t xyz[3], double* val, void* ctx)
ui3[2] = (uint32_t)xyz[2];
mcode = morton_xyz_encode_u21(ui3);
- *val = (double)(mcode % 8) / (double)4;
+ *val = (double)mcode;
+}
+
+static void
+check_voxel
+ (const double val, const double low[3], const double upp[3], void* context)
+{
+ struct context* ctx = context;
+ uint64_t mcode;
+ uint32_t xyz[3];
+ double lower[3];
+ double delta[3];
+
+ CHK(val >= 0);
+ CHK(low != NULL);
+ CHK(upp != NULL);
+ CHK(ctx != NULL);
+ CHK(low[0] < upp[0]);
+ CHK(low[1] < upp[1]);
+ CHK(low[2] < upp[2]);
+
+ mcode = (uint64_t)val;
+ CHK(val == (double)mcode);
+
+ delta[0] = (ctx->upper[0] - ctx->lower[0]) / (double)ctx->nvoxels[0];
+ delta[1] = (ctx->upper[1] - ctx->lower[1]) / (double)ctx->nvoxels[1];
+ delta[2] = (ctx->upper[2] - ctx->lower[2]) / (double)ctx->nvoxels[2];
+
+ morton_xyz_decode_u21(mcode, xyz);
+ lower[0] = xyz[0] * delta[0];
+ lower[1] = xyz[1] * delta[1];
+ lower[2] = xyz[2] * delta[2];
+
+ CHK(eq_eps(lower[0], low[0], 1.e-6));
+ CHK(eq_eps(lower[1], low[1], 1.e-6));
+ CHK(eq_eps(lower[2], low[2], 1.e-6));
+ CHK(eq_eps(lower[0] + delta[0], upp[0], 1.e-6));
+ CHK(eq_eps(lower[1] + delta[1], upp[1], 1.e-6));
+ CHK(eq_eps(lower[2] + delta[2], upp[2], 1.e-6));
}
int
@@ -52,7 +97,8 @@ main(int argc, char** argv)
double low[3];
double upp[3];
size_t nvxls[3];
- void* ctx = (void*)0xDECAFBAD;
+ struct context ctx;
+ void* ptr = (void*)0xDECAFBAD;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
@@ -63,9 +109,13 @@ main(int argc, char** argv)
d3_splat(upp, 1.0);
nvxls[0] = nvxls[1] = nvxls[2] = 10;
+ ctx.lower = low;
+ ctx.upper = upp;
+ ctx.nvoxels = nvxls;
+
#define NEW_SCN htvox_scene_create
- CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_OK);
+ CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_OK);
CHK(htvox_scene_ref_get(NULL) == RES_BAD_ARG);
CHK(htvox_scene_ref_get(scn) == RES_OK);
@@ -74,25 +124,27 @@ main(int argc, char** argv)
CHK(htvox_scene_ref_put(scn) == RES_OK);
upp[0] = low[0];
- CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG);
upp[0] = 1.0;
nvxls[2] = 0;
- CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG);
- nvxls[2] = 10;
+ CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG);
+ nvxls[2] = nvxls[0];
- CHK(NEW_SCN(NULL, low, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, NULL, upp, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, low, NULL, nvxls, get, merge, ctx, &scn) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, low, upp, NULL, get, merge, ctx, &scn) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, low, upp, nvxls, NULL, merge, ctx, &scn) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, low, upp, nvxls, get, NULL, ctx, &scn) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, NULL) == RES_BAD_ARG);
+ CHK(NEW_SCN(NULL, low, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, NULL, upp, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, low, NULL, nvxls, get, merge, ptr, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, low, upp, NULL, get, merge, ptr, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, low, upp, nvxls, NULL, merge, ptr, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, low, upp, nvxls, get, NULL, ptr, &scn) == RES_BAD_ARG);
+ CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, NULL) == RES_BAD_ARG);
- CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ctx, &scn) == RES_OK);
+ CHK(NEW_SCN(dev, low, upp, nvxls, get, merge, ptr, &scn) == RES_OK);
#undef NEW_SCN
+ CHK(htvox_scene_for_each_voxel(scn, check_voxel, &ctx) == RES_OK);
+
d3_splat(low, DBL_MAX);
d3_splat(upp,-DBL_MAX);
CHK(htvox_scene_get_aabb(scn, low, upp) == RES_OK);