fix: alot of stuff changed. Mostly bugfixxes / architechture changes
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
#include <destrum/Scene/Scene.h>
|
||||
|
||||
Component::Component(GameObject& pParent, const std::string& name)
|
||||
: Object(name),
|
||||
@@ -14,6 +16,7 @@ Transform& Component::GetTransform() const {
|
||||
|
||||
void Component::Destroy() {
|
||||
Object::Destroy();
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
void Component::Start() {
|
||||
@@ -21,12 +24,30 @@ void Component::Start() {
|
||||
|
||||
void Component::SetEnabled(bool enabled) {
|
||||
m_IsEnabled = enabled;
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
void Component::LateUpdate() {
|
||||
void Component::NotifyPhysicsChanged() {
|
||||
if (m_ParentGameObjectPtr != nullptr) {
|
||||
if (auto* rigidbody = m_ParentGameObjectPtr->GetComponent<Rigidbody>();
|
||||
rigidbody != nullptr && rigidbody->GetPhysicsWorld() != nullptr) {
|
||||
rigidbody->GetPhysicsWorld()->RefreshRigidbody(*rigidbody);
|
||||
} else {
|
||||
m_ParentGameObjectPtr->RefreshPhysics();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Component::FixedUpdate() {
|
||||
void Component::Update(float dt) {
|
||||
m_LastUpdateDeltaTime = dt;
|
||||
}
|
||||
|
||||
void Component::LateUpdate(float dt) {
|
||||
m_LastUpdateDeltaTime = dt;
|
||||
}
|
||||
|
||||
void Component::FixedUpdate(float fixedDt) {
|
||||
m_LastFixedDeltaTime = fixedDt;
|
||||
}
|
||||
|
||||
void Component::ImGuiInspector() {
|
||||
@@ -35,5 +56,5 @@ void Component::ImGuiInspector() {
|
||||
void Component::ImGuiRender() {
|
||||
}
|
||||
|
||||
void Component::Render(const RenderContext& ctx) {
|
||||
}
|
||||
void Component::Render(const RenderContext&) {
|
||||
}
|
||||
|
||||
@@ -1,32 +1,72 @@
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/Util/DeltaTime.h>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace {
|
||||
[[nodiscard]] std::vector<Component*> SnapshotComponents(const GameObject& object) {
|
||||
std::vector<Component*> components;
|
||||
components.reserve(object.GetComponents().size());
|
||||
for (const auto& component : object.GetComponents()) {
|
||||
if (component != nullptr) {
|
||||
components.push_back(component.get());
|
||||
}
|
||||
}
|
||||
return components;
|
||||
}
|
||||
|
||||
bool EnsureComponentStarted(Component& component) {
|
||||
if (!component.HasStarted) {
|
||||
component.Start();
|
||||
component.HasStarted = true;
|
||||
}
|
||||
return !component.IsBeingDestroyed();
|
||||
}
|
||||
}
|
||||
|
||||
GameObject::~GameObject() {
|
||||
// spdlog::debug("GameObject destroyed: {}", GetName());
|
||||
if (!IsBeingDestroyed()) {
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
GameObject::GameObject(const std::string& name)
|
||||
: Object(name),
|
||||
m_Id(s_NextId++) {
|
||||
m_Id(AllocateId()) {
|
||||
}
|
||||
|
||||
void GameObject::SetIdForDeserialization(ObjectId id) {
|
||||
if (id == InvalidObjectId || id >= std::numeric_limits<ObjectId>::max() - 1) {
|
||||
throw std::out_of_range("Object ID is reserved or cannot be incremented");
|
||||
}
|
||||
|
||||
m_Id = id;
|
||||
|
||||
// Prevent newly created objects from reusing loaded IDs.
|
||||
if (id >= s_NextId) {
|
||||
if (id != std::numeric_limits<ObjectId>::max() && id >= s_NextId) {
|
||||
s_NextId = id + 1;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectId GameObject::AllocateId() {
|
||||
if (s_NextId == InvalidObjectId ||
|
||||
s_NextId >= std::numeric_limits<ObjectId>::max() - 1) {
|
||||
throw std::overflow_error("Object ID range exhausted");
|
||||
}
|
||||
return s_NextId++;
|
||||
}
|
||||
|
||||
void GameObject::SetActiveDirty() {
|
||||
m_ActiveDirty = true;
|
||||
|
||||
for (const Transform* child : m_TransformPtr.GetChildren()) {
|
||||
child->GetOwner()->SetActiveDirty();
|
||||
if (child != nullptr && child->GetOwner() != nullptr) {
|
||||
child->GetOwner()->SetActiveDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,8 +75,10 @@ void GameObject::UpdateActiveState() {
|
||||
|
||||
if (parentPtr == nullptr) {
|
||||
m_ActiveInHierarchy = m_Active;
|
||||
} else {
|
||||
} else if (parentPtr->GetOwner() != nullptr) {
|
||||
m_ActiveInHierarchy = m_Active && parentPtr->GetOwner()->IsActiveInHierarchy();
|
||||
} else {
|
||||
m_ActiveInHierarchy = m_Active;
|
||||
}
|
||||
|
||||
m_ActiveDirty = false;
|
||||
@@ -50,61 +92,112 @@ bool GameObject::IsActiveInHierarchy() {
|
||||
return m_ActiveInHierarchy;
|
||||
}
|
||||
|
||||
void GameObject::Update() {
|
||||
for (const auto& component : m_Components) {
|
||||
void GameObject::Update(float dt) {
|
||||
for (Component* component : SnapshotComponents(*this)) {
|
||||
if (component->IsBeingDestroyed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!component->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!component->HasStarted) {
|
||||
component->Start();
|
||||
component->HasStarted = true;
|
||||
if (!EnsureComponentStarted(*component)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
component->Update();
|
||||
component->Update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::LateUpdate() {
|
||||
for (const auto& component : m_Components) {
|
||||
if (component->isEnabled()) {
|
||||
component->LateUpdate();
|
||||
void GameObject::LateUpdate(float dt) {
|
||||
for (Component* component : SnapshotComponents(*this)) {
|
||||
if (component->isEnabled() && !component->IsBeingDestroyed()) {
|
||||
if (!EnsureComponentStarted(*component)) {
|
||||
continue;
|
||||
}
|
||||
component->LateUpdate(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::FixedUpdate() {
|
||||
for (const auto& component : m_Components) {
|
||||
if (component->isEnabled()) {
|
||||
component->FixedUpdate();
|
||||
void GameObject::FixedUpdate(float fixedDt) {
|
||||
for (Component* component : SnapshotComponents(*this)) {
|
||||
if (component->isEnabled() && !component->IsBeingDestroyed()) {
|
||||
if (!EnsureComponentStarted(*component)) {
|
||||
continue;
|
||||
}
|
||||
component->FixedUpdate(fixedDt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::Render(const RenderContext& ctx) const {
|
||||
for (const auto& component : m_Components) {
|
||||
if (component->isEnabled()) {
|
||||
for (Component* component : SnapshotComponents(*this)) {
|
||||
if (component->isEnabled() && !component->IsBeingDestroyed()) {
|
||||
if (!EnsureComponentStarted(*component)) {
|
||||
continue;
|
||||
}
|
||||
component->Render(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::Destroy() {
|
||||
if (IsBeingDestroyed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object::Destroy();
|
||||
|
||||
if (m_Scene != nullptr) {
|
||||
m_Scene->GetPhysics().UnregisterGameObject(*this);
|
||||
}
|
||||
|
||||
for (Component* component : SnapshotComponents(*this)) {
|
||||
if (auto* rigidbody = dynamic_cast<Rigidbody*>(component);
|
||||
rigidbody != nullptr && rigidbody->GetPhysicsWorld() != nullptr) {
|
||||
rigidbody->GetPhysicsWorld()->UnregisterRigidbody(*rigidbody);
|
||||
}
|
||||
}
|
||||
|
||||
m_TransformPtr.SetParent(nullptr);
|
||||
|
||||
for (const auto& component : m_Components) {
|
||||
component->Destroy();
|
||||
for (Component* component : SnapshotComponents(*this)) {
|
||||
if (component != nullptr) {
|
||||
component->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto child : m_TransformPtr.GetChildren()) {
|
||||
child->GetOwner()->Destroy();
|
||||
// Destroying a child detaches it from this transform, so iterate over a
|
||||
// snapshot rather than the live child vector.
|
||||
const std::vector<Transform*> children = m_TransformPtr.GetChildren();
|
||||
for (Transform* child : children) {
|
||||
if (child != nullptr && child->GetOwner() != nullptr) {
|
||||
child->GetOwner()->Destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::CleanupComponents() {
|
||||
for (const auto& component : m_Components) {
|
||||
if (!component || !component->IsBeingDestroyed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto* rigidbody = dynamic_cast<Rigidbody*>(component.get()); rigidbody != nullptr &&
|
||||
rigidbody->GetPhysicsWorld() != nullptr) {
|
||||
rigidbody->GetPhysicsWorld()->UnregisterRigidbody(*rigidbody);
|
||||
}
|
||||
}
|
||||
|
||||
std::erase_if(m_Components, [](const std::unique_ptr<Component>& component) {
|
||||
return component->IsBeingDestroyed();
|
||||
return component == nullptr || component->IsBeingDestroyed();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::RefreshPhysics() {
|
||||
if (m_Scene != nullptr) {
|
||||
m_Scene->RefreshPhysics();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
#include <destrum/ObjectModel/Object.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
Object::~Object() {
|
||||
if (!m_BeingDestroyed) {
|
||||
assert(false && "Objects destructor called before destroy");
|
||||
}
|
||||
// spdlog::debug("Object Destroyed: {}", m_Name);
|
||||
}
|
||||
|
||||
void Object::Destroy() {
|
||||
// spdlog::debug("Object marked for destruction: {}", m_Name);
|
||||
if (m_BeingDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_BeingDestroyed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,53 +1,119 @@
|
||||
#include <destrum/ObjectModel/Transform.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <stdexcept>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtx/matrix_decompose.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
namespace {
|
||||
bool IsChildRecursive(const Transform* parent,
|
||||
const Transform* target,
|
||||
std::unordered_set<const Transform*>& visited) {
|
||||
if (parent == nullptr || !visited.insert(parent).second) {
|
||||
return false;
|
||||
}
|
||||
for (const Transform* candidate : parent->GetChildren()) {
|
||||
if (candidate == target || IsChildRecursive(candidate, target, visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] glm::mat4 ComposeMatrix(const glm::vec3& position,
|
||||
const glm::quat& rotation,
|
||||
const glm::vec3& scale) {
|
||||
return glm::translate(glm::mat4{1.0f}, position)
|
||||
* glm::mat4_cast(rotation)
|
||||
* glm::scale(glm::mat4{1.0f}, scale);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool DecomposeMatrix(const glm::mat4& matrix,
|
||||
glm::vec3& position,
|
||||
glm::quat& rotation,
|
||||
glm::vec3& scale) {
|
||||
glm::vec3 skew{};
|
||||
glm::vec4 perspective{};
|
||||
if (!glm::decompose(matrix, scale, rotation, position, skew, perspective)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (glm::length(skew) > 0.0001f ||
|
||||
glm::length(perspective - glm::vec4{0.0f, 0.0f, 0.0f, 1.0f}) > 0.0001f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const float rotationLength = glm::length(rotation);
|
||||
if (rotationLength <= 0.000001f || !std::isfinite(rotationLength)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rotation = glm::normalize(rotation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Transform::Transform(GameObject* owner): m_Owner(owner) {
|
||||
}
|
||||
|
||||
Transform::~Transform() {
|
||||
SetParent(nullptr);
|
||||
if (m_Parent != nullptr) {
|
||||
Transform* parent = m_Parent;
|
||||
m_Parent = nullptr;
|
||||
parent->RemoveChild(this);
|
||||
}
|
||||
|
||||
for (auto it = m_Children.begin(); it != m_Children.end();) {
|
||||
Transform* child = *it;
|
||||
it = m_Children.erase(it);
|
||||
child->SetParent(nullptr);
|
||||
// Do not call SetParent while the owning object is being torn down. The
|
||||
// parent may already be in its destructor, so update the links directly.
|
||||
const std::vector<Transform*> children = std::move(m_Children);
|
||||
m_Children.clear();
|
||||
for (Transform* child : children) {
|
||||
if (child == nullptr || child->m_Parent != this) {
|
||||
continue;
|
||||
}
|
||||
|
||||
child->m_Parent = nullptr;
|
||||
child->SetPositionDirty();
|
||||
}
|
||||
}
|
||||
|
||||
const glm::vec3& Transform::GetWorldPosition() {
|
||||
if (m_PositionDirty) {
|
||||
UpdateWorldPosition();
|
||||
if (m_PositionDirty || m_RotationDirty || m_ScaleDirty || m_MatrixDirty) {
|
||||
UpdateWorldCache();
|
||||
}
|
||||
return m_WorldPosition;
|
||||
}
|
||||
|
||||
const glm::quat& Transform::GetWorldRotation() {
|
||||
if (m_RotationDirty) {
|
||||
UpdateWorldRotation();
|
||||
if (m_PositionDirty || m_RotationDirty || m_ScaleDirty || m_MatrixDirty) {
|
||||
UpdateWorldCache();
|
||||
}
|
||||
return m_WorldRotation;
|
||||
}
|
||||
|
||||
const glm::vec3& Transform::GetWorldScale() {
|
||||
if (m_ScaleDirty) {
|
||||
UpdateWorldScale();
|
||||
if (m_PositionDirty || m_RotationDirty || m_ScaleDirty || m_MatrixDirty) {
|
||||
UpdateWorldCache();
|
||||
}
|
||||
return m_WorldScale;
|
||||
}
|
||||
|
||||
const glm::mat4& Transform::GetWorldMatrix() {
|
||||
if (m_MatrixDirty) {
|
||||
UpdateWorldMatrix();
|
||||
if (m_PositionDirty || m_RotationDirty || m_ScaleDirty || m_MatrixDirty) {
|
||||
UpdateWorldCache();
|
||||
}
|
||||
return m_WorldMatrix;
|
||||
}
|
||||
|
||||
void Transform::SetWorldPosition(const glm::vec3& position) {
|
||||
if (m_Parent == nullptr) {
|
||||
SetLocalPosition(position);
|
||||
} else {
|
||||
SetLocalPosition(position - m_Parent->GetWorldPosition());
|
||||
}
|
||||
glm::mat4 worldMatrix = GetWorldMatrix();
|
||||
worldMatrix[3] = glm::vec4(position, 1.0f);
|
||||
SetLocalFromWorldMatrix(worldMatrix);
|
||||
}
|
||||
|
||||
void Transform::SetWorldPosition(float x, float y, float z) {
|
||||
@@ -55,11 +121,10 @@ void Transform::SetWorldPosition(float x, float y, float z) {
|
||||
}
|
||||
|
||||
void Transform::SetWorldRotation(const glm::quat& rotation) {
|
||||
if(m_Parent == nullptr) {
|
||||
SetLocalRotation(rotation);
|
||||
} else {
|
||||
SetLocalRotation(glm::inverse(m_Parent->GetWorldRotation()) * rotation);
|
||||
}
|
||||
const glm::vec3 worldPosition = GetWorldPosition();
|
||||
const glm::vec3 worldScale = GetWorldScale();
|
||||
const glm::mat4 worldMatrix = ComposeMatrix(worldPosition, rotation, worldScale);
|
||||
SetLocalFromWorldMatrix(worldMatrix);
|
||||
}
|
||||
|
||||
void Transform::SetWorldRotation(const glm::vec3& rotation) {
|
||||
@@ -75,11 +140,10 @@ void Transform::SetWorldScale(double x, double y, double z) {
|
||||
}
|
||||
|
||||
void Transform::SetWorldScale(const glm::vec3& scale) {
|
||||
if (m_Parent == nullptr) {
|
||||
SetLocalScale(scale);
|
||||
} else {
|
||||
SetLocalScale(scale - m_Parent->GetWorldScale());
|
||||
}
|
||||
const glm::vec3 worldPosition = GetWorldPosition();
|
||||
const glm::quat worldRotation = GetWorldRotation();
|
||||
const glm::mat4 worldMatrix = ComposeMatrix(worldPosition, worldRotation, scale);
|
||||
SetLocalFromWorldMatrix(worldMatrix);
|
||||
}
|
||||
|
||||
void Transform::Move(const glm::vec3& move) {
|
||||
@@ -87,7 +151,7 @@ void Transform::Move(const glm::vec3& move) {
|
||||
}
|
||||
|
||||
void Transform::Move(double x, double y, double z) {
|
||||
this->Move(glm::vec3(x, y, z));
|
||||
Move(glm::vec3(x, y, z));
|
||||
}
|
||||
|
||||
void Transform::SetLocalPosition(const glm::vec3& position) {
|
||||
@@ -108,7 +172,10 @@ void Transform::SetLocalRotation(const glm::vec3& rotation) {
|
||||
}
|
||||
|
||||
void Transform::SetLocalRotation(const glm::quat& rotation) {
|
||||
m_LocalRotation = rotation;
|
||||
const float length = glm::length(rotation);
|
||||
m_LocalRotation = length > 0.000001f
|
||||
? glm::normalize(rotation)
|
||||
: glm::quat{1.0f, 0.0f, 0.0f, 0.0f};
|
||||
SetRotationDirty();
|
||||
}
|
||||
|
||||
@@ -122,132 +189,196 @@ void Transform::SetLocalScale(const glm::vec3& scale) {
|
||||
}
|
||||
|
||||
void Transform::RemoveChild(Transform* transform) {
|
||||
std::erase(m_Children, transform);
|
||||
const auto it = std::find(m_Children.begin(), m_Children.end(), transform);
|
||||
if (it != m_Children.end()) {
|
||||
m_Children.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void Transform::AddChild(Transform* transform) {
|
||||
// if (transform == this or transform == nullptr) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (transform->m_Parent) {
|
||||
// transform->m_Parent->RemoveChild(transform);
|
||||
// }
|
||||
//
|
||||
// transform->SetParent(this);
|
||||
m_Children.push_back(transform);
|
||||
//
|
||||
// transform->SetPositionDirty();
|
||||
}
|
||||
|
||||
void Transform::SetParent(Transform* parent, bool useWorldPosition) {
|
||||
if (parent == m_Parent or parent == this or IsChild(parent)) {
|
||||
if (transform == nullptr || transform == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent == nullptr) {
|
||||
SetLocalPosition(GetWorldPosition());
|
||||
} else {
|
||||
if (std::find(m_Children.begin(), m_Children.end(), transform) != m_Children.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Children.push_back(transform);
|
||||
}
|
||||
|
||||
void Transform::SetParent(Transform* parent, bool useWorldPosition) {
|
||||
if (parent == m_Parent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A transform cannot be parented to itself or to one of its descendants.
|
||||
if (parent == this || IsChild(parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (parent != nullptr) {
|
||||
GameObject* parentOwner = parent->GetOwner();
|
||||
if (parentOwner == nullptr || parentOwner->IsBeingDestroyed() ||
|
||||
(m_Owner != nullptr && m_Owner->GetScene() != parentOwner->GetScene())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
glm::mat4 worldMatrix{1.0f};
|
||||
if (useWorldPosition) {
|
||||
worldMatrix = GetWorldMatrix();
|
||||
}
|
||||
|
||||
Transform* previousParent = m_Parent;
|
||||
if (previousParent != nullptr) {
|
||||
previousParent->RemoveChild(this);
|
||||
}
|
||||
|
||||
m_Parent = parent;
|
||||
if (m_Parent != nullptr) {
|
||||
m_Parent->AddChild(this);
|
||||
}
|
||||
|
||||
if (m_Owner != nullptr) {
|
||||
m_Owner->SetActiveDirty();
|
||||
m_Owner->RefreshPhysics();
|
||||
}
|
||||
|
||||
try {
|
||||
if (useWorldPosition) {
|
||||
SetLocalPosition(GetWorldPosition() - parent->GetWorldPosition());
|
||||
SetLocalFromWorldMatrix(worldMatrix);
|
||||
} else {
|
||||
SetPositionDirty();
|
||||
}
|
||||
} catch (...) {
|
||||
if (m_Parent != nullptr) {
|
||||
m_Parent->RemoveChild(this);
|
||||
}
|
||||
m_Parent = previousParent;
|
||||
if (m_Parent != nullptr) {
|
||||
m_Parent->AddChild(this);
|
||||
}
|
||||
SetPositionDirty();
|
||||
}
|
||||
if (m_Parent) {
|
||||
m_Parent->RemoveChild(this);
|
||||
}
|
||||
m_Parent = parent;
|
||||
if (m_Parent) {
|
||||
m_Parent->AddChild(this);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Transform::IsChild(Transform* child) const {
|
||||
return std::ranges::find(m_Children, child) != m_Children.end();
|
||||
if (child == nullptr) {
|
||||
return false;
|
||||
}
|
||||
std::unordered_set<const Transform*> visited;
|
||||
return IsChildRecursive(this, child, visited);
|
||||
}
|
||||
|
||||
const std::vector<Transform*>& Transform::GetChildren() const {
|
||||
// std::vector<Transform*> validChildren;
|
||||
// for (auto* child : m_Children) {
|
||||
// if (child && !child->GetOwner()->IsBeingDestroyed()) {
|
||||
// validChildren.push_back(child);
|
||||
// }
|
||||
// }
|
||||
// return validChildren;
|
||||
return m_Children;
|
||||
}
|
||||
|
||||
GameObject *Transform::GetOwner() const {
|
||||
GameObject* Transform::GetOwner() const {
|
||||
return m_Owner;
|
||||
}
|
||||
|
||||
void Transform::SetPositionDirty() {
|
||||
m_PositionDirty = true;
|
||||
m_RotationDirty = true;
|
||||
m_ScaleDirty = true;
|
||||
m_MatrixDirty = true;
|
||||
for (const auto child: m_Children) {
|
||||
child->SetPositionDirty();
|
||||
|
||||
for (Transform* child : m_Children) {
|
||||
if (child != nullptr) {
|
||||
child->SetPositionDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Transform::SetRotationDirty() {
|
||||
m_PositionDirty = true;
|
||||
m_RotationDirty = true;
|
||||
m_ScaleDirty = true;
|
||||
m_MatrixDirty = true;
|
||||
|
||||
for(Transform* childPtr : m_Children) {
|
||||
if(not childPtr->m_RotationDirty) {
|
||||
childPtr->SetRotationDirty();
|
||||
for (Transform* child : m_Children) {
|
||||
if (child != nullptr) {
|
||||
child->SetRotationDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Transform::SetScaleDirty() {
|
||||
m_PositionDirty = true;
|
||||
m_RotationDirty = true;
|
||||
m_ScaleDirty = true;
|
||||
m_MatrixDirty = true;
|
||||
|
||||
for(Transform* childPtr : m_Children) {
|
||||
if(not childPtr->m_ScaleDirty) {
|
||||
childPtr->SetScaleDirty();
|
||||
for (Transform* child : m_Children) {
|
||||
if (child != nullptr) {
|
||||
child->SetScaleDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Transform::UpdateWorldPosition() {
|
||||
if (m_Parent) {
|
||||
m_WorldPosition = m_Parent->GetWorldPosition() + m_LocalPosition;
|
||||
} else {
|
||||
m_WorldPosition = m_LocalPosition;
|
||||
}
|
||||
m_PositionDirty = false;
|
||||
UpdateWorldCache();
|
||||
}
|
||||
|
||||
void Transform::UpdateWorldRotation() {
|
||||
if (m_Parent == nullptr) {
|
||||
m_WorldRotation = m_LocalRotation;
|
||||
} else {
|
||||
m_WorldRotation = m_LocalRotation * m_Parent->GetWorldRotation();
|
||||
}
|
||||
|
||||
m_RotationDirty = false;
|
||||
UpdateWorldCache();
|
||||
}
|
||||
|
||||
void Transform::UpdateWorldScale() {
|
||||
if(m_Parent == nullptr) {
|
||||
m_WorldScale = m_LocalScale;
|
||||
} else {
|
||||
m_WorldScale = m_LocalScale * m_Parent->GetWorldScale();
|
||||
}
|
||||
|
||||
m_ScaleDirty = false;
|
||||
UpdateWorldCache();
|
||||
}
|
||||
|
||||
void Transform::UpdateWorldMatrix() {
|
||||
const glm::mat4 trans = glm::translate(glm::mat4(1.0f), GetWorldPosition());
|
||||
const glm::mat4 rot = glm::mat4_cast(GetWorldRotation());
|
||||
const glm::mat4 scale = glm::scale(glm::mat4(1.0f), GetWorldScale());
|
||||
|
||||
m_WorldMatrix = trans * rot * scale;
|
||||
m_MatrixDirty = false;
|
||||
UpdateWorldCache();
|
||||
}
|
||||
|
||||
void Transform::SetLocalFromWorldMatrix(const glm::mat4& worldMatrix) {
|
||||
glm::mat4 localMatrix = worldMatrix;
|
||||
if (m_Parent != nullptr) {
|
||||
const glm::mat4 parentMatrix = m_Parent->GetWorldMatrix();
|
||||
if (std::abs(glm::determinant(parentMatrix)) <= 0.000001f) {
|
||||
throw std::runtime_error("Cannot set a world transform under a singular parent");
|
||||
}
|
||||
localMatrix = glm::inverse(parentMatrix) * worldMatrix;
|
||||
}
|
||||
|
||||
glm::vec3 position{};
|
||||
glm::quat rotation{};
|
||||
glm::vec3 scale{};
|
||||
if (DecomposeMatrix(localMatrix, position, rotation, scale)) {
|
||||
m_LocalPosition = position;
|
||||
m_LocalRotation = rotation;
|
||||
m_LocalScale = scale;
|
||||
} else {
|
||||
throw std::runtime_error("World transform cannot be represented as position/rotation/scale");
|
||||
}
|
||||
|
||||
SetPositionDirty();
|
||||
}
|
||||
|
||||
void Transform::UpdateWorldCache() {
|
||||
if (!m_PositionDirty && !m_RotationDirty && !m_ScaleDirty && !m_MatrixDirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
const glm::mat4 localMatrix = ComposeMatrix(m_LocalPosition, m_LocalRotation, m_LocalScale);
|
||||
m_WorldMatrix = m_Parent != nullptr
|
||||
? m_Parent->GetWorldMatrix() * localMatrix
|
||||
: localMatrix;
|
||||
|
||||
if (!DecomposeMatrix(m_WorldMatrix, m_WorldPosition, m_WorldRotation, m_WorldScale)) {
|
||||
m_WorldPosition = glm::vec3(m_WorldMatrix[3]);
|
||||
m_WorldRotation = m_Parent != nullptr
|
||||
? glm::normalize(m_Parent->GetWorldRotation() * m_LocalRotation)
|
||||
: m_LocalRotation;
|
||||
m_WorldScale = m_LocalScale;
|
||||
}
|
||||
|
||||
m_PositionDirty = false;
|
||||
m_RotationDirty = false;
|
||||
m_ScaleDirty = false;
|
||||
m_MatrixDirty = false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user