fogd-engine/src/core/transformable.h
2024-09-13 00:01:21 +02:00

97 lines
5 KiB
C

#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