fogd-engine/src/camera_controller.c

60 lines
2.1 KiB
C

#include "camera_controller.h"
#include "utils/mirror.h"
START_REFLECT(CameraController);
REFLECT_TYPECLASS(CameraController, SceneNodeEntity);
END_REFLECT(CameraController);
impl_Drop_for(CameraController,
DestroyCameraController
)
impl_SceneNodeEntity_for(CameraController,
CameraControllerEnterTree,
CameraControllerExitTree,
CameraControllerTick
)
SceneNode *CreateCameraController(Transformable target) {
CameraController *self = new(CameraController);
*self = (CameraController){
.transform = tc_null(Transformable),
.rotation_speed = 5.f,
.max_speed_time = 4.f,
.target = target,
.time_rotated = 0.f
};
SceneNode *node = CreateSceneNode(CameraController_as_SceneNodeEntity(self));
return node;
}
void DestroyCameraController(CameraController *self) {
free(self);
}
void CameraControllerEnterTree(CameraController *self) {
self->transform = TC_CAST(self->node->parent->entity, Transformable);
self->global = self->transform.tc->get_global_transform(self->transform.data);
}
void CameraControllerExitTree(CameraController *self) {}
void CameraControllerTick(CameraController *self, double delta) {
Transform current = self->transform.tc->get_global_transform(self->transform.data);
self->target.tc->force_update(self->target.data);
Transform target = self->target.tc->get_global_transform(self->target.data);
// calculate time multiplier...
float const time_mul = fminf(1.f, fmaxf(0.1f, powf(self->time_rotated / self->max_speed_time, 0.5f)));
// ... angle difference ...
float const angle = QuaternionAngleDifference(current.rotation, target.rotation);
// ... and maximum frame step size
float const step = self->rotation_speed * time_mul * delta;
if(angle > 0.f)
target.rotation = QuaternionSlerp(current.rotation, target.rotation, fminf(fminf(step, angle) / angle, 0.99f));
if(step > angle && self->time_rotated > delta)
self->time_rotated -= 3.f * delta;
else if(step > angle)
self->time_rotated = 0.f;
self->time_rotated += delta;
self->transform.tc->set_global_transform(self->transform.data, target);
}