fix: transform updating is now _actually_ recursive through the whole tree

This commit is contained in:
Sara 2024-09-13 11:28:02 +02:00
parent c7265739cc
commit 09e52d007a
2 changed files with 31 additions and 25 deletions

View file

@ -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);
} }

View file

@ -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) {\