solstice-anim

Geometry animation library of the solstice app
git clone git://git.meso-star.com/solstice-anim.git
Log | Files | Refs | README | LICENSE

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:
Msrc/sanim.h | 37++++++++++++++++++++++++++-----------
Msrc/sanim_node.c | 168++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Msrc/sanim_node_c.h | 18++++++++++--------
Msrc/test_sanim_node.c | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
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);