fix: alot of stuff changed. Mostly bugfixxes / architechture changes
This commit is contained in:
@@ -1,33 +1,247 @@
|
||||
#include <destrum/Components/Animator.h>
|
||||
#include <destrum/Graphics/Pipelines/SkinningPipeline.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
namespace {
|
||||
nlohmann::json Vec3Json(const glm::vec3& value) {
|
||||
return {value.x, value.y, value.z};
|
||||
}
|
||||
|
||||
glm::vec3 ReadVec3(const nlohmann::json& value) {
|
||||
return {value.at(0).get<float>(), value.at(1).get<float>(), value.at(2).get<float>()};
|
||||
}
|
||||
|
||||
nlohmann::json QuatJson(const glm::quat& value) {
|
||||
return {value.x, value.y, value.z, value.w};
|
||||
}
|
||||
|
||||
glm::quat ReadQuat(const nlohmann::json& value) {
|
||||
return {
|
||||
value.at(3).get<float>(),
|
||||
value.at(0).get<float>(),
|
||||
value.at(1).get<float>(),
|
||||
value.at(2).get<float>()
|
||||
};
|
||||
}
|
||||
|
||||
nlohmann::json Mat4Json(const glm::mat4& value) {
|
||||
nlohmann::json result = nlohmann::json::array();
|
||||
for (std::size_t column = 0; column < 4; ++column) {
|
||||
for (std::size_t row = 0; row < 4; ++row) {
|
||||
result.push_back(value[static_cast<glm::mat4::length_type>(column)]
|
||||
[static_cast<glm::mat4::length_type>(row)]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::mat4 ReadMat4(const nlohmann::json& value) {
|
||||
glm::mat4 result{1.0f};
|
||||
for (std::size_t column = 0; column < 4; ++column) {
|
||||
for (std::size_t row = 0; row < 4; ++row) {
|
||||
result[static_cast<glm::mat4::length_type>(column)]
|
||||
[static_cast<glm::mat4::length_type>(row)] =
|
||||
value.at(column * 4 + row).get<float>();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Animator::Animator(GameObject& parent)
|
||||
: Component(parent, "Animator") {}
|
||||
|
||||
void Animator::Update() {
|
||||
nlohmann::json Animator::Serialize() const {
|
||||
nlohmann::json skeleton;
|
||||
skeleton["hierarchy"] = nlohmann::json::array();
|
||||
for (const auto& node : m_skeleton.hierarchy) {
|
||||
skeleton["hierarchy"].push_back({
|
||||
{"id", node.id},
|
||||
{"children", node.children}
|
||||
});
|
||||
}
|
||||
skeleton["inverseBindMatrices"] = nlohmann::json::array();
|
||||
for (const auto& matrix : m_skeleton.inverseBindMatrices) {
|
||||
skeleton["inverseBindMatrices"].push_back(Mat4Json(matrix));
|
||||
}
|
||||
skeleton["joints"] = nlohmann::json::array();
|
||||
for (const auto& joint : m_skeleton.joints) {
|
||||
skeleton["joints"].push_back({
|
||||
{"id", joint.id},
|
||||
{"translation", Vec3Json(joint.localTranslation)},
|
||||
{"rotation", QuatJson(joint.localRotation)},
|
||||
{"scale", Vec3Json(joint.localScale)}
|
||||
});
|
||||
}
|
||||
skeleton["jointNames"] = m_skeleton.jointNames;
|
||||
skeleton["parentIndex"] = m_skeleton.parentIndex;
|
||||
skeleton["rootPreTransform"] = Mat4Json(m_skeleton.rootPreTransform);
|
||||
|
||||
nlohmann::json clips = nlohmann::json::array();
|
||||
for (const auto& [name, clip] : m_clips) {
|
||||
nlohmann::json clipJson{
|
||||
{"name", name},
|
||||
{"duration", clip->duration},
|
||||
{"looped", clip->looped},
|
||||
{"startFrame", clip->startFrame},
|
||||
{"tracks", nlohmann::json::array()},
|
||||
{"events", nlohmann::json::object()}
|
||||
};
|
||||
for (const auto& track : clip->tracks) {
|
||||
nlohmann::json trackJson{
|
||||
{"jointIndex", track.jointIndex},
|
||||
{"keyframes", nlohmann::json::array()}
|
||||
};
|
||||
for (const auto& keyframe : track.keyframes) {
|
||||
trackJson["keyframes"].push_back({
|
||||
{"time", keyframe.time},
|
||||
{"translation", Vec3Json(keyframe.translation)},
|
||||
{"rotation", QuatJson(keyframe.rotation)},
|
||||
{"scale", Vec3Json(keyframe.scale)}
|
||||
});
|
||||
}
|
||||
clipJson["tracks"].push_back(std::move(trackJson));
|
||||
}
|
||||
for (const auto& [frame, events] : clip->events) {
|
||||
clipJson["events"][std::to_string(frame)] = events;
|
||||
}
|
||||
clips.push_back(std::move(clipJson));
|
||||
}
|
||||
|
||||
const auto playback = [](const PlaybackState& state, const std::string& name) {
|
||||
return nlohmann::json{
|
||||
{"clip", name},
|
||||
{"time", state.time},
|
||||
{"speed", state.speed}
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
{"skeleton", std::move(skeleton)},
|
||||
{"clips", std::move(clips)},
|
||||
{"current", playback(m_current, m_currentClipName)},
|
||||
{"previous", playback(m_previous, m_previous.clip ? m_previous.clip->name : std::string{})},
|
||||
{"blendT", m_blendT},
|
||||
{"blendDuration", m_blendDuration}
|
||||
};
|
||||
}
|
||||
|
||||
void Animator::Deserialize(const nlohmann::json& data) {
|
||||
m_skeleton = {};
|
||||
m_clips.clear();
|
||||
m_current = {};
|
||||
m_previous = {};
|
||||
m_currentClipName.clear();
|
||||
|
||||
if (data.contains("skeleton")) {
|
||||
const auto& skeleton = data.at("skeleton");
|
||||
for (const auto& node : skeleton.value("hierarchy", nlohmann::json::array())) {
|
||||
m_skeleton.hierarchy.push_back({
|
||||
node.at("id").get<JointId>(),
|
||||
node.value("children", std::vector<JointId>{})
|
||||
});
|
||||
}
|
||||
for (const auto& matrix : skeleton.value("inverseBindMatrices", nlohmann::json::array())) {
|
||||
m_skeleton.inverseBindMatrices.push_back(ReadMat4(matrix));
|
||||
}
|
||||
for (const auto& joint : skeleton.value("joints", nlohmann::json::array())) {
|
||||
m_skeleton.joints.push_back({
|
||||
joint.at("id").get<JointId>(),
|
||||
ReadVec3(joint.at("translation")),
|
||||
ReadQuat(joint.at("rotation")),
|
||||
ReadVec3(joint.at("scale"))
|
||||
});
|
||||
}
|
||||
m_skeleton.jointNames = skeleton.value("jointNames", std::vector<std::string>{});
|
||||
m_skeleton.parentIndex = skeleton.value("parentIndex", std::vector<int>{});
|
||||
if (skeleton.contains("rootPreTransform")) {
|
||||
m_skeleton.rootPreTransform = ReadMat4(skeleton.at("rootPreTransform"));
|
||||
}
|
||||
if (m_skeleton.parentIndex.size() != m_skeleton.joints.size()) {
|
||||
buildParentIndex(m_skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& clipJson : data.value("clips", nlohmann::json::array())) {
|
||||
auto clip = std::make_shared<SkeletalAnimation>();
|
||||
clip->name = clipJson.at("name").get<std::string>();
|
||||
clip->duration = clipJson.value("duration", 0.0f);
|
||||
clip->looped = clipJson.value("looped", true);
|
||||
clip->startFrame = clipJson.value("startFrame", 0);
|
||||
for (const auto& trackJson : clipJson.value("tracks", nlohmann::json::array())) {
|
||||
SkeletalAnimation::Track track;
|
||||
track.jointIndex = trackJson.at("jointIndex").get<std::uint32_t>();
|
||||
for (const auto& keyframeJson : trackJson.value("keyframes", nlohmann::json::array())) {
|
||||
track.keyframes.push_back({
|
||||
keyframeJson.at("time").get<float>(),
|
||||
ReadVec3(keyframeJson.at("translation")),
|
||||
ReadQuat(keyframeJson.at("rotation")),
|
||||
ReadVec3(keyframeJson.at("scale"))
|
||||
});
|
||||
}
|
||||
clip->tracks.push_back(std::move(track));
|
||||
}
|
||||
if (clipJson.contains("events")) {
|
||||
for (auto it = clipJson.at("events").begin(); it != clipJson.at("events").end(); ++it) {
|
||||
clip->events[std::stoi(it.key())] = it.value().get<std::vector<std::string>>();
|
||||
}
|
||||
}
|
||||
m_clips[clip->name] = std::move(clip);
|
||||
}
|
||||
|
||||
const auto restorePlayback = [this](const nlohmann::json& playback, PlaybackState& state,
|
||||
std::string* clipName) {
|
||||
const std::string name = playback.value("clip", std::string{});
|
||||
state.time = playback.value("time", 0.0f);
|
||||
state.speed = playback.value("speed", 1.0f);
|
||||
state.clip = nullptr;
|
||||
if (!name.empty()) {
|
||||
const auto it = m_clips.find(name);
|
||||
if (it == m_clips.end()) {
|
||||
throw std::runtime_error("Animator clip not found: " + name);
|
||||
}
|
||||
state.clip = it->second.get();
|
||||
}
|
||||
if (clipName != nullptr) {
|
||||
*clipName = name;
|
||||
}
|
||||
};
|
||||
|
||||
if (data.contains("current")) {
|
||||
restorePlayback(data.at("current"), m_current, &m_currentClipName);
|
||||
}
|
||||
if (data.contains("previous")) {
|
||||
restorePlayback(data.at("previous"), m_previous, nullptr);
|
||||
}
|
||||
m_blendT = data.value("blendT", 0.0f);
|
||||
m_blendDuration = data.value("blendDuration", 0.0f);
|
||||
}
|
||||
|
||||
void Animator::Update(float dt) {
|
||||
if (!m_current.clip) return;
|
||||
|
||||
const float dt = Time::GetInstance().DeltaTime();
|
||||
|
||||
m_current.time += dt * m_current.speed;
|
||||
if (m_current.clip->looped)
|
||||
if (m_current.clip->duration > 0.0f && m_current.clip->looped)
|
||||
m_current.time = std::fmod(m_current.time, m_current.clip->duration);
|
||||
else
|
||||
else if (m_current.clip->duration > 0.0f)
|
||||
m_current.time = std::min(m_current.time, m_current.clip->duration);
|
||||
|
||||
if (m_previous.clip) {
|
||||
m_previous.time += dt * m_previous.speed;
|
||||
if (m_previous.clip->looped)
|
||||
if (m_previous.clip->duration > 0.0f && m_previous.clip->looped)
|
||||
m_previous.time = std::fmod(m_previous.time, m_previous.clip->duration);
|
||||
|
||||
m_blendT += dt / m_blendDuration;
|
||||
if (m_blendDuration > 0.0f) {
|
||||
m_blendT += dt / m_blendDuration;
|
||||
} else {
|
||||
m_blendT = 1.0f;
|
||||
}
|
||||
if (m_blendT >= 1.f) {
|
||||
m_blendT = 1.f;
|
||||
m_previous = {};
|
||||
@@ -184,4 +398,4 @@ glm::vec3 Animator::sampleScale(const SkeletalAnimation::Track& track, float t)
|
||||
}
|
||||
}
|
||||
return kf.back().scale;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "destrum/ObjectModel/GameObject.h"
|
||||
#include "destrum/Util/GameState.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
MeshRendererComponent::MeshRendererComponent(GameObject& parent): Component(parent, "MeshRendererComponent") {
|
||||
|
||||
@@ -12,7 +13,11 @@ MeshRendererComponent::MeshRendererComponent(GameObject& parent): Component(pare
|
||||
|
||||
void MeshRendererComponent::Start() {
|
||||
Component::Start();
|
||||
if (auto* animator = GetGameObject()->GetComponent<Animator>()) {
|
||||
ResolveReferences(ObjectMap{});
|
||||
if (GetGameObject()->GetComponent<Animator>() &&
|
||||
meshID != NULL_MESH_ID &&
|
||||
GameState::GetInstance().HasGfxDevice() &&
|
||||
GameState::GetInstance().HasRenderer()) {
|
||||
const auto& gfxDevice = GameState::GetInstance().Gfx();
|
||||
const auto& mesh = GameState::GetInstance().Renderer().getResources()->meshes().getMesh(meshID);
|
||||
|
||||
@@ -26,14 +31,101 @@ void MeshRendererComponent::Start() {
|
||||
}
|
||||
}
|
||||
|
||||
void MeshRendererComponent::Update() {
|
||||
void MeshRendererComponent::Destroy()
|
||||
{
|
||||
if (m_skinnedMesh && GameState::GetInstance().HasGfxDevice()) {
|
||||
auto& gfxDevice = GameState::GetInstance().Gfx();
|
||||
gfxDevice.waitIdle();
|
||||
gfxDevice.destroyBuffer(m_skinnedMesh->skinnedVertexBuffer);
|
||||
}
|
||||
m_skinnedMesh.reset();
|
||||
Component::Destroy();
|
||||
}
|
||||
|
||||
void MeshRendererComponent::Update(float) {
|
||||
}
|
||||
|
||||
nlohmann::json MeshRendererComponent::Serialize() const {
|
||||
return {
|
||||
{"meshId", meshID},
|
||||
{"materialId", materialID},
|
||||
{"meshKey", meshKey},
|
||||
{"materialKey", materialKey}
|
||||
};
|
||||
}
|
||||
|
||||
void MeshRendererComponent::Deserialize(const nlohmann::json& data) {
|
||||
if (data.contains("meshId")) {
|
||||
meshID = data.at("meshId").get<MeshID>();
|
||||
}
|
||||
if (data.contains("materialId")) {
|
||||
materialID = data.at("materialId").get<MaterialID>();
|
||||
}
|
||||
if (data.contains("meshKey")) {
|
||||
meshKey = data.at("meshKey").get<std::string>();
|
||||
}
|
||||
if (data.contains("materialKey")) {
|
||||
materialKey = data.at("materialKey").get<std::string>();
|
||||
}
|
||||
}
|
||||
|
||||
void MeshRendererComponent::ResolveReferences(const ObjectMap&) {
|
||||
if (!GameState::GetInstance().HasRenderer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderResources* resources = GameState::GetInstance().Renderer().getResources();
|
||||
if (resources == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!meshKey.empty()) {
|
||||
const auto resolved = resources->meshes().findMeshByKey(meshKey);
|
||||
if (!resolved) {
|
||||
throw std::runtime_error("Mesh resource not found: " + meshKey);
|
||||
}
|
||||
meshID = *resolved;
|
||||
}
|
||||
if (!materialKey.empty()) {
|
||||
const auto resolved = resources->materials().findMaterialByKey(materialKey);
|
||||
if (!resolved) {
|
||||
throw std::runtime_error("Material resource not found: " + materialKey);
|
||||
}
|
||||
materialID = *resolved;
|
||||
}
|
||||
|
||||
if (meshID != NULL_MESH_ID && meshKey.empty()) {
|
||||
(void)resources->meshes().getMesh(meshID);
|
||||
}
|
||||
if (materialID != NULL_MATERIAL_ID && materialKey.empty()) {
|
||||
(void)resources->materials().getMaterial(materialID);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshRendererComponent::SetMeshID(MeshID id) {
|
||||
meshID = id;
|
||||
meshKey.clear();
|
||||
if (id != NULL_MESH_ID && GameState::GetInstance().HasRenderer()) {
|
||||
if (auto* resources = GameState::GetInstance().Renderer().getResources()) {
|
||||
meshKey = resources->meshes().getMeshKey(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MeshRendererComponent::SetMaterialID(MaterialID id) {
|
||||
materialID = id;
|
||||
materialKey.clear();
|
||||
if (id != NULL_MATERIAL_ID && GameState::GetInstance().HasRenderer()) {
|
||||
if (auto* resources = GameState::GetInstance().Renderer().getResources()) {
|
||||
materialKey = resources->materials().getMaterialKey(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MeshRendererComponent::Render(const RenderContext& ctx) {
|
||||
if (meshID == NULL_MESH_ID || materialID == NULL_MATERIAL_ID) return;
|
||||
|
||||
if (auto* animator = GetGameObject()->GetComponent<Animator>(); animator && m_skinnedMesh) {
|
||||
const auto& mesh = ctx.renderer.getResources()->meshes().getCPUMesh(meshID);
|
||||
const auto skeleton = GetGameObject()->GetComponent<Animator>()->getSkeleton();
|
||||
std::uint32_t frameIdx = GameState::GetInstance().Gfx().getCurrentFrameIndex();
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "destrum/ObjectModel/Transform.h"
|
||||
#include "destrum/Components/MeshRendererComponent.h"
|
||||
#include "destrum/Util/GameState.h"
|
||||
#include "destrum/Util/DeltaTime.h"
|
||||
|
||||
static glm::vec3 RandomUnitVector(std::mt19937& rng)
|
||||
{
|
||||
@@ -54,6 +55,9 @@ void OrbitAndSpin::Randomize(uint32_t seed)
|
||||
|
||||
void OrbitAndSpin::BuildOrbitBasis()
|
||||
{
|
||||
if (glm::dot(m_OrbitAxis, m_OrbitAxis) < 1e-8f)
|
||||
m_OrbitAxis = glm::vec3(0, 1, 0);
|
||||
|
||||
m_OrbitAxis = glm::normalize(m_OrbitAxis);
|
||||
|
||||
// pick any vector not parallel to axis
|
||||
@@ -63,9 +67,8 @@ void OrbitAndSpin::BuildOrbitBasis()
|
||||
m_V = glm::normalize(glm::cross(m_OrbitAxis, m_U));
|
||||
}
|
||||
|
||||
void OrbitAndSpin::Update()
|
||||
void OrbitAndSpin::Update(float dt)
|
||||
{
|
||||
float dt = 1.0f / 60.0f;
|
||||
|
||||
// orbit
|
||||
m_OrbitAngle += m_OrbitSpeed * dt;
|
||||
@@ -84,8 +87,6 @@ void OrbitAndSpin::Update()
|
||||
// grow (always positive)
|
||||
m_GrowPhase += m_GrowSpeed * dt;
|
||||
|
||||
m_GrowPhase += m_GrowSpeed * dt;
|
||||
|
||||
// 0..1
|
||||
float t = 0.5f * (std::sin(m_GrowPhase) + 1.0f);
|
||||
|
||||
@@ -93,7 +94,7 @@ void OrbitAndSpin::Update()
|
||||
float s = glm::mix(m_GrowMin, m_GrowMax, t);
|
||||
|
||||
// respect original scale
|
||||
GetTransform().SetLocalScale(glm::vec3(s));
|
||||
GetTransform().SetLocalScale(m_BaseScale * s);
|
||||
|
||||
// GetTransform().SetLocalScale(glm::vec3(std::sin(m_GrowPhase)));
|
||||
|
||||
@@ -109,8 +110,68 @@ void OrbitAndSpin::Update()
|
||||
|
||||
void OrbitAndSpin::Start() {
|
||||
auto meshComp = this->GetGameObject()->GetComponent<MeshRendererComponent>();
|
||||
m_MaterialID = meshComp->GetMaterialID();
|
||||
if (meshComp != nullptr) {
|
||||
m_MaterialID = meshComp->GetMaterialID();
|
||||
}
|
||||
|
||||
m_BaseScale = GetTransform().GetLocalScale(); // <-- important
|
||||
if (!m_BaseScaleLoaded) {
|
||||
m_BaseScale = GetTransform().GetLocalScale();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nlohmann::json OrbitAndSpin::Serialize() const {
|
||||
return {
|
||||
{"radius", m_Radius},
|
||||
{"center", {m_Center.x, m_Center.y, m_Center.z}},
|
||||
{"orbitAxis", {m_OrbitAxis.x, m_OrbitAxis.y, m_OrbitAxis.z}},
|
||||
{"orbitSpeed", m_OrbitSpeed},
|
||||
{"orbitAngle", m_OrbitAngle},
|
||||
{"orbitPhase", m_OrbitPhase},
|
||||
{"growPhase", m_GrowPhase},
|
||||
{"growSpeed", m_GrowSpeed},
|
||||
{"growMin", m_GrowMin},
|
||||
{"growMax", m_GrowMax},
|
||||
{"spinAxis", {m_SpinAxis.x, m_SpinAxis.y, m_SpinAxis.z}},
|
||||
{"spinSpeed", m_SpinSpeed},
|
||||
{"baseScale", {m_BaseScale.x, m_BaseScale.y, m_BaseScale.z}},
|
||||
{"materialId", m_MaterialID}
|
||||
};
|
||||
}
|
||||
|
||||
void OrbitAndSpin::Deserialize(const nlohmann::json& data) {
|
||||
const auto readVec3 = [&data](const char* key, glm::vec3& value) {
|
||||
if (!data.contains(key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& array = data.at(key);
|
||||
value = {array.at(0).get<float>(), array.at(1).get<float>(), array.at(2).get<float>()};
|
||||
};
|
||||
|
||||
if (data.contains("radius")) m_Radius = data.at("radius").get<float>();
|
||||
readVec3("center", m_Center);
|
||||
readVec3("orbitAxis", m_OrbitAxis);
|
||||
if (data.contains("orbitSpeed")) m_OrbitSpeed = data.at("orbitSpeed").get<float>();
|
||||
if (data.contains("orbitAngle")) m_OrbitAngle = data.at("orbitAngle").get<float>();
|
||||
if (data.contains("orbitPhase")) m_OrbitPhase = data.at("orbitPhase").get<float>();
|
||||
if (data.contains("growPhase")) m_GrowPhase = data.at("growPhase").get<float>();
|
||||
if (data.contains("growSpeed")) m_GrowSpeed = data.at("growSpeed").get<float>();
|
||||
if (data.contains("growMin")) m_GrowMin = data.at("growMin").get<float>();
|
||||
if (data.contains("growMax")) m_GrowMax = data.at("growMax").get<float>();
|
||||
readVec3("spinAxis", m_SpinAxis);
|
||||
readVec3("baseScale", m_BaseScale);
|
||||
m_BaseScaleLoaded = data.contains("baseScale");
|
||||
if (data.contains("spinSpeed")) m_SpinSpeed = data.at("spinSpeed").get<float>();
|
||||
if (data.contains("materialId")) m_MaterialID = data.at("materialId").get<MaterialID>();
|
||||
|
||||
if (m_GrowMin > m_GrowMax) {
|
||||
std::swap(m_GrowMin, m_GrowMax);
|
||||
}
|
||||
if (glm::dot(m_SpinAxis, m_SpinAxis) < 1e-8f) {
|
||||
m_SpinAxis = glm::vec3(0, 1, 0);
|
||||
} else {
|
||||
m_SpinAxis = glm::normalize(m_SpinAxis);
|
||||
}
|
||||
BuildOrbitBasis();
|
||||
}
|
||||
|
||||
@@ -1 +1,19 @@
|
||||
#include <destrum/Components/Physics/BoxCollider.h>
|
||||
#include <destrum/Components/Physics/BoxCollider.h>
|
||||
|
||||
nlohmann::json BoxCollider::Serialize() const {
|
||||
auto data = SerializeCollider();
|
||||
data["halfExtents"] = {m_HalfExtents.x, m_HalfExtents.y, m_HalfExtents.z};
|
||||
return data;
|
||||
}
|
||||
|
||||
void BoxCollider::Deserialize(const nlohmann::json& data) {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("halfExtents")) {
|
||||
const auto& extents = data.at("halfExtents");
|
||||
SetHalfExtents({
|
||||
extents.at(0).get<float>(),
|
||||
extents.at(1).get<float>(),
|
||||
extents.at(2).get<float>()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,59 @@
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
|
||||
#include <destrum/Physics/PhysicsWorld.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Scene/Scene.h>
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] const char* RigidbodyTypeName(RigidbodyType type) {
|
||||
switch (type) {
|
||||
case RigidbodyType::Static:
|
||||
return "Static";
|
||||
case RigidbodyType::Kinematic:
|
||||
return "Kinematic";
|
||||
case RigidbodyType::Dynamic:
|
||||
default:
|
||||
return "Dynamic";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] RigidbodyType ParseRigidbodyType(const nlohmann::json& value) {
|
||||
if (value.is_string()) {
|
||||
const std::string type = value.get<std::string>();
|
||||
if (type == "Static") return RigidbodyType::Static;
|
||||
if (type == "Kinematic") return RigidbodyType::Kinematic;
|
||||
return RigidbodyType::Dynamic;
|
||||
}
|
||||
|
||||
const int type = value.get<int>();
|
||||
switch (type) {
|
||||
case 0: return RigidbodyType::Static;
|
||||
case 2: return RigidbodyType::Kinematic;
|
||||
case 1:
|
||||
default: return RigidbodyType::Dynamic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rigidbody::~Rigidbody() {
|
||||
if (m_World != nullptr) {
|
||||
m_World->UnregisterRigidbody(*this);
|
||||
}
|
||||
}
|
||||
|
||||
void Rigidbody::Destroy() {
|
||||
if (m_World != nullptr) {
|
||||
m_World->UnregisterRigidbody(*this);
|
||||
}
|
||||
Component::Destroy();
|
||||
}
|
||||
|
||||
void Rigidbody::Start()
|
||||
{
|
||||
if (GetGameObject() != nullptr && GetGameObject()->GetScene() != nullptr) {
|
||||
GetGameObject()->GetScene()->GetPhysics().RegisterGameObject(*GetGameObject());
|
||||
}
|
||||
}
|
||||
|
||||
void Rigidbody::AttachPhysicsBody(PhysicsWorld* world, PhysicsBodyHandle body) {
|
||||
m_World = world;
|
||||
@@ -43,3 +96,35 @@ glm::vec3 Rigidbody::GetLinearVelocity() const {
|
||||
|
||||
return m_World->GetLinearVelocity(m_Body);
|
||||
}
|
||||
|
||||
nlohmann::json Rigidbody::Serialize() const {
|
||||
return {
|
||||
{"type", RigidbodyTypeName(m_Type)},
|
||||
{"mass", m_Mass},
|
||||
{"friction", m_Friction},
|
||||
{"restitution", m_Restitution},
|
||||
{"useGravity", m_UseGravity},
|
||||
{"allowSleep", m_AllowSleep}
|
||||
};
|
||||
}
|
||||
|
||||
void Rigidbody::Deserialize(const nlohmann::json& data) {
|
||||
if (data.contains("type")) {
|
||||
m_Type = ParseRigidbodyType(data.at("type"));
|
||||
}
|
||||
if (data.contains("mass")) {
|
||||
SetMass(data.at("mass").get<float>());
|
||||
}
|
||||
if (data.contains("friction")) {
|
||||
SetFriction(data.at("friction").get<float>());
|
||||
}
|
||||
if (data.contains("restitution")) {
|
||||
SetRestitution(data.at("restitution").get<float>());
|
||||
}
|
||||
if (data.contains("useGravity")) {
|
||||
m_UseGravity = data.at("useGravity").get<bool>();
|
||||
}
|
||||
if (data.contains("allowSleep")) {
|
||||
m_AllowSleep = data.at("allowSleep").get<bool>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,14 @@
|
||||
#include <destrum/Components/Physics/SphereCollider.h>
|
||||
#include <destrum/Components/Physics/SphereCollider.h>
|
||||
|
||||
nlohmann::json SphereCollider::Serialize() const {
|
||||
auto data = SerializeCollider();
|
||||
data["radius"] = m_Radius;
|
||||
return data;
|
||||
}
|
||||
|
||||
void SphereCollider::Deserialize(const nlohmann::json& data) {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("radius")) {
|
||||
SetRadius(data.at("radius").get<float>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <cmath>
|
||||
#include <glm/gtc/quaternion.hpp> // glm::quat, glm::angleAxis
|
||||
#include <glm/gtx/quaternion.hpp> // operator*(quat, vec3)
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
glm::vec3 Rotator::MakePerpendicularUnitVector(const glm::vec3& axis)
|
||||
{
|
||||
@@ -84,12 +85,46 @@ void Rotator::SetDistance(float distance)
|
||||
m_InitialOffset = MakePerpendicularUnitVector(m_Axis) * m_Distance;
|
||||
}
|
||||
|
||||
void Rotator::Update()
|
||||
void Rotator::Update(float dt)
|
||||
{
|
||||
// Replace 0.001f with your engine delta time if you have one.
|
||||
m_CurrentAngle += m_Speed * 0.001f;
|
||||
m_CurrentAngle += m_Speed * dt;
|
||||
|
||||
const glm::quat q = glm::angleAxis(m_CurrentAngle, glm::normalize(m_Axis));
|
||||
const glm::vec3 rotatedOffset = q * m_InitialOffset;
|
||||
GetTransform().SetLocalPosition(m_Pivot + rotatedOffset);
|
||||
}
|
||||
|
||||
nlohmann::json Rotator::Serialize() const {
|
||||
return {
|
||||
{"distance", m_Distance},
|
||||
{"speed", m_Speed},
|
||||
{"currentAngle", m_CurrentAngle},
|
||||
{"pivot", {m_Pivot.x, m_Pivot.y, m_Pivot.z}},
|
||||
{"axis", {m_Axis.x, m_Axis.y, m_Axis.z}},
|
||||
{"initialOffset", {m_InitialOffset.x, m_InitialOffset.y, m_InitialOffset.z}}
|
||||
};
|
||||
}
|
||||
|
||||
void Rotator::Deserialize(const nlohmann::json& data) {
|
||||
if (data.contains("distance")) {
|
||||
m_Distance = data.at("distance").get<float>();
|
||||
}
|
||||
if (data.contains("speed")) {
|
||||
m_Speed = data.at("speed").get<float>();
|
||||
}
|
||||
if (data.contains("currentAngle")) {
|
||||
m_CurrentAngle = data.at("currentAngle").get<float>();
|
||||
}
|
||||
if (data.contains("pivot")) {
|
||||
const auto& value = data.at("pivot");
|
||||
m_Pivot = {value.at(0).get<float>(), value.at(1).get<float>(), value.at(2).get<float>()};
|
||||
}
|
||||
if (data.contains("axis")) {
|
||||
const auto& value = data.at("axis");
|
||||
SetAxis({value.at(0).get<float>(), value.at(1).get<float>(), value.at(2).get<float>()});
|
||||
}
|
||||
if (data.contains("initialOffset")) {
|
||||
const auto& value = data.at("initialOffset");
|
||||
m_InitialOffset = {value.at(0).get<float>(), value.at(1).get<float>(), value.at(2).get<float>()};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,24 +3,33 @@
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include "destrum/ObjectModel/Transform.h"
|
||||
#include "destrum/Util/DeltaTime.h"
|
||||
|
||||
void Spinner::Update()
|
||||
void Spinner::Update(float dt)
|
||||
{
|
||||
// Replace with your engine dt if you have it available in Component.
|
||||
const float dt = 1.0f / 60.0f;
|
||||
|
||||
|
||||
m_Angle += m_Speed * dt;
|
||||
|
||||
// If you already have SetLocalRotation / SetWorldRotation, use that.
|
||||
// Here I'm assuming you can set rotation as a quaternion or Euler somewhere.
|
||||
// If not, tell me your Transform rotation API and I’ll adjust.
|
||||
|
||||
const glm::quat q = glm::angleAxis(m_Angle, m_Axis);
|
||||
|
||||
// Example APIs you might have:
|
||||
// GetTransform().SetLocalRotation(q);
|
||||
// or GetTransform().SetWorldRotation(q);
|
||||
|
||||
GetTransform().SetLocalRotation(q);
|
||||
}
|
||||
|
||||
nlohmann::json Spinner::Serialize() const {
|
||||
return {
|
||||
{"axis", {m_Axis.x, m_Axis.y, m_Axis.z}},
|
||||
{"speed", m_Speed},
|
||||
{"angle", m_Angle}
|
||||
};
|
||||
}
|
||||
|
||||
void Spinner::Deserialize(const nlohmann::json& data) {
|
||||
if (data.contains("axis")) {
|
||||
const auto& value = data.at("axis");
|
||||
SetAxis({value.at(0).get<float>(), value.at(1).get<float>(), value.at(2).get<float>()});
|
||||
}
|
||||
if (data.contains("speed")) {
|
||||
m_Speed = data.at("speed").get<float>();
|
||||
}
|
||||
if (data.contains("angle")) {
|
||||
m_Angle = data.at("angle").get<float>();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user