#ifndef TRANSFORMABLE_H #define TRANSFORMABLE_H #include "scene.h" #include "utils/mirror.h" #include "utils/typeclass_helpers.h" #include "raylib.h" #include "raymath.h" struct Transformable; typedef struct ITransformable { SceneNode *node; Transform (*const get_transform)(void*); void (*const set_transform)(void*, Transform); Transform (*const get_global_transform)(void*); void (*const set_global_transform)(void*, Transform); void (*const force_update)(void*); unsigned char (*const get_dirty_bit)(void*); struct Transformable (*const get_parent_transformable)(void*); } ITransformable; typedef struct Transformable { ITransformable const *tc; void *data; IMirror const *mirror; ISceneNodeEntity const *scene_node_entity; } Transformable; extern Transform TransformIdentity(); extern Matrix TransformGetMatrix(Transform const *self); extern Vector3 TransformPosition(Transform const *self, Vector3 local_pos); extern Vector3 TransformDirection(Transform const *self, Vector3 local_direction); extern Vector3 TransformScale(Transform const *self, Vector3 local_scale); extern Quaternion TransformRotation(Transform const *self, Quaternion local_rotation); extern Transform TransformTransform(Transform const *self, Transform const *other); extern Vector3 InverseTransformPosition(Transform const *self, Vector3 global_pos); extern Vector3 InverseTransformDirection(Transform const *self, Vector3 global_direction); extern Vector3 InverseTransformScale(Transform const *self, Vector3 global_scale); extern Quaternion InverseTransformRotation(Transform const *self, Quaternion quat); extern Transform InverseTransformTransform(Transform const *self, Transform const *other); #define MATRIX_UP(self_) ((Vector3){self_.m0, self_.m1, self_.m2}) #define MATRIX_RIGHT(self_) ((Vector3){self_.m4, self_.m5, self_.m6}) #define MATRIX_FORWARD(self_) ((Vector3){self_.m8, self_.m9, self_.m10}) #define VECTOR3_RIGHT ((Vector3){1.f, 0.f, 0.f}) #define VECTOR3_UP ((Vector3){0.f, 1.f, 0.f}) #define VECTOR3_FORWARD ((Vector3){0.f, 0.f, 1.f}) //! Defines the variables required to implement Transformable. Put at the start of a struct #define ExtendsTransformable Transform transform; Transform global_transform; Transformable parent_transformable; unsigned char dirty_bit //! Define transformable getter-setters for type T //! Requires member variables: Transform transform; Transform global_transform; Transformable parent_transformable; unsigned char dirty_bit; //! 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 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 */\ }\ }\ static void T##_force_update_GEN_(T *self) {\ if(tc_is_null(self->parent_transformable)) {\ self->global_transform = self->transform;\ return;\ }\ 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 Transformable T##_get_parent_transformable_GEN_(T *self) { return self->parent_transformable; }\ Transformable T##_as_Transformable(T *x) {\ static ITransformable const tc = {\ .get_transform = (Transform (*const)(void*)) T##_get_transform_GEN_,\ .set_transform = (void (*const)(void*,Transform)) T##_set_transform_GEN_,\ .get_global_transform = (Transform (*const)(void*)) T##_get_global_transform_GEN_,\ .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_,\ .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 };\ } #endif // !TRANSFORMABLE_H