Separating state out of the location

This commit is contained in:
Vladislav Khorev committed 2026-10-30 14:56:24 +06:00
1 parent 5e9a663812
commit 297bd7377f
45 files changed
+2114 -778

No files matched your search

+2 -180
View File
@@ -51,7 +51,8 @@ namespace FRG {
obj.loadedObject.mesh.RefreshVBO();
// Center mesh at origin; adjust world position by the centering offset.
// Interactive-object definitions store the centered world position.
// Center the presentation mesh at the origin without changing state.
if (!obj.loadedObject.mesh.data.PositionData.empty()) {
Eigen::Vector3f meshMin = obj.loadedObject.mesh.data.PositionData[0];
Eigen::Vector3f meshMax = obj.loadedObject.mesh.data.PositionData[0];
@@ -62,129 +63,11 @@ namespace FRG {
const Eigen::Vector3f meshCenter = (meshMin + meshMax) * 0.5f;
obj.loadedObject.mesh.data.Move(-meshCenter);
obj.loadedObject.mesh.RefreshVBO();
obj.state.position = Eigen::Vector3f(obj.state.jsonPositionX,
obj.state.jsonPositionY,
obj.state.jsonPositionZ) + meshCenter;
} else {
obj.state.position = Eigen::Vector3f(obj.state.jsonPositionX,
obj.state.jsonPositionY,
obj.state.jsonPositionZ);
}
return obj;
}
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.elapsedMs = 0.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.elapsedMs = 0.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.elapsedMs = 0.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; // reuse startScale to hold start alpha
task.targetPos = position;
task.targetRotY = rotationY;
task.targetScale = targetAlpha; // reuse targetScale to hold target alpha
task.durationMs = durationSec * 1000.f;
task.elapsedMs = 0.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 t = (std::min)(task.elapsedMs / task.durationMs, 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) {
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 InteractiveObject::drawDarklands(Renderer& renderer) const {
if (!state.isActive || !loadedObject.textureDarklands) return;
@@ -237,65 +120,4 @@ namespace FRG {
renderer.RenderUniform1f("uAlpha", 1.0f);
}
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.has_value()) {
nlohmann::json at;
at["type"] = static_cast<int>(animTask->type);
at["startPosX"] = animTask->startPos.x();
at["startPosY"] = animTask->startPos.y();
at["startPosZ"] = animTask->startPos.z();
at["startRotY"] = animTask->startRotY;
at["startScale"] = animTask->startScale;
at["targetPosX"] = animTask->targetPos.x();
at["targetPosY"] = animTask->targetPos.y();
at["targetPosZ"] = animTask->targetPos.z();
at["targetRotY"] = animTask->targetRotY;
at["targetScale"] = animTask->targetScale;
at["durationMs"] = animTask->durationMs;
at["elapsedMs"] = animTask->elapsedMs;
if (!animTask->onCompleteName.empty())
at["onCompleteName"] = animTask->onCompleteName;
out["animTask"] = std::move(at);
}
}
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()) {
const auto& at = in["animTask"];
AnimTask task;
task.type = static_cast<AnimTask::Type>(at.value("type", 0));
task.startPos = { at.value("startPosX", 0.f), at.value("startPosY", 0.f), at.value("startPosZ", 0.f) };
task.startRotY = at.value("startRotY", 0.f);
task.startScale = at.value("startScale", 1.f);
task.targetPos = { at.value("targetPosX", 0.f), at.value("targetPosY", 0.f), at.value("targetPosZ", 0.f) };
task.targetRotY = at.value("targetRotY", 0.f);
task.targetScale = at.value("targetScale", 1.f);
task.durationMs = at.value("durationMs", 1000.f);
task.elapsedMs = at.value("elapsedMs", 0.f);
task.onCompleteName = at.value("onCompleteName", std::string());
animTask = std::move(task);
}
}
} // namespace FRG