#include "InteractiveObject.h" #include "render/Renderer.h" #include "render/TextureManager.h" #include #include #include #include namespace ZL { extern const std::string textureUniformName; } namespace ZL { void InteractiveObject::moveTo(const Eigen::Vector3f& target, float durationSec, std::function 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 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 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 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(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 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