commit 70ea012ad35a3a124fd8b654f87507da7f2eb22b
parent 44806b993440aeca99a6e4f80e108dbfb45c1bd4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 21 Feb 2020 16:22:26 +0100
Merge branch 'release_0.1'
Diffstat:
22 files changed, 633 insertions(+), 91 deletions(-)
diff --git a/README.md b/README.md
@@ -1,7 +1,7 @@
# Star-VoXel
-Star-VX is C library whose purpose is to manage volume elements - named voxels
-- structured as a set of axis aligned cuboids. This library does not know
+Star-VX is C library whose purpose is to manage volume elements, named voxels,
+structured as a set of axis aligned cuboids. This library does not know
anything about the volumic data that it handles: it only provides data
structures that partition voxels according to user criteria. It also implements
efficient ways to index voxels into the space partitioning data structures or
@@ -38,10 +38,18 @@ resulting project can be edited, built, tested and installed as any CMake
project. Refer to the [CMake](https://cmake.org/documentation) for further
informations on CMake.
-## Licenses
+## Release notes
-Star-VX is free software copyright (C) 2018 Université Paul Sabatier
-(<contact-edstar@laplace.univ-tlse.fr>), |Meso|Star> (<contact@meso-star.com>).
-It is 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 details.
+### Version 0.1
+
+- Add the `svx_tree_write` and the `svx_tree_create_from_stream` functions used
+ to serialize and de-serialize the tree data structure, respectively.
+
+## License
+
+Copyright (C) 2018, 2020 [|Meso|Star>](https://www.meso-star.com)
+(<contact@meso-star.com>). Copyright (C) 2018 Université Paul Sabatier
+(<contact-edstar@laplace.univ-tlse.fr>). Star-VoXel 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
+details.
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+# Copyright (C) 2018 Université Paul Sabatier
+# Copyright (C) 2018, 2020 |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
@@ -36,8 +37,8 @@ include_directories(${RSys_INCLUDE_DIR})
# 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(SVX_FILES_SRC
diff --git a/src/svx.h b/src/svx.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -236,6 +237,12 @@ svx_bintree_create
struct svx_tree** tree);
SVX_API res_T
+svx_tree_create_from_stream
+ (struct svx_device* dev,
+ FILE* stream,
+ struct svx_tree** tree);
+
+SVX_API res_T
svx_tree_ref_get
(struct svx_tree* tree);
@@ -273,5 +280,10 @@ svx_tree_at
void* context, /* Client data sent as the last argument of the filter func */
struct svx_voxel* voxel);
+SVX_API res_T
+svx_tree_write
+ (const struct svx_tree* tree,
+ FILE* stream);
+
#endif /* SVX_H */
diff --git a/src/svx_bintree.c b/src/svx_bintree.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -120,7 +121,7 @@ svx_bintree_create
#ifndef NDEBUG
{
size_t nleaves = 0;
- bintree_check(&bintree->buffer, bintree->root, &nleaves);
+ CHK(buffer_check_tree(&bintree->buffer, bintree->root, 1, &nleaves) == RES_OK);
CHK(nleaves == bintree->nleaves);
}
#endif
diff --git a/src/svx_bintree_trace_ray.c b/src/svx_bintree_trace_ray.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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/svx_buffer.c b/src/svx_buffer.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -15,13 +16,14 @@
#include "svx_buffer.h"
+#include <rsys/math.h>
#include <rsys/mem_allocator.h>
#ifdef COMPILER_CL
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
#else
-#include <unistd.h>
+ #include <unistd.h>
#endif
/*******************************************************************************
@@ -43,8 +45,8 @@ ensure_allocated_nodes(struct buffer* buf, const size_t nnodes)
if(nnode_pages > UINT32_MAX) { res = RES_MEM_ERR; goto error; }
ASSERT(nnode_pages == buf->node_head.ipage + 1);
- /* Alloc and register a node page containing the node and the far indices */
- node_page = MEM_ALLOC(buf->allocator, buf->pagesize);
+ /* Alloc and register a node page containing the nodes and the far indices */
+ node_page = MEM_CALLOC(buf->allocator, 1, buf->pagesize);
if(!node_page) { res = RES_MEM_ERR; goto error; }
res = darray_page_push_back(&buf->node_pages, &node_page);
if(res != RES_OK) goto error;
@@ -77,7 +79,7 @@ ensure_allocated_attrs(struct buffer* buf, const size_t nattrs)
ASSERT(nattr_pages == buf->attr_head.ipage + 1);
/* Alloc and register a attr page */
- attr_page = MEM_ALLOC(buf->allocator, buf->pagesize);
+ attr_page = MEM_CALLOC(buf->allocator, 1, buf->pagesize);
if(!attr_page) { res = RES_MEM_ERR; goto error; }
res = darray_page_push_back(&buf->attr_pages, &attr_page);
if(res != RES_OK) goto error;
@@ -147,7 +149,6 @@ buffer_alloc_nodes
*first_node = buf->node_head;
buf->node_head.inode = (uint16_t)(buf->node_head.inode + nnodes);
return RES_OK;
-
}
res_T
@@ -207,3 +208,153 @@ buffer_clear(struct buffer* buf)
buf->attr_head = BUFFER_INDEX_NULL;
}
+res_T
+buffer_write(const struct buffer* buf, FILE* stream)
+{
+ size_t ipage = 0;
+ size_t npages = 0;
+ res_T res = RES_OK;
+ ASSERT(buf && stream);
+
+ #define WRITE(Var, N) { \
+ if(fwrite((Var), sizeof(*(Var)), (N), stream) != (N)) { \
+ res = RES_IO_ERR; \
+ goto error; \
+ } \
+ } (void)0
+ WRITE(&BUFFER_VERSION, 1);
+ WRITE(&buf->pagesize, 1);
+ WRITE(&buf->voxsize, 1);
+ WRITE(&buf->node_head, 1);
+ WRITE(&buf->attr_head, 1);
+
+ npages = darray_page_size_get(&buf->node_pages);
+ WRITE(&npages, 1);
+ FOR_EACH(ipage, 0, npages) {
+ WRITE(darray_page_cdata_get(&buf->node_pages)[ipage], buf->pagesize);
+ }
+
+ npages = darray_page_size_get(&buf->attr_pages);
+ WRITE(&npages, 1);
+ FOR_EACH(ipage, 0, npages) {
+ WRITE(darray_page_cdata_get(&buf->attr_pages)[ipage], buf->pagesize);
+ }
+ #undef WRITE
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+buffer_read(struct buffer* buf, FILE* stream)
+{
+ int version = 0;
+ char* page = NULL;
+ size_t ipage = 0;
+ size_t npages = 0;
+ res_T res = RES_OK;
+ ASSERT(buf && stream);
+
+ buffer_clear(buf);
+
+ #define READ(Var, N) { \
+ if(fread((Var), sizeof(*(Var)), (N), stream) != (N)) { \
+ if(feof(stream)) { \
+ res = RES_BAD_ARG; \
+ } else if(ferror(stream)) { \
+ res = RES_IO_ERR; \
+ } else { \
+ res = RES_UNKNOWN_ERR; \
+ } \
+ goto error; \
+ } \
+ } (void)0
+
+ /* Currently only one version of the buffer data structure could be
+ * serialized. The version management is thus as simple as rejecting any
+ * buffer data structure whose version is not the current version. */
+ READ(&version, 1);
+ if(version != BUFFER_VERSION) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ READ(&buf->pagesize, 1);
+ READ(&buf->voxsize, 1);
+ READ(&buf->node_head, 1);
+ READ(&buf->attr_head, 1);
+
+ READ(&npages, 1);
+ res = darray_page_reserve(&buf->node_pages, npages);
+ if(res != RES_OK) goto error;
+
+ /* Read the pages of nodes */
+ FOR_EACH(ipage, 0, npages) {
+ page = MEM_ALLOC(buf->allocator, buf->pagesize);
+ if(!page) { res = RES_MEM_ERR; goto error; }
+
+ READ(page, buf->pagesize);
+ CHK(darray_page_push_back(&buf->node_pages, &page) == RES_OK);
+ page = NULL;
+ }
+
+ READ(&npages, 1);
+ res = darray_page_reserve(&buf->attr_pages, npages);
+ if(res != RES_OK) goto error;
+
+ /* Read the pages of attribs */
+ FOR_EACH(ipage, 0, npages) {
+ page = MEM_ALLOC(buf->allocator, buf->pagesize);
+ if(!page) { res = RES_MEM_ERR; goto error; }
+
+ READ(page, buf->pagesize);
+ CHK(darray_page_push_back(&buf->attr_pages, &page) == RES_OK);
+ page = NULL;
+ }
+ #undef READ
+
+exit:
+ return res;
+error:
+ if(page) MEM_RM(buf->allocator, page);
+ buffer_clear(buf);
+ goto exit;
+}
+
+res_T
+buffer_check_tree
+ (struct buffer* buf,
+ const struct buffer_index root,
+ const size_t tree_dimension,
+ size_t* nleaves)
+{
+ const struct buffer_xnode* node;
+ const int nchildren = BIT((int)tree_dimension);
+ int ichild;
+ res_T res = RES_OK;
+ ASSERT(buf);
+ ASSERT(0 < tree_dimension && tree_dimension <= 3);
+
+ node = buffer_get_node(buf, root);
+ FOR_EACH(ichild, 0, nchildren) {
+ const int ichild_flag = BIT(ichild);
+ if((node->is_valid & ichild_flag) == 0) continue;
+
+ if(node->is_leaf & ichild_flag) {
+ struct buffer_index iattr;
+ iattr = buffer_get_child_attr_index(buf, root, ichild);
+ if(buffer_get_attr(buf, iattr) == NULL)
+ return RES_BAD_ARG;
+ *nleaves += 1;
+ } else {
+ struct buffer_index child;
+ child = buffer_get_child_node_index(buf, root, ichild);
+ res = buffer_check_tree(buf, child, tree_dimension, nleaves);
+ if(res != RES_OK) return res;
+ }
+ }
+ return RES_OK;
+}
+
diff --git a/src/svx_buffer.h b/src/svx_buffer.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -47,7 +48,7 @@ struct buffer_xnode {
/* Offset to retrieve the children. If the BUFFER_XNODE_FLAG_FAR_INDEX bit is
* not set, the children are stored in the same page at the position `offset
* & BUFFER_XNODE_MASK'. If BUFFER_XNODE_FLAG_FAR_INDEX is set, `offset &
- * BUFFER_XNODE_MASK' reference an buffer_index toward the node children */
+ * BUFFER_XNODE_MASK' reference a buffer_index toward the node children */
uint16_t node_offset;
uint16_t attr_offset;
uint8_t is_valid; /* Mask defining if the children are valid */
@@ -76,6 +77,9 @@ static const struct buffer_index BUFFER_INDEX_NULL = BUFFER_INDEX_NULL__;
#define DARRAY_DATA char*
#include <rsys/dynamic_array.h>
+/* Current version the buffer index data structure */
+static const int BUFFER_VERSION = 0;
+
struct buffer {
size_t pagesize; /* Memory page size in bytes */
size_t voxsize; /* Memory size of a voxel in bytes */
@@ -110,7 +114,7 @@ buffer_alloc_attrs
const size_t nattrs,
struct buffer_index* first_attr); /* Index toward the 1st allocated attrib */
-/* Allocate an buffer_index in the current buffer page. Return RES_MEM_ERR if
+/* Allocate a buffer_index in the current buffer page. Return RES_MEM_ERR if
* the node index cannot be allocated in the current page. In this case one
* have to alloc new nodes */
extern LOCAL_SYM res_T
@@ -122,6 +126,24 @@ extern LOCAL_SYM void
buffer_clear
(struct buffer* buf);
+extern LOCAL_SYM res_T
+buffer_write
+ (const struct buffer* buf,
+ FILE* stream);
+
+extern LOCAL_SYM res_T
+buffer_read
+ (struct buffer* buf,
+ FILE* stream);
+
+/* Check buffer data regarding a given tree root and tree dimension */
+extern LOCAL_SYM res_T
+buffer_check_tree
+ (struct buffer* buffer,
+ const struct buffer_index root, /* Root of the tree */
+ const size_t tree_dimension, /* Dimension of the tree */
+ size_t* nleaves); /* Overall #leaves of the tree */
+
static FINLINE int
buffer_is_empty(const struct buffer* buf)
{
diff --git a/src/svx_c.h b/src/svx_c.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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/svx_device.c b/src/svx_device.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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/svx_device.h b/src/svx_device.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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/svx_octree.c b/src/svx_octree.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -154,7 +155,7 @@ svx_octree_create
#ifndef NDEBUG
{
size_t nleaves = 0;
- octree_check(&oct->buffer, oct->root, &nleaves);
+ CHK(buffer_check_tree(&oct->buffer, oct->root, 3, &nleaves) == RES_OK);
CHK(nleaves == oct->nleaves);
}
#endif
@@ -175,4 +176,3 @@ error:
goto exit;
}
-
diff --git a/src/svx_octree_trace_ray.c b/src/svx_octree_trace_ray.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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/svx_tree.c b/src/svx_tree.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -31,6 +32,123 @@
/*******************************************************************************
* Helper function
******************************************************************************/
+static res_T
+check_octree(struct svx_tree* tree)
+{
+ ASSERT(tree && tree->type == SVX_OCTREE);
+
+ if(tree->frame[0] != SVX_AXIS_X
+ && tree->frame[1] != SVX_AXIS_Y
+ && tree->frame[2] != SVX_AXIS_Z)
+ return RES_BAD_ARG;
+
+ if(!IS_POW2(tree->definition))
+ return RES_BAD_ARG;
+
+ if(tree->lower[0] >= tree->upper[0]
+ || tree->lower[1] >= tree->upper[1]
+ || tree->lower[2] >= tree->upper[2])
+ return RES_BAD_ARG;
+
+ if(tree->tree_low[0] >= tree->tree_upp[0]
+ || tree->tree_low[1] >= tree->tree_upp[1]
+ || tree->tree_low[2] >= tree->tree_upp[2])
+ return RES_BAD_ARG;
+
+ if(tree->tree_low[0] != tree->lower[0]
+ || tree->tree_low[1] != tree->lower[1]
+ || tree->tree_low[2] != tree->lower[2])
+ return RES_BAD_ARG;
+
+ if(tree->tree_upp[0] < tree->upper[0]
+ || tree->tree_upp[1] < tree->upper[1]
+ || tree->tree_upp[2] < tree->upper[2])
+ return RES_BAD_ARG;
+
+ if(tree->tree_size[0] != tree->tree_upp[0] - tree->tree_low[0]
+ || tree->tree_size[1] != tree->tree_upp[1] - tree->tree_low[1]
+ || tree->tree_size[2] != tree->tree_upp[2] - tree->tree_low[2])
+ return RES_BAD_ARG;
+
+ #ifndef NDEBUG
+ {
+ size_t nleaves = 0;
+ res_T res = buffer_check_tree(&tree->buffer, tree->root, 3, &nleaves);
+ if(res != RES_OK) return res;
+
+ if(nleaves != tree->nleaves)
+ return RES_BAD_ARG;
+ }
+ #endif
+
+ return RES_OK;
+}
+
+static res_T
+check_bintree(struct svx_tree* tree)
+{
+ enum svx_axis axis = SVX_AXIS_NONE__;
+ ASSERT(tree && tree->type == SVX_BINTREE);
+
+ if(tree->frame[0] == SVX_AXIS_NONE__
+ || tree->frame[1] != SVX_AXIS_NONE__
+ || tree->frame[2] != SVX_AXIS_NONE__)
+ return RES_BAD_ARG;
+
+ if(!IS_POW2(tree->definition))
+ return RES_BAD_ARG;
+
+ axis = tree->frame[0];
+ if(tree->lower[axis] >= tree->upper[axis])
+ return RES_BAD_ARG;
+
+ if(tree->tree_low[axis] >= tree->tree_upp[axis])
+ return RES_BAD_ARG;
+
+ if(tree->tree_low[axis] != tree->lower[axis])
+ return RES_BAD_ARG;
+
+ if(tree->tree_upp[axis] < tree->upper[axis])
+ return RES_BAD_ARG;
+
+ if(tree->tree_size[axis] != tree->tree_upp[axis] - tree->tree_low[axis])
+ return RES_BAD_ARG;
+
+ #ifndef NDEBUG
+ {
+ size_t nleaves = 0;
+ res_T res = buffer_check_tree(&tree->buffer, tree->root, 1, &nleaves);
+ if(res != RES_OK) return res;
+
+ if(nleaves != tree->nleaves)
+ return RES_BAD_ARG;
+ }
+ #endif
+
+ return RES_OK;
+}
+
+static void
+tree_clear(struct svx_tree* tree)
+{
+ ASSERT(tree);
+ tree->definition = 0;
+ d3_splat(tree->lower, DBL_MAX);
+ d3_splat(tree->upper,-DBL_MAX);
+ d3_splat(tree->tree_low, DBL_MAX);
+ d3_splat(tree->tree_upp,-DBL_MAX);
+ d3_splat(tree->tree_size, -1);
+ tree->root = BUFFER_INDEX_NULL;
+ buffer_clear(&tree->buffer);
+ memset(tree->root_attr, 0, sizeof(tree->root_attr));
+ tree->nleaves = 0;
+ tree->depth = 0;
+ tree->frame[0] = SVX_AXIS_NONE__;
+ tree->frame[1] = SVX_AXIS_NONE__;
+ tree->frame[2] = SVX_AXIS_NONE__;
+ tree->type = -1;
+}
+
static void
tree_release(ref_T* ref)
{
@@ -48,6 +166,43 @@ tree_release(ref_T* ref)
* Exported functions
******************************************************************************/
res_T
+svx_tree_create_from_stream
+ (struct svx_device* dev,
+ FILE* stream,
+ struct svx_tree** out_tree)
+{
+ struct svx_tree* tree = NULL;
+ res_T res = RES_BAD_ARG;
+
+ if(!stream || !out_tree) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = tree_create
+ (dev, -1/* Unknown tree type */, 1/* Dummy voxel size */, &tree);
+ if(res != RES_OK) goto error;
+
+ /* Setup the tree data from the stream */
+ res = tree_read(tree, stream);
+ if(res != RES_OK) goto error;
+
+ switch(tree->type) {
+ case SVX_OCTREE: res = check_octree(tree); break;
+ case SVX_BINTREE: res = check_bintree(tree); break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ if(res != RES_OK) goto error;
+
+exit:
+ if(out_tree) *out_tree = tree;
+ return res;
+error:
+ if(tree) { SVX(tree_ref_put(tree)); tree = NULL; }
+ goto exit;
+}
+
+res_T
svx_tree_ref_get(struct svx_tree* tree)
{
if(!tree) return RES_BAD_ARG;
@@ -139,6 +294,46 @@ svx_tree_at
return res;
}
+res_T
+svx_tree_write(const struct svx_tree* tree, FILE* stream)
+{
+ res_T res = RES_OK;
+
+ if(!tree || !stream) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ #define WRITE(Var, N) { \
+ if(fwrite((Var), sizeof(*(Var)), (N), stream) != (N)) { \
+ res = RES_IO_ERR; \
+ goto error; \
+ } \
+ } (void)0
+ WRITE(&SVX_TREE_VERSION, 1);
+ WRITE(&tree->definition, 1);
+ WRITE(tree->lower, 3);
+ WRITE(tree->upper, 3);
+ WRITE(tree->tree_low, 3);
+ WRITE(tree->tree_upp, 3);
+ WRITE(tree->tree_size, 3);
+ WRITE(&tree->nleaves, 1);
+ WRITE(&tree->depth, 1);
+ WRITE(tree->frame, 3);
+ WRITE(&tree->type, 1);
+ WRITE(&tree->root, 1);
+ WRITE(tree->root_attr, SVX_MAX_SIZEOF_VOXEL);
+ #undef WRITE
+
+ res = buffer_write(&tree->buffer, stream);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
/*******************************************************************************
* Local functions
******************************************************************************/
@@ -187,3 +382,61 @@ error:
goto exit;
}
+res_T
+tree_read(struct svx_tree* tree, FILE* stream)
+{
+ int version = 0;
+ res_T res = RES_OK;
+ ASSERT(tree && stream);
+
+ tree_clear(tree);
+
+ #define READ(Var, N) { \
+ if(fread((Var), sizeof(*(Var)), (N), stream) != (N)) { \
+ if(feof(stream)) { \
+ res = RES_BAD_ARG; \
+ } else if(ferror(stream)) { \
+ res = RES_IO_ERR; \
+ } else { \
+ res = RES_UNKNOWN_ERR; \
+ } \
+ goto error; \
+ } \
+ } (void)0
+
+ /* Currently only one version of the tree data structure could be serialized.
+ * The version management is thus as simple as rejecting any tree data
+ * structure whose version is not the current version. */
+ READ(&version, 1);
+ if(version != SVX_TREE_VERSION) {
+ log_err(tree->dev,
+ "%s: unexpected tree version %d. Expecting a tree in version %d.\n",
+ FUNC_NAME, version, SVX_TREE_VERSION);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ READ(&tree->definition, 1);
+ READ(tree->lower, 3);
+ READ(tree->upper, 3);
+ READ(tree->tree_low, 3);
+ READ(tree->tree_upp, 3);
+ READ(tree->tree_size, 3);
+ READ(&tree->nleaves, 1);
+ READ(&tree->depth, 1);
+ READ(tree->frame, 3);
+ READ(&tree->type, 1);
+ READ(&tree->root, 1);
+ READ(tree->root_attr, SVX_MAX_SIZEOF_VOXEL);
+ #undef READ
+
+ res = buffer_read(&tree->buffer, stream);
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ tree_clear(tree);
+ goto exit;
+}
+
diff --git a/src/svx_tree.h b/src/svx_tree.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -19,6 +20,11 @@
#include "svx_buffer.h"
#include <rsys/ref_count.h>
+/* Current version the tree data structure. One should increment it and perform
+ * a version management onto serialized data when the tree data structure is
+ * updated. */
+static const int SVX_TREE_VERSION = 0;
+
struct svx_tree {
size_t definition; /* #voxels of the tree along its dimensions */
@@ -74,5 +80,10 @@ bintree_trace_ray
void* context,
struct svx_hit* hit);
+extern LOCAL_SYM res_T
+tree_read
+ (struct svx_tree* tree,
+ FILE* stream);
+
#endif /* SVX_TREE_H */
diff --git a/src/svx_tree_builder.h b/src/svx_tree_builder.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -92,33 +93,6 @@ struct XD(builder) {
/*******************************************************************************
* Stack functions
******************************************************************************/
-#ifndef NDEBUG
-static void
-XD(check)(struct buffer* buf, const struct buffer_index root, size_t* nleaves)
-{
- const struct buffer_xnode* node;
- int ichild;
- ASSERT(buf);
-
- node = buffer_get_node(buf, root);
- FOR_EACH(ichild, 0, NCHILDREN) {
- const int ichild_flag = BIT(ichild);
- if((node->is_valid & ichild_flag) == 0) continue;
-
- if(node->is_leaf & ichild_flag) {
- struct buffer_index iattr;
- iattr = buffer_get_child_attr_index(buf, root, ichild);
- ASSERT(buffer_get_attr(buf, iattr) != NULL);
- *nleaves += 1;
- } else {
- struct buffer_index child;
- child = buffer_get_child_node_index(buf, root, ichild);
- XD(check)(buf, child, nleaves);
- }
- }
-}
-#endif
-
static INLINE void
XD(stack_clear)(struct XD(stack)* stack)
{
diff --git a/src/svx_tree_generic_func.h b/src/svx_tree_generic_func.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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_svx_bintree.c b/src/test_svx_bintree.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -303,6 +304,7 @@ main(int argc, char** argv)
double low, upp;
size_t nvxls;
void* ptr = (void*)(intptr_t)0xDECAFBAD;
+ FILE* stream = NULL;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
@@ -381,6 +383,22 @@ main(int argc, char** argv)
CHK(tree_desc.upper[axis] == upp);
test_at_accessor(tree, nvxls);
+
+ CHK(stream = tmpfile());
+ CHK(svx_tree_write(NULL, stream) == RES_BAD_ARG);
+ CHK(svx_tree_write(tree, NULL) == RES_BAD_ARG);
+ CHK(svx_tree_write(tree, stream) == RES_OK);
+
+ CHK(svx_tree_ref_put(tree) == RES_OK);
+
+ rewind(stream);
+ CHK(svx_tree_create_from_stream(NULL, stream, &tree) == RES_BAD_ARG);
+ CHK(svx_tree_create_from_stream(dev, NULL, &tree) == RES_BAD_ARG);
+ CHK(svx_tree_create_from_stream(dev, stream, NULL) == RES_BAD_ARG);
+ CHK(svx_tree_create_from_stream(dev, stream, &tree) == RES_OK);
+ fclose(stream);
+
+ test_at_accessor(tree, nvxls);
CHK(svx_tree_ref_put(tree) == RES_OK);
build_ctx.max_depth = (size_t)log2i((int)round_up_pow2(nvxls));
diff --git a/src/test_svx_bintree_trace_ray.c b/src/test_svx_bintree_trace_ray.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -157,7 +158,7 @@ hit_filter3
}
static void
-draw_image(FILE* stream, struct svx_tree* btree)
+draw_image(struct image* img, struct svx_tree* btree)
{
struct camera cam;
unsigned char* pixels = NULL;
@@ -166,17 +167,15 @@ draw_image(FILE* stream, struct svx_tree* btree)
const double pos[3] = { 0, 0, 0};
const double tgt[3] = { 0, 0, 1};
const double up[3] = { 1, 0, 0};
- struct image img;
double pix[2];
size_t ix, iy;
- CHK(btree);
+ CHK(btree && img);
camera_init(&cam, pos, tgt, up, (double)width/(double)height);
- image_init(NULL, &img);
- CHK(image_setup(&img, width, height, sizeof_image_format(IMAGE_RGB8)*width,
+ CHK(image_setup(img, width, height, sizeof_image_format(IMAGE_RGB8)*width,
IMAGE_RGB8, NULL) == RES_OK);
- pixels = (unsigned char*)img.pixels;
+ pixels = (unsigned char*)img->pixels;
FOR_EACH(iy, 0, height) {
pix[1] = (double)iy / (double)height;
@@ -204,16 +203,16 @@ draw_image(FILE* stream, struct svx_tree* btree)
}
}
}
-
- CHK(image_write_ppm_stream(&img, 0, stream) == RES_OK);
- image_release(&img);
}
int
main(int argc, char** argv)
{
+ struct image img, img2;
+ FILE* stream = NULL;
struct svx_device* dev = NULL;
struct svx_tree* btree = NULL;
+ struct svx_tree* btree2 = NULL;
struct svx_voxel_desc voxel_desc = SVX_VOXEL_DESC_NULL;
struct svx_voxel voxel = SVX_VOXEL_NULL;
struct svx_hit hit;
@@ -243,11 +242,19 @@ main(int argc, char** argv)
CHK(svx_bintree_create(dev, lower, upper, definition, scn.axis,
&voxel_desc, &btree) == RES_OK);
+ /* Duplicate the binary tree through serialization */
+ CHK(stream = tmpfile());
+ CHK(svx_tree_write(btree, stream) == RES_OK);
+ CHK(svx_tree_create_from_stream(dev, stream, &btree2) == RES_BAD_ARG);
+ rewind(stream);
+ CHK(svx_tree_create_from_stream(dev, stream, &btree2) == RES_OK);
+ fclose(stream);
+
+ #define RT svx_tree_trace_ray
d3(r.org, -1.01, 0, 0);
d3(r.dir, -1, 0, 0);
d2(r.range, 0, DBL_MAX);
- #define RT svx_tree_trace_ray
CHK(RT(NULL, r.org, r.dir, r.range, NULL, NULL, NULL, &hit) == RES_BAD_ARG);
CHK(RT(btree, NULL, r.dir, r.range, NULL, NULL, NULL, &hit) == RES_BAD_ARG);
CHK(RT(btree, r.org, NULL, r.range, NULL, NULL, NULL, &hit) == RES_BAD_ARG);
@@ -441,9 +448,21 @@ main(int argc, char** argv)
CHK(SVX_HIT_NONE(&hit));
CHK(accum == 1);
- draw_image(stdout, btree);
+ image_init(NULL, &img);
+ image_init(NULL, &img2);
+ draw_image(&img, btree);
+ draw_image(&img2, btree2);
+
+ /* Check that using oct or oct2 produces effectively the same image */
+ check_img_eq(&img, &img2);
+
+ /* Write the drawn image on stdout */
+ CHK(image_write_ppm_stream(&img, 0/*binary*/, stdout) == RES_OK);
+ image_release(&img);
+ image_release(&img2);
CHK(svx_tree_ref_put(btree) == RES_OK);
+ CHK(svx_tree_ref_put(btree2) == RES_OK);
CHK(svx_device_ref_put(dev) == RES_OK);
CHK(mem_allocated_size() == 0);
return 0;
diff --git a/src/test_svx_device.c b/src/test_svx_device.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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_svx_octree.c b/src/test_svx_octree.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -395,6 +396,7 @@ main(int argc, char** argv)
size_t nvxls[3];
struct leaves_context ctx;
void* ptr = (void*)(intptr_t)0xDECAFBAD;
+ FILE* stream = NULL;
(void)argc, (void)argv;
CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK);
@@ -478,6 +480,21 @@ main(int argc, char** argv)
test_at_accessor(oct, nvxls);
+ CHK(stream = tmpfile());
+ CHK(svx_tree_write(NULL, stream) == RES_BAD_ARG);
+ CHK(svx_tree_write(oct, NULL) == RES_BAD_ARG);
+ CHK(svx_tree_write(oct, stream) == RES_OK);
+
+ CHK(svx_tree_ref_put(oct) == RES_OK);
+
+ rewind(stream);
+ CHK(svx_tree_create_from_stream(NULL, stream, &oct) == RES_BAD_ARG);
+ CHK(svx_tree_create_from_stream(dev, NULL, &oct) == RES_BAD_ARG);
+ CHK(svx_tree_create_from_stream(dev, stream, NULL) == RES_BAD_ARG);
+ CHK(svx_tree_create_from_stream(dev, stream, &oct) == RES_OK);
+ fclose(stream);
+
+ test_at_accessor(oct, nvxls);
CHK(svx_tree_ref_put(oct) == RES_OK);
nvxls[0] = nvxls[1] = nvxls[2] = 32;
diff --git a/src/test_svx_octree_trace_ray.c b/src/test_svx_octree_trace_ray.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -188,7 +189,7 @@ hit_challenge(const struct svx_hit* hit, void* context)
}
static void
-draw_image(FILE* stream, struct svx_tree* oct, const struct scene* scn)
+draw_image(struct image* img, struct svx_tree* oct, const struct scene* scn)
{
char buf[32];
struct time t0, t1;
@@ -199,17 +200,15 @@ draw_image(FILE* stream, struct svx_tree* oct, const struct scene* scn)
const double pos[3] = { 0,-1.5, 0};
const double tgt[3] = { 0, 0, 0};
const double up[3] = { 0, 0, 1};
- struct image img;
double pix[2];
size_t ix, iy;
- CHK(oct);
+ CHK(oct && img);
camera_init(&cam, pos, tgt, up, (double)width/(double)height);
- image_init(NULL, &img);
- CHK(image_setup(&img, width, height, sizeof_image_format(IMAGE_RGB8)*width,
+ CHK(image_setup(img, width, height, sizeof_image_format(IMAGE_RGB8)*width,
IMAGE_RGB8, NULL) == RES_OK);
- pixels = (unsigned char*)img.pixels;
+ pixels = (unsigned char*)img->pixels;
time_current(&t0);
FOR_EACH(iy, 0, height) {
@@ -245,9 +244,6 @@ draw_image(FILE* stream, struct svx_tree* oct, const struct scene* scn)
time_sub(&t0, time_current(&t1), &t0);
time_dump(&t0, TIME_ALL, NULL, buf, sizeof(buf));
fprintf(stderr, "Render time: %s\n", buf);
-
- CHK(image_write_ppm_stream(&img, 0, stream) == RES_OK);
- image_release(&img);
}
int
@@ -255,8 +251,11 @@ main(int argc, char** argv)
{
struct scene scn;
struct ray r;
+ struct image img, img2;
+ FILE* stream = NULL;
struct svx_device* dev = NULL;
struct svx_tree* oct = NULL;
+ struct svx_tree* oct2 = NULL;
struct svx_tree_desc tree_desc = SVX_TREE_DESC_NULL;
struct svx_voxel_desc voxel_desc = SVX_VOXEL_DESC_NULL;
struct svx_hit hit = SVX_HIT_NULL;
@@ -295,6 +294,14 @@ main(int argc, char** argv)
CHK(svx_octree_create(dev, lower, upper, def, &voxel_desc, &oct) == RES_OK);
+ /* Duplicate the octree through serialization */
+ CHK(stream = tmpfile());
+ CHK(svx_tree_write(oct, stream) == RES_OK);
+ CHK(svx_tree_create_from_stream(dev, stream, &oct2) == RES_BAD_ARG);
+ rewind(stream);
+ CHK(svx_tree_create_from_stream(dev, stream, &oct2) == RES_OK);
+ fclose(stream);
+
/*dump_data(stdout, oct, CHAR__, 1, write_scalars);*/
#define RT svx_tree_trace_ray
@@ -386,9 +393,21 @@ main(int argc, char** argv)
CHK(SVX_HIT_NONE(&hit));
CHK(accum != 0);
- draw_image(stdout, oct, &scn);
+ image_init(NULL, &img);
+ image_init(NULL, &img2);
+ draw_image(&img, oct, &scn);
+ draw_image(&img2, oct2, &scn);
+
+ /* Check that using oct or oct2 produces effectively the same image */
+ check_img_eq(&img, &img2);
+
+ /* Write the drawn image on stdout */
+ CHK(image_write_ppm_stream(&img, 0/*binary*/, stdout) == RES_OK);
+ image_release(&img);
+ image_release(&img2);
CHK(svx_tree_ref_put(oct) == RES_OK);
+ CHK(svx_tree_ref_put(oct2) == RES_OK);
CHK(svx_device_ref_put(dev) == RES_OK);
CHK(mem_allocated_size() == 0);
return 0;
diff --git a/src/test_svx_utils.h b/src/test_svx_utils.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2018 |Meso|Star>, Université Paul Sabatier
+/* Copyright (C) 2018, 2020 |Meso|Star> (contact@meso-star.com)
+ * Copyright (C) 2018 Université Paul Sabatier
*
* 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
@@ -18,6 +19,7 @@
#include <rsys/double2.h>
#include <rsys/double3.h>
+#include <rsys/image.h>
#include <rsys/mem_allocator.h>
#include <stdio.h>
@@ -176,6 +178,33 @@ dump_data
CHK(svx_tree_for_each_leaf(tree, write_leaf_data, stream) == RES_OK);
}
+static INLINE void
+check_img_eq(const struct image* img0, const struct image* img1)
+{
+ size_t ix, iy;
+ size_t pixsz;
+
+ CHK(img0 && img1);
+ CHK(img0->format == IMAGE_RGB8);
+ CHK(img1->format == IMAGE_RGB8);
+ CHK(img0->width == img1->width);
+ CHK(img0->height == img1->height);
+ CHK(img0->pitch == img1->pitch);
+
+ pixsz = sizeof_image_format(img0->format);
+
+ FOR_EACH(iy, 0, img0->height) {
+ const char* row0 = img0->pixels + iy * img0->pitch;
+ const char* row1 = img1->pixels + iy * img1->pitch;
+ FOR_EACH(ix, 0, img0->width) {
+ const uint8_t* pix0 = (const uint8_t*)(row0 + ix*pixsz);
+ const uint8_t* pix1 = (const uint8_t*)(row1 + ix*pixsz);
+ CHK(pix0[0] == pix1[0]);
+ CHK(pix0[1] == pix1[1]);
+ CHK(pix0[2] == pix1[2]);
+ }
+ }
+}
static INLINE void
check_memory_allocator(struct mem_allocator* allocator)