diff --git a/src/core/camera_node.c b/src/core/camera_node.c index 1b6fa9b..6d21434 100644 --- a/src/core/camera_node.c +++ b/src/core/camera_node.c @@ -54,7 +54,7 @@ Camera3D CameraNodeGetCamera(CameraNode *self) { .fovy = 90, .position = global_transform.translation, .projection = CAMERA_PERSPECTIVE, - .target = Vector3Add(global_transform.translation, Vector3Scale(forward, 1000.f)), - .up = (Vector3){mat.m4, mat.m5, mat.m6} + .target = Vector3Add(global_transform.translation, forward), + .up = MATRIX_UP(mat) }; } diff --git a/src/core/scene.c b/src/core/scene.c index c29477a..50b9b4d 100644 --- a/src/core/scene.c +++ b/src/core/scene.c @@ -28,6 +28,23 @@ void Internal_SceneNodeUpdateTransform(SceneNode *self) { } } +//! Update global transforms of all children recursively +static +void Internal_SceneNodeUpdateTransformRecursive(SceneNode *self, bool is_dirty) { + if(TC_MIRRORS(self->entity, Transformable)) { + Transformable transformable = TC_CAST(self->entity, Transformable); + is_dirty = is_dirty || transformable.tc->get_dirty_bit(transformable.data); + if(is_dirty) { + transformable.tc->force_update(transformable.data); + transformable.tc->clear_dirty_bit(transformable.data); + } + } else { + is_dirty = false; + } + list_foreach(SceneNode **,child, &self->children) + Internal_SceneNodeUpdateTransformRecursive(*child, is_dirty); +} + //! Remove a single node (does NOT recurse to children children) from this scene. static void Internal_SceneRemoveNode(Scene *self, SceneNode *node) { @@ -73,14 +90,6 @@ void Internal_SceneAddNode(Scene *self, SceneNode *node) { Internal_SceneAddNode(self, *child); } -//! Update global transforms of all children recursively -static -void Internal_SceneNodeUpdateTransformRecursive(SceneNode *self) { - Internal_SceneNodeUpdateTransform(self); - list_foreach(SceneNode **,child, &self->children) - Internal_SceneNodeUpdateTransformRecursive(*child); -} - SceneNode *CreateSceneNode(SceneNodeEntity entity) { // initialize memory SceneNode *self = new(SceneNode); @@ -173,5 +182,5 @@ void DestroyScene(Scene *self) { void SceneTick(Scene* self, double delta_time) { Internal_SceneNodeTick(self->root, delta_time); - Internal_SceneNodeUpdateTransformRecursive(self->root); + Internal_SceneNodeUpdateTransformRecursive(self->root, false); } diff --git a/src/core/transform_node.c b/src/core/transform_node.c index f060287..62e3e69 100644 --- a/src/core/transform_node.c +++ b/src/core/transform_node.c @@ -20,7 +20,7 @@ impl_SceneNodeEntity_for(TransformNode, SceneNode *CreateTransformNode() { TransformNode *self = new(TransformNode); - self->dirty_bit = 0x0; + self->dirty_bit = 1; self->node = NULL; self->parent_transformable = tc_null(Transformable); self->global_transform = TransformIdentity(); diff --git a/src/core/transformable.c b/src/core/transformable.c index e548780..1de61b2 100644 --- a/src/core/transformable.c +++ b/src/core/transformable.c @@ -25,7 +25,7 @@ Vector3 TransformDirection(Transform self, Vector3 local_direction) { } Vector3 TransformScale(Transform self, Vector3 local_scale) { - return Vector3Multiply(self.scale, TransformDirection(self, local_scale)); + return Vector3Multiply(local_scale, self.scale); } Quaternion TransformRotation(Transform self, Quaternion local_rotation) { @@ -54,11 +54,11 @@ Vector3 InverseTransformDirection(Transform self, Vector3 global_direction) { } Vector3 InverseTransformScale(Transform self, Vector3 global_scale) { - return Vector3Multiply(Vector3Invert(self.scale), InverseTransformDirection(self, global_scale)); + return Vector3Multiply(global_scale, Vector3Invert(self.scale)); } Quaternion InverseTransformRotation(Transform self, Quaternion global_rotation) { - return QuaternionDivide(self.rotation, global_rotation); + return QuaternionMultiply(QuaternionInvert(self.rotation), global_rotation); } Transform InverseTransformTransform(Transform self, Transform other) { diff --git a/src/core/transformable.h b/src/core/transformable.h index bab525e..c80884c 100644 --- a/src/core/transformable.h +++ b/src/core/transformable.h @@ -17,6 +17,7 @@ typedef struct ITransformable { void (*const set_global_transform)(void*, Transform); void (*const force_update)(void*); unsigned char (*const get_dirty_bit)(void*); + void (*const clear_dirty_bit)(void*); struct Transformable (*const get_parent_transformable)(void*); } ITransformable; @@ -58,26 +59,29 @@ extern Transform InverseTransformTransform(Transform self, Transform other); //! 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 |= 1u; } /*!< sets dirty bit */\ +static void T##_set_transform_GEN_(T* self, Transform value) { self->transform = value; self->dirty_bit = 1; } /*!< 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 {\ + if(self->parent_transformable.tc->get_dirty_bit(self->parent_transformable.data))\ + self->parent_transformable.tc->force_update(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 parent transform to transform the local transform to the new global transform */\ + self->dirty_bit = 1;\ }\ }\ static void T##_force_update_GEN_(T *self) {\ if(tc_is_null(self->parent_transformable)) {\ self->global_transform = self->transform;\ - return;\ + } else {\ + Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ + self->global_transform = TransformTransform(parent_global, self->transform);\ }\ - Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ - self->global_transform = TransformTransform(parent_global, self->transform);\ }\ static unsigned char T##_get_dirty_bit_GEN_(T *self) { return self->dirty_bit; }\ +static void T##_clear_dirty_bit_GEN_(T *self) { self->dirty_bit = 0; }\ static Transformable T##_get_parent_transformable_GEN_(T *self) { return self->parent_transformable; }\ Transformable T##_as_Transformable(T *x) {\ static ITransformable const tc = {\ @@ -87,6 +91,7 @@ Transformable T##_as_Transformable(T *x) {\ .set_global_transform = (void (*const)(void*,Transform)) T##_set_global_transform_GEN_,\ .force_update = (void (*const)(void*)) T##_force_update_GEN_,\ .get_dirty_bit = (unsigned char (*const)(void*)) T##_get_dirty_bit_GEN_,\ + .clear_dirty_bit = (void (*const)(void*)) T##_clear_dirty_bit_GEN_,\ .get_parent_transformable = (Transformable (*const)(void*)) T##_get_parent_transformable_GEN_\ };\ return (Transformable){ .tc = &tc, .data = x, .scene_node_entity = T##_as_SceneNodeEntity(x).tc, .mirror = T##_as_Mirror(x).tc };\ diff --git a/src/main.c b/src/main.c index 481ebac..fabcbeb 100644 --- a/src/main.c +++ b/src/main.c @@ -10,17 +10,19 @@ Scene *CreateInitialScene() { SceneNode *root = CreateTransformNode(); + SceneNode *model_parent = CreateTransformNode(); + SceneNodeAddChild(root, model_parent); + SceneNode *camera_parent = CreateTransformNode(); + SceneNodeAddChild(model_parent, camera_parent); // set camera parent location Transformable transformable = TC_CAST(camera_parent->entity, Transformable); Transform transform = transformable.tc->get_transform(transformable.data); transform.translation = (Vector3){0.f, 10.f, -10.f}; transform.rotation = QuaternionFromEuler(45.f * DEG2RAD, 0.f, 0.f); transformable.tc->set_transform(transformable.data, transform); + SceneNodeAddChild(camera_parent, CreateCameraNode()); - SceneNode *model_parent = CreateTransformNode(); - SceneNodeAddChild(root, model_parent); - SceneNodeAddChild(model_parent, camera_parent); SceneNodeAddChild(model_parent, CreateMeshRenderEntity("spacefighter.glb")); SceneNodeAddChild(model_parent, CreateTestObject()); return CreateScene(root);