173 lines
6.1 KiB
C++
173 lines
6.1 KiB
C++
#include "InteractiveObject.h"
|
|
#include "render/Renderer.h"
|
|
#include "render/TextureManager.h"
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <algorithm>
|
|
#include <Eigen/Geometry>
|
|
|
|
namespace ZL {
|
|
extern const std::string textureUniformName;
|
|
}
|
|
|
|
namespace ZL {
|
|
|
|
void InteractiveObject::moveTo(const Eigen::Vector3f& target, float durationSec, std::function<void()> onComplete) {
|
|
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.onComplete = std::move(onComplete);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObject::rotateTo(float targetRotY, float durationSec, std::function<void()> onComplete) {
|
|
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.onComplete = std::move(onComplete);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObject::scaleTo(float targetScale, float durationSec, std::function<void()> onComplete) {
|
|
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.onComplete = std::move(onComplete);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObject::fadeTo(float targetAlpha, float durationSec, std::function<void()> onComplete) {
|
|
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.onComplete = std::move(onComplete);
|
|
animTask = std::move(task);
|
|
isAnimating = true;
|
|
}
|
|
|
|
void InteractiveObject::update(int64_t deltaMs) {
|
|
if (!isAnimating || !animTask) return;
|
|
|
|
AnimTask& task = *animTask;
|
|
task.elapsedMs += static_cast<float>(deltaMs);
|
|
|
|
const float t = 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) {
|
|
// Snap to exact target
|
|
position = task.targetPos;
|
|
rotationY = task.targetRotY;
|
|
scale = task.targetScale;
|
|
|
|
std::function<void()> cb = std::move(task.onComplete);
|
|
animTask.reset();
|
|
isAnimating = false;
|
|
|
|
if (cb) cb();
|
|
}
|
|
}
|
|
|
|
void InteractiveObject::drawDarklands(Renderer& renderer) const {
|
|
if (!isActive || !loadedObject.textureDarklands) return;
|
|
|
|
if (alpha < 0.999f) {
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix(position);
|
|
if (rotationY != 0.f) {
|
|
renderer.TranslateMatrix(pivot);
|
|
renderer.RotateMatrix(Eigen::AngleAxisf(rotationY, Eigen::Vector3f::UnitY()).toRotationMatrix());
|
|
renderer.TranslateMatrix(-pivot);
|
|
}
|
|
if (scale != 1.f)
|
|
renderer.ScaleMatrix(scale);
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
renderer.RenderUniform1f("uAlpha", alpha);
|
|
glBindTexture(GL_TEXTURE_2D, loadedObject.textureDarklands->getTexID());
|
|
renderer.DrawVertexRenderStruct(loadedObject.mesh);
|
|
renderer.PopMatrix();
|
|
|
|
renderer.RenderUniform1f("uAlpha", 1.0f);
|
|
}
|
|
|
|
void InteractiveObject::draw(Renderer& renderer) const {
|
|
if (!isActive || !loadedObject.texture) return;
|
|
|
|
if (alpha < 0.999f) {
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
}
|
|
|
|
renderer.PushMatrix();
|
|
renderer.TranslateMatrix(position);
|
|
if (rotationY != 0.f) {
|
|
renderer.TranslateMatrix(pivot);
|
|
renderer.RotateMatrix(Eigen::AngleAxisf(rotationY, Eigen::Vector3f::UnitY()).toRotationMatrix());
|
|
renderer.TranslateMatrix(-pivot);
|
|
}
|
|
if (scale != 1.f)
|
|
renderer.ScaleMatrix(scale);
|
|
renderer.RenderUniform1i(textureUniformName, 0);
|
|
renderer.RenderUniform1f("uAlpha", alpha);
|
|
glBindTexture(GL_TEXTURE_2D, loadedObject.texture->getTexID());
|
|
renderer.DrawVertexRenderStruct(loadedObject.mesh);
|
|
renderer.PopMatrix();
|
|
|
|
// Restore uAlpha so subsequent fog-shader users (character weapons, etc.) are not affected.
|
|
renderer.RenderUniform1f("uAlpha", 1.0f);
|
|
}
|
|
|
|
} // namespace ZL
|