commit c70b0d454c420a36a464955e7e4584c7829861e7
parent bf95aaacd786465fc67925271fd46d8c85a08276
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Tue, 11 Oct 2016 18:36:28 +0200
Add node_data type and API.
Nodes are now a public type with private data and are now uncounted.
They are typicaly included in a client type that do the refcounting.
Diffstat:
4 files changed, 260 insertions(+), 116 deletions(-)
diff --git a/src/sanim.h b/src/sanim.h
@@ -43,11 +43,15 @@
/* Forward declaration of external types */
struct logger;
struct mem_allocator;
-struct ssp_rng;
+struct sanim_node_data;
/* Opaque Solstice Anim types */
struct sanim_device;
-struct sanim_node;
+
+/* sanim_node type for building own node types */
+struct sanim_node {
+ struct sanim_node_data* data;
+};
BEGIN_DECLS
@@ -65,19 +69,23 @@ sanim_device_create
SANIM_API res_T
sanim_device_ref_get
-(struct sanim_device* dev);
+ (struct sanim_device* dev);
SANIM_API res_T
sanim_device_ref_put
-(struct sanim_device* dev);
+ (struct sanim_device* dev);
/*******************************************************************************
* Node API.
******************************************************************************/
SANIM_API res_T
-sanim_node_create
- (struct sanim_device* dev,
- struct sanim_node** node);
+sanim_node_initialize
+ (struct mem_allocator* allocator, /* May be NULL <=> use default allocator */
+ struct sanim_node* node);
+
+SANIM_API res_T
+sanim_node_release
+ (struct sanim_node* node);
SANIM_API res_T
sanim_node_add_child
@@ -85,12 +93,19 @@ sanim_node_add_child
struct sanim_node* child);
SANIM_API res_T
-sanim_node_ref_get
- (struct sanim_node* node);
+sanim_node_set_translation
+ (struct sanim_node* node,
+ const double translation[3]);
SANIM_API res_T
-sanim_node_ref_put
- (struct sanim_node* node);
+sanim_node_set_rotations
+ (struct sanim_node* node,
+ const double rotations[3]); /* XYZ convention */
+
+SANIM_API res_T
+sanim_node_get_world_transform
+ (struct sanim_node* node,
+ double transform[12]); /* 3x4 column major matrix */
END_DECLS
diff --git a/src/sanim_node.c b/src/sanim_node.c
@@ -19,122 +19,158 @@
#include <rsys/mem_allocator.h>
#include <rsys/ref_count.h>
+#include <rsys/double33.h>
+#include <rsys/double44.h>
/*******************************************************************************
* Helper functions
******************************************************************************/
-static void
-node_release(ref_T* ref)
-{
- struct sanim_device* dev;
- struct sanim_node* node = CONTAINER_OF(ref, struct sanim_node, ref);
- ASSERT(ref);
- dev = node->dev;
- ASSERT(dev && dev->allocator);
- darray_children_release(&node->children);
- /* FIXME: use refcount for father/children? */
- MEM_RM(dev->allocator, node);
- SANIM(device_ref_put(dev));
-}
-
static int
-is_ascendant(const struct sanim_node* node, const struct sanim_node* ascendant)
+is_ascendant
+ (const struct sanim_node_data* data, const struct sanim_node_data* asc_data)
{
- ASSERT(node && ascendant);
- while (node) {
- if (node == ascendant) return 1;
- node = node->father;
+ ASSERT(data && asc_data);
+ while (data) {
+ if (data == asc_data) return 1;
+ data = data->father;
}
return 0;
}
+static double*
+node_get_transform(struct sanim_node_data* data, double transform[16]) {
+ double tmp[12];
+ ASSERT(data && transform);
+ d33_rotation(tmp, SPLIT3(data->rotations));
+ d3_set(transform, tmp);
+ transform[3] = 0;
+ d3_set(transform + 4, tmp + 3);
+ transform[7] = 0;
+ d3_set(transform + 8, tmp + 6);
+ transform[11] = 0;
+ d3_set(transform + 12, data->translation);
+ transform[15] = 1;
+ return transform;
+}
+
+static void
+d33_setd44(double dst[12], double src[16]) {
+ d3_set(dst, src);
+ d3_set(dst + 3, src + 4);
+ d3_set(dst + 6, src + 8);
+ d3_set(dst + 9, src + 12);
+ ASSERT(!src[3] && !src[7] && !src[11] && src[15] == 1);
+}
+
/*******************************************************************************
* Exported ssol_spectrum functions
******************************************************************************/
res_T
-sanim_node_create
- (struct sanim_device* dev,
- struct sanim_node** out_node)
+sanim_node_add_child
+ (struct sanim_node* node,
+ struct sanim_node* child)
{
- struct sanim_node* node = NULL;
res_T res = RES_OK;
- if (!dev || !out_node) {
- res = RES_BAD_ARG;
- goto error;
- }
+ if (!node || !child) return RES_BAD_ARG;
+ if (child->data->father) return RES_BAD_ARG;
+ if (is_ascendant(node->data, child->data)) return RES_BAD_ARG;
- node = (struct sanim_node*)MEM_CALLOC
- (dev->allocator, 1, sizeof(struct sanim_node));
- if (!node) {
- res = RES_MEM_ERR;
+ child->data->father = node->data;
+ res = darray_children_push_back(&node->data->children, &child->data);
+ if (res != RES_OK) {
goto error;
}
- darray_children_init(dev->allocator, &node->children);
-
- SANIM(device_ref_get(dev));
- node->dev = dev;
- ref_init(&node->ref);
-
exit:
- if (out_node) *out_node = node;
return res;
error:
- if (node) {
- SANIM(node_ref_put(node));
- node = NULL;
+ if (child->data) {
+ child->data = NULL;
}
goto exit;
}
res_T
-sanim_node_add_child
- (struct sanim_node* node,
- struct sanim_node* child)
+sanim_node_initialize
+ (struct mem_allocator* allocator,
+ struct sanim_node* node)
{
+ struct mem_allocator* alloc;
res_T res = RES_OK;
- if (!node || !child) return RES_BAD_ARG;
- if (child->father) {
- log_warning
- (node->dev, "%s: the node has a father already.\n", FUNC_NAME);
- return RES_BAD_ARG;
- }
- if (is_ascendant(node, child)) {
- log_warning
- (node->dev, "%s: creating a cycle.\n", FUNC_NAME);
- return RES_BAD_ARG;
- }
+ if (!node) return RES_BAD_ARG;
+ alloc = allocator ? allocator : &mem_default_allocator;
- child->father = node;
- res = darray_children_push_back(&node->children, &child);
- if (res != RES_OK) {
+ node->data = MEM_CALLOC(alloc, 1, sizeof(struct sanim_node_data));
+ if (!node->data) {
+ res = RES_MEM_ERR;
goto error;
}
- /* FIXME: use refcount for father/children? */
+
+ darray_children_init(alloc, &node->data->children);
+ node->data->father = NULL;
+ node->data->allocator = alloc;
+ d3_splat(node->data->translation, 0);
+ d3_splat(node->data->rotations, 0);
exit:
return res;
error:
- child->father = NULL;
+ if (node->data) {
+ darray_children_release(&node->data->children);
+ node->data = NULL;
+ }
goto exit;
}
res_T
-sanim_node_ref_get
+sanim_node_release
(struct sanim_node* node)
{
if (!node) return RES_BAD_ARG;
- ref_get(&node->ref);
+ if (node->data) {
+ darray_children_release(&node->data->children);
+ MEM_RM(node->data->allocator, node->data);
+ }
return RES_OK;
}
res_T
-sanim_node_ref_put
- (struct sanim_node* node)
+sanim_node_set_translation
+ (struct sanim_node* node,
+ const double translation[3])
{
- if (!node) return RES_BAD_ARG;
- ref_put(&node->ref, node_release);
+ if (!node || !node->data || !translation) return RES_BAD_ARG;
+ d3_set(node->data->translation, translation);
+ return RES_OK;
+}
+
+res_T
+sanim_node_set_rotations
+ (struct sanim_node* node,
+ const double rotations[3])
+{
+ if (!node || !node->data || !rotations) return RES_BAD_ARG;
+ d3_set(node->data->rotations, rotations);
+ return RES_OK;
+}
+
+res_T
+sanim_node_get_world_transform
+ (struct sanim_node* node,
+ double transform[12])
+{
+ double world[16], tmp[16]; /* 4x4 column major matrix */
+ struct sanim_node_data* ptr;
+ if (!node || !node->data || !transform) return RES_BAD_ARG;
+ node_get_transform(node->data, world);
+ ptr = node->data->father;
+ while (ptr) {
+ node_get_transform(ptr, tmp);
+ d44_muld44(world, world, tmp);
+ ptr = ptr->father;
+ }
+ d33_setd44(transform, world);
return RES_OK;
}
diff --git a/src/sanim_node_c.h b/src/sanim_node_c.h
@@ -16,21 +16,23 @@
#ifndef SANIM_NODE_C_H
#define SANIM_NODE_C_H
-#include <rsys/ref_count.h>
-#include <rsys/ref_count.h>
+struct sanim_node_data;
+struct mem_allocator;
+
#include <rsys/dynamic_array.h>
/* Define the darray_children data structure */
#define DARRAY_NAME children
-#define DARRAY_DATA struct sanim_node*
+#define DARRAY_DATA struct sanim_node_data*
#include <rsys/dynamic_array.h>
-struct sanim_node {
- struct sanim_node* father; /* can be NULL: root node */
+struct sanim_node_data {
+ double translation[3];
+ double rotations[3];
+ struct sanim_node_data* father; /* can be NULL: root node */
struct darray_children children;
-
- struct sanim_device* dev;
- ref_T ref;
+ struct mem_allocator* allocator;
};
+
#endif /* SANIM_NODE_C_H */
diff --git a/src/test_sanim_node.c b/src/test_sanim_node.c
@@ -16,53 +16,144 @@
#include "sanim.h"
#include "test_sanim_utils.h"
-#include <rsys/logger.h>
+#include <rsys/double33.h>
+
+struct my_type {
+ struct sanim_node node;
+ double my_data;
+ /* may be some ref count mechanism */
+};
+
+static res_T
+my_type_init(struct mem_allocator *allocator, struct my_type* t) {
+ if (!t) return RES_BAD_ARG;
+ /* init my stuff */
+ t->my_data = 0;
+ /* init node stuff */
+ return sanim_node_initialize(allocator, &t->node);
+}
+
+static res_T
+my_type_release(struct my_type* t) {
+ if (!t) return RES_BAD_ARG;
+ /* release my stuff */
+ /* release node stuff */
+ return sanim_node_release(&t->node);
+}
+
+static res_T
+my_type_add_child(struct my_type* t, struct my_type* child) {
+ if (!t || !child) return RES_BAD_ARG;
+ /* release my stuff */
+ /* release node stuff */
+ return sanim_node_add_child(&t->node, &child->node);
+}
+
+static res_T
+my_type_set_translation(struct my_type* t, const double translation[3]) {
+ if (!t || !translation) return RES_BAD_ARG;
+ return sanim_node_set_translation(&t->node, translation);
+}
+
+static res_T
+my_type_set_rotations(struct my_type* t, const double rotations[3]) {
+ if (!t || !rotations) return RES_BAD_ARG;
+ return sanim_node_set_rotations(&t->node, rotations);
+}
+
+static res_T
+my_type_get_world_transform(struct my_type* t, double transform[12]) {
+ if (!t || !transform) return RES_BAD_ARG;
+ return sanim_node_get_world_transform(&t->node, transform);
+}
+
+static char
+d3_is_zero_eps(const double v[3], const double eps) {
+ int x;
+ ASSERT(eps >= 0);
+ FOR_EACH(x, 0, 3) {
+ if (fabs(v[x]) > eps) return 0;
+ }
+ return 1;
+}
+
+static char
+d3_is_zero(const double v[3]) {
+ int x;
+ FOR_EACH(x, 0, 3) {
+ if (v[x]) return 0;
+ }
+ return 1;
+}
+
+static char
+d33_is_identity_eps(const double v[9], const double eps) {
+ int i = 0, x, y;
+ ASSERT(eps >= 0);
+ FOR_EACH(x, 0, 3) {
+ FOR_EACH(y, 0, 3) {
+ if (fabs(v[i] - (x == y ? 1 : 0)) > eps) return 0;
+ ++i;
+ }
+ }
+ return 1;
+}
int
main(int argc, char** argv)
{
- struct logger logger;
struct mem_allocator allocator;
- struct sanim_device* dev;
- struct sanim_node* node1;
- struct sanim_node* node2;
+ struct my_type t1, t2;
+ double transl[3], rot[3], transform[12];
(void) argc, (void) argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ /* test a typical use in my_type */
+ CHECK(my_type_init(NULL, &t1), RES_OK);
+ CHECK(my_type_release(NULL), RES_BAD_ARG);
+ CHECK(my_type_release(&t1), RES_OK);
+ CHECK(my_type_init(&allocator, &t1), RES_OK);
+ CHECK(my_type_init(&allocator, NULL), RES_BAD_ARG);
+ CHECK(my_type_init(&allocator, &t2), RES_OK);
- CHECK(logger_init(&allocator, &logger), RES_OK);
- logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
- logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
- logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
+ CHECK(my_type_add_child(NULL, &t1), RES_BAD_ARG);
+ CHECK(my_type_add_child(&t1, NULL), RES_BAD_ARG);
+ CHECK(my_type_add_child(&t1, &t1), RES_BAD_ARG);
+ CHECK(my_type_add_child(&t1, &t2), RES_OK);
+ CHECK(my_type_add_child(&t1, &t2), RES_BAD_ARG);
+ CHECK(my_type_add_child(&t2, &t1), RES_BAD_ARG);
- CHECK(sanim_device_create
- (&logger, &allocator, SANIM_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+ d3_splat(transl, +1);
+ CHECK(my_type_set_translation(NULL, transl), RES_BAD_ARG);
+ CHECK(my_type_set_translation(&t1, NULL), RES_BAD_ARG);
+ CHECK(my_type_set_translation(&t1, transl), RES_OK);
- CHECK(sanim_node_create(NULL, &node1), RES_BAD_ARG);
- CHECK(sanim_node_create(dev, NULL), RES_BAD_ARG);
- CHECK(sanim_node_create(dev, &node1), RES_OK);
- CHECK(sanim_node_ref_get(NULL), RES_BAD_ARG);
- CHECK(sanim_node_ref_get(node1), RES_OK);
- CHECK(sanim_node_ref_put(NULL), RES_BAD_ARG);
- CHECK(sanim_node_ref_put(node1), RES_OK);
- CHECK(sanim_node_ref_put(node1), RES_OK);
+ d3_splat(transl, -1);
+ CHECK(my_type_set_translation(&t2, transl), RES_OK);
- CHECK(sanim_node_create(dev, &node1), RES_OK);
- CHECK(sanim_node_create(dev, &node2), RES_OK);
+ CHECK(my_type_get_world_transform(NULL, transform), RES_BAD_ARG);
+ CHECK(my_type_get_world_transform(&t2, NULL), RES_BAD_ARG);
+ CHECK(my_type_get_world_transform(&t2, transform), RES_OK);
+ CHECK(d33_is_identity(transform), 1);
+ CHECK(d3_is_zero(transform + 9), 1);
- CHECK(sanim_node_add_child(NULL, node1), RES_BAD_ARG);
- CHECK(sanim_node_add_child(node1, NULL), RES_BAD_ARG);
- CHECK(sanim_node_add_child(node1, node1), RES_BAD_ARG);
- CHECK(sanim_node_add_child(node1, node2), RES_OK);
- CHECK(sanim_node_add_child(node1, node2), RES_BAD_ARG);
- CHECK(sanim_node_add_child(node2, node1), RES_BAD_ARG);
+ d3(rot, PI, 0, 0);
+ CHECK(my_type_set_rotations(NULL, rot), RES_BAD_ARG);
+ CHECK(my_type_set_rotations(&t1, NULL), RES_BAD_ARG);
+ CHECK(my_type_set_rotations(&t1, rot), RES_OK);
+ CHECK(my_type_set_rotations(&t2, rot), RES_OK);
+ d3(transl, 0, +1, 0);
+ CHECK(my_type_set_translation(&t1, transl), RES_OK);
+ CHECK(my_type_set_translation(&t2, transl), RES_OK);
- CHECK(sanim_node_ref_put(node1), RES_OK);
- CHECK(sanim_node_ref_put(node2), RES_OK);
+ CHECK(my_type_get_world_transform(&t2, transform), RES_OK);
+ CHECK(d33_is_identity_eps(transform, 1e-10), 1);
+ CHECK(d3_is_zero_eps(transform + 9, 1e-10), 1);
- CHECK(sanim_device_ref_put(dev), RES_OK);
+ CHECK(my_type_release(&t1), RES_OK);
+ CHECK(my_type_release(&t2), RES_OK);
- logger_release(&logger);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
CHECK(mem_allocated_size(), 0);