Working on game states
This commit is contained in:
1 parent
0ca00f965d
commit
e0968b5522
10 files changed
+340
-251
No files matched your search
+125
-70
@@ -1,6 +1,7 @@
|
||||
#include "InteractiveObject.h"
|
||||
#include "render/Renderer.h"
|
||||
#include "render/TextureManager.h"
|
||||
#include "../TextModel.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
@@ -14,133 +15,188 @@ namespace ZL {
|
||||
using std::max;
|
||||
#endif
|
||||
|
||||
InteractiveObject InteractiveObject::createFromState(InteractiveObjectState st,
|
||||
Renderer& renderer,
|
||||
const std::string& zipPath)
|
||||
{
|
||||
InteractiveObject obj;
|
||||
obj.state = std::move(st);
|
||||
|
||||
const LoadedGameObjectState& info = obj.state.objectInfo;
|
||||
|
||||
obj.loadedObject.texture = renderer.textureManager.LoadFromPng(info.texturePath, zipPath);
|
||||
if (!info.textureDarkandsPath.empty())
|
||||
obj.loadedObject.textureDarklands = renderer.textureManager.LoadFromPng(info.textureDarkandsPath, zipPath);
|
||||
|
||||
if (info.meshPath.size() > 4 && info.meshPath.compare(info.meshPath.size() - 4, 4, ".bin") == 0)
|
||||
obj.loadedObject.mesh.data = LoadModelFromBinFile(info.meshPath, zipPath);
|
||||
else
|
||||
obj.loadedObject.mesh.data = LoadFromTextFile02(info.meshPath, zipPath);
|
||||
|
||||
constexpr float kDeg2Rad = static_cast<float>(M_PI) / 180.0f;
|
||||
Eigen::Quaternionf rot = Eigen::Quaternionf::Identity();
|
||||
if (info.meshRotationX != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(info.meshRotationX * kDeg2Rad, Eigen::Vector3f::UnitX())) * rot;
|
||||
if (info.meshRotationY != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(info.meshRotationY * kDeg2Rad, Eigen::Vector3f::UnitY())) * rot;
|
||||
if (info.meshRotationZ != 0.0f)
|
||||
rot = Eigen::Quaternionf(Eigen::AngleAxisf(info.meshRotationZ * kDeg2Rad, Eigen::Vector3f::UnitZ())) * rot;
|
||||
obj.loadedObject.mesh.data.RotateByMatrix(rot.toRotationMatrix());
|
||||
|
||||
if (info.meshScale != 1.0f)
|
||||
obj.loadedObject.mesh.data.Scale(info.meshScale);
|
||||
|
||||
obj.loadedObject.mesh.RefreshVBO();
|
||||
|
||||
// Center mesh at origin; adjust world position by the centering offset.
|
||||
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];
|
||||
for (const auto& v : obj.loadedObject.mesh.data.PositionData) {
|
||||
meshMin = meshMin.cwiseMin(v);
|
||||
meshMax = meshMax.cwiseMax(v);
|
||||
}
|
||||
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 InteractiveObject::moveTo(const Eigen::Vector3f& target, float durationSec, std::function<void()> onComplete) {
|
||||
if (isAnimating) return;
|
||||
if (state.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.type = AnimTask::Type::Move;
|
||||
task.startPos = state.position;
|
||||
task.startRotY = state.rotationY;
|
||||
task.startScale = state.scale;
|
||||
task.targetPos = target;
|
||||
task.targetRotY = state.rotationY;
|
||||
task.targetScale = state.scale;
|
||||
task.durationMs = durationSec * 1000.f;
|
||||
task.elapsedMs = 0.f;
|
||||
task.onComplete = std::move(onComplete);
|
||||
animTask = std::move(task);
|
||||
isAnimating = true;
|
||||
state.animTask = std::move(task);
|
||||
state.isAnimating = true;
|
||||
}
|
||||
|
||||
void InteractiveObject::rotateTo(float targetRotY, float durationSec, std::function<void()> onComplete) {
|
||||
if (isAnimating) return;
|
||||
if (state.isAnimating) return;
|
||||
AnimTask task;
|
||||
task.type = AnimTask::Type::Rotate;
|
||||
task.startPos = position;
|
||||
task.startRotY = rotationY;
|
||||
task.startScale = scale;
|
||||
task.targetPos = position;
|
||||
task.startPos = state.position;
|
||||
task.startRotY = state.rotationY;
|
||||
task.startScale = state.scale;
|
||||
task.targetPos = state.position;
|
||||
task.targetRotY = targetRotY;
|
||||
task.targetScale = scale;
|
||||
task.targetScale = state.scale;
|
||||
task.durationMs = durationSec * 1000.f;
|
||||
task.elapsedMs = 0.f;
|
||||
task.onComplete = std::move(onComplete);
|
||||
animTask = std::move(task);
|
||||
isAnimating = true;
|
||||
state.animTask = std::move(task);
|
||||
state.isAnimating = true;
|
||||
}
|
||||
|
||||
void InteractiveObject::scaleTo(float targetScale, float durationSec, std::function<void()> onComplete) {
|
||||
if (isAnimating) return;
|
||||
if (state.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.startPos = state.position;
|
||||
task.startRotY = state.rotationY;
|
||||
task.startScale = state.scale;
|
||||
task.targetPos = state.position;
|
||||
task.targetRotY = state.rotationY;
|
||||
task.targetScale = targetScale;
|
||||
task.durationMs = durationSec * 1000.f;
|
||||
task.elapsedMs = 0.f;
|
||||
task.onComplete = std::move(onComplete);
|
||||
animTask = std::move(task);
|
||||
isAnimating = true;
|
||||
state.animTask = std::move(task);
|
||||
state.isAnimating = true;
|
||||
}
|
||||
|
||||
void InteractiveObject::fadeTo(float targetAlpha, float durationSec, std::function<void()> onComplete) {
|
||||
if (isAnimating) return;
|
||||
if (state.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.startPos = state.position;
|
||||
task.startRotY = state.rotationY;
|
||||
task.startScale = state.alpha; // reuse startScale to hold start alpha
|
||||
task.targetPos = state.position;
|
||||
task.targetRotY = state.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;
|
||||
state.animTask = std::move(task);
|
||||
state.isAnimating = true;
|
||||
}
|
||||
|
||||
void InteractiveObject::update(int64_t deltaMs) {
|
||||
if (!isAnimating || !animTask) return;
|
||||
if (!state.isAnimating || !state.animTask) return;
|
||||
|
||||
AnimTask& task = *animTask;
|
||||
AnimTask& task = *state.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;
|
||||
state.position = task.startPos + (task.targetPos - task.startPos) * t;
|
||||
break;
|
||||
case AnimTask::Type::Rotate:
|
||||
rotationY = task.startRotY + (task.targetRotY - task.startRotY) * t;
|
||||
state.rotationY = task.startRotY + (task.targetRotY - task.startRotY) * t;
|
||||
break;
|
||||
case AnimTask::Type::Scale:
|
||||
scale = task.startScale + (task.targetScale - task.startScale) * t;
|
||||
state.scale = task.startScale + (task.targetScale - task.startScale) * t;
|
||||
break;
|
||||
case AnimTask::Type::Fade:
|
||||
alpha = task.startScale + (task.targetScale - task.startScale) * t;
|
||||
state.alpha = task.startScale + (task.targetScale - task.startScale) * t;
|
||||
break;
|
||||
}
|
||||
|
||||
if (t >= 1.0f) {
|
||||
// Snap to exact target
|
||||
position = task.targetPos;
|
||||
rotationY = task.targetRotY;
|
||||
state.position = task.targetPos;
|
||||
state.rotationY = task.targetRotY;
|
||||
if (task.type == AnimTask::Type::Fade)
|
||||
alpha = task.targetScale; // targetScale reused to hold targetAlpha for Fade
|
||||
state.alpha = task.targetScale;
|
||||
else
|
||||
scale = task.targetScale;
|
||||
state.scale = task.targetScale;
|
||||
|
||||
std::function<void()> cb = std::move(task.onComplete);
|
||||
animTask.reset();
|
||||
isAnimating = false;
|
||||
state.animTask.reset();
|
||||
state.isAnimating = false;
|
||||
|
||||
if (cb) cb();
|
||||
}
|
||||
}
|
||||
|
||||
void InteractiveObject::drawDarklands(Renderer& renderer) const {
|
||||
if (!isActive || !loadedObject.textureDarklands) return;
|
||||
if (!state.isActive || !loadedObject.textureDarklands) return;
|
||||
|
||||
if (alpha < 0.999f) {
|
||||
if (state.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);
|
||||
renderer.TranslateMatrix(state.position);
|
||||
if (state.rotationY != 0.f) {
|
||||
renderer.TranslateMatrix(state.pivot);
|
||||
renderer.RotateMatrix(Eigen::AngleAxisf(state.rotationY, Eigen::Vector3f::UnitY()).toRotationMatrix());
|
||||
renderer.TranslateMatrix(-state.pivot);
|
||||
}
|
||||
if (scale != 1.f)
|
||||
renderer.ScaleMatrix(scale);
|
||||
if (state.scale != 1.f)
|
||||
renderer.ScaleMatrix(state.scale);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.RenderUniform1f("uAlpha", alpha);
|
||||
renderer.RenderUniform1f("uAlpha", state.alpha);
|
||||
glBindTexture(GL_TEXTURE_2D, loadedObject.textureDarklands->getTexID());
|
||||
renderer.DrawVertexRenderStruct(loadedObject.mesh);
|
||||
renderer.PopMatrix();
|
||||
@@ -149,30 +205,29 @@ namespace ZL {
|
||||
}
|
||||
|
||||
void InteractiveObject::draw(Renderer& renderer) const {
|
||||
if (!isActive || !loadedObject.texture) return;
|
||||
if (!state.isActive || !loadedObject.texture) return;
|
||||
|
||||
if (alpha < 0.999f) {
|
||||
if (state.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);
|
||||
renderer.TranslateMatrix(state.position);
|
||||
if (state.rotationY != 0.f) {
|
||||
renderer.TranslateMatrix(state.pivot);
|
||||
renderer.RotateMatrix(Eigen::AngleAxisf(state.rotationY, Eigen::Vector3f::UnitY()).toRotationMatrix());
|
||||
renderer.TranslateMatrix(-state.pivot);
|
||||
}
|
||||
if (scale != 1.f)
|
||||
renderer.ScaleMatrix(scale);
|
||||
if (state.scale != 1.f)
|
||||
renderer.ScaleMatrix(state.scale);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.RenderUniform1f("uAlpha", alpha);
|
||||
renderer.RenderUniform1f("uAlpha", state.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
|
||||
} // namespace ZL
|
||||
Reference in new issue
Block a user