Separating state out of the location
This commit is contained in:
1 parent
5e9a663812
commit
297bd7377f
45 files changed
+2114
-778
No files matched your search
@@ -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
|
||||
Reference in new issue
Block a user