star-vx

Structuring voxels for ray-tracing
git clone git://git.meso-star.fr/star-vx.git
Log | Files | Refs | README | LICENSE

commit 3d6f5bd34402a9cbf1ecefd479c47e6df772593f
parent 59831938eed74e099aaedc84004084fdd79e0b99
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 27 Feb 2018 15:31:47 +0100

Make the voxel data "generic"

The caller can now define the size of the voxel. This size could be at
most equal to the constant HTVOX_MAX_SIZEOF_VOXEL.

Diffstat:
Msrc/htvox.h | 53+++++++++++++++++++++++++++++++++++++++++++----------
Msrc/htvox_octree_buffer.c | 11++++++++---
Msrc/htvox_octree_buffer.h | 14++++++++------
Msrc/htvox_scene.c | 93+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/test_htvox_scene.c | 111++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
5 files changed, 197 insertions(+), 85 deletions(-)

diff --git a/src/htvox.h b/src/htvox.h @@ -37,16 +37,51 @@ #define HTVOX(Func) htvox_ ## Func #endif +/* Maximum memory size of a voxel */ +#define HTVOX_MAX_SIZEOF_VOXEL (sizeof(double)*16) + struct htvox_voxel { - double data; /* Data of the voxel */ + const void* data; /* Data of the voxel */ size_t id; /* Indentifier of the voxel */ }; -#define HTVOX_VOXEL_NULL__ { DBL_MAX, SIZE_MAX } +#define HTVOX_VOXEL_NULL__ { NULL, SIZE_MAX } static const struct htvox_voxel HTVOX_VOXEL_NULL = HTVOX_VOXEL_NULL__; #define HTVOX_VOXEL_NONE(Voxel) ((Voxel)->id == HTVOX_VOXEL_NULL.id) +/* Descriptor of a voxel */ +struct htvox_voxel_desc { + /* Retrieve the data of the voxels*/ + void + (*get) + (const size_t xyz[3], /* Voxel coordinate in voxel space */ + void* dst, /* Where to store data */ + void* ctx); /* Pointer toward user data */ + + /* Merge the data of N voxels */ + void + (*merge) + (void* dst, /* Merged data */ + const void* voxels[], /* Data to merge */ + const size_t nvoxels, /* #submitted data */ + void* ctx); /* Pointer toward user data */ + + /* Check if the voxel's data can be merged */ + int + (*challenge_merge) + (const void* voxels[], /* Data candidates to the merge */ + const size_t nvoxels, /* #candidates */ + void* ctx); /* Pointer toward user data */ + + void* context; /* Client side data sent as the last argument of the clbbs */ + size_t size; /* Size in bytes of a voxel. Must be <= HTVOX_MAX_SIZEOF_VOXE */ +}; + +#define HTVOX_VOXEL_DESC_NULL__ { NULL, NULL, NULL, NULL, 0 } +static const struct htvox_voxel_desc HTVOX_VOXEL_DESC_NULL = + HTVOX_VOXEL_DESC_NULL__; + struct htvox_hit { double distance; /* Distance from the ray origin to the impacted voxel */ struct htvox_voxel voxel; /* Intersected voxel */ @@ -94,9 +129,7 @@ htvox_scene_create const double lower[3], /* Lower bound of the scene */ const double upper[3], /* Upper bound of the scene */ const size_t nvoxels[3], /* # voxels along the 3 axis */ - void (*get)(const size_t xyz[3], double* value, void* ctx), - int (*merge)(const double min_val, const double max_val, void* ctx), - void* context, /* Client data sent as the last param of the callbacks */ + const struct htvox_voxel_desc* desc, /* Descriptor of a voxel */ struct htvox_scene** scn); HTVOX_API res_T @@ -122,11 +155,11 @@ HTVOX_API res_T htvox_scene_for_each_voxel (struct htvox_scene* scn, void (*functor) - (const double val, /* Value of the voxel */ - const size_t ivoxel, /* Identifier of the voxel */ - const double low[3], /* World space lower bound of the voxel */ - const double upp[3], /* World space upper bound of the voxel */ - void* ctx), /* Client data */ + (const void* val, /* Value of the voxel */ + const size_t ivoxel, /* Identifier of the voxel */ + const double low[3], /* World space lower bound of the voxel */ + const double upp[3], /* World space upper bound of the voxel */ + void* ctx), /* Client data */ void* context); /* Client data sent as the last argument of the callback */ HTVOX_API res_T diff --git a/src/htvox_octree_buffer.c b/src/htvox_octree_buffer.c @@ -64,7 +64,7 @@ ensure_allocated_leaves(struct octree_buffer* buf, const size_t nleaves) ASSERT(buf); if(buf->leaf_head.ipage != OCTREE_INDEX_NULL.ipage - && buf->leaf_head.inode + nleaves <= buf->pagesize/sizeof(double)) + && buf->leaf_head.inode + nleaves <= buf->pagesize/buf->voxsize) goto exit; nleaf_pages = darray_page_size_get(&buf->leaf_pages); @@ -92,16 +92,21 @@ error: * Local functions ******************************************************************************/ void -octree_buffer_init(struct mem_allocator* allocator, struct octree_buffer* buf) +octree_buffer_init + (struct mem_allocator* allocator, + const size_t voxel_size, + struct octree_buffer* buf) { ASSERT(buf && allocator); memset(buf, 0, sizeof(struct octree_buffer)); buf->pagesize = (size_t)sysconf(_SC_PAGESIZE); + buf->voxsize = voxel_size; darray_page_init(allocator, &buf->node_pages); darray_page_init(allocator, &buf->leaf_pages); buf->node_head = OCTREE_INDEX_NULL; buf->leaf_head = OCTREE_INDEX_NULL; buf->allocator = allocator; + CHK(buf->voxsize <= buf->pagesize); } void @@ -141,7 +146,7 @@ octree_buffer_alloc_leaves res_T res = RES_OK; ASSERT(buf && first_leaf); - if(nleaves >= buf->pagesize / sizeof(double)) return RES_MEM_ERR; + if(nleaves >= buf->pagesize / buf->voxsize) return RES_MEM_ERR; res = ensure_allocated_leaves(buf, nleaves); if(res != RES_OK) return res; diff --git a/src/htvox_octree_buffer.h b/src/htvox_octree_buffer.h @@ -47,7 +47,7 @@ struct octree_xnode { uint16_t node_offset; uint16_t leaf_offset; uint8_t is_valid; /* Mask defining if the children are valid */ - uint8_t is_leaf; /* Mask defining if the children are leafs */ + uint8_t is_leaf; /* Mask defining if the children are leaves */ uint16_t dummy__; /* Ensure that the size of the node is 8 bytes */ }; @@ -72,6 +72,7 @@ static const struct octree_index OCTREE_INDEX_NULL = OCTREE_INDEX_NULL__; struct octree_buffer { size_t pagesize; /* Memory page size in bytes */ + size_t voxsize; /* Memory size of a voxel in bytes */ struct darray_page node_pages; /* List of pages storing nodes */ struct darray_page leaf_pages; /* List of pages storing leaves */ @@ -84,6 +85,7 @@ struct octree_buffer { extern LOCAL_SYM void octree_buffer_init (struct mem_allocator* allocator, + const size_t sizeof_voxel, /* Size in bytes of a voxel */ struct octree_buffer* buf); extern LOCAL_SYM void @@ -147,17 +149,17 @@ octree_buffer_get_far_index return (struct octree_index*)mem; } -static FINLINE double* +static FINLINE void* octree_buffer_get_leaf (struct octree_buffer* buf, - const struct octree_index id) + const struct octree_index id) { char* mem; - ASSERT(buf && id.inode < buf->pagesize/sizeof(double)); + ASSERT(buf && id.inode < buf->pagesize/buf->voxsize); ASSERT(id.ipage < darray_page_size_get(&buf->leaf_pages)); mem = darray_page_data_get(&buf->leaf_pages)[id.ipage]; - mem += id.inode * sizeof(double); - return (double*)mem; + mem += id.inode * buf->voxsize; + return mem; } static FINLINE struct octree_index diff --git a/src/htvox_scene.c b/src/htvox_scene.c @@ -25,15 +25,16 @@ struct voxel { uint64_t mcode; /* Morton code of the voxel */ - double data; /* Data of the voxel */ + void* data; /* Data of the voxel */ }; +static const struct voxel VOXEL_NULL = {0, NULL}; struct octree_node { struct octree_index ichild_node; /* Index of the 1st child node */ struct octree_index ichild_leaf; /* Index of the 1st child leaf */ uint8_t is_valid; /* Mask defining whether the children are valid or not */ uint8_t is_leaf; /* Mask defining whether the children are leaves or not */ - double data[8]; /* Data of the leaves */ + ALIGN(16) char data[8][HTVOX_MAX_SIZEOF_VOXEL]; /* Data of the leaves */ }; /* Stacked children of an octree node */ @@ -46,9 +47,7 @@ struct octree_builder { struct stack stacks[OCTREE_DEPTH_MAX]; struct octree_buffer* buffer; - int (*merge)(const double min_val, const double max_val, void* ctx); - void* context; /* Client side data sent to the merge callback */ - + const struct htvox_voxel_desc* desc; int octree_depth; uint64_t mcode; /* Morton code of the last registered voxels */ @@ -83,6 +82,17 @@ check_octree(struct octree_buffer* buf, const struct octree_index root) } #endif +static INLINE int +check_htvox_voxel_desc(const struct htvox_voxel_desc* desc) +{ + return desc + && desc->get + && desc->merge + && desc->challenge_merge + && desc->size > 0 + && desc->size <= HTVOX_MAX_SIZEOF_VOXEL; +} + static INLINE void stack_clear(struct stack* stack) { @@ -94,7 +104,7 @@ stack_clear(struct stack* stack) stack->nodes[inode].ichild_node = OCTREE_INDEX_NULL; stack->nodes[inode].ichild_leaf = OCTREE_INDEX_NULL; FOR_EACH(ileaf, 0, 8) { - stack->nodes[inode].data[ileaf] = 0; + memset(stack->nodes[inode].data[ileaf], 0, HTVOX_MAX_SIZEOF_VOXEL); } } stack->mask = 0; @@ -105,11 +115,10 @@ static INLINE void stack_setup_node (struct stack* stack, struct octree_node* node, - int (*merge_func)(const double min_val, const double max_val, void* ctx), - void* context) + const struct htvox_voxel_desc* desc) { int ichild; - ASSERT(stack && node && merge_func); + ASSERT(stack && node && check_htvox_voxel_desc(desc)); node->ichild_node = OCTREE_INDEX_NULL; node->ichild_leaf = OCTREE_INDEX_NULL; @@ -120,8 +129,7 @@ stack_setup_node /* Try to merge the child's leaves */ FOR_EACH(ichild, 0, 8) { - double data_min = DBL_MAX; - double data_max =-DBL_MAX; + const void* data[8]; struct octree_node* child = stack->nodes + ichild; int ileaf; @@ -130,13 +138,13 @@ stack_setup_node /* Find the minimum and maximum of the leaves */ FOR_EACH(ileaf, 0, 8) { - data_min = MMIN(child->data[ileaf], data_min); - data_max = MMAX(child->data[ileaf], data_max); + data[ileaf] = child->data[ileaf]; } + /* Challenge the merge function */ - if(merge_func(data_min, data_max, context)) { + if(desc->challenge_merge(data, 8, desc->context)) { const uint8_t ichild_flag = (uint8_t)BIT(ichild); - node->data[ichild] = data_max; + desc->merge(node->data[ichild], data, 8, desc->context); node->is_leaf |= ichild_flag; /* The node does not exist anymore in the stack since it became a leaf @@ -165,7 +173,7 @@ stack_write /* Write the leaves */ FOR_EACH(inode, 0, 8) { size_t nleaves; - double* leaves; + char* leaves; size_t nvoxs_node; int ileaf; @@ -182,7 +190,11 @@ stack_write leaves = octree_buffer_get_leaf(buffer, node->ichild_leaf); nvoxs_node = 0; FOR_EACH(ileaf, 0, 8) { - if(node->is_leaf & BIT(ileaf)) leaves[nvoxs_node++] = node->data[ileaf]; + if(node->is_leaf & BIT(ileaf)) { + memcpy(leaves + nvoxs_node*buffer->voxsize, node->data[ileaf], + buffer->voxsize); + ++nvoxs_node; + } } ASSERT(nvoxs_node == nleaves); } @@ -263,13 +275,12 @@ static res_T octree_builder_init (struct octree_builder* bldr, const size_t definition, - int (*merge)(const double min_val, const double max_val, void* ctx), - void* context, + const struct htvox_voxel_desc* desc, struct octree_buffer* buffer) { int ilvl; res_T res = RES_OK; - ASSERT(bldr && IS_POW2(definition) && merge); + ASSERT(bldr && IS_POW2(definition) && check_htvox_voxel_desc(desc)); memset(bldr, 0, sizeof(struct octree_builder)); /* Compute the maximum depth of the octree */ @@ -285,8 +296,7 @@ octree_builder_init } octree_buffer_clear(buffer); - bldr->merge = merge; - bldr->context = context; + bldr->desc = desc; bldr->buffer = buffer; exit: @@ -337,8 +347,7 @@ octree_builder_add_voxel /* The next voxel is not in the ilvl^th stack. Setup the parent node of the * nodes registered into the stack */ stack_node = &bldr->stacks[ilvl+1].nodes[inode]; - stack_setup_node - (&bldr->stacks[ilvl], stack_node, bldr->merge, bldr->context); + stack_setup_node(&bldr->stacks[ilvl], stack_node, bldr->desc); bldr->stacks[ilvl+1].mask |= (uint8_t)BIT(inode); /* Write the nodes of the stack of the current octree level into the buf */ @@ -357,7 +366,7 @@ octree_builder_add_voxel ichild_flag = (uint8_t)BIT(ichild); /* Register the voxel */ - bldr->stacks[0].nodes[inode].data[ichild] = vox->data; + memcpy(bldr->stacks[0].nodes[inode].data[ichild], vox->data, bldr->desc->size); bldr->stacks[0].nodes[inode].is_valid |= ichild_flag; bldr->stacks[0].nodes[inode].is_leaf |= ichild_flag; @@ -394,8 +403,7 @@ octree_builder_finalize /* Setup the parent node of the nodes registered into the current stack */ parent_node = &bldr->stacks[ilvl+1].nodes[inode]; /* Fetch the parent node */ - stack_setup_node - (&bldr->stacks[ilvl], parent_node, bldr->merge, bldr->context); + stack_setup_node(&bldr->stacks[ilvl], parent_node, bldr->desc); bldr->stacks[ilvl+1].mask |= (uint8_t)BIT(inode); /* Write the stacked nodes of the current level */ @@ -437,19 +445,19 @@ htvox_scene_create const double lower[3], /* Lower bound of the scene */ const double upper[3], /* Upper bound of the scene */ const size_t nvoxels[3], /* # voxels along the 3 axis */ - void (*get)(const size_t xyz[3], double* value, void* ctx), - int (*merge)(const double min_val, const double max_val, void* ctx), - void* context, /* Client data send as the last param of the `get' callback */ + const struct htvox_voxel_desc* desc, /* Descriptor of a voxel */ struct htvox_scene** out_scn) { struct htvox_scene* scn = NULL; double vox_sz[3]; /* World space size of a voxel */ struct octree_builder bldr; + struct voxel vox = VOXEL_NULL; uint64_t mcode_max; uint64_t mcode; res_T res = RES_OK; - if(!dev || !lower || !upper || !nvoxels || !get || !merge || !out_scn) { + if(!dev || !lower || !upper || !nvoxels + || !check_htvox_voxel_desc(desc) || !out_scn) { res = RES_BAD_ARG; goto error; } @@ -481,7 +489,7 @@ htvox_scene_create } ref_init(&scn->ref); HTVOX(device_ref_get(dev)); - octree_buffer_init(dev->allocator, &scn->buffer); + octree_buffer_init(dev->allocator, desc->size, &scn->buffer); scn->dev = dev; /* Compute the octree definition */ @@ -491,13 +499,17 @@ htvox_scene_create scn->definition = round_up_pow2(scn->definition); /* Intialize the octree builder */ - res = octree_builder_init - (&bldr, scn->definition, merge, context, &scn->buffer); + res = octree_builder_init(&bldr, scn->definition, desc, &scn->buffer); if(res != RES_OK) goto error; + vox.data = MEM_CALLOC(dev->allocator, 1, desc->size); + if(!vox.data) { + res = RES_MEM_ERR; + goto error; + } + mcode_max = scn->definition * scn->definition * scn->definition; FOR_EACH(mcode, 0, mcode_max) { - struct voxel vox; size_t xyz[3]; uint32_t ui3[3]; @@ -513,7 +525,7 @@ htvox_scene_create xyz[0] = (size_t)ui3[0]; xyz[1] = (size_t)ui3[1]; xyz[2] = (size_t)ui3[2]; - get(xyz, &vox.data, context); + desc->get(xyz, vox.data, desc->context); vox.mcode = mcode; /* Register the voxel against the octree */ @@ -543,6 +555,7 @@ htvox_scene_create scn->ocupp[2] = (double)scn->definition * vox_sz[2]; exit: + if(vox.data) MEM_RM(dev->allocator, vox.data); if(out_scn) *out_scn = scn; return res; error: @@ -598,7 +611,7 @@ res_T htvox_scene_for_each_voxel (struct htvox_scene* scn, void (*func) - (const double val, + (const void* val, const size_t ivoxel, const double low[3], const double upp[3], @@ -655,10 +668,10 @@ htvox_scene_for_each_voxel if(node->is_leaf & ichild_flag) { struct octree_index ileaf; size_t ivoxel; - double val; + const void* val; ileaf = octree_buffer_get_leaf_index(&scn->buffer, entry.inode, ichild); - val = *octree_buffer_get_leaf(&scn->buffer, ileaf); + val = octree_buffer_get_leaf(&scn->buffer, ileaf); ASSERT(upp[0] <= scn->upper[0]); ASSERT(upp[1] <= scn->upper[1]); @@ -747,7 +760,7 @@ htvox_scene_at break; } else if(node->is_leaf & ichild_flag) { /* Leaf node */ inode = octree_buffer_get_leaf_index(&scn->buffer, inode, ichild); - voxel->data = *octree_buffer_get_leaf(&scn->buffer, inode); + voxel->data = octree_buffer_get_leaf(&scn->buffer, inode); voxel->id = inode.ipage * scn->buffer.pagesize / sizeof(double) + inode.inode; break; diff --git a/src/test_htvox_scene.c b/src/test_htvox_scene.c @@ -26,26 +26,58 @@ struct check_context { }; static int -no_merge(const double min_val, const double max_val, void* ctx) +no_merge(const void* voxels[], const size_t nvoxels, void* ctx) { - CHK(min_val <= max_val); + CHK(voxels != NULL); + CHK(nvoxels != 0); CHK((intptr_t)ctx == 0xDECAFBAD); return 0; /* Merge nothing */ } static int -merge_level0(const double min_val, const double max_val, void* ctx) +merge_level0(const void** voxels, const size_t nvoxels, void* ctx) { - CHK(min_val <= max_val); + double min_val = DBL_MAX; + double max_val =-DBL_MAX; + size_t i; + CHK(voxels != NULL); + CHK(nvoxels != 0); CHK((intptr_t)ctx == 0xDECAFBAD); + + FOR_EACH(i, 0, nvoxels) { + const double* val = voxels[i]; + min_val = MMIN(min_val, *val); + max_val = MMAX(max_val, *val); + } + return (max_val - min_val) < 8; } static void -get(const size_t xyz[3], double* val, void* ctx) +keep_max(void* dst, const void* voxels[], const size_t nvoxels, void* ctx) +{ + double* vox_dst = dst; + double max_val = -DBL_MAX; + size_t i; + + CHK(dst != NULL); + CHK(voxels != NULL); + CHK(nvoxels != 0); + CHK(ctx != NULL); + + FOR_EACH(i, 0, nvoxels) { + const double* val = voxels[i]; + max_val = MMAX(max_val, *val); + } + *vox_dst = max_val; +} + +static void +get(const size_t xyz[3], void* dst, void* ctx) { uint32_t ui3[3]; uint64_t mcode; + double* val = dst; CHK(xyz != NULL); CHK(val != NULL); CHK((intptr_t)ctx == 0xDECAFBAD); @@ -60,19 +92,20 @@ get(const size_t xyz[3], double* val, void* ctx) static void check_voxel - (const double val, + (const void* val, const size_t ivoxel, const double low[3], const double upp[3], void* context) { + const double* dbl = val; struct check_context* ctx = context; uint64_t mcode; uint32_t xyz[3]; double lower[3]; double delta[3]; - CHK(val >= 0); + CHK(val != NULL); CHK(low != NULL); CHK(upp != NULL); CHK(ctx != NULL); @@ -80,9 +113,10 @@ check_voxel CHK(low[1] < upp[1]); CHK(low[2] < upp[2]); CHK(ivoxel < ctx->nvoxels[0]*ctx->nvoxels[1]*ctx->nvoxels[2]); + CHK(*dbl >= 0); - mcode = (uint64_t)val; - CHK(val == (double)mcode); + mcode = (uint64_t)(*dbl); + CHK(*dbl == (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]; @@ -103,7 +137,7 @@ check_voxel static void write_points - (const double val, + (const void* val, const size_t ivoxel, const double low[3], const double upp[3], @@ -129,7 +163,7 @@ write_points static void write_cells - (const double val, + (const void* val, const size_t ivoxel, const double low[3], const double upp[3], @@ -153,7 +187,7 @@ write_cells static void write_scalars - (const double val, + (const void* val, const size_t ivoxel, const double low[3], const double upp[3], @@ -164,7 +198,7 @@ write_scalars CHK(stream != NULL); CHK(low != NULL); CHK(upp != NULL); - fprintf(stream, "%g\n", val); + fprintf(stream, "%g\n", *(double*)val); } static void @@ -205,6 +239,7 @@ main(int argc, char** argv) struct htvox_device* dev = NULL; struct htvox_scene* scn = NULL; struct mem_allocator allocator; + struct htvox_voxel_desc desc = HTVOX_VOXEL_DESC_NULL; double low[3]; double upp[3]; double pos[3]; @@ -230,7 +265,12 @@ main(int argc, char** argv) #define NEW_SCN htvox_scene_create - CHK(NEW_SCN(dev, low, upp, nvxls, get, no_merge, ptr, &scn) == RES_OK); + desc.get = get; + desc.merge = keep_max; + desc.challenge_merge = no_merge; + desc.context = ptr; + desc.size = sizeof(double); + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_OK); CHK(htvox_scene_ref_get(NULL) == RES_BAD_ARG); CHK(htvox_scene_ref_get(scn) == RES_OK); @@ -239,22 +279,40 @@ 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, no_merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); upp[0] = 1.0; nvxls[2] = 0; - CHK(NEW_SCN(dev, low, upp, nvxls, get, no_merge, ptr, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); nvxls[2] = nvxls[0]; - CHK(NEW_SCN(NULL, low, upp, nvxls, get, no_merge, ptr, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, NULL, upp, nvxls, get, no_merge, ptr, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, NULL, nvxls, get, no_merge, ptr, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, NULL, get, no_merge, ptr, &scn) == RES_BAD_ARG); - CHK(NEW_SCN(dev, low, upp, nvxls, NULL, no_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, no_merge, ptr, NULL) == RES_BAD_ARG); + CHK(NEW_SCN(NULL, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, NULL, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, NULL, nvxls, &desc, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, NULL, &desc, &scn) == RES_BAD_ARG); + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, NULL) == RES_BAD_ARG); + + desc.get = NULL; + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + desc.get = get; + + desc.merge = NULL; + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + desc.merge = keep_max; + + desc.challenge_merge = NULL; + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + desc.challenge_merge = no_merge; + + desc.size = 0; + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + desc.size = sizeof(double); + + desc.size = HTVOX_MAX_SIZEOF_VOXEL + 1; + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_BAD_ARG); + desc.size = sizeof(double); - CHK(NEW_SCN(dev, low, upp, nvxls, get, no_merge, ptr, &scn) == RES_OK); + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_OK); CHK(htvox_scene_for_each_voxel(scn, check_voxel, &ctx) == RES_OK); @@ -286,7 +344,7 @@ main(int argc, char** argv) CHK(!HTVOX_VOXEL_NONE(&vox)); mcode = morton_xyz_encode_u21(ui3); - CHK(vox.data == mcode); + CHK(*((double*)vox.data) == mcode); } } } @@ -303,7 +361,8 @@ main(int argc, char** argv) CHK(htvox_scene_ref_put(scn) == RES_OK); nvxls[0] = nvxls[1] = nvxls[2] = 8; - CHK(NEW_SCN(dev, low, upp, nvxls, get, merge_level0, ptr, &scn) == RES_OK); + desc.challenge_merge = merge_level0; + CHK(NEW_SCN(dev, low, upp, nvxls, &desc, &scn) == RES_OK); CHK(htvox_scene_get_voxels_count(scn, &nvoxels) == RES_OK); CHK(nvoxels == nvxls[0]*nvxls[1]*nvxls[2] / 8);