From 8b734caeac7e25fc7cc83aeab1ec1966298b61a6 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Fri, 17 Mar 2023 19:22:09 +0100 Subject: [PATCH] Utility/Node: Massively improve skeletal animations performance by allowing to invalidate the whole skeleton only once Thanks to @SirMishaa for pointing that out --- include/Nazara/Utility/Joint.hpp | 12 +- include/Nazara/Utility/Joint.inl | 113 ++++ include/Nazara/Utility/Node.hpp | 136 ++-- include/Nazara/Utility/Node.inl | 488 ++++++++++++++ include/Nazara/Widgets/BaseWidget.hpp | 2 +- .../Components/SharedSkeletonComponent.cpp | 18 +- src/Nazara/Utility/Joint.cpp | 76 +-- src/Nazara/Utility/Node.cpp | 629 +++--------------- src/Nazara/Widgets/BaseWidget.cpp | 4 +- 9 files changed, 783 insertions(+), 695 deletions(-) create mode 100644 include/Nazara/Utility/Joint.inl create mode 100644 include/Nazara/Utility/Node.inl diff --git a/include/Nazara/Utility/Joint.hpp b/include/Nazara/Utility/Joint.hpp index 5de52b274..ee16f5061 100644 --- a/include/Nazara/Utility/Joint.hpp +++ b/include/Nazara/Utility/Joint.hpp @@ -19,8 +19,9 @@ namespace Nz class NAZARA_UTILITY_API Joint : public Node { public: - Joint(Skeleton* skeleton); - Joint(const Joint& joint); + inline Joint(Skeleton* skeleton); + inline Joint(const Joint& joint); + inline Joint(Joint&&) noexcept; ~Joint() = default; void EnsureSkinningMatrixUpdate() const; @@ -34,8 +35,11 @@ namespace Nz void SetInverseBindMatrix(const Matrix4f& matrix); void SetName(std::string name); + inline Joint& operator=(const Joint& joint); + inline Joint& operator=(Joint&& joint) noexcept; + private: - void InvalidateNode() override; + void InvalidateNode(Invalidation invalidation) override; void UpdateSkinningMatrix() const; Matrix4f m_inverseBindMatrix; @@ -46,4 +50,6 @@ namespace Nz }; } +#include + #endif // NAZARA_UTILITY_JOINT_HPP diff --git a/include/Nazara/Utility/Joint.inl b/include/Nazara/Utility/Joint.inl new file mode 100644 index 000000000..ef1390461 --- /dev/null +++ b/include/Nazara/Utility/Joint.inl @@ -0,0 +1,113 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline Joint::Joint(Skeleton* skeleton) : + m_skeleton(skeleton), + m_skinningMatrixUpdated(false) + { + } + + inline Joint::Joint(const Joint& joint) : + Node(joint), + m_inverseBindMatrix(joint.m_inverseBindMatrix), + m_name(joint.m_name), + m_skeleton(joint.m_skeleton), + m_skinningMatrixUpdated(false) + { + } + + inline Joint::Joint(Joint&& joint) noexcept : + Node(std::move(joint)), + m_inverseBindMatrix(joint.m_inverseBindMatrix), + m_name(joint.m_name), + m_skeleton(joint.m_skeleton), + m_skinningMatrixUpdated(false) + { + } + + inline void Joint::EnsureSkinningMatrixUpdate() const + { + if (!m_skinningMatrixUpdated) + UpdateSkinningMatrix(); + } + + inline const Matrix4f& Joint::GetInverseBindMatrix() const + { + return m_inverseBindMatrix; + } + + inline const std::string& Joint::GetName() const + { + return m_name; + } + + inline Skeleton* Joint::GetSkeleton() + { + return m_skeleton; + } + + inline const Skeleton* Joint::GetSkeleton() const + { + return m_skeleton; + } + + inline const Matrix4f& Joint::GetSkinningMatrix() const + { + EnsureSkinningMatrixUpdate(); + return m_skinningMatrix; + } + + inline void Joint::SetInverseBindMatrix(const Matrix4f& matrix) + { + m_inverseBindMatrix = matrix; + m_skinningMatrixUpdated = false; + } + + inline void Joint::SetName(std::string name) + { + m_name = std::move(name); + + m_skeleton->InvalidateJointMap(); + } + + inline Joint& Joint::operator=(const Joint& joint) + { + Node::operator=(joint); + + m_inverseBindMatrix = joint.m_inverseBindMatrix; + m_name = joint.m_name; + m_skeleton = joint.m_skeleton; + m_skinningMatrixUpdated = false; + + return *this; + } + + inline Joint& Joint::operator=(Joint&& joint) noexcept + { + Node::operator=(std::move(joint)); + + m_inverseBindMatrix = joint.m_inverseBindMatrix; + m_name = joint.m_name; + m_skeleton = joint.m_skeleton; + m_skinningMatrixUpdated = false; + + return *this; + } + + inline void Joint::UpdateSkinningMatrix() const + { + EnsureTransformMatrixUpdate(); + + m_skinningMatrix = Matrix4f::ConcatenateTransform(m_inverseBindMatrix, m_transformMatrix); + m_skinningMatrixUpdated = true; + } +} + +#include +#include "Joint.hpp" diff --git a/include/Nazara/Utility/Node.hpp b/include/Nazara/Utility/Node.hpp index 5eb4b81c5..ed2a2a771 100644 --- a/include/Nazara/Utility/Node.hpp +++ b/include/Nazara/Utility/Node.hpp @@ -22,90 +22,102 @@ namespace Nz class NAZARA_UTILITY_API Node { public: - Node(); - Node(const Node& node); - Node(Node&& node) noexcept; + enum class Invalidation; + + inline Node(); + inline Node(const Node& node); + inline Node(Node&& node) noexcept; virtual ~Node(); - void EnsureDerivedUpdate() const; - void EnsureTransformMatrixUpdate() const; + inline void EnsureDerivedUpdate() const; + inline void EnsureTransformMatrixUpdate() const; - virtual Vector3f GetBackward() const; - const std::vector& GetChilds() const; - virtual Vector3f GetDown() const; - virtual Vector3f GetForward() const; - bool GetInheritPosition() const; - bool GetInheritRotation() const; - bool GetInheritScale() const; - Vector3f GetInitialPosition() const; - Quaternionf GetInitialRotation() const; - Vector3f GetInitialScale() const; - virtual Vector3f GetLeft() const; + inline Vector3f GetBackward() const; + inline const std::vector& GetChilds() const; + inline Vector3f GetDown() const; + inline Vector3f GetForward() const; + inline bool GetInheritPosition() const; + inline bool GetInheritRotation() const; + inline bool GetInheritScale() const; + inline Vector3f GetInitialPosition() const; + inline Quaternionf GetInitialRotation() const; + inline Vector3f GetInitialScale() const; + inline Vector3f GetLeft() const; virtual NodeType GetNodeType() const; - const Node* GetParent() const; - Vector3f GetPosition(CoordSys coordSys = CoordSys::Local) const; - virtual Vector3f GetRight() const; - Quaternionf GetRotation(CoordSys coordSys = CoordSys::Local) const; - Vector3f GetScale(CoordSys coordSys = CoordSys::Local) const; - const Matrix4f& GetTransformMatrix() const; - virtual Vector3f GetUp() const; + inline const Node* GetParent() const; + inline Vector3f GetPosition(CoordSys coordSys = CoordSys::Local) const; + inline Vector3f GetRight() const; + inline Quaternionf GetRotation(CoordSys coordSys = CoordSys::Local) const; + inline Vector3f GetScale(CoordSys coordSys = CoordSys::Local) const; + inline const Matrix4f& GetTransformMatrix() const; + inline Vector3f GetUp() const; - bool HasChilds() const; + inline bool HasChilds() const; - Node& Interpolate(const Node& nodeA, const Node& nodeB, float interpolation, CoordSys coordSys = CoordSys::Global); + inline void Invalidate(Invalidation invalidation = Invalidation::InvalidateRecursively); - Node& Move(const Vector3f& movement, CoordSys coordSys = CoordSys::Local); - Node& Move(float movementX, float movementY, float movementZ = 0.f, CoordSys coordSys = CoordSys::Local); + Node& Interpolate(const Node& nodeA, const Node& nodeB, float interpolation, CoordSys coordSys = CoordSys::Global, Invalidation invalidation = Invalidation::InvalidateRecursively); - Node& Rotate(const Quaternionf& rotation, CoordSys coordSys = CoordSys::Local); + Node& Move(const Vector3f& movement, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline Node& Move(float movementX, float movementY, float movementZ = 0.f, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); - Node& Scale(const Vector3f& scale); - Node& Scale(float scale); - Node& Scale(float scaleX, float scaleY, float scaleZ = 1.f); + Node& Rotate(const Quaternionf& rotation, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); - void SetInheritPosition(bool inheritPosition); - void SetInheritRotation(bool inheritRotation); - void SetInheritScale(bool inheritScale); - void SetInitialPosition(const Vector3f& translation); - void SetInitialPosition(float translationX, float translationXY, float translationZ = 0.f); - void SetInitialRotation(const Quaternionf& quat); - void SetInitialScale(const Vector3f& scale); - void SetInitialScale(float scale); - void SetInitialScale(float scaleX, float scaleY, float scaleZ = 1.f); - void SetParent(const Node* node = nullptr, bool keepDerived = false); - void SetParent(const Node& node, bool keepDerived = false); - void SetPosition(const Vector3f& translation, CoordSys coordSys = CoordSys::Local); - void SetPosition(float translationX, float translationY, float translationZ = 0.f, CoordSys coordSys = CoordSys::Local); - void SetRotation(const Quaternionf& quat, CoordSys coordSys = CoordSys::Local); - void SetScale(const Vector2f& scale, CoordSys coordSys = CoordSys::Local); - void SetScale(const Vector3f& scale, CoordSys coordSys = CoordSys::Local); - void SetScale(float scale, CoordSys coordSys = CoordSys::Local); - void SetScale(float scaleX, float scaleY, float scaleZ = 1.f, CoordSys coordSys = CoordSys::Local); - void SetTransformMatrix(const Matrix4f& matrix); + inline Node& Scale(const Vector3f& scale, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline Node& Scale(float scale, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline Node& Scale(float scaleX, float scaleY, float scaleZ = 1.f, Invalidation invalidation = Invalidation::InvalidateRecursively); + + inline void SetInheritPosition(bool inheritPosition, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInheritRotation(bool inheritRotation, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInheritScale(bool inheritScale, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInitialPosition(const Vector3f& translation, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInitialPosition(float translationX, float translationXY, float translationZ = 0.f, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInitialRotation(const Quaternionf& quat, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInitialScale(const Vector3f& scale, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInitialScale(float scale, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetInitialScale(float scaleX, float scaleY, float scaleZ = 1.f, Invalidation invalidation = Invalidation::InvalidateRecursively); + void SetParent(const Node* node = nullptr, bool keepDerived = false, Invalidation invalidation = Invalidation::InvalidateRecursively); + void SetParent(const Node& node, bool keepDerived = false, Invalidation invalidation = Invalidation::InvalidateRecursively); + void SetPosition(const Vector3f& translation, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetPosition(float translationX, float translationY, float translationZ = 0.f, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + void SetRotation(const Quaternionf& rotation, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetScale(const Vector2f& scale, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + void SetScale(const Vector3f& scale, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetScale(float scale, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetScale(float scaleX, float scaleY, float scaleZ = 1.f, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale, CoordSys coordSys = CoordSys::Local, Invalidation invalidation = Invalidation::InvalidateRecursively); + inline void SetTransformMatrix(const Matrix4f& matrix, Invalidation invalidation = Invalidation::InvalidateRecursively); // Local -> global - Vector3f ToGlobalPosition(const Vector3f& localPosition) const; - Quaternionf ToGlobalRotation(const Quaternionf& localRotation) const; - Vector3f ToGlobalScale(const Vector3f& localScale) const; + inline Vector3f ToGlobalPosition(const Vector3f& localPosition) const; + inline Quaternionf ToGlobalRotation(const Quaternionf& localRotation) const; + inline Vector3f ToGlobalScale(const Vector3f& localScale) const; // Global -> local - Vector3f ToLocalPosition(const Vector3f& globalPosition) const; - Quaternionf ToLocalRotation(const Quaternionf& globalRotation) const; - Vector3f ToLocalScale(const Vector3f& globalScale) const; + inline Vector3f ToLocalPosition(const Vector3f& globalPosition) const; + inline Quaternionf ToLocalRotation(const Quaternionf& globalRotation) const; + inline Vector3f ToLocalScale(const Vector3f& globalScale) const; - Node& operator=(const Node& node); - Node& operator=(Node&& node) noexcept; + inline Node& operator=(const Node& node); + inline Node& operator=(Node&& node) noexcept; // Signals: NazaraSignal(OnNodeInvalidation, const Node* /*node*/); NazaraSignal(OnNodeNewParent, const Node* /*node*/, const Node* /*parent*/); NazaraSignal(OnNodeRelease, const Node* /*node*/); + enum class Invalidation + { + InvalidateRecursively, + InvalidateNodeOnly, + DontInvalidate + }; + protected: - void AddChild(Node* node) const; - virtual void InvalidateNode(); + inline void AddChild(Node* node) const; + virtual void InvalidateNode(Invalidation invalidation); virtual void OnParenting(const Node* parent); - void RemoveChild(Node* node) const; + inline void RemoveChild(Node* node) const; virtual void UpdateDerived() const; virtual void UpdateTransformMatrix() const; @@ -129,4 +141,6 @@ namespace Nz }; } +#include + #endif // NAZARA_UTILITY_NODE_HPP diff --git a/include/Nazara/Utility/Node.inl b/include/Nazara/Utility/Node.inl new file mode 100644 index 000000000..8bc79c48e --- /dev/null +++ b/include/Nazara/Utility/Node.inl @@ -0,0 +1,488 @@ +// Copyright (C) 2023 Jérôme "Lynix" Leclercq (lynix680@gmail.com) +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + inline Node::Node() : + m_initialRotation(Quaternionf::Identity()), + m_rotation(Quaternionf::Identity()), + m_initialPosition(Vector3f::Zero()), + m_initialScale(Vector3f(1.f, 1.f, 1.f)), + m_position(Vector3f::Zero()), + m_scale(Vector3f(1.f, 1.f, 1.f)), + m_parent(nullptr), + m_derivedUpdated(false), + m_inheritPosition(true), + m_inheritRotation(true), + m_inheritScale(true), + m_transformMatrixUpdated(false) + { + } + + inline Node::Node(const Node& node) : + m_initialRotation(node.m_initialRotation), + m_rotation(node.m_rotation), + m_initialPosition(node.m_initialPosition), + m_initialScale(node.m_initialScale), + m_position(node.m_position), + m_scale(node.m_scale), + m_parent(nullptr), + m_derivedUpdated(false), + m_inheritPosition(node.m_inheritPosition), + m_inheritRotation(node.m_inheritRotation), + m_inheritScale(node.m_inheritScale), + m_transformMatrixUpdated(false) + { + SetParent(node.m_parent, false); + } + + inline Node::Node(Node&& node) noexcept : + OnNodeInvalidation(std::move(node.OnNodeInvalidation)), + OnNodeNewParent(std::move(node.OnNodeNewParent)), + OnNodeRelease(std::move(node.OnNodeRelease)), + m_childs(std::move(node.m_childs)), + m_initialRotation(node.m_initialRotation), + m_rotation(node.m_rotation), + m_initialPosition(node.m_initialPosition), + m_initialScale(node.m_initialScale), + m_position(node.m_position), + m_scale(node.m_scale), + m_parent(node.m_parent), + m_derivedUpdated(false), + m_inheritPosition(node.m_inheritPosition), + m_inheritRotation(node.m_inheritRotation), + m_inheritScale(node.m_inheritScale), + m_transformMatrixUpdated(false) + { + if (m_parent) + { + m_parent->RemoveChild(&node); + m_parent->AddChild(this); + node.m_parent = nullptr; + } + + for (Node* child : m_childs) + child->m_parent = this; + } + + inline void Node::EnsureDerivedUpdate() const + { + if (!m_derivedUpdated) + UpdateDerived(); + } + + inline void Node::EnsureTransformMatrixUpdate() const + { + if (!m_transformMatrixUpdated) + UpdateTransformMatrix(); + } + + inline Vector3f Node::GetBackward() const + { + EnsureDerivedUpdate(); + return m_derivedRotation * Vector3f::Backward(); + } + + inline const std::vector& Node::GetChilds() const + { + return m_childs; + } + + inline Vector3f Node::GetDown() const + { + EnsureDerivedUpdate(); + return m_derivedRotation * Vector3f::Down(); + } + + inline Vector3f Node::GetForward() const + { + EnsureDerivedUpdate(); + return m_derivedRotation * Vector3f::Forward(); + } + + inline bool Node::GetInheritPosition() const + { + return m_inheritPosition; + } + + inline bool Node::GetInheritRotation() const + { + return m_inheritRotation; + } + + inline bool Node::GetInheritScale() const + { + return m_inheritScale; + } + + inline Vector3f Node::GetInitialPosition() const + { + return m_initialPosition; + } + + inline Quaternionf Node::GetInitialRotation() const + { + return m_initialRotation; + } + + inline Vector3f Node::GetInitialScale() const + { + return m_initialScale; + } + + inline Vector3f Node::GetLeft() const + { + EnsureDerivedUpdate(); + return m_derivedRotation * Vector3f::Left(); + } + + inline const Node* Node::GetParent() const + { + return m_parent; + } + + inline Vector3f Node::GetPosition(CoordSys coordSys) const + { + switch (coordSys) + { + case CoordSys::Global: + EnsureDerivedUpdate(); + return m_derivedPosition; + + case CoordSys::Local: + return m_position; + } + + NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); + return Vector3f(); + } + + inline Vector3f Node::GetRight() const + { + EnsureDerivedUpdate(); + return m_derivedRotation * Vector3f::Right(); + } + + inline Quaternionf Node::GetRotation(CoordSys coordSys) const + { + switch (coordSys) + { + case CoordSys::Global: + EnsureDerivedUpdate(); + return m_derivedRotation; + + case CoordSys::Local: + return m_rotation; + } + + NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); + return Quaternionf(); + } + + inline Vector3f Node::GetScale(CoordSys coordSys) const + { + switch (coordSys) + { + case CoordSys::Global: + EnsureDerivedUpdate(); + return m_derivedScale; + + case CoordSys::Local: + return m_scale; + } + + NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); + return Vector3f(); + } + + inline const Matrix4f& Node::GetTransformMatrix() const + { + EnsureTransformMatrixUpdate(); + return m_transformMatrix; + } + + inline Vector3f Node::GetUp() const + { + EnsureDerivedUpdate(); + return m_derivedRotation * Vector3f::Up(); + } + + inline bool Node::HasChilds() const + { + return !m_childs.empty(); + } + + inline void Node::Invalidate(Invalidation invalidation) + { + if (invalidation != Invalidation::DontInvalidate) + InvalidateNode(invalidation); + } + + inline Node& Node::Move(float moveX, float moveY, float moveZ, CoordSys coordSys, Invalidation invalidation) + { + return Move(Vector3f(moveX, moveY, moveZ), coordSys, invalidation); + } + + inline Node& Node::Scale(const Vector3f& scale, Invalidation invalidation) + { + m_scale *= scale; + + Invalidate(invalidation); + + return *this; + } + + inline Node& Node::Scale(float scale, Invalidation invalidation) + { + m_scale *= scale; + + Invalidate(invalidation); + + return *this; + } + + inline Node& Node::Scale(float scaleX, float scaleY, float scaleZ, Invalidation invalidation) + { + m_scale.x *= scaleX; + m_scale.y *= scaleY; + m_scale.z *= scaleZ; + + Invalidate(invalidation); + + return *this; + } + + inline void Node::SetInheritPosition(bool inheritPosition, Invalidation invalidation) + { + ///DOC: Un appel redondant est sans effet + if (m_inheritPosition != inheritPosition) + { + m_inheritPosition = inheritPosition; + + Invalidate(invalidation); + } + } + + inline void Node::SetInheritRotation(bool inheritRotation, Invalidation invalidation) + { + ///DOC: Un appel redondant est sans effet + if (m_inheritRotation != inheritRotation) + { + m_inheritRotation = inheritRotation; + + Invalidate(invalidation); + } + } + + inline void Node::SetInheritScale(bool inheritScale, Invalidation invalidation) + { + ///DOC: Un appel redondant est sans effet + if (m_inheritScale != inheritScale) + { + m_inheritScale = inheritScale; + + Invalidate(invalidation); + } + } + + inline void Node::SetInitialPosition(const Vector3f& position, Invalidation invalidation) + { + m_initialPosition = position; + + Invalidate(invalidation); + } + + inline void Node::SetInitialPosition(float positionX, float positionY, float positionZ, Invalidation invalidation) + { + m_initialPosition.Set(positionX, positionY, positionZ); + + Invalidate(invalidation); + } + + inline void Node::SetInitialRotation(const Quaternionf& rotation, Invalidation invalidation) + { + m_initialRotation = rotation; + + Invalidate(invalidation); + } + + inline void Node::SetInitialScale(const Vector3f& scale, Invalidation invalidation) + { + m_initialScale = scale; + + Invalidate(invalidation); + } + + inline void Node::SetInitialScale(float scale, Invalidation invalidation) + { + m_initialScale.Set(scale); + + Invalidate(invalidation); + } + + inline void Node::SetInitialScale(float scaleX, float scaleY, float scaleZ, Invalidation invalidation) + { + m_initialScale.Set(scaleX, scaleY, scaleZ); + + Invalidate(invalidation); + } + + inline void Node::SetParent(const Node& node, bool keepDerived, Invalidation invalidation) + { + SetParent(&node, keepDerived, invalidation); + } + + inline void Node::SetPosition(float positionX, float positionY, float positionZ, CoordSys coordSys, Invalidation invalidation) + { + SetPosition(Vector3f(positionX, positionY, positionZ), coordSys, invalidation); + } + + inline void Node::SetScale(const Vector2f& scale, CoordSys coordSys, Invalidation invalidation) + { + // Prevent Z scale at zero (can happen when using SetScale with a Vec2) + SetScale(scale.x, scale.y, 1.f, coordSys, invalidation); + } + + inline void Node::SetScale(float scale, CoordSys coordSys, Invalidation invalidation) + { + SetScale(Vector3f(scale), coordSys, invalidation); + } + + inline void Node::SetScale(float scaleX, float scaleY, float scaleZ, CoordSys coordSys, Invalidation invalidation) + { + SetScale(Vector3f(scaleX, scaleY, scaleZ), coordSys, invalidation); + } + + inline void Node::SetTransformMatrix(const Matrix4f& matrix, Invalidation invalidation) + { + SetPosition(matrix.GetTranslation(), CoordSys::Global, Invalidation::DontInvalidate); + SetRotation(matrix.GetRotation(), CoordSys::Global, Invalidation::DontInvalidate); + SetScale(matrix.GetScale(), CoordSys::Global, Invalidation::DontInvalidate); + + Invalidate(invalidation); + + m_transformMatrix = matrix; + m_transformMatrixUpdated = true; + } + + inline Vector3f Node::ToGlobalPosition(const Vector3f& localPosition) const + { + EnsureDerivedUpdate(); + return TransformPositionTRS(m_derivedPosition, m_derivedRotation, m_derivedScale, localPosition); + } + + inline Quaternionf Node::ToGlobalRotation(const Quaternionf& localRotation) const + { + EnsureDerivedUpdate(); + return TransformRotationTRS(m_derivedRotation, m_derivedScale, localRotation); + } + + inline Vector3f Node::ToGlobalScale(const Vector3f& localScale) const + { + EnsureDerivedUpdate(); + return TransformScaleTRS(m_derivedScale, localScale); + } + + inline Vector3f Node::ToLocalPosition(const Vector3f& globalPosition) const + { + EnsureDerivedUpdate(); + return m_derivedRotation.GetConjugate() * (globalPosition - m_derivedPosition) / m_derivedScale; + } + + inline Quaternionf Node::ToLocalRotation(const Quaternionf& globalRotation) const + { + EnsureDerivedUpdate(); + return m_derivedRotation.GetConjugate() * globalRotation; + } + + inline Vector3f Node::ToLocalScale(const Vector3f& globalScale) const + { + EnsureDerivedUpdate(); + return globalScale / m_derivedScale; + } + + inline Node& Node::operator=(const Node& node) + { + SetParent(node.m_parent, false, Invalidation::DontInvalidate); + + m_inheritPosition = node.m_inheritPosition; + m_inheritRotation = node.m_inheritRotation; + m_inheritScale = node.m_inheritScale; + m_initialPosition = node.m_initialPosition; + m_initialRotation = node.m_initialRotation; + m_initialScale = node.m_initialScale; + m_position = node.m_position; + m_rotation = node.m_rotation; + m_scale = node.m_scale; + + InvalidateNode(Invalidation::InvalidateRecursively); + + return *this; + } + + inline Node& Node::operator=(Node&& node) noexcept + { + if (m_parent) + SetParent(nullptr); + + m_inheritPosition = node.m_inheritPosition; + m_inheritRotation = node.m_inheritRotation; + m_inheritScale = node.m_inheritScale; + m_initialPosition = node.m_initialPosition; + m_initialRotation = node.m_initialRotation; + m_initialScale = node.m_initialScale; + m_position = node.m_position; + m_rotation = node.m_rotation; + m_scale = node.m_scale; + + m_childs = std::move(node.m_childs); + for (Node* child : m_childs) + child->m_parent = this; + + m_parent = node.m_parent; + if (m_parent) + { + m_parent->RemoveChild(&node); + m_parent->AddChild(this); + node.m_parent = nullptr; + } + + OnNodeInvalidation = std::move(node.OnNodeInvalidation); + OnNodeNewParent = std::move(node.OnNodeNewParent); + OnNodeRelease = std::move(node.OnNodeRelease); + + InvalidateNode(Invalidation::InvalidateRecursively); + + return *this; + } + + inline void Node::AddChild(Node* node) const + { +#ifdef NAZARA_DEBUG + if (std::find(m_childs.begin(), m_childs.end(), node) != m_childs.end()) + { + NazaraWarning("Child node is already a child of parent node"); + return; + } +#endif + + m_childs.push_back(node); + } + + inline void Node::RemoveChild(Node* node) const + { + auto it = std::find(m_childs.begin(), m_childs.end(), node); + if (it != m_childs.end()) + m_childs.erase(it); + else + NazaraWarning("Child not found"); + } +} + +#include diff --git a/include/Nazara/Widgets/BaseWidget.hpp b/include/Nazara/Widgets/BaseWidget.hpp index 87757b20b..6e5b33e62 100644 --- a/include/Nazara/Widgets/BaseWidget.hpp +++ b/include/Nazara/Widgets/BaseWidget.hpp @@ -118,7 +118,7 @@ namespace Nz inline entt::registry& GetRegistry(); inline const entt::registry& GetRegistry() const; - void InvalidateNode() override; + void InvalidateNode(Invalidation invalidation) override; Rectf GetScissorRect() const; diff --git a/src/Nazara/Utility/Components/SharedSkeletonComponent.cpp b/src/Nazara/Utility/Components/SharedSkeletonComponent.cpp index 7b1965534..5f71867e1 100644 --- a/src/Nazara/Utility/Components/SharedSkeletonComponent.cpp +++ b/src/Nazara/Utility/Components/SharedSkeletonComponent.cpp @@ -77,19 +77,19 @@ namespace Nz void SharedSkeletonComponent::UpdateAttachedSkeletonJoints() { - assert(m_referenceSkeleton->GetJointCount() == m_attachedSkeleton.GetJointCount()); std::size_t jointCount = m_referenceSkeleton->GetJointCount(); + assert(jointCount == m_attachedSkeleton.GetJointCount()); + if (jointCount == 0) + return; // TODO: This will trigger a lot of invalidation which can be avoided - for (std::size_t i = 0; i < jointCount; ++i) - { - const Joint* referenceJoint = m_referenceSkeleton->GetJoint(i); - Joint* attachedJoint = m_attachedSkeleton.GetJoint(i); + const Joint* referenceJoints = m_referenceSkeleton->GetJoints(); + Joint* attachedJoints = m_attachedSkeleton.GetJoints(); - attachedJoint->SetPosition(referenceJoint->GetPosition()); - attachedJoint->SetRotation(referenceJoint->GetRotation()); - attachedJoint->SetScale(referenceJoint->GetScale()); - } + for (std::size_t i = 0; i < jointCount; ++i) + attachedJoints[i].SetTransform(referenceJoints[i].GetPosition(), referenceJoints[i].GetRotation(), referenceJoints[i].GetScale(), CoordSys::Local, Node::Invalidation::DontInvalidate); + + m_attachedSkeleton.GetRootJoint()->Invalidate(); m_skeletonJointInvalidated = false; } diff --git a/src/Nazara/Utility/Joint.cpp b/src/Nazara/Utility/Joint.cpp index a136c440c..b8355e263 100644 --- a/src/Nazara/Utility/Joint.cpp +++ b/src/Nazara/Utility/Joint.cpp @@ -3,86 +3,14 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include #include namespace Nz { - Joint::Joint(Skeleton* skeleton) : - m_skeleton(skeleton), - m_skinningMatrixUpdated(false) + void Joint::InvalidateNode(Invalidation invalidation) { - } - - Joint::Joint(const Joint& joint) : - Node(joint), - m_inverseBindMatrix(joint.m_inverseBindMatrix), - m_name(joint.m_name), - m_skeleton(joint.m_skeleton), - m_skinningMatrixUpdated(false) - { - } - - void Joint::EnsureSkinningMatrixUpdate() const - { - if (!m_skinningMatrixUpdated) - UpdateSkinningMatrix(); - } - - const Matrix4f& Joint::GetInverseBindMatrix() const - { - return m_inverseBindMatrix; - } - - const std::string& Joint::GetName() const - { - return m_name; - } - - Skeleton* Joint::GetSkeleton() - { - return m_skeleton; - } - - const Skeleton* Joint::GetSkeleton() const - { - return m_skeleton; - } - - const Matrix4f& Joint::GetSkinningMatrix() const - { - if (!m_skinningMatrixUpdated) - UpdateSkinningMatrix(); - - return m_skinningMatrix; - } - - void Joint::SetInverseBindMatrix(const Matrix4f& matrix) - { - m_inverseBindMatrix = matrix; - m_skinningMatrixUpdated = false; - } - - void Joint::SetName(std::string name) - { - m_name = std::move(name); - - m_skeleton->InvalidateJointMap(); - } - - void Joint::InvalidateNode() - { - Node::InvalidateNode(); + Node::InvalidateNode(invalidation); m_skinningMatrixUpdated = false; } - - void Joint::UpdateSkinningMatrix() const - { - if (!m_transformMatrixUpdated) - UpdateTransformMatrix(); - - m_skinningMatrix = Matrix4f::ConcatenateTransform(m_inverseBindMatrix, m_transformMatrix); - m_skinningMatrixUpdated = true; - } } diff --git a/src/Nazara/Utility/Node.cpp b/src/Nazara/Utility/Node.cpp index e768dab19..8d5ff2cd6 100644 --- a/src/Nazara/Utility/Node.cpp +++ b/src/Nazara/Utility/Node.cpp @@ -3,74 +3,10 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include #include namespace Nz { - Node::Node() : - m_initialRotation(Quaternionf::Identity()), - m_rotation(Quaternionf::Identity()), - m_initialPosition(Vector3f::Zero()), - m_initialScale(Vector3f(1.f, 1.f, 1.f)), - m_position(Vector3f::Zero()), - m_scale(Vector3f(1.f, 1.f, 1.f)), - m_parent(nullptr), - m_derivedUpdated(false), - m_inheritPosition(true), - m_inheritRotation(true), - m_inheritScale(true), - m_transformMatrixUpdated(false) - { - } - - Node::Node(const Node& node) : - m_initialRotation(node.m_initialRotation), - m_rotation(node.m_rotation), - m_initialPosition(node.m_initialPosition), - m_initialScale(node.m_initialScale), - m_position(node.m_position), - m_scale(node.m_scale), - m_parent(nullptr), - m_derivedUpdated(false), - m_inheritPosition(node.m_inheritPosition), - m_inheritRotation(node.m_inheritRotation), - m_inheritScale(node.m_inheritScale), - m_transformMatrixUpdated(false) - { - SetParent(node.m_parent, false); - } - - Node::Node(Node&& node) noexcept : - OnNodeInvalidation(std::move(node.OnNodeInvalidation)), - OnNodeNewParent(std::move(node.OnNodeNewParent)), - OnNodeRelease(std::move(node.OnNodeRelease)), - m_childs(std::move(node.m_childs)), - m_initialRotation(node.m_initialRotation), - m_rotation(node.m_rotation), - m_initialPosition(node.m_initialPosition), - m_initialScale(node.m_initialScale), - m_position(node.m_position), - m_scale(node.m_scale), - m_parent(node.m_parent), - m_derivedUpdated(false), - m_inheritPosition(node.m_inheritPosition), - m_inheritRotation(node.m_inheritRotation), - m_inheritScale(node.m_inheritScale), - m_transformMatrixUpdated(false) - { - if (m_parent) - { - m_parent->RemoveChild(&node); - m_parent->AddChild(this); - node.m_parent = nullptr; - } - - for (Node* child : m_childs) - child->m_parent = this; - } - Node::~Node() { OnNodeRelease(this); @@ -79,195 +15,25 @@ namespace Nz { // child->SetParent(nullptr); serait problématique car elle nous appellerait child->m_parent = nullptr; - child->InvalidateNode(); + child->InvalidateNode(Invalidation::InvalidateRecursively); child->OnParenting(nullptr); } SetParent(nullptr); } - void Node::EnsureDerivedUpdate() const - { - if (!m_derivedUpdated) - UpdateDerived(); - } - - void Node::EnsureTransformMatrixUpdate() const - { - if (!m_transformMatrixUpdated) - UpdateTransformMatrix(); - } - - Vector3f Node::GetBackward() const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation * Vector3f::Backward(); - } - - const std::vector& Node::GetChilds() const - { - return m_childs; - } - - Vector3f Node::GetDown() const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation * Vector3f::Down(); - } - - Vector3f Node::GetForward() const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation * Vector3f::Forward(); - } - - bool Node::GetInheritPosition() const - { - return m_inheritPosition; - } - - bool Node::GetInheritRotation() const - { - return m_inheritRotation; - } - - bool Node::GetInheritScale() const - { - return m_inheritScale; - } - - Vector3f Node::GetInitialPosition() const - { - return m_initialPosition; - } - - Quaternionf Node::GetInitialRotation() const - { - return m_initialRotation; - } - - Vector3f Node::GetInitialScale() const - { - return m_initialScale; - } - - Vector3f Node::GetLeft() const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation * Vector3f::Left(); - } - NodeType Node::GetNodeType() const { return NodeType::Default; } - const Node* Node::GetParent() const - { - return m_parent; - } - - Vector3f Node::GetPosition(CoordSys coordSys) const + Node& Node::Interpolate(const Node& nodeA, const Node& nodeB, float interpolation, CoordSys coordSys, Invalidation invalidation) { switch (coordSys) { case CoordSys::Global: - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedPosition; - - case CoordSys::Local: - return m_position; - } - - NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); - return Vector3f(); - } - - Vector3f Node::GetRight() const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation * Vector3f::Right(); - } - - Quaternionf Node::GetRotation(CoordSys coordSys) const - { - switch (coordSys) - { - case CoordSys::Global: - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation; - - case CoordSys::Local: - return m_rotation; - } - - NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); - return Quaternionf(); - } - - Vector3f Node::GetScale(CoordSys coordSys) const - { - switch (coordSys) - { - case CoordSys::Global: - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedScale; - - case CoordSys::Local: - return m_scale; - } - - NazaraError("Coordinate system out of enum (0x" + NumberToString(UnderlyingCast(coordSys), 16) + ')'); - return Vector3f(); - } - - const Matrix4f& Node::GetTransformMatrix() const - { - if (!m_transformMatrixUpdated) - UpdateTransformMatrix(); - - return m_transformMatrix; - } - - Vector3f Node::GetUp() const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation * Vector3f::Up(); - } - - bool Node::HasChilds() const - { - return !m_childs.empty(); - } - - Node& Node::Interpolate(const Node& nodeA, const Node& nodeB, float interpolation, CoordSys coordSys) - { - switch (coordSys) - { - case CoordSys::Global: - if (!nodeA.m_derivedUpdated) - nodeA.UpdateDerived(); - - if (!nodeB.m_derivedUpdated) - nodeB.UpdateDerived(); + nodeA.EnsureDerivedUpdate(); + nodeB.EnsureDerivedUpdate(); m_position = ToLocalPosition(Vector3f::Lerp(nodeA.m_derivedPosition, nodeB.m_derivedPosition, interpolation)); m_rotation = ToLocalRotation(Quaternionf::Slerp(nodeA.m_derivedRotation, nodeB.m_derivedRotation, interpolation)); @@ -281,11 +47,12 @@ namespace Nz break; } - InvalidateNode(); + Invalidate(invalidation); + return *this; } - Node& Node::Move(const Vector3f& movement, CoordSys coordSys) + Node& Node::Move(const Vector3f& movement, CoordSys coordSys, Invalidation invalidation) { switch (coordSys) { @@ -293,8 +60,7 @@ namespace Nz { if (m_parent) { - if (!m_parent->m_derivedUpdated) - m_parent->UpdateDerived(); + m_parent->EnsureDerivedUpdate(); m_position += (m_parent->m_derivedRotation.GetConjugate()*(movement - m_parent->m_derivedPosition))/m_parent->m_derivedScale; // Compensation } @@ -309,146 +75,36 @@ namespace Nz break; } - InvalidateNode(); + Invalidate(invalidation); + return *this; } - Node& Node::Move(float moveX, float moveY, float moveZ, CoordSys coordSys) + Node& Node::Rotate(const Quaternionf& rotation, CoordSys coordSys, Invalidation invalidation) { - return Move(Vector3f(moveX, moveY, moveZ), coordSys); - } - - Node& Node::Rotate(const Quaternionf& rotation, CoordSys coordSys) - { - // Évitons toute mauvaise surprise .. - Quaternionf q(rotation); - q.Normalize(); - switch (coordSys) { case CoordSys::Global: { - if (!m_derivedUpdated) - UpdateDerived(); + EnsureDerivedUpdate(); - m_rotation *= m_derivedRotation.GetInverse() * q * m_derivedRotation; ///FIXME: Correct ? + m_rotation *= m_derivedRotation.GetInverse() * rotation * m_derivedRotation; ///FIXME: Correct ? break; } case CoordSys::Local: - m_rotation *= q; + m_rotation *= rotation; break; } m_rotation.Normalize(); - InvalidateNode(); + Invalidate(invalidation); + return *this; } - Node& Node::Scale(const Vector3f& scale) - { - m_scale *= scale; - - InvalidateNode(); - return *this; - } - - Node& Node::Scale(float scale) - { - m_scale *= scale; - - InvalidateNode(); - return *this; - } - - Node& Node::Scale(float scaleX, float scaleY, float scaleZ) - { - m_scale.x *= scaleX; - m_scale.y *= scaleY; - m_scale.z *= scaleZ; - - InvalidateNode(); - return *this; - } - - void Node::SetInheritPosition(bool inheritPosition) - { - ///DOC: Un appel redondant est sans effet - if (m_inheritPosition != inheritPosition) - { - m_inheritPosition = inheritPosition; - - InvalidateNode(); - } - } - - void Node::SetInheritRotation(bool inheritRotation) - { - ///DOC: Un appel redondant est sans effet - if (m_inheritRotation != inheritRotation) - { - m_inheritRotation = inheritRotation; - - InvalidateNode(); - } - } - - void Node::SetInheritScale(bool inheritScale) - { - ///DOC: Un appel redondant est sans effet - if (m_inheritScale != inheritScale) - { - m_inheritScale = inheritScale; - - InvalidateNode(); - } - } - - void Node::SetInitialPosition(const Vector3f& position) - { - m_initialPosition = position; - - InvalidateNode(); - } - - void Node::SetInitialPosition(float positionX, float positionY, float positionZ) - { - m_initialPosition.Set(positionX, positionY, positionZ); - - InvalidateNode(); - } - - void Node::SetInitialRotation(const Quaternionf& rotation) - { - m_initialRotation = rotation; - m_initialRotation.Normalize(); // Évitons toute mauvaise surprise ... - - InvalidateNode(); - } - - void Node::SetInitialScale(const Vector3f& scale) - { - m_initialScale = scale; - - InvalidateNode(); - } - - void Node::SetInitialScale(float scale) - { - m_initialScale.Set(scale); - - InvalidateNode(); - } - - void Node::SetInitialScale(float scaleX, float scaleY, float scaleZ) - { - m_initialScale.Set(scaleX, scaleY, scaleZ); - - InvalidateNode(); - } - - void Node::SetParent(const Node* node, bool keepDerived) + void Node::SetParent(const Node* node, bool keepDerived, Invalidation invalidation) { #if NAZARA_UTILITY_SAFE // On vérifie que le node n'est pas son propre parent @@ -470,8 +126,7 @@ namespace Nz if (keepDerived) { - if (!m_derivedUpdated) - UpdateDerived(); + EnsureDerivedUpdate(); if (m_parent) m_parent->RemoveChild(this); @@ -480,9 +135,11 @@ namespace Nz if (m_parent) m_parent->AddChild(this); - SetRotation(m_derivedRotation, CoordSys::Global); - SetScale(m_derivedScale, CoordSys::Global); - SetPosition(m_derivedPosition, CoordSys::Global); + SetRotation(m_derivedRotation, CoordSys::Global, Invalidation::DontInvalidate); + SetScale(m_derivedScale, CoordSys::Global, Invalidation::DontInvalidate); + SetPosition(m_derivedPosition, CoordSys::Global, Invalidation::DontInvalidate); + + Invalidate(invalidation); } else { @@ -493,52 +150,39 @@ namespace Nz if (m_parent) m_parent->AddChild(this); - InvalidateNode(); + Invalidate(invalidation); } OnParenting(node); } - void Node::SetParent(const Node& node, bool keepDerived) - { - SetParent(&node, keepDerived); - } - - void Node::SetPosition(const Vector3f& position, CoordSys coordSys) + void Node::SetPosition(const Vector3f& position, CoordSys coordSys, Invalidation invalidation) { switch (coordSys) { case CoordSys::Global: + { if (m_parent && m_inheritPosition) { - if (!m_parent->m_derivedUpdated) - m_parent->UpdateDerived(); + m_parent->EnsureDerivedUpdate(); - m_position = (m_parent->m_derivedRotation.GetConjugate()*(position - m_parent->m_derivedPosition))/m_parent->m_derivedScale - m_initialPosition; + m_position = (m_parent->m_derivedRotation.GetConjugate() * (position - m_parent->m_derivedPosition)) / m_parent->m_derivedScale - m_initialPosition; } else m_position = position - m_initialPosition; break; + } case CoordSys::Local: m_position = position; break; } - InvalidateNode(); + Invalidate(invalidation); } - void Node::SetPosition(float positionX, float positionY, float positionZ, CoordSys coordSys) + void Node::SetRotation(const Quaternionf& rotation, CoordSys coordSys, Invalidation invalidation) { - SetPosition(Vector3f(positionX, positionY, positionZ), coordSys); - } - - void Node::SetRotation(const Quaternionf& rotation, CoordSys coordSys) - { - // Évitons toute mauvaise surprise .. - Quaternionf q(rotation); - q.Normalize(); - switch (coordSys) { case CoordSys::Global: @@ -546,28 +190,22 @@ namespace Nz { Quaternionf rot(m_parent->GetRotation() * m_initialRotation); - m_rotation = rot.GetConjugate() * q; + m_rotation = rot.GetConjugate() * rotation; } else - m_rotation = q; + m_rotation = rotation; break; case CoordSys::Local: - m_rotation = q; + m_rotation = rotation; break; } - InvalidateNode(); + Invalidate(invalidation); } - void Node::SetScale(const Vector2f& scale, CoordSys coordSys) - { - // Prevent Z scale at zero (can happen when using SetScale with a Vec2) - SetScale(scale.x, scale.y, 1.f, coordSys); - } - - void Node::SetScale(const Vector3f& scale, CoordSys coordSys) + void Node::SetScale(const Vector3f& scale, CoordSys coordSys, Invalidation invalidation) { switch (coordSys) { @@ -583,152 +221,64 @@ namespace Nz break; } - InvalidateNode(); + Invalidate(invalidation); } - void Node::SetScale(float scale, CoordSys coordSys) + void Node::SetTransform(const Vector3f& position, const Quaternionf& rotation, const Vector3f& scale, CoordSys coordSys, Invalidation invalidation) { - SetScale(Vector3f(scale), coordSys); - } - - void Node::SetScale(float scaleX, float scaleY, float scaleZ, CoordSys coordSys) - { - SetScale(Vector3f(scaleX, scaleY, scaleZ), coordSys); - } - - void Node::SetTransformMatrix(const Matrix4f& matrix) - { - SetPosition(matrix.GetTranslation(), CoordSys::Global); - SetRotation(matrix.GetRotation(), CoordSys::Global); - SetScale(matrix.GetScale(), CoordSys::Global); - - m_transformMatrix = matrix; - m_transformMatrixUpdated = true; - } - - Vector3f Node::ToGlobalPosition(const Vector3f& localPosition) const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return TransformPositionTRS(m_derivedPosition, m_derivedRotation, m_derivedScale, localPosition); - } - - Quaternionf Node::ToGlobalRotation(const Quaternionf& localRotation) const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return TransformRotationTRS(m_derivedRotation, m_derivedScale, localRotation); - } - - Vector3f Node::ToGlobalScale(const Vector3f& localScale) const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return TransformScaleTRS(m_derivedScale, localScale); - } - - Vector3f Node::ToLocalPosition(const Vector3f& globalPosition) const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation.GetConjugate()*(globalPosition - m_derivedPosition)/m_derivedScale; - } - - Quaternionf Node::ToLocalRotation(const Quaternionf& globalRotation) const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return m_derivedRotation.GetConjugate() * globalRotation; - } - - Vector3f Node::ToLocalScale(const Vector3f& globalScale) const - { - if (!m_derivedUpdated) - UpdateDerived(); - - return globalScale / m_derivedScale; - } - - Node& Node::operator=(const Node& node) - { - SetParent(node.m_parent); - - m_inheritPosition = node.m_inheritPosition; - m_inheritRotation = node.m_inheritRotation; - m_inheritScale = node.m_inheritScale; - m_initialPosition = node.m_initialPosition; - m_initialRotation = node.m_initialRotation; - m_initialScale = node.m_initialScale; - m_position = node.m_position; - m_rotation = node.m_rotation; - m_scale = node.m_scale; - - InvalidateNode(); - - return *this; - } - - Node& Node::operator=(Node&& node) noexcept - { - if (m_parent) - SetParent(nullptr); - - m_inheritPosition = node.m_inheritPosition; - m_inheritRotation = node.m_inheritRotation; - m_inheritScale = node.m_inheritScale; - m_initialPosition = node.m_initialPosition; - m_initialRotation = node.m_initialRotation; - m_initialScale = node.m_initialScale; - m_position = node.m_position; - m_rotation = node.m_rotation; - m_scale = node.m_scale; - - m_childs = std::move(node.m_childs); - for (Node* child : m_childs) - child->m_parent = this; - - m_parent = node.m_parent; - if (m_parent) + switch (coordSys) { - m_parent->RemoveChild(&node); - m_parent->AddChild(this); - node.m_parent = nullptr; + case CoordSys::Global: + { + // Position + if (m_parent && m_inheritPosition) + { + m_parent->EnsureDerivedUpdate(); + + m_position = (m_parent->m_derivedRotation.GetConjugate() * (position - m_parent->m_derivedPosition)) / m_parent->m_derivedScale - m_initialPosition; + } + else + m_position = position - m_initialPosition; + + // Rotation + if (m_parent && m_inheritRotation) + { + Quaternionf rot(m_parent->GetRotation() * m_initialRotation); + + m_rotation = rot.GetConjugate() * rotation; + } + else + m_rotation = rotation; + + // Scale + if (m_parent && m_inheritScale) + m_scale = scale / (m_initialScale * m_parent->GetScale()); + else + m_scale = scale / m_initialScale; + + break; + } + + case CoordSys::Local: + m_position = position; + m_rotation = rotation; + m_scale = scale; + break; } - OnNodeInvalidation = std::move(node.OnNodeInvalidation); - OnNodeNewParent = std::move(node.OnNodeNewParent); - OnNodeRelease = std::move(node.OnNodeRelease); - - InvalidateNode(); - - return *this; + Invalidate(invalidation); } - void Node::AddChild(Node* node) const - { - #ifdef NAZARA_DEBUG - if (std::find(m_childs.begin(), m_childs.end(), node) != m_childs.end()) - { - NazaraWarning("Child node is already a child of parent node"); - return; - } - #endif - - m_childs.push_back(node); - } - - void Node::InvalidateNode() + void Node::InvalidateNode(Invalidation invalidation) { m_derivedUpdated = false; m_transformMatrixUpdated = false; - for (Node* node : m_childs) - node->InvalidateNode(); + if (invalidation == Invalidation::InvalidateRecursively) + { + for (Node* node : m_childs) + node->InvalidateNode(invalidation); + } OnNodeInvalidation(this); } @@ -738,21 +288,11 @@ namespace Nz OnNodeNewParent(this, parent); } - void Node::RemoveChild(Node* node) const - { - auto it = std::find(m_childs.begin(), m_childs.end(), node); - if (it != m_childs.end()) - m_childs.erase(it); - else - NazaraWarning("Child not found"); - } - void Node::UpdateDerived() const { if (m_parent) { - if (!m_parent->m_derivedUpdated) - m_parent->UpdateDerived(); + m_parent->EnsureDerivedUpdate(); if (m_inheritPosition) m_derivedPosition = m_parent->m_derivedRotation*(m_parent->m_derivedScale * (m_initialPosition + m_position)) + m_parent->m_derivedPosition; @@ -787,8 +327,7 @@ namespace Nz void Node::UpdateTransformMatrix() const { - if (!m_derivedUpdated) - UpdateDerived(); + EnsureDerivedUpdate(); m_transformMatrix.MakeTransform(m_derivedPosition, m_derivedRotation, m_derivedScale); m_transformMatrixUpdated = true; diff --git a/src/Nazara/Widgets/BaseWidget.cpp b/src/Nazara/Widgets/BaseWidget.cpp index 0507d253c..8801920d7 100644 --- a/src/Nazara/Widgets/BaseWidget.cpp +++ b/src/Nazara/Widgets/BaseWidget.cpp @@ -237,9 +237,9 @@ namespace Nz UpdatePositionAndSize(); } - void BaseWidget::InvalidateNode() + void BaseWidget::InvalidateNode(Invalidation invalidation) { - Node::InvalidateNode(); + Node::InvalidateNode(invalidation); UpdatePositionAndSize(); }