From 09e52d007a95c572b90d76e5d489aff8c0f0594a Mon Sep 17 00:00:00 2001 From: Sara Date: Fri, 13 Sep 2024 11:28:02 +0200 Subject: [PATCH] fix: transform updating is now _actually_ recursive through the whole tree --- src/core/scene.c | 51 +++++++++++++++++++++++----------------- src/core/transformable.h | 5 ++-- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/core/scene.c b/src/core/scene.c index d53d542..c29477a 100644 --- a/src/core/scene.c +++ b/src/core/scene.c @@ -5,6 +5,29 @@ #include "utils/drop.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. static void Internal_SceneRemoveNode(Scene *self, SceneNode *node) { @@ -44,34 +67,18 @@ void Internal_SceneAddNode(Scene *self, SceneNode *node) { list_add(&self->nodes, &node); // establish two-way relationship Internal_SceneNodeSetScene(node, self); + Internal_SceneNodeUpdateTransform(node); // do the same for all children (and their children) recursively list_foreach(SceneNode **,child, &node->children) 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 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); - } - } +void Internal_SceneNodeUpdateTransformRecursive(SceneNode *self) { + Internal_SceneNodeUpdateTransform(self); list_foreach(SceneNode **,child, &self->children) - Internal_SceneNodeUpdateTransform(*child); + Internal_SceneNodeUpdateTransformRecursive(*child); } SceneNode *CreateSceneNode(SceneNodeEntity entity) { @@ -159,12 +166,12 @@ Scene *CreateScene(SceneNode *root) { } void DestroyScene(Scene *self) { - DestroySceneNode(self->root); + DestroySceneNode(self->root); // recurses to the rest of the scene list_empty(&self->nodes); free(self); } void SceneTick(Scene* self, double delta_time) { Internal_SceneNodeTick(self->root, delta_time); - Internal_SceneNodeUpdateTransform(self->root); + Internal_SceneNodeUpdateTransformRecursive(self->root); } diff --git a/src/core/transformable.h b/src/core/transformable.h index 294d98d..097eece 100644 --- a/src/core/transformable.h +++ b/src/core/transformable.h @@ -58,16 +58,15 @@ extern Transform InverseTransformTransform(Transform const *self, Transform cons //! Macro implements the interface functions itself to ensure consistent behaviour. #define impl_Transformable_for(T)\ 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 void T##_set_global_transform_GEN_(T* self, Transform value) {\ self->global_transform = value;\ if(tc_is_null(self->parent_transformable)) {\ self->transform = value;\ } 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);\ - 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) {\