182 lines
5.4 KiB
C++
182 lines
5.4 KiB
C++
#include "InteractiveObjectState.h"
|
|
#include <algorithm>
|
|
#include <utility>
|
|
|
|
namespace FRG {
|
|
|
|
void InteractiveObjectState::moveTo(
|
|
const Eigen::Vector3f& target, float durationSec, std::string onCompleteName)
|
|
{
|
|
if (isAnimating) return;
|
|
AnimTask task;
|
|
task.type = AnimTask::Type::Move;
|
|
task.startPos = position;
|
|
task.startRotY = rotationY;
|
|
task.startScale = scale;
|
|
task.targetPos = target;
|
|
task.targetRotY = rotationY;
|
|
task.targetScale = scale;
|
|
task.durationMs = durationSec * 1000.f;
|
|
task.onCompleteName = std::move(onCompleteName);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObjectState::rotateTo(
|
|
float targetRotY, float durationSec, std::string onCompleteName)
|
|
{
|
|
if (isAnimating) return;
|
|
AnimTask task;
|
|
task.type = AnimTask::Type::Rotate;
|
|
task.startPos = position;
|
|
task.startRotY = rotationY;
|
|
task.startScale = scale;
|
|
task.targetPos = position;
|
|
task.targetRotY = targetRotY;
|
|
task.targetScale = scale;
|
|
task.durationMs = durationSec * 1000.f;
|
|
task.onCompleteName = std::move(onCompleteName);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObjectState::scaleTo(
|
|
float targetScale, float durationSec, std::string onCompleteName)
|
|
{
|
|
if (isAnimating) return;
|
|
AnimTask task;
|
|
task.type = AnimTask::Type::Scale;
|
|
task.startPos = position;
|
|
task.startRotY = rotationY;
|
|
task.startScale = scale;
|
|
task.targetPos = position;
|
|
task.targetRotY = rotationY;
|
|
task.targetScale = targetScale;
|
|
task.durationMs = durationSec * 1000.f;
|
|
task.onCompleteName = std::move(onCompleteName);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObjectState::fadeTo(
|
|
float targetAlpha, float durationSec, std::string onCompleteName)
|
|
{
|
|
if (isAnimating) return;
|
|
AnimTask task;
|
|
task.type = AnimTask::Type::Fade;
|
|
task.startPos = position;
|
|
task.startRotY = rotationY;
|
|
task.startScale = alpha;
|
|
task.targetPos = position;
|
|
task.targetRotY = rotationY;
|
|
task.targetScale = targetAlpha;
|
|
task.durationMs = durationSec * 1000.f;
|
|
task.onCompleteName = std::move(onCompleteName);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
InteractiveObjectUpdateEvents InteractiveObjectState::update(std::int64_t deltaMs)
|
|
{
|
|
InteractiveObjectUpdateEvents events;
|
|
if (!isAnimating || !animTask) return events;
|
|
|
|
AnimTask& task = *animTask;
|
|
task.elapsedMs += static_cast<float>(deltaMs);
|
|
const float duration = (std::max)(task.durationMs, 0.001f);
|
|
const float t = (std::min)(task.elapsedMs / duration, 1.0f);
|
|
|
|
switch (task.type) {
|
|
case AnimTask::Type::Move:
|
|
position = task.startPos + (task.targetPos - task.startPos) * t;
|
|
break;
|
|
case AnimTask::Type::Rotate:
|
|
rotationY = task.startRotY + (task.targetRotY - task.startRotY) * t;
|
|
break;
|
|
case AnimTask::Type::Scale:
|
|
scale = task.startScale + (task.targetScale - task.startScale) * t;
|
|
break;
|
|
case AnimTask::Type::Fade:
|
|
alpha = task.startScale + (task.targetScale - task.startScale) * t;
|
|
break;
|
|
}
|
|
|
|
if (t < 1.0f) return events;
|
|
position = task.targetPos;
|
|
rotationY = task.targetRotY;
|
|
if (task.type == AnimTask::Type::Fade)
|
|
alpha = task.targetScale;
|
|
else
|
|
scale = task.targetScale;
|
|
events.onCompleteName = std::move(task.onCompleteName);
|
|
animTask.reset();
|
|
isAnimating = false;
|
|
return events;
|
|
}
|
|
|
|
void InteractiveObjectState::save(nlohmann::json& out) const
|
|
{
|
|
out["positionX"] = position.x();
|
|
out["positionY"] = position.y();
|
|
out["positionZ"] = position.z();
|
|
out["rotationY"] = rotationY;
|
|
out["scale"] = scale;
|
|
out["alpha"] = alpha;
|
|
out["isActive"] = isActive;
|
|
out["isAnimating"] = isAnimating;
|
|
|
|
if (isAnimating && animTask) {
|
|
out["animTask"] = {
|
|
{"type", static_cast<int>(animTask->type)},
|
|
{"startPosX", animTask->startPos.x()},
|
|
{"startPosY", animTask->startPos.y()},
|
|
{"startPosZ", animTask->startPos.z()},
|
|
{"startRotY", animTask->startRotY},
|
|
{"startScale", animTask->startScale},
|
|
{"targetPosX", animTask->targetPos.x()},
|
|
{"targetPosY", animTask->targetPos.y()},
|
|
{"targetPosZ", animTask->targetPos.z()},
|
|
{"targetRotY", animTask->targetRotY},
|
|
{"targetScale", animTask->targetScale},
|
|
{"durationMs", animTask->durationMs},
|
|
{"elapsedMs", animTask->elapsedMs},
|
|
{"onCompleteName", animTask->onCompleteName}};
|
|
}
|
|
}
|
|
|
|
void InteractiveObjectState::load(const nlohmann::json& in)
|
|
{
|
|
position.x() = in.value("positionX", position.x());
|
|
position.y() = in.value("positionY", position.y());
|
|
position.z() = in.value("positionZ", position.z());
|
|
rotationY = in.value("rotationY", rotationY);
|
|
scale = in.value("scale", scale);
|
|
alpha = in.value("alpha", alpha);
|
|
isActive = in.value("isActive", isActive);
|
|
isAnimating = in.value("isAnimating", false);
|
|
animTask.reset();
|
|
|
|
if (!isAnimating || !in.contains("animTask") ||
|
|
!in["animTask"].is_object()) {
|
|
return;
|
|
}
|
|
const auto& value = in["animTask"];
|
|
AnimTask task;
|
|
task.type = static_cast<AnimTask::Type>(value.value("type", 0));
|
|
task.startPos = {value.value("startPosX", 0.f),
|
|
value.value("startPosY", 0.f), value.value("startPosZ", 0.f)};
|
|
task.startRotY = value.value("startRotY", 0.f);
|
|
task.startScale = value.value("startScale", 1.f);
|
|
task.targetPos = {value.value("targetPosX", 0.f),
|
|
value.value("targetPosY", 0.f), value.value("targetPosZ", 0.f)};
|
|
task.targetRotY = value.value("targetRotY", 0.f);
|
|
task.targetScale = value.value("targetScale", 1.f);
|
|
task.durationMs = value.value("durationMs", 1000.f);
|
|
task.elapsedMs = value.value("elapsedMs", 0.f);
|
|
task.onCompleteName =
|
|
value.value("onCompleteName", std::string());
|
|
animTask = std::move(task);
|
|
}
|
|
|
|
} // namespace FRG
|