#include "InteractiveObjectState.h" #include #include 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(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(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(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