fix: transform updating is now _actually_ recursive through the whole tree
This commit is contained in:
parent
c7265739cc
commit
09e52d007a
|
@ -5,6 +5,29 @@
|
||||||
#include "utils/drop.h"
|
#include "utils/drop.h"
|
||||||
#include "utils/mirror.h"
|
#include "utils/mirror.h"
|
||||||
|
|
||||||
|
//! Tick a node and all children recursively
|
||||||
|
static
|
||||||
|
void Internal_SceneNodeTick(SceneNode *self, double delta) {
|
||||||
|
// tick self first
|
||||||
|
self->entity.tc->tick(self->entity.data, delta);
|
||||||
|
// fix the number of elements to update now,
|
||||||
|
// so that if/when new children are added, they don't get ticked until next frame
|
||||||
|
size_t const len = self->children.len;
|
||||||
|
for(size_t i = 0; i < len; ++i)
|
||||||
|
Internal_SceneNodeTick(*list_at_as(SceneNode*, &self->children, i), delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Update global transform of a node
|
||||||
|
static
|
||||||
|
void Internal_SceneNodeUpdateTransform(SceneNode *self) {
|
||||||
|
if(TC_MIRRORS(self->entity, Transformable)) {
|
||||||
|
Transformable transformable = TC_CAST(self->entity, Transformable);
|
||||||
|
if(transformable.tc->get_dirty_bit(transformable.data)) {
|
||||||
|
transformable.tc->force_update(transformable.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//! Remove a single node (does NOT recurse to children children) from this scene.
|
//! Remove a single node (does NOT recurse to children children) from this scene.
|
||||||
static
|
static
|
||||||
void Internal_SceneRemoveNode(Scene *self, SceneNode *node) {
|
void Internal_SceneRemoveNode(Scene *self, SceneNode *node) {
|
||||||
|
@ -44,34 +67,18 @@ void Internal_SceneAddNode(Scene *self, SceneNode *node) {
|
||||||
list_add(&self->nodes, &node);
|
list_add(&self->nodes, &node);
|
||||||
// establish two-way relationship
|
// establish two-way relationship
|
||||||
Internal_SceneNodeSetScene(node, self);
|
Internal_SceneNodeSetScene(node, self);
|
||||||
|
Internal_SceneNodeUpdateTransform(node);
|
||||||
// do the same for all children (and their children) recursively
|
// do the same for all children (and their children) recursively
|
||||||
list_foreach(SceneNode **,child, &node->children)
|
list_foreach(SceneNode **,child, &node->children)
|
||||||
Internal_SceneAddNode(self, *child);
|
Internal_SceneAddNode(self, *child);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tick a node and all children recursively
|
|
||||||
static
|
|
||||||
void Internal_SceneNodeTick(SceneNode *self, double delta) {
|
|
||||||
// tick self first
|
|
||||||
self->entity.tc->tick(self->entity.data, delta);
|
|
||||||
// fix the number of elements to update now,
|
|
||||||
// so that if/when new children are added, they don't get ticked until next frame
|
|
||||||
size_t const len = self->children.len;
|
|
||||||
for(size_t i = 0; i < len; ++i)
|
|
||||||
Internal_SceneNodeTick(*list_at_as(SceneNode*, &self->children, i), delta);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Update global transforms of all children recursively
|
//! Update global transforms of all children recursively
|
||||||
static
|
static
|
||||||
void Internal_SceneNodeUpdateTransform(SceneNode *self) {
|
void Internal_SceneNodeUpdateTransformRecursive(SceneNode *self) {
|
||||||
if(TC_MIRRORS(self->entity, Transformable)) {
|
Internal_SceneNodeUpdateTransform(self);
|
||||||
Transformable transformable = TC_CAST(self->entity, Transformable);
|
|
||||||
if(transformable.tc->get_dirty_bit(transformable.data)) {
|
|
||||||
transformable.tc->force_update(transformable.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_foreach(SceneNode **,child, &self->children)
|
list_foreach(SceneNode **,child, &self->children)
|
||||||
Internal_SceneNodeUpdateTransform(*child);
|
Internal_SceneNodeUpdateTransformRecursive(*child);
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneNode *CreateSceneNode(SceneNodeEntity entity) {
|
SceneNode *CreateSceneNode(SceneNodeEntity entity) {
|
||||||
|
@ -159,12 +166,12 @@ Scene *CreateScene(SceneNode *root) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyScene(Scene *self) {
|
void DestroyScene(Scene *self) {
|
||||||
DestroySceneNode(self->root);
|
DestroySceneNode(self->root); // recurses to the rest of the scene
|
||||||
list_empty(&self->nodes);
|
list_empty(&self->nodes);
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneTick(Scene* self, double delta_time) {
|
void SceneTick(Scene* self, double delta_time) {
|
||||||
Internal_SceneNodeTick(self->root, delta_time);
|
Internal_SceneNodeTick(self->root, delta_time);
|
||||||
Internal_SceneNodeUpdateTransform(self->root);
|
Internal_SceneNodeUpdateTransformRecursive(self->root);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,16 +58,15 @@ extern Transform InverseTransformTransform(Transform const *self, Transform cons
|
||||||
//! Macro implements the interface functions itself to ensure consistent behaviour.
|
//! Macro implements the interface functions itself to ensure consistent behaviour.
|
||||||
#define impl_Transformable_for(T)\
|
#define impl_Transformable_for(T)\
|
||||||
static Transform T##_get_transform_GEN_(T* self) { return self->transform; }\
|
static Transform T##_get_transform_GEN_(T* self) { return self->transform; }\
|
||||||
static void T##_set_transform_GEN_(T* self, Transform value) { self->transform = value; self->dirty_bit |= 0x1; } /*!< sets local dirty bit */\
|
static void T##_set_transform_GEN_(T* self, Transform value) { self->transform = value; self->dirty_bit |= 1u; } /*!< sets dirty bit */\
|
||||||
static Transform T##_get_global_transform_GEN_(T* self) { return self->global_transform; }\
|
static Transform T##_get_global_transform_GEN_(T* self) { return self->global_transform; }\
|
||||||
static void T##_set_global_transform_GEN_(T* self, Transform value) {\
|
static void T##_set_global_transform_GEN_(T* self, Transform value) {\
|
||||||
self->global_transform = value;\
|
self->global_transform = value;\
|
||||||
if(tc_is_null(self->parent_transformable)) {\
|
if(tc_is_null(self->parent_transformable)) {\
|
||||||
self->transform = value;\
|
self->transform = value;\
|
||||||
} else {\
|
} else {\
|
||||||
self->parent_transformable.tc->force_update(self->parent_transformable.data); /* Force a transform update for the parent, to ensure its global transform is up-to-date */\
|
|
||||||
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\
|
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\
|
||||||
self->transform = InverseTransformTransform(&parent_global, &value); /* Use up-to-date parent transform to get the local transform to the new global transform */\
|
self->transform = InverseTransformTransform(&parent_global, &value); /* Use parent transform to transform the local transform to the new global transform */\
|
||||||
}\
|
}\
|
||||||
}\
|
}\
|
||||||
static void T##_force_update_GEN_(T *self) {\
|
static void T##_force_update_GEN_(T *self) {\
|
||||||
|
|
Loading…
Reference in a new issue