From a3fd69a453f929780c8c9dc26b31a10d3042705c Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 14 Nov 2018 23:54:31 +0100 Subject: [PATCH 01/77] Lua/LuaState: Add RawEqual function --- ChangeLog.md | 1 + include/Nazara/Lua/LuaState.hpp | 2 ++ src/Nazara/Lua/LuaState.cpp | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index ad2dd0a55..4f37e76d8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -155,6 +155,7 @@ Nazara Engine: - Added ENetHost and ENetPeer accessor to total packet/data received/sent/lost - ⚠ **Changed the way resources were Loaded, almost every LoadFromX and OpenFromX methods are now static and create the object themselves.** - ⚠ SoundStream is now responsible for loaders instead of Music, and is now threadsafe (you can now load a stream only once and play it multiple times at the same time) +- Added LuaState::RawEqual Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Lua/LuaState.hpp b/include/Nazara/Lua/LuaState.hpp index 47c6d07cf..4890eae30 100644 --- a/include/Nazara/Lua/LuaState.hpp +++ b/include/Nazara/Lua/LuaState.hpp @@ -157,6 +157,8 @@ namespace Nz void* PushUserdata(std::size_t size) const; void PushValue(int index) const; + bool RawEqual(int index1, int index2) const; + void Remove(int index) const; void Replace(int index) const; diff --git a/src/Nazara/Lua/LuaState.cpp b/src/Nazara/Lua/LuaState.cpp index dfbec1117..6065087d6 100644 --- a/src/Nazara/Lua/LuaState.cpp +++ b/src/Nazara/Lua/LuaState.cpp @@ -712,6 +712,11 @@ namespace Nz lua_pushvalue(m_state, index); } + bool LuaState::RawEqual(int index1, int index2) const + { + return lua_rawequal(m_state, index1, index2); + } + void LuaState::Remove(int index) const { lua_remove(m_state, index); From beed59b94c5fcbaaee8f81af69bf73d7037f6c9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 16 Nov 2018 17:42:59 +0100 Subject: [PATCH 02/77] Physics2D/RigidBody2D: Fix potential crash if closestDistance is passed as nullptr --- src/Nazara/Physics2D/RigidBody2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 4abd6505b..97b778089 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -156,7 +156,7 @@ namespace Nz if (closestPoint) *closestPoint = closest; - if (minDistance) + if (closestDistance) *closestDistance = minDistance; return true; From 0740ee456a4c1b49b9185ca497ef03e2299a00fe Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 19 Dec 2018 22:08:50 +0100 Subject: [PATCH 03/77] Lua/LuaCoroutine: Fixed movement assignation operator --- ChangeLog.md | 1 + include/Nazara/Lua/LuaCoroutine.inl | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 4f37e76d8..1c4e14c6a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -156,6 +156,7 @@ Nazara Engine: - ⚠ **Changed the way resources were Loaded, almost every LoadFromX and OpenFromX methods are now static and create the object themselves.** - ⚠ SoundStream is now responsible for loaders instead of Music, and is now threadsafe (you can now load a stream only once and play it multiple times at the same time) - Added LuaState::RawEqual +- Fixed LuaCoroutine movement assignation operator Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Lua/LuaCoroutine.inl b/include/Nazara/Lua/LuaCoroutine.inl index 63c7d0eda..43a3f87cb 100644 --- a/include/Nazara/Lua/LuaCoroutine.inl +++ b/include/Nazara/Lua/LuaCoroutine.inl @@ -15,8 +15,7 @@ namespace Nz { LuaState::operator=(std::move(instance)); - m_ref = instance.m_ref; - instance.m_ref = -1; + std::swap(m_ref, instance.m_ref); return *this; } From cd54cf641bce1d960352b57765cdcb96c7ad617c Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 19 Dec 2018 22:22:30 +0100 Subject: [PATCH 04/77] Alignment fix --- src/Nazara/Physics2D/RigidBody2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 97b778089..cbeb23cd1 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -105,7 +105,7 @@ namespace Nz cpBodyApplyForceAtLocalPoint(m_handle, cpv(force.x, force.y), cpv(point.x, point.y)); break; } -} + } void RigidBody2D::AddImpulse(const Vector2f& impulse, CoordSys coordSys) { From fc86d098c3b146a89fe5e8f7a2ded36cc1825728 Mon Sep 17 00:00:00 2001 From: Faymoon Date: Fri, 11 Jan 2019 09:29:37 +0100 Subject: [PATCH 05/77] Update Velocity[System/Component] to add CoordSys_Local support (#193) --- SDK/include/NDK/Components/VelocityComponent.hpp | 3 ++- SDK/include/NDK/Components/VelocityComponent.inl | 5 +++-- SDK/src/NDK/Systems/VelocitySystem.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/SDK/include/NDK/Components/VelocityComponent.hpp b/SDK/include/NDK/Components/VelocityComponent.hpp index 8785f6861..2c619da76 100644 --- a/SDK/include/NDK/Components/VelocityComponent.hpp +++ b/SDK/include/NDK/Components/VelocityComponent.hpp @@ -19,10 +19,11 @@ namespace Ndk class NDK_API VelocityComponent : public Component { public: - VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero()); + VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero(), Nz::CoordSys coordSystem = Nz::CoordSys_Global); ~VelocityComponent() = default; Nz::Vector3f linearVelocity; + Nz::CoordSys coordSys; VelocityComponent& operator=(const Nz::Vector3f& vel); diff --git a/SDK/include/NDK/Components/VelocityComponent.inl b/SDK/include/NDK/Components/VelocityComponent.inl index 3ca449132..2adedf413 100644 --- a/SDK/include/NDK/Components/VelocityComponent.inl +++ b/SDK/include/NDK/Components/VelocityComponent.inl @@ -16,8 +16,9 @@ namespace Ndk * \param velocity Linear velocity */ - inline VelocityComponent::VelocityComponent(const Nz::Vector3f& velocity) : - linearVelocity(velocity) + inline VelocityComponent::VelocityComponent(const Nz::Vector3f& velocity, Nz::CoordSys coordSystem) : + linearVelocity(velocity), + coordSys(coordSystem) { } diff --git a/SDK/src/NDK/Systems/VelocitySystem.cpp b/SDK/src/NDK/Systems/VelocitySystem.cpp index 0b1845bfb..b633d7b68 100644 --- a/SDK/src/NDK/Systems/VelocitySystem.cpp +++ b/SDK/src/NDK/Systems/VelocitySystem.cpp @@ -43,7 +43,7 @@ namespace Ndk NodeComponent& node = entity->GetComponent(); const VelocityComponent& velocity = entity->GetComponent(); - node.Move(velocity.linearVelocity * elapsedTime, Nz::CoordSys_Global); + node.Move(velocity.linearVelocity * elapsedTime, velocity.coordSys); } } From c152d2b62bbc696e86e08e3f84c129b4d3400c67 Mon Sep 17 00:00:00 2001 From: Alexandre Janniaux Date: Mon, 14 Jan 2019 22:09:03 +0100 Subject: [PATCH 06/77] unicode: silence shadow variable warnings (#194) --- src/Nazara/Core/Unicode.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Core/Unicode.cpp b/src/Nazara/Core/Unicode.cpp index 477a77ff4..5b20ebce6 100644 --- a/src/Nazara/Core/Unicode.cpp +++ b/src/Nazara/Core/Unicode.cpp @@ -37,13 +37,13 @@ namespace Nz { const UnicodeCharacter* GetCharacter(Nz::UInt32 codepoint) { - auto it = std::lower_bound(std::begin(unicodeCharacters), std::end(unicodeCharacters), codepoint, [](const UnicodeCharacter& character, Nz::UInt32 codepoint) { return character.codepoint < codepoint; }); + auto it = std::lower_bound(std::begin(unicodeCharacters), std::end(unicodeCharacters), codepoint, [](const UnicodeCharacter& character, Nz::UInt32 otherCodepoint) { return character.codepoint < otherCodepoint; }); if (it != std::end(unicodeCharacters) && it->codepoint == codepoint) return &*it; else { // Character is not part of the common character array, search in set - auto itSet = std::lower_bound(std::begin(unicodeSets), std::end(unicodeSets), codepoint, [](const UnicodeSet& character, Nz::UInt32 codepoint) { return character.firstCodepoint < codepoint; }); + auto itSet = std::lower_bound(std::begin(unicodeSets), std::end(unicodeSets), codepoint, [](const UnicodeSet& character, Nz::UInt32 otherCodepoint) { return character.firstCodepoint < otherCodepoint; }); if (itSet != std::begin(unicodeSets)) { --itSet; @@ -58,7 +58,7 @@ namespace Nz template const UnicodeCharacterSimpleMapping* GetCharacterMapping(Nz::UInt32 codepoint, const UnicodeCharacterSimpleMapping(&mapping)[N]) { - auto it = std::lower_bound(std::begin(mapping), std::end(mapping), codepoint, [](const UnicodeCharacterSimpleMapping& character, Nz::UInt32 codepoint) { return character.codepoint < codepoint; }); + auto it = std::lower_bound(std::begin(mapping), std::end(mapping), codepoint, [](const UnicodeCharacterSimpleMapping& character, Nz::UInt32 otherCodepoint) { return character.codepoint < otherCodepoint; }); if (it != std::end(mapping) && it->codepoint == codepoint) return &*it; else From ecd42704a610f2fc063162674ca580bb5420ca1d Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 19 Jan 2019 02:21:29 +0100 Subject: [PATCH 07/77] Remove MSVC-specific fix --- include/Nazara/Graphics/CullingList.inl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/Nazara/Graphics/CullingList.inl b/include/Nazara/Graphics/CullingList.inl index 5e924d013..341508351 100644 --- a/include/Nazara/Graphics/CullingList.inl +++ b/include/Nazara/Graphics/CullingList.inl @@ -408,12 +408,7 @@ namespace Nz template template - #ifdef NAZARA_COMPILER_MSVC - // MSVC bug - typename CullingList::Entry& CullingList::Entry::operator=(Entry&& entry) - #else typename CullingList::template Entry& CullingList::Entry::operator=(Entry&& entry) - #endif { m_index = entry.m_index; m_parent = entry.m_parent; From 9be8d0eae45ff1d6fce91bcfbdbe9e95864af4a6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 19 Jan 2019 02:25:45 +0100 Subject: [PATCH 08/77] Add RigidBody2D::GetBodies --- ChangeLog.md | 1 + include/Nazara/Physics2D/Arbiter2D.hpp | 14 +++++++++----- src/Nazara/Physics2D/Arbiter2D.cpp | 13 +++++++++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 1c4e14c6a..7ca8835ef 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -157,6 +157,7 @@ Nazara Engine: - ⚠ SoundStream is now responsible for loaders instead of Music, and is now threadsafe (you can now load a stream only once and play it multiple times at the same time) - Added LuaState::RawEqual - Fixed LuaCoroutine movement assignation operator +- Added Arbiter2D::GetBodies Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Physics2D/Arbiter2D.hpp b/include/Nazara/Physics2D/Arbiter2D.hpp index 64c38dd8d..b8683e2eb 100644 --- a/include/Nazara/Physics2D/Arbiter2D.hpp +++ b/include/Nazara/Physics2D/Arbiter2D.hpp @@ -16,6 +16,8 @@ struct cpArbiter; namespace Nz { + class RigidBody2D; + class NAZARA_PHYSICS2D_API Arbiter2D { public: @@ -27,22 +29,24 @@ namespace Nz float ComputeTotalKinematicEnergy() const; Nz::Vector2f ComputeTotalImpulse() const; + std::pair GetBodies() const; + std::size_t GetContactCount() const; float GetContactDepth(std::size_t i) const; - Nz::Vector2f GetContactPointA(std::size_t i) const; - Nz::Vector2f GetContactPointB(std::size_t i) const; + Vector2f GetContactPointA(std::size_t i) const; + Vector2f GetContactPointB(std::size_t i) const; float GetElasticity() const; float GetFriction() const; - Nz::Vector2f GetNormal() const; - Nz::Vector2f GetSurfaceVelocity() const; + Vector2f GetNormal() const; + Vector2f GetSurfaceVelocity() const; bool IsFirstContact() const; bool IsRemoval() const; void SetElasticity(float elasticity); void SetFriction(float friction); - void SetSurfaceVelocity(const Nz::Vector2f& surfaceVelocity); + void SetSurfaceVelocity(const Vector2f& surfaceVelocity); Arbiter2D& operator=(const Arbiter2D&) = delete; Arbiter2D& operator=(Arbiter2D&&) = default; diff --git a/src/Nazara/Physics2D/Arbiter2D.cpp b/src/Nazara/Physics2D/Arbiter2D.cpp index 8a1243d26..56668bbe5 100644 --- a/src/Nazara/Physics2D/Arbiter2D.cpp +++ b/src/Nazara/Physics2D/Arbiter2D.cpp @@ -19,6 +19,19 @@ namespace Nz return Nz::Vector2f(Nz::Vector2(impulse.x, impulse.y)); } + std::pair Arbiter2D::GetBodies() const + { + std::pair bodies; + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(m_arbiter, &firstBody, &secondBody); + + bodies.first = static_cast(cpBodyGetUserData(firstBody)); + bodies.second = static_cast(cpBodyGetUserData(secondBody)); + + return bodies; + } + std::size_t Arbiter2D::GetContactCount() const { return cpArbiterGetCount(m_arbiter); From 40cd8a798778c2bb14cd5606ea0319f514973bf5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 19 Jan 2019 02:29:27 +0100 Subject: [PATCH 09/77] Physics2D/RigidBody2D: Add ForEachArbiter method --- ChangeLog.md | 1 + .../NDK/Components/PhysicsComponent2D.hpp | 2 ++ .../NDK/Components/PhysicsComponent2D.inl | 9 +++++++++ include/Nazara/Physics2D/RigidBody2D.hpp | 2 ++ src/Nazara/Physics2D/RigidBody2D.cpp | 16 ++++++++++++++++ 5 files changed, 30 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 7ca8835ef..7ad72fb66 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -158,6 +158,7 @@ Nazara Engine: - Added LuaState::RawEqual - Fixed LuaCoroutine movement assignation operator - Added Arbiter2D::GetBodies +- Added RigidBody2D::ForEachArbiter Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.hpp b/SDK/include/NDK/Components/PhysicsComponent2D.hpp index 696a8f99d..38a8c0608 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent2D.hpp @@ -38,6 +38,8 @@ namespace Ndk inline void EnableNodeSynchronization(bool nodeSynchronization); + inline void ForEachArbiter(const std::function& callback); + inline Nz::Rectf GetAABB() const; inline float GetAngularDamping() const; inline Nz::RadianAnglef GetAngularVelocity() const; diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.inl b/SDK/include/NDK/Components/PhysicsComponent2D.inl index dd90b5f9a..74de89e65 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent2D.inl @@ -138,6 +138,15 @@ namespace Ndk m_entity->Invalidate(); } + /*! + TODO + */ + inline void PhysicsComponent2D::ForEachArbiter(const std::function& callback) + { + NazaraAssert(m_object, "Invalid physics object"); + + return m_object->ForEachArbiter(callback); + } /*! * \brief Gets the AABB of the physics object * \return AABB of the object diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index 39dbb0b83..da5646fb0 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -41,6 +41,8 @@ namespace Nz void EnableSimulation(bool simulation); + void ForEachArbiter(std::function callback); + Rectf GetAABB() const; inline float GetAngularDamping() const; RadianAnglef GetAngularVelocity() const; diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index cbeb23cd1..1f4ca07a4 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include #include #include @@ -175,6 +176,21 @@ namespace Nz } } + void RigidBody2D::ForEachArbiter(std::function callback) + { + using CallbackType = decltype(callback); + + auto RealCallback = [](cpBody* body, cpArbiter* arbiter, void* data) + { + CallbackType& cb = *static_cast(data); + + Arbiter2D nzArbiter(arbiter); + cb(nzArbiter); + }; + + cpBodyEachArbiter(m_handle, RealCallback, &callback); + } + Rectf RigidBody2D::GetAABB() const { if (m_shapes.empty()) From 662ccbd5d00bc0b3ce28e8fa56535299109ddf61 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 19 Jan 2019 02:31:29 +0100 Subject: [PATCH 10/77] Physics2D/RigidBody2D: Add possibility to setup a custom velocity function --- ChangeLog.md | 1 + .../NDK/Components/PhysicsComponent2D.hpp | 8 +++ .../NDK/Components/PhysicsComponent2D.inl | 59 ++++++++++++++++++- include/Nazara/Physics2D/RigidBody2D.hpp | 11 ++++ src/Nazara/Physics2D/RigidBody2D.cpp | 35 +++++++++++ 5 files changed, 113 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 7ad72fb66..ba7748cda 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -159,6 +159,7 @@ Nazara Engine: - Fixed LuaCoroutine movement assignation operator - Added Arbiter2D::GetBodies - Added RigidBody2D::ForEachArbiter +- Added possibility to change the RigidBody2D velocity function called by the physics engine Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.hpp b/SDK/include/NDK/Components/PhysicsComponent2D.hpp index 38a8c0608..63abb6c40 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent2D.hpp @@ -24,6 +24,8 @@ namespace Ndk friend class ConstraintComponent2D; public: + using VelocityFunc = Nz::RigidBody2D::VelocityFunc; + PhysicsComponent2D(); PhysicsComponent2D(const PhysicsComponent2D& physics); ~PhysicsComponent2D() = default; @@ -55,10 +57,13 @@ namespace Ndk inline Nz::Vector2f GetSurfaceVelocity(std::size_t shapeIndex = 0) const; inline std::size_t GetShapeCount() const; inline Nz::Vector2f GetVelocity() const; + const VelocityFunc& GetVelocityFunction() const; inline bool IsNodeSynchronizationEnabled() const; inline bool IsSleeping() const; + inline void ResetVelocityFunction(); + inline void SetAngularDamping(float angularDamping); inline void SetAngularVelocity(const Nz::RadianAnglef& angularVelocity); inline void SetElasticity(float elasticity); @@ -73,6 +78,9 @@ namespace Ndk inline void SetSurfaceVelocity(const Nz::Vector2f& velocity); inline void SetSurfaceVelocity(std::size_t shapeIndex, const Nz::Vector2f& velocity); inline void SetVelocity(const Nz::Vector2f& velocity); + inline void SetVelocityFunction(VelocityFunc velocityFunc); + + inline void UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime); static ComponentIndex componentIndex; diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.inl b/SDK/include/NDK/Components/PhysicsComponent2D.inl index 74de89e65..6a4ae478a 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent2D.inl @@ -338,7 +338,6 @@ namespace Ndk * * \remark Produces a NazaraAssert if the physics object is invalid */ - inline Nz::Vector2f PhysicsComponent2D::GetVelocity() const { NazaraAssert(m_object, "Invalid physics object"); @@ -346,6 +345,19 @@ namespace Ndk return m_object->GetVelocity(); } + /*! + * \brief Gets the custom velocity function of the physics object + * \return Velocity function of the object (may be empty if default function is used) + * + * \remark Produces a NazaraAssert if the physics object is invalid + */ + inline auto PhysicsComponent2D::GetVelocityFunction() const -> const VelocityFunc& + { + NazaraAssert(m_object, "Invalid physics object"); + + return m_object->GetVelocityFunction(); + } + /*! * \brief Checks if position & rotation are synchronized with NodeComponent * \return true If synchronization is enabled @@ -370,6 +382,18 @@ namespace Ndk return m_object->IsSleeping(); } + /*! + * \brief Reset velocity function to default one + * + * \remark Produces a NazaraAssert if the physics object is invalid + */ + inline void PhysicsComponent2D::ResetVelocityFunction() + { + NazaraAssert(m_object, "Invalid physics object"); + + return m_object->ResetVelocityFunction(); + } + /*! * \brief Sets the angular damping or moment of inertia of the physics object * @@ -580,6 +604,39 @@ namespace Ndk m_object->SetVelocity(velocity); } + /*! + * \brief Sets a custom velocity function for the physics object + * + * A velocity function is called (for non-kinematic and non-static objects) at every physics update to compute the new velocity of the object. + * You may call UpdateVelocity (the default velocity function) to let the physics engine compute that itself and then adjust it using GetVelocity/SetVelocity as you need. + * + * \param velocityFunc New custom velocity function + * + * \remark Passing an empty VelocityFunc has the same effect as calling ResetVelocityFunction + * \see ResetVelocityFunction + * \see UpdateVelocity + */ + inline void PhysicsComponent2D::SetVelocityFunction(VelocityFunc velocityFunc) + { + NazaraAssert(m_object, "Invalid physics object"); + + m_object->SetVelocityFunction(std::move(velocityFunc)); + } + + /*! + * \brief Calls the physics engine default velocity function + * + * \param gravity Physics system gravity + * \param damping Physics system damping (adjusted to deltaTime) + * \param deltaTime Elapsed time since last physics update + */ + inline void PhysicsComponent2D::UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime) + { + NazaraAssert(m_object, "Invalid physics object"); + + m_object->UpdateVelocity(gravity, damping, deltaTime); + } + /*! * \brief Gets the underlying physics object * \return A reference to the physics object diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index da5646fb0..aa5664978 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -14,17 +14,21 @@ #include #include #include +#include #include struct cpBody; namespace Nz { + class Arbiter2D; class PhysWorld2D; class NAZARA_PHYSICS2D_API RigidBody2D { public: + using VelocityFunc = std::function; + RigidBody2D(PhysWorld2D* world, float mass); RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom); RigidBody2D(const RigidBody2D& object); @@ -62,6 +66,7 @@ namespace Nz Vector2f GetSurfaceVelocity(std::size_t shapeIndex = 0) const; void* GetUserdata() const; Vector2f GetVelocity() const; + const VelocityFunc& GetVelocityFunction() const; PhysWorld2D* GetWorld() const; bool IsKinematic() const; @@ -69,6 +74,8 @@ namespace Nz bool IsSleeping() const; bool IsStatic() const; + void ResetVelocityFunction(); + inline void SetAngularDamping(float angularDamping); void SetAngularVelocity(const RadianAnglef& angularVelocity); void SetElasticity(float elasticity); @@ -86,6 +93,9 @@ namespace Nz void SetStatic(bool setStaticBody = true); void SetUserdata(void* ud); void SetVelocity(const Vector2f& velocity); + void SetVelocityFunction(VelocityFunc velocityFunc); + + void UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime); RigidBody2D& operator=(const RigidBody2D& object); RigidBody2D& operator=(RigidBody2D&& object); @@ -104,6 +114,7 @@ namespace Nz static void CopyBodyData(cpBody* from, cpBody* to); static void CopyShapeData(cpShape* from, cpShape* to); + VelocityFunc m_velocityFunc; std::vector m_shapes; Collider2DRef m_geom; cpBody* m_handle; diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 1f4ca07a4..88fd792f8 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -296,6 +296,11 @@ namespace Nz return Vector2f(static_cast(vel.x), static_cast(vel.y)); } + const RigidBody2D::VelocityFunc& RigidBody2D::GetVelocityFunction() const + { + return m_velocityFunc; + } + PhysWorld2D* RigidBody2D::GetWorld() const { return m_world; @@ -321,6 +326,11 @@ namespace Nz return m_isStatic; } + void RigidBody2D::ResetVelocityFunction() + { + m_handle->velocity_func = cpBodyUpdateVelocity; + } + void RigidBody2D::SetAngularVelocity(const RadianAnglef& angularVelocity) { cpBodySetAngularVelocity(m_handle, angularVelocity.value); @@ -516,6 +526,30 @@ namespace Nz cpBodySetVelocity(m_handle, cpv(velocity.x, velocity.y)); } + void RigidBody2D::SetVelocityFunction(VelocityFunc velocityFunc) + { + m_velocityFunc = std::move(velocityFunc); + + if (m_velocityFunc) + { + m_handle->velocity_func = [](cpBody* body, cpVect gravity, cpFloat damping, cpFloat dt) + { + RigidBody2D* rigidBody = static_cast(cpBodyGetUserData(body)); + const auto& callback = rigidBody->GetVelocityFunction(); + assert(callback); + + callback(*rigidBody, Nz::Vector2f(float(gravity.x), float(gravity.y)), float(damping), float(dt)); + }; + } + else + m_handle->velocity_func = cpBodyUpdateVelocity; + } + + void RigidBody2D::UpdateVelocity(const Nz::Vector2f & gravity, float damping, float deltaTime) + { + cpBodyUpdateVelocity(m_handle, cpv(gravity.x, gravity.y), damping, deltaTime); + } + RigidBody2D& RigidBody2D::operator=(const RigidBody2D& object) { RigidBody2D physObj(object); @@ -538,6 +572,7 @@ namespace Nz m_mass = object.m_mass; m_shapes = std::move(object.m_shapes); m_userData = object.m_userData; + m_velocityFunc = std::move(object.m_velocityFunc); m_world = object.m_world; cpBodySetUserData(m_handle, this); From b0679533738480a485d320bfabcf15013154ee07 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 19 Jan 2019 02:31:53 +0100 Subject: [PATCH 11/77] I can't remember why I did this, but it fixes something --- thirdparty/src/Lua/loadlib.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/thirdparty/src/Lua/loadlib.cpp b/thirdparty/src/Lua/loadlib.cpp index a20e68efc..f5319da42 100644 --- a/thirdparty/src/Lua/loadlib.cpp +++ b/thirdparty/src/Lua/loadlib.cpp @@ -176,6 +176,8 @@ static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { ** ======================================================================= */ +#define WIN32_LEAN_AND_MEAN + #include #undef setprogdir From e075b590197fe421bc933790151ce89c3a112e1a Mon Sep 17 00:00:00 2001 From: Alexandre Janniaux Date: Mon, 21 Jan 2019 15:27:40 +0100 Subject: [PATCH 12/77] premake: use omitframepointer instead of deprecated NoFramePointer (#195) * premake: update to version 5 alpha 13 * premake: use omitframepointer instead of deprecated NoFramePointer --- build/scripts/common.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/scripts/common.lua b/build/scripts/common.lua index 20472cf0d..ad37e7fd7 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -841,7 +841,7 @@ function NazaraBuild:PrepareGeneric() symbols("On") filter("configurations:not *Debug*") - flags("NoFramePointer") + omitframepointer("On") -- Setup some optimizations for release filter("configurations:Release*") From 58c99e80f18602aff9f9804f7fec26ed03ab3f71 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 2 Feb 2019 02:09:34 +0100 Subject: [PATCH 13/77] Enable MSVC conformance options --- build/scripts/common.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/scripts/common.lua b/build/scripts/common.lua index 20472cf0d..b2ba6d4f3 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -855,6 +855,10 @@ function NazaraBuild:PrepareGeneric() filter("configurations:*Dynamic") kind("SharedLib") + -- Enable MSVC conformance (not required but better) + filter("action:vs*") + buildoptions({"/permissive-", "/Zc:__cplusplus", "/Zc:referenceBinding", "/Zc:throwingNew"}) + -- Enable SSE math and vectorization optimizations filter({"configurations:Release*", clangGccActions}) buildoptions("-mfpmath=sse") From 2873a60775cb9ce808c48ba49d463986447b02f1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 2 Feb 2019 03:00:48 +0100 Subject: [PATCH 14/77] SDK/GraphicsComponent: Fix AABB miscalculation (may occur with 2D objects when depth is zero) --- SDK/src/NDK/Components/GraphicsComponent.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/SDK/src/NDK/Components/GraphicsComponent.cpp b/SDK/src/NDK/Components/GraphicsComponent.cpp index 5182e2d2d..ac1029742 100644 --- a/SDK/src/NDK/Components/GraphicsComponent.cpp +++ b/SDK/src/NDK/Components/GraphicsComponent.cpp @@ -297,6 +297,9 @@ namespace Ndk RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem(); m_aabb.Set(-1.f, -1.f, -1.f); + + bool isAabbSet = false; + for (const Renderable& r : m_renderables) { r.boundingVolume = r.renderable->GetBoundingVolume(); @@ -305,10 +308,13 @@ namespace Ndk { r.boundingVolume.Update(r.data.transformMatrix); - if (m_aabb.IsValid()) + if (isAabbSet) m_aabb.ExtendTo(r.boundingVolume.aabb); else + { m_aabb.Set(r.boundingVolume.aabb); + isAabbSet = true; + } } } From 54fb983f9e1d38b6565f89d1bd4d69e7ae15ef0c Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 2 Feb 2019 03:01:07 +0100 Subject: [PATCH 15/77] Sdk/PhysicsComponent2D: Add IsValid() method --- SDK/include/NDK/Components/PhysicsComponent2D.hpp | 1 + SDK/include/NDK/Components/PhysicsComponent2D.inl | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.hpp b/SDK/include/NDK/Components/PhysicsComponent2D.hpp index 63abb6c40..93383d707 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent2D.hpp @@ -61,6 +61,7 @@ namespace Ndk inline bool IsNodeSynchronizationEnabled() const; inline bool IsSleeping() const; + inline bool IsValid() const; inline void ResetVelocityFunction(); diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.inl b/SDK/include/NDK/Components/PhysicsComponent2D.inl index 6a4ae478a..f30dd8618 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.inl +++ b/SDK/include/NDK/Components/PhysicsComponent2D.inl @@ -382,6 +382,18 @@ namespace Ndk return m_object->IsSleeping(); } + /*! + * \brief Checks if this component is bound to a valid rigid body + * + * A component may not be bound to a rigid body if the component is not bound to an entity or if this entity is being destroyed + * + * \return true If bound, false otherwise + */ + inline bool PhysicsComponent2D::IsValid() const + { + return bool(m_object); + } + /*! * \brief Reset velocity function to default one * From a18dbf6bc48746d077d4ee305b17d0e32137526f Mon Sep 17 00:00:00 2001 From: larnin Date: Wed, 13 Feb 2019 01:02:57 +0100 Subject: [PATCH 16/77] Fix empty tilemap (#198) * Fix empty tilemap * Yay --- src/Nazara/Graphics/TileMap.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nazara/Graphics/TileMap.cpp b/src/Nazara/Graphics/TileMap.cpp index eb1831bcf..4ff59ec7b 100644 --- a/src/Nazara/Graphics/TileMap.cpp +++ b/src/Nazara/Graphics/TileMap.cpp @@ -31,6 +31,9 @@ namespace Nz std::size_t spriteCount = 0; for (const Layer& layer : m_layers) { + if (layer.tiles.empty()) + continue; + renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(matCount++), &vertices[4 * spriteCount], layer.tiles.size(), scissorRect); spriteCount += layer.tiles.size(); From b002a054dfc47222defe8972d7062324647d64ff Mon Sep 17 00:00:00 2001 From: larnin Date: Wed, 13 Feb 2019 01:03:47 +0100 Subject: [PATCH 17/77] Fix tilemap multimaterial (#197) --- include/Nazara/Graphics/TileMap.inl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Graphics/TileMap.inl b/include/Nazara/Graphics/TileMap.inl index 23065d429..bb24ea3d4 100644 --- a/include/Nazara/Graphics/TileMap.inl +++ b/include/Nazara/Graphics/TileMap.inl @@ -149,8 +149,8 @@ namespace Nz m_layers[materialIndex].tiles.insert(tileIndex); else if (materialIndex != tile.layerIndex) { - m_layers[materialIndex].tiles.erase(tileIndex); - m_layers[tile.layerIndex].tiles.insert(tileIndex); + m_layers[tile.layerIndex].tiles.erase(tileIndex); + m_layers[materialIndex].tiles.insert(tileIndex); invalidatedLayers |= 1U << tile.layerIndex; } @@ -285,8 +285,8 @@ namespace Nz m_layers[materialIndex].tiles.insert(tileIndex); else if (materialIndex != tile.layerIndex) { - m_layers[materialIndex].tiles.erase(tileIndex); - m_layers[tile.layerIndex].tiles.insert(tileIndex); + m_layers[tile.layerIndex].tiles.erase(tileIndex); + m_layers[materialIndex].tiles.insert(tileIndex); invalidatedLayers |= 1U << tile.layerIndex; } From 5343b581ad3e41570f4d7ad515b84887136a4d9e Mon Sep 17 00:00:00 2001 From: Alexandre Janniaux Date: Wed, 13 Feb 2019 01:05:07 +0100 Subject: [PATCH 18/77] Warnings: fix opengl redefined name (#196) * opengl: use official include names * thirdparty: rename GL3 into GL --- include/Nazara/Renderer/OpenGL.hpp | 10 ++++++---- thirdparty/include/{GL3 => GL}/glcorearb.h | 0 thirdparty/include/{GL3 => GL}/glext.h | 0 thirdparty/include/{GL3 => GL}/glxext.h | 0 thirdparty/include/{GL3 => GL}/wglext.h | 0 5 files changed, 6 insertions(+), 4 deletions(-) rename thirdparty/include/{GL3 => GL}/glcorearb.h (100%) rename thirdparty/include/{GL3 => GL}/glext.h (100%) rename thirdparty/include/{GL3 => GL}/glxext.h (100%) rename thirdparty/include/{GL3 => GL}/wglext.h (100%) diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index c87426f12..77fe10ad3 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -17,16 +17,18 @@ #include // Inclusion des headers OpenGL -#include -#include + +#include +#include + #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_GLX) namespace GLX { #include // Defined in a namespace to avoid conflict } - #include + #include #endif namespace Nz diff --git a/thirdparty/include/GL3/glcorearb.h b/thirdparty/include/GL/glcorearb.h similarity index 100% rename from thirdparty/include/GL3/glcorearb.h rename to thirdparty/include/GL/glcorearb.h diff --git a/thirdparty/include/GL3/glext.h b/thirdparty/include/GL/glext.h similarity index 100% rename from thirdparty/include/GL3/glext.h rename to thirdparty/include/GL/glext.h diff --git a/thirdparty/include/GL3/glxext.h b/thirdparty/include/GL/glxext.h similarity index 100% rename from thirdparty/include/GL3/glxext.h rename to thirdparty/include/GL/glxext.h diff --git a/thirdparty/include/GL3/wglext.h b/thirdparty/include/GL/wglext.h similarity index 100% rename from thirdparty/include/GL3/wglext.h rename to thirdparty/include/GL/wglext.h From 90609476e9a725b56498f74af4e77df1aa98944e Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 6 Mar 2019 21:17:01 +0100 Subject: [PATCH 19/77] Platform/Event: Change mouse absolute position from unsigned to signed Fixes cases where mouse is out of the window by either up or left sides --- include/Nazara/Platform/Event.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/Nazara/Platform/Event.hpp b/include/Nazara/Platform/Event.hpp index ece401890..1fe219e8e 100644 --- a/include/Nazara/Platform/Event.hpp +++ b/include/Nazara/Platform/Event.hpp @@ -36,8 +36,8 @@ namespace Nz struct MouseButtonEvent { Mouse::Button button; - unsigned int x; - unsigned int y; + int x; + int y; }; // Used by: @@ -46,8 +46,8 @@ namespace Nz { int deltaX; int deltaY; - unsigned int x; - unsigned int y; + int x; + int y; }; // Used by: From f4e6f6a44f401e0b5cee516f8d767770d1d303f6 Mon Sep 17 00:00:00 2001 From: Apjue Date: Wed, 6 Mar 2019 23:00:30 +0100 Subject: [PATCH 20/77] Premake: Set libraries' rpath to current folder (#199) * Set libraries' rpath to . * Update changelog --- ChangeLog.md | 1 + build/scripts/common.lua | 1 + 2 files changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index ba7748cda..3e9a527be 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -19,6 +19,7 @@ Miscellaneous: - When supported, projects are now parts of a virtual "workspace group" according to their kind - Fixed .dll copy when building Nazara occuring on Linux when targeting Windows (MinGW) - ⚠ Appveyor nightlies are now compiled with VS2017 +- Set libraries' rpath to current folder (.) Nazara Engine: - VertexMapper:GetComponentPtr no longer throw an error if component is disabled or incompatible with template type, instead a null pointer is returned. diff --git a/build/scripts/common.lua b/build/scripts/common.lua index ac854c29c..f5f50a9f8 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -876,6 +876,7 @@ function NazaraBuild:PrepareMainWorkspace() -- Add lib/conf/arch to library search path self:FilterLibDirectory("../lib/", libdirs) + self:FilterLibDirectory("../lib/", runpathdirs) filter("action:vs*") buildoptions({"/MP", "/bigobj"}) -- Multiprocessus build and big .obj From e0d460eb95599ea6ff67569bbde49f2833f98339 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 6 Mar 2019 23:01:42 +0100 Subject: [PATCH 21/77] Update ChangeLog.md --- ChangeLog.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog.md b/ChangeLog.md index 3e9a527be..a5606276d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -161,6 +161,7 @@ Nazara Engine: - Added Arbiter2D::GetBodies - Added RigidBody2D::ForEachArbiter - Added possibility to change the RigidBody2D velocity function called by the physics engine +- Fixed MouseButtonEvent and MouseMoveEvent mouse absolute position being unsigned (now signed) Nazara Development Kit: - Added ImageWidget (#139) From 8c91d6a77d387c1b91a1d4be438f6418cf97b704 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 10 Mar 2019 15:11:16 +0100 Subject: [PATCH 22/77] Platform/Window: Fix SetCursor always changing cursor --- ChangeLog.md | 1 + src/Nazara/Platform/Win32/WindowImpl.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index a5606276d..58c91edc9 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -162,6 +162,7 @@ Nazara Engine: - Added RigidBody2D::ForEachArbiter - Added possibility to change the RigidBody2D velocity function called by the physics engine - Fixed MouseButtonEvent and MouseMoveEvent mouse absolute position being unsigned (now signed) +- Fixed Window::SetCursor changing cursor even if window was in foreground on Windows Nazara Development Kit: - Added ImageWidget (#139) diff --git a/src/Nazara/Platform/Win32/WindowImpl.cpp b/src/Nazara/Platform/Win32/WindowImpl.cpp index 07f952e96..f22569872 100644 --- a/src/Nazara/Platform/Win32/WindowImpl.cpp +++ b/src/Nazara/Platform/Win32/WindowImpl.cpp @@ -289,7 +289,9 @@ namespace Nz { m_cursor = cursor.m_impl->GetCursor(); - ::SetCursor(m_cursor); + // Applies cursor only if we have focus + if (GetForegroundWindow() == m_handle) + ::SetCursor(m_cursor); } void WindowImpl::SetEventListener(bool listener) @@ -653,7 +655,7 @@ namespace Nz { m_mouseInside = true; - // On créé un évènement pour être informé de la sortie de la fenêtre + // Track mouse event to be notified when mouse leaves window TRACKMOUSEEVENT mouseEvent; mouseEvent.cbSize = sizeof(TRACKMOUSEEVENT); mouseEvent.dwFlags = TME_LEAVE; From ec3cb12451c780a8907cb39e038ef894bf2e8295 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 10 Mar 2019 15:12:20 +0100 Subject: [PATCH 23/77] Platform/Cursor: Fixed SystemCursor_Move on Windows --- ChangeLog.md | 1 + src/Nazara/Platform/Win32/CursorImpl.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 58c91edc9..66c7756aa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -163,6 +163,7 @@ Nazara Engine: - Added possibility to change the RigidBody2D velocity function called by the physics engine - Fixed MouseButtonEvent and MouseMoveEvent mouse absolute position being unsigned (now signed) - Fixed Window::SetCursor changing cursor even if window was in foreground on Windows +- Fixed SystemCursor_Move not showing up on Windows Nazara Development Kit: - Added ImageWidget (#139) diff --git a/src/Nazara/Platform/Win32/CursorImpl.cpp b/src/Nazara/Platform/Win32/CursorImpl.cpp index 399320c59..48d960f92 100644 --- a/src/Nazara/Platform/Win32/CursorImpl.cpp +++ b/src/Nazara/Platform/Win32/CursorImpl.cpp @@ -48,7 +48,7 @@ namespace Nz bool CursorImpl::Create(SystemCursor cursor) { - if (cursor != SystemCursor_Move) + if (cursor != SystemCursor_None) m_cursor = static_cast(LoadImage(nullptr, s_systemCursorIds[cursor], IMAGE_CURSOR, 0, 0, LR_SHARED)); else m_cursor = nullptr; From 097d16f664e7fd37830bd52164206ee34fea62fa Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 10 Mar 2019 15:13:16 +0100 Subject: [PATCH 24/77] SDK/GraphicsComponent: Fix material update not invalidating culling --- ChangeLog.md | 1 + SDK/src/NDK/Components/GraphicsComponent.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 66c7756aa..712e89340 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -235,6 +235,7 @@ Nazara Development Kit: - Added EntityOwner::Release - Add missing `recomputeMoment` parameter to PhysicsComponent2D::SetMass - Added possibility of disabling synchronization between PhysicsComponent2D and NodeComponent +- Fixed GraphicsComponent not invalidating render queue on material change (causing crashes or visual errors) # 0.4: diff --git a/SDK/src/NDK/Components/GraphicsComponent.cpp b/SDK/src/NDK/Components/GraphicsComponent.cpp index ac1029742..43bfa3b54 100644 --- a/SDK/src/NDK/Components/GraphicsComponent.cpp +++ b/SDK/src/NDK/Components/GraphicsComponent.cpp @@ -124,9 +124,11 @@ namespace Ndk const Nz::MaterialRef& oldMat = renderable->GetMaterial(skinIndex, matIndex); UnregisterMaterial(oldMat); + + ForceCullingInvalidation(); } - void Ndk::GraphicsComponent::InvalidateReflectionMap() + void GraphicsComponent::InvalidateReflectionMap() { m_entity->Invalidate(); @@ -230,6 +232,8 @@ namespace Ndk std::size_t materialCount = renderable->GetMaterialCount(); for (std::size_t i = 0; i < materialCount; ++i) UnregisterMaterial(renderable->GetMaterial(i)); + + ForceCullingInvalidation(); } void GraphicsComponent::OnInstancedRenderableSkinChange(const Nz::InstancedRenderable* renderable, std::size_t newSkinIndex) @@ -240,6 +244,8 @@ namespace Ndk for (std::size_t i = 0; i < materialCount; ++i) UnregisterMaterial(renderable->GetMaterial(i)); + + ForceCullingInvalidation(); } void GraphicsComponent::OnMaterialReflectionChange(const Nz::Material* material, Nz::ReflectionMode reflectionMode) From 23b2f0a48dd5d84e0d7e8c30da9bacee46e26162 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 10 Mar 2019 15:50:16 +0100 Subject: [PATCH 25/77] Platform/Window: Make PushEvent public --- ChangeLog.md | 2 + include/Nazara/Platform/Window.hpp | 14 +++- include/Nazara/Platform/Window.inl | 15 +--- src/Nazara/Platform/Win32/WindowImpl.cpp | 14 ++-- src/Nazara/Platform/Win32/WindowImpl.hpp | 2 + src/Nazara/Platform/Window.cpp | 93 ++++++++++++++++++++++-- src/Nazara/Platform/X11/WindowImpl.cpp | 4 + src/Nazara/Platform/X11/WindowImpl.hpp | 2 + 8 files changed, 118 insertions(+), 28 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 712e89340..0225f87aa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -164,6 +164,8 @@ Nazara Engine: - Fixed MouseButtonEvent and MouseMoveEvent mouse absolute position being unsigned (now signed) - Fixed Window::SetCursor changing cursor even if window was in foreground on Windows - Fixed SystemCursor_Move not showing up on Windows +- Fixed Window movement constructor/assignation operator +- Window::PushEvent is now public (useful for pushing external events ie. when using Qt or similar framework controlling window) Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Platform/Window.hpp b/include/Nazara/Platform/Window.hpp index 7eb5f449a..47d416930 100644 --- a/include/Nazara/Platform/Window.hpp +++ b/include/Nazara/Platform/Window.hpp @@ -40,7 +40,7 @@ namespace Nz inline Window(VideoMode mode, const String& title, WindowStyleFlags style = WindowStyle_Default); inline explicit Window(WindowHandle handle); Window(const Window&) = delete; - Window(Window&&) = default; + Window(Window&& window); virtual ~Window(); inline void Close(); @@ -78,6 +78,8 @@ namespace Nz NAZARA_DEPRECATED("Event pooling/waiting is deprecated, please use the EventHandler system") bool PollEvent(WindowEvent* event); + void PushEvent(const WindowEvent& event); + void ProcessEvents(bool block = false); void SetCursor(CursorRef cursor); @@ -101,7 +103,7 @@ namespace Nz bool WaitEvent(WindowEvent* event); Window& operator=(const Window&) = delete; - Window& operator=(Window&&) = default; + Window& operator=(Window&& window); protected: virtual bool OnWindowCreated(); @@ -111,13 +113,17 @@ namespace Nz MovablePtr m_impl; private: + void ConnectSlots(); + void DisconnectSlots(); + void IgnoreNextMouseEvent(int mouseX, int mouseY) const; - inline void HandleEvent(const WindowEvent& event); - inline void PushEvent(const WindowEvent& event); + void HandleEvent(const WindowEvent& event); static bool Initialize(); static void Uninitialize(); + NazaraSlot(CursorController, OnCursorUpdated, m_cursorUpdateSlot); + std::queue m_events; std::vector m_pendingEvents; ConditionVariable m_eventCondition; diff --git a/include/Nazara/Platform/Window.inl b/include/Nazara/Platform/Window.inl index 9ce95a78a..1be1a773f 100644 --- a/include/Nazara/Platform/Window.inl +++ b/include/Nazara/Platform/Window.inl @@ -2,6 +2,7 @@ // This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include #include @@ -90,20 +91,6 @@ namespace Nz SetCursor(Cursor::Get(systemCursor)); } - inline void Window::HandleEvent(const WindowEvent& event) - { - if (m_eventPolling) - m_events.push(event); - - m_eventHandler.Dispatch(event); - - if (event.type == WindowEventType_Resized) - OnWindowResized(); - - if (event.type == WindowEventType_Quit && m_closeOnQuit) - Close(); - } - inline void Window::PushEvent(const WindowEvent& event) { if (!m_asyncWindow) diff --git a/src/Nazara/Platform/Win32/WindowImpl.cpp b/src/Nazara/Platform/Win32/WindowImpl.cpp index f22569872..9d7c6e9a6 100644 --- a/src/Nazara/Platform/Win32/WindowImpl.cpp +++ b/src/Nazara/Platform/Win32/WindowImpl.cpp @@ -269,6 +269,11 @@ namespace Nz return IsWindowVisible(m_handle) == TRUE; } + void WindowImpl::RefreshCursor() + { + ::SetCursor(m_cursor); + } + void WindowImpl::ProcessEvents(bool block) { if (m_ownsWindow) @@ -289,9 +294,8 @@ namespace Nz { m_cursor = cursor.m_impl->GetCursor(); - // Applies cursor only if we have focus - if (GetForegroundWindow() == m_handle) - ::SetCursor(m_cursor); + if (HasFocus()) + RefreshCursor(); } void WindowImpl::SetEventListener(bool listener) @@ -405,12 +409,12 @@ namespace Nz break; - case WM_SETCURSOR: + /*case WM_SETCURSOR: // http://msdn.microsoft.com/en-us/library/windows/desktop/ms648382(v=vs.85).aspx if (LOWORD(lParam) == HTCLIENT) ::SetCursor(m_cursor); - break; + break;*/ case WM_WINDOWPOSCHANGING: { diff --git a/src/Nazara/Platform/Win32/WindowImpl.hpp b/src/Nazara/Platform/Win32/WindowImpl.hpp index b9d18dcd9..e05a86fdf 100644 --- a/src/Nazara/Platform/Win32/WindowImpl.hpp +++ b/src/Nazara/Platform/Win32/WindowImpl.hpp @@ -58,6 +58,8 @@ namespace Nz bool IsMinimized() const; bool IsVisible() const; + void RefreshCursor(); + void ProcessEvents(bool block); void SetCursor(const Cursor& cursor); diff --git a/src/Nazara/Platform/Window.cpp b/src/Nazara/Platform/Window.cpp index 69758cdb0..e3b9c913c 100644 --- a/src/Nazara/Platform/Window.cpp +++ b/src/Nazara/Platform/Window.cpp @@ -33,11 +33,28 @@ namespace Nz m_eventPolling(false), m_waitForEvent(false) { - m_cursorController.OnCursorUpdated.Connect([this](const CursorController*, const CursorRef& cursor) - { - if (IsValid()) - SetCursor(cursor); - }); + ConnectSlots(); + } + + Window::Window(Window&& window) : + m_events(std::move(window.m_events)), + m_pendingEvents(std::move(window.m_pendingEvents)), + m_eventCondition(std::move(window.m_eventCondition)), + m_cursorController(std::move(window.m_cursorController)), + m_cursor(std::move(window.m_cursor)), + m_eventHandler(std::move(window.m_eventHandler)), + m_icon(std::move(window.m_icon)), + m_eventMutex(std::move(window.m_eventMutex)), + m_eventConditionMutex(std::move(window.m_eventConditionMutex)), + m_asyncWindow(window.m_asyncWindow), + m_closed(window.m_asyncWindow), + m_closeOnQuit(window.m_closeOnQuit), + m_eventPolling(window.m_eventPolling), + m_ownsWindow(window.m_asyncWindow), + m_waitForEvent(window.m_waitForEvent) + { + window.DisconnectSlots(); + ConnectSlots(); } Window::~Window() @@ -582,6 +599,30 @@ namespace Nz } } + Window& Window::operator=(Window&& window) + { + m_events = std::move(window.m_events); + m_pendingEvents = std::move(window.m_pendingEvents); + m_eventCondition = std::move(window.m_eventCondition); + m_cursorController = std::move(window.m_cursorController); + m_cursor = std::move(window.m_cursor); + m_eventHandler = std::move(window.m_eventHandler); + m_icon = std::move(window.m_icon); + m_eventMutex = std::move(window.m_eventMutex); + m_eventConditionMutex = std::move(window.m_eventConditionMutex); + m_asyncWindow = window.m_asyncWindow; + m_closed = window.m_asyncWindow; + m_closeOnQuit = window.m_closeOnQuit; + m_eventPolling = window.m_eventPolling; + m_ownsWindow = window.m_asyncWindow; + m_waitForEvent = window.m_waitForEvent; + + window.DisconnectSlots(); + ConnectSlots(); + + return *this; + } + bool Window::OnWindowCreated() { return true; @@ -595,6 +636,20 @@ namespace Nz { } + void Window::ConnectSlots() + { + m_cursorUpdateSlot.Connect(m_cursorController.OnCursorUpdated, [this](const CursorController*, const CursorRef& cursor) + { + if (IsValid()) + SetCursor(cursor); + }); + } + + void Window::DisconnectSlots() + { + m_cursorUpdateSlot.Disconnect(); + } + void Window::IgnoreNextMouseEvent(int mouseX, int mouseY) const { #if NAZARA_PLATFORM_SAFE @@ -608,6 +663,34 @@ namespace Nz m_impl->IgnoreNextMouseEvent(mouseX, mouseY); } + void Window::HandleEvent(const WindowEvent& event) + { + if (m_eventPolling) + m_events.push(event); + + m_eventHandler.Dispatch(event); + + switch (event.type) + { + case WindowEventType_MouseEntered: + m_impl->RefreshCursor(); + break; + + case WindowEventType_Resized: + OnWindowResized(); + break; + + case WindowEventType_Quit: + if (m_closeOnQuit) + Close(); + + break; + + default: + break; + } + } + bool Window::Initialize() { return WindowImpl::Initialize(); diff --git a/src/Nazara/Platform/X11/WindowImpl.cpp b/src/Nazara/Platform/X11/WindowImpl.cpp index 4a5f8208e..0e8215e37 100644 --- a/src/Nazara/Platform/X11/WindowImpl.cpp +++ b/src/Nazara/Platform/X11/WindowImpl.cpp @@ -412,6 +412,10 @@ namespace Nz } } + void WindowImpl::RefreshCursor() + { + } + void WindowImpl::SetCursor(const Cursor& cursor) { xcb_cursor_t cursorImpl = cursor.m_impl->GetCursor(); diff --git a/src/Nazara/Platform/X11/WindowImpl.hpp b/src/Nazara/Platform/X11/WindowImpl.hpp index d9e9d8652..ecf5e0233 100644 --- a/src/Nazara/Platform/X11/WindowImpl.hpp +++ b/src/Nazara/Platform/X11/WindowImpl.hpp @@ -58,6 +58,8 @@ namespace Nz bool IsMinimized() const; bool IsVisible() const; + void RefreshCursor(); + void ProcessEvents(bool block); void SetCursor(const Cursor& cursor); From 4bf92457c537dc6b1a834a13f1ae4ace7812bde5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 10 Mar 2019 15:56:42 +0100 Subject: [PATCH 26/77] Platform: Fix cursor disappearing on Windows in some cases --- src/Nazara/Platform/Win32/WindowImpl.cpp | 1 + src/Nazara/Platform/Window.cpp | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Nazara/Platform/Win32/WindowImpl.cpp b/src/Nazara/Platform/Win32/WindowImpl.cpp index 9d7c6e9a6..1e5135168 100644 --- a/src/Nazara/Platform/Win32/WindowImpl.cpp +++ b/src/Nazara/Platform/Win32/WindowImpl.cpp @@ -53,6 +53,7 @@ namespace Nz m_smoothScrolling(false), m_scrolling(0) { + m_cursor = static_cast(LoadImage(nullptr, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED)); } bool WindowImpl::Create(const VideoMode& mode, const String& title, WindowStyleFlags style) diff --git a/src/Nazara/Platform/Window.cpp b/src/Nazara/Platform/Window.cpp index e3b9c913c..9ce743ad4 100644 --- a/src/Nazara/Platform/Window.cpp +++ b/src/Nazara/Platform/Window.cpp @@ -122,8 +122,6 @@ namespace Nz m_impl->SetMinimumSize(-1, -1); m_impl->SetVisible(true); - SetCursor(Cursor::Get(SystemCursor_Default)); - if (opened) m_impl->SetPosition(position.x, position.y); From cdf9611080c433bd81f55b121661017a414b742f Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 10 Mar 2019 18:13:03 +0100 Subject: [PATCH 27/77] Graphics/TileMap: Fix material index rendering --- ChangeLog.md | 1 + src/Nazara/Graphics/TileMap.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 0225f87aa..313c52f49 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -166,6 +166,7 @@ Nazara Engine: - Fixed SystemCursor_Move not showing up on Windows - Fixed Window movement constructor/assignation operator - Window::PushEvent is now public (useful for pushing external events ie. when using Qt or similar framework controlling window) +- Fixed TileMap not rendering the right materials if it had no tile using some materials in-between Nazara Development Kit: - Added ImageWidget (#139) diff --git a/src/Nazara/Graphics/TileMap.cpp b/src/Nazara/Graphics/TileMap.cpp index 4ff59ec7b..4789f4a8b 100644 --- a/src/Nazara/Graphics/TileMap.cpp +++ b/src/Nazara/Graphics/TileMap.cpp @@ -27,14 +27,14 @@ namespace Nz { const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(instanceData.data.data()); - std::size_t matCount = 0; std::size_t spriteCount = 0; - for (const Layer& layer : m_layers) + for (std::size_t layerIndex = 0; layerIndex < m_layers.size(); ++layerIndex) { + const auto& layer = m_layers[layerIndex]; if (layer.tiles.empty()) continue; - renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(matCount++), &vertices[4 * spriteCount], layer.tiles.size(), scissorRect); + renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(layerIndex), &vertices[4 * spriteCount], layer.tiles.size(), scissorRect); spriteCount += layer.tiles.size(); } From c2a44f76165fd1dbacc62a7d92bb94db6c817821 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 16 Mar 2019 15:40:52 +0100 Subject: [PATCH 28/77] Math: Added Vector[2|3|4](u)i64 typedefs --- ChangeLog.md | 1 + include/Nazara/Math/Vector2.hpp | 2 ++ include/Nazara/Math/Vector3.hpp | 2 ++ include/Nazara/Math/Vector4.hpp | 2 ++ 4 files changed, 7 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 313c52f49..3894c28f3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -167,6 +167,7 @@ Nazara Engine: - Fixed Window movement constructor/assignation operator - Window::PushEvent is now public (useful for pushing external events ie. when using Qt or similar framework controlling window) - Fixed TileMap not rendering the right materials if it had no tile using some materials in-between +- Added Vector[2|3|4](u)i64 typedefs Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 28985305e..d8a53eb47 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -109,7 +109,9 @@ namespace Nz using Vector2i = Vector2; using Vector2ui = Vector2; using Vector2i32 = Vector2; + using Vector2i64 = Vector2; using Vector2ui32 = Vector2; + using Vector2ui64 = Vector2; template bool Serialize(SerializationContext& context, const Vector2& vector, TypeTag>); template bool Unserialize(SerializationContext& context, Vector2* vector, TypeTag>); diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index 4bd026acf..b46f2e40b 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -129,7 +129,9 @@ namespace Nz using Vector3i = Vector3; using Vector3ui = Vector3; using Vector3i32 = Vector3; + using Vector3i64 = Vector3; using Vector3ui32 = Vector3; + using Vector3ui64 = Vector3; template bool Serialize(SerializationContext& context, const Vector3& vector, TypeTag>); template bool Unserialize(SerializationContext& context, Vector3* vector, TypeTag>); diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index f1a799fb3..7a34a6d11 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -106,7 +106,9 @@ namespace Nz using Vector4i = Vector4; using Vector4ui = Vector4; using Vector4i32 = Vector4; + using Vector4i64 = Vector4; using Vector4ui32 = Vector4; + using Vector4ui64 = Vector4; template bool Serialize(SerializationContext& context, const Vector4& vector, TypeTag>); template bool Unserialize(SerializationContext& context, Vector4* vector, TypeTag>); From b6c1bfb5d01a26d8625c6656e47070a5111f382a Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 16 Mar 2019 15:43:37 +0100 Subject: [PATCH 29/77] Math/Vector4: Fixed missing implementation --- ChangeLog.md | 1 + include/Nazara/Math/Vector4.inl | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index 3894c28f3..8be3f7553 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -168,6 +168,7 @@ Nazara Engine: - Window::PushEvent is now public (useful for pushing external events ie. when using Qt or similar framework controlling window) - Fixed TileMap not rendering the right materials if it had no tile using some materials in-between - Added Vector[2|3|4](u)i64 typedefs +- Fixed missing static Vector4::DotProduct implementation Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 69d0b513f..8c602d214 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -899,6 +899,21 @@ namespace Nz return !operator<(vec); } + /*! + * \brief Calculates the dot (scalar) product with two vectors + * \return The value of the dot product + * + * \param vec1 The first vector to calculate the dot product with + * \param vec2 The second vector to calculate the dot product with + * + * \see AbsDotProduct, DotProduct + */ + template + T Vector4::DotProduct(const Vector4& vec1, const Vector4& vec2) + { + return vec1.DotProduct(vec2); + } + /*! * \brief Interpolates the vector to other one with a factor of interpolation * \return A new vector which is the interpolation of two vectors @@ -911,7 +926,6 @@ namespace Nz * * \see Lerp */ - template Vector4 Vector4::Lerp(const Vector4& from, const Vector4& to, T interpolation) { From 439a62a7f87aaf25e4fe3dc28af6a695f8799b8b Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 17 Mar 2019 15:56:38 +0100 Subject: [PATCH 30/77] Physics2D: Automatically compute center of mass --- ChangeLog.md | 2 ++ include/Nazara/Physics2D/Collider2D.hpp | 7 +++++ include/Nazara/Physics2D/RigidBody2D.hpp | 2 +- src/Nazara/Physics2D/Collider2D.cpp | 40 +++++++++++++++++++++++- src/Nazara/Physics2D/RigidBody2D.cpp | 7 +++-- 5 files changed, 54 insertions(+), 4 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 8be3f7553..2909afceb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -169,6 +169,8 @@ Nazara Engine: - Fixed TileMap not rendering the right materials if it had no tile using some materials in-between - Added Vector[2|3|4](u)i64 typedefs - Fixed missing static Vector4::DotProduct implementation +- ⚠ **By default, Nazara computes the mass center of all 2D physics object when calling SetGeom** +- ⚠ Added Collider2D::ComputeCenterOfMass Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp index 8b69bd780..cc2f62eac 100644 --- a/include/Nazara/Physics2D/Collider2D.hpp +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -41,6 +41,7 @@ namespace Nz Collider2D(Collider2D&&) = delete; virtual ~Collider2D(); + virtual Nz::Vector2f ComputeCenterOfMass() const = 0; virtual float ComputeMomentOfInertia(float mass) const = 0; inline UInt32 GetCategoryMask() const; @@ -99,6 +100,7 @@ namespace Nz BoxCollider2D(const Vector2f& size, float radius = 0.f); BoxCollider2D(const Rectf& rect, float radius = 0.f); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline float GetRadius() const; @@ -125,6 +127,7 @@ namespace Nz public: CircleCollider2D(float radius, const Vector2f& offset = Vector2f::Zero()); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline const Vector2f& GetOffset() const; @@ -150,6 +153,7 @@ namespace Nz public: CompoundCollider2D(std::vector geoms); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline bool DoesOverrideCollisionProperties() const; @@ -179,6 +183,7 @@ namespace Nz public: ConvexCollider2D(SparsePtr vertices, std::size_t vertexCount, float radius = 0.f); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; ColliderType2D GetType() const override; @@ -203,6 +208,7 @@ namespace Nz public: NullCollider2D() = default; + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; ColliderType2D GetType() const override; @@ -223,6 +229,7 @@ namespace Nz public: inline SegmentCollider2D(const Vector2f& first, const Vector2f& second, float thickness = 1.f); + Nz::Vector2f ComputeCenterOfMass() const override; float ComputeMomentOfInertia(float mass) const override; inline const Vector2f& GetFirstPoint() const; diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index aa5664978..be90acc92 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -82,7 +82,7 @@ namespace Nz void SetElasticity(std::size_t shapeIndex, float elasticity); void SetFriction(float friction); void SetFriction(std::size_t shapeIndex, float friction); - void SetGeom(Collider2DRef geom, bool recomputeMoment = true); + void SetGeom(Collider2DRef geom, bool recomputeMoment = true, bool recomputeMassCenter = true); void SetMass(float mass, bool recomputeMoment = true); void SetMassCenter(const Vector2f& center, CoordSys coordSys = CoordSys_Local); void SetMomentOfInertia(float moment); diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 0be746838..75f5fe332 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -20,7 +20,7 @@ namespace Nz { cpShape* shape = (*shapes)[i]; - cpShapeSetCollisionType(shape, cpFloat(m_collisionId)); + cpShapeSetCollisionType(shape, m_collisionId); cpShapeSetElasticity(shape, cpFloat(m_elasticity)); cpShapeSetFilter(shape, filter); cpShapeSetFriction(shape, cpFloat(m_friction)); @@ -44,6 +44,11 @@ namespace Nz { } + Nz::Vector2f BoxCollider2D::ComputeCenterOfMass() const + { + return m_rect.GetCenter(); + } + float BoxCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForBox2(mass, cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height))); @@ -68,6 +73,11 @@ namespace Nz { } + Nz::Vector2f CircleCollider2D::ComputeCenterOfMass() const + { + return m_offset + Nz::Vector2f(m_radius, m_radius); + } + float CircleCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForCircle(mass, 0.f, m_radius, cpv(m_offset.x, m_offset.y))); @@ -92,6 +102,15 @@ namespace Nz { } + Nz::Vector2f CompoundCollider2D::ComputeCenterOfMass() const + { + Nz::Vector2f centerOfMass = Nz::Vector2f::Zero(); + for (const auto& geom : m_geoms) + centerOfMass += geom->ComputeCenterOfMass(); + + return centerOfMass / float(m_geoms.size()); + } + float CompoundCollider2D::ComputeMomentOfInertia(float mass) const { ///TODO: Correctly compute moment using parallel axis theorem: @@ -144,6 +163,15 @@ namespace Nz m_vertices[i].Set(*vertices++); } + Nz::Vector2f ConvexCollider2D::ComputeCenterOfMass() const + { + static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); + + cpVect center = cpCentroidForPoly(int(m_vertices.size()), reinterpret_cast(m_vertices.data())); + + return Nz::Vector2f(float(center.x), float(center.y)); + } + float ConvexCollider2D::ComputeMomentOfInertia(float mass) const { static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); @@ -169,6 +197,11 @@ namespace Nz return ColliderType2D_Null; } + Nz::Vector2f NullCollider2D::ComputeCenterOfMass() const + { + return Nz::Vector2f::Zero(); + } + float NullCollider2D::ComputeMomentOfInertia(float mass) const { return (mass > 0.f) ? 1.f : 0.f; //< Null inertia is only possible for static/kinematic objects @@ -181,6 +214,11 @@ namespace Nz /******************************** SegmentCollider2D *********************************/ + Nz::Vector2f SegmentCollider2D::ComputeCenterOfMass() const + { + return (m_first + m_second) / 2.f; + } + float SegmentCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForSegment(mass, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness)); diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 88fd792f8..cc181930f 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -48,7 +48,7 @@ namespace Nz NazaraAssert(m_geom, "Invalid geometry"); m_handle = Create(m_mass, object.GetMomentOfInertia()); - SetGeom(object.GetGeom(), false); + SetGeom(object.GetGeom(), false, false); CopyBodyData(object.GetHandle(), m_handle); @@ -362,7 +362,7 @@ namespace Nz cpShapeSetFriction(m_shapes[shapeIndex], cpFloat(friction)); } - void RigidBody2D::SetGeom(Collider2DRef geom, bool recomputeMoment) + void RigidBody2D::SetGeom(Collider2DRef geom, bool recomputeMoment, bool recomputeMassCenter) { // We have no public way of getting rid of an existing geom without removing the whole body // So let's save some attributes of the body, destroy it and rebuild it @@ -399,6 +399,9 @@ namespace Nz if (!IsStatic() && !IsKinematic()) cpBodySetMoment(m_handle, m_geom->ComputeMomentOfInertia(m_mass)); } + + if (recomputeMassCenter) + SetMassCenter(m_geom->ComputeCenterOfMass()); } void RigidBody2D::SetMass(float mass, bool recomputeMoment) From bdb5a4b3bde3918abcc9e0aa788f0ef7ba903590 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 17 Mar 2019 18:06:05 +0100 Subject: [PATCH 31/77] Core/Signal: Implement copy constructor/copy assignation operator --- ChangeLog.md | 1 + include/Nazara/Core/Signal.hpp | 4 ++-- include/Nazara/Core/Signal.inl | 25 +++++++++++++++++++++++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 2909afceb..945d1f3ab 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -171,6 +171,7 @@ Nazara Engine: - Fixed missing static Vector4::DotProduct implementation - ⚠ **By default, Nazara computes the mass center of all 2D physics object when calling SetGeom** - ⚠ Added Collider2D::ComputeCenterOfMass +- Signal now implement a copy constructor and copy assignation operator for convenience Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Core/Signal.hpp b/include/Nazara/Core/Signal.hpp index 1569c5d0e..973181e47 100644 --- a/include/Nazara/Core/Signal.hpp +++ b/include/Nazara/Core/Signal.hpp @@ -32,7 +32,7 @@ namespace Nz class ConnectionGuard; Signal(); - Signal(const Signal&) = delete; + Signal(const Signal&); Signal(Signal&& signal) noexcept; ~Signal() = default; @@ -47,7 +47,7 @@ namespace Nz void operator()(Args... args) const; - Signal& operator=(const Signal&) = delete; + Signal& operator=(const Signal&); Signal& operator=(Signal&& signal) noexcept; private: diff --git a/include/Nazara/Core/Signal.inl b/include/Nazara/Core/Signal.inl index c4e89bd40..47d490a09 100644 --- a/include/Nazara/Core/Signal.inl +++ b/include/Nazara/Core/Signal.inl @@ -18,13 +18,23 @@ namespace Nz /*! * \brief Constructs a Signal object by default */ - template Signal::Signal() : m_slotIterator(0) { } + /*! + * \brief Constructs a Signal object by default + * + * \remark It doesn't make sense to copy a signal, this is only available for convenience to allow compiler-generated copy constructors + */ + template + Signal::Signal(const Signal&) : + Signal() + { + } + /*! * \brief Constructs a Signal object by move semantic * @@ -174,13 +184,24 @@ namespace Nz m_slots[m_slotIterator]->callback(args...); } + /*! + * \brief Doesn't do anything + * \return A reference to this + * + * \remark This is only for convenience to allow compiled-generated assignation operator + */ + template + Signal& Signal::operator=(const Signal&) + { + return *this; + } + /*! * \brief Moves the signal into this * \return A reference to this * * \param signal Signal to move in this */ - template Signal& Signal::operator=(Signal&& signal) noexcept { From 853e01c192888b30d1cdc277b2033e2ba97a5fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 20 Mar 2019 17:12:34 +0100 Subject: [PATCH 32/77] Enet fixes (#200) * Network/ENet: Fix UnreliableFragment flag * Network/ENet: Match libenet new behavior on DisconnectLater --- ChangeLog.md | 2 ++ include/Nazara/Network/ENetPeer.inl | 2 +- src/Nazara/Network/ENetPeer.cpp | 15 +++++++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 945d1f3ab..410312517 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -172,6 +172,8 @@ Nazara Engine: - ⚠ **By default, Nazara computes the mass center of all 2D physics object when calling SetGeom** - ⚠ Added Collider2D::ComputeCenterOfMass - Signal now implement a copy constructor and copy assignation operator for convenience +- Fixed ENet UnreliableFragment packets sent as Unreliable (and such being incomplete upon reception) +- ENet DisconnectLater now reflects libenet behavior (and is waiting for unreliable commands to be sent before disconnecting for good) Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl index 04ec4aae2..7820620ca 100644 --- a/include/Nazara/Network/ENetPeer.inl +++ b/include/Nazara/Network/ENetPeer.inl @@ -74,7 +74,7 @@ namespace Nz inline bool ENetPeer::HasPendingCommands() { - return m_outgoingReliableCommands.empty() && m_outgoingUnreliableCommands.empty() && m_sentReliableCommands.empty(); + return m_outgoingReliableCommands.empty() && m_outgoingUnreliableCommands.empty() && m_sentReliableCommands.empty() && m_sentUnreliableCommands.empty(); } inline bool ENetPeer::IsConnected() const diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp index fbae65e14..823eaaf18 100644 --- a/src/Nazara/Network/ENetPeer.cpp +++ b/src/Nazara/Network/ENetPeer.cpp @@ -212,7 +212,7 @@ namespace Nz if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_UnreliableFragment)) == ENetPacketFlag_UnreliableFragment && channel.outgoingUnreliableSequenceNumber < 0xFFFF) { - commandNumber = ENetProtocolCommand_SendUnreliable; + commandNumber = ENetProtocolCommand_SendUnreliableFragment; startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); } else @@ -770,7 +770,7 @@ namespace Nz break; if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || - totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) return false; startCommand = &incomingCommand; @@ -778,9 +778,10 @@ namespace Nz } } - if (startCommand) + if (!startCommand) { - if (!QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) + startCommand = QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount); + if (!startCommand) return false; } @@ -1040,7 +1041,13 @@ namespace Nz void ENetPeer::RemoveSentUnreliableCommands() { + if (m_sentUnreliableCommands.empty()) + return; + m_sentUnreliableCommands.clear(); + + if (m_state == ENetPeerState::DisconnectLater && !HasPendingCommands()) + Disconnect(m_eventData); } void ENetPeer::ResetQueues() From ffc58e9806176caca24d1bc9b569b88794e7849a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 20 Mar 2019 17:18:45 +0100 Subject: [PATCH 33/77] Fix compilation --- include/Nazara/Utility/GuillotineImageAtlas.hpp | 7 ++++++- src/Nazara/Utility/GuillotineImageAtlas.cpp | 2 -- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/Nazara/Utility/GuillotineImageAtlas.hpp b/include/Nazara/Utility/GuillotineImageAtlas.hpp index 5a1633113..506922c46 100644 --- a/include/Nazara/Utility/GuillotineImageAtlas.hpp +++ b/include/Nazara/Utility/GuillotineImageAtlas.hpp @@ -21,7 +21,9 @@ namespace Nz { public: GuillotineImageAtlas(); - virtual ~GuillotineImageAtlas(); + GuillotineImageAtlas(const GuillotineImageAtlas&) = delete; + GuillotineImageAtlas(GuillotineImageAtlas&&) noexcept = default; + ~GuillotineImageAtlas() = default; void Clear() override; @@ -38,6 +40,9 @@ namespace Nz void SetRectChoiceHeuristic(GuillotineBinPack::FreeRectChoiceHeuristic heuristic); void SetRectSplitHeuristic(GuillotineBinPack::GuillotineSplitHeuristic heuristic); + GuillotineImageAtlas& operator=(const GuillotineImageAtlas&) = delete; + GuillotineImageAtlas& operator=(GuillotineImageAtlas&&) noexcept = default; + protected: struct Layer; diff --git a/src/Nazara/Utility/GuillotineImageAtlas.cpp b/src/Nazara/Utility/GuillotineImageAtlas.cpp index 4660a69b8..2593bc368 100644 --- a/src/Nazara/Utility/GuillotineImageAtlas.cpp +++ b/src/Nazara/Utility/GuillotineImageAtlas.cpp @@ -19,8 +19,6 @@ namespace Nz { } - GuillotineImageAtlas::~GuillotineImageAtlas() = default; - void GuillotineImageAtlas::Clear() { m_layers.clear(); From 3beeeebc1da4a270d1438ce2cbefa543c44ca84a Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 18:59:18 +0100 Subject: [PATCH 34/77] Physics2D/RigidBody: Add position offset --- .../NDK/Components/CollisionComponent2D.hpp | 6 ++ .../NDK/Components/CollisionComponent2D.inl | 10 --- .../NDK/Components/CollisionComponent2D.cpp | 67 +++++++++++++++---- include/Nazara/Physics2D/RigidBody2D.hpp | 5 +- include/Nazara/Physics2D/RigidBody2D.inl | 5 ++ src/Nazara/Physics2D/RigidBody2D.cpp | 22 ++++-- 6 files changed, 86 insertions(+), 29 deletions(-) diff --git a/SDK/include/NDK/Components/CollisionComponent2D.hpp b/SDK/include/NDK/Components/CollisionComponent2D.hpp index aecdc5197..140846d62 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.hpp +++ b/SDK/include/NDK/Components/CollisionComponent2D.hpp @@ -28,10 +28,14 @@ namespace Ndk CollisionComponent2D(const CollisionComponent2D& collision); ~CollisionComponent2D() = default; + void Align(const Nz::Rectf& aabb); + Nz::Rectf GetAABB() const; const Nz::Collider2DRef& GetGeom() const; + const Nz::Vector2f& GetGeomOffset() const; void SetGeom(Nz::Collider2DRef geom); + void SetGeomOffset(const Nz::Vector2f& geomOffset); CollisionComponent2D& operator=(Nz::Collider2DRef geom); CollisionComponent2D& operator=(CollisionComponent2D&& collision) = default; @@ -40,6 +44,8 @@ namespace Ndk private: void InitializeStaticBody(); + Nz::RigidBody2D* GetRigidBody(); + const Nz::RigidBody2D* GetRigidBody() const; Nz::RigidBody2D* GetStaticBody(); void OnAttached() override; diff --git a/SDK/include/NDK/Components/CollisionComponent2D.inl b/SDK/include/NDK/Components/CollisionComponent2D.inl index b85fe3017..010780443 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.inl +++ b/SDK/include/NDK/Components/CollisionComponent2D.inl @@ -28,16 +28,6 @@ namespace Ndk { } - /*! - * \brief Gets the collision box representing the entity - * \return The physics collision box - */ - - inline Nz::Rectf CollisionComponent2D::GetAABB() const - { - return m_staticBody->GetAABB(); - } - /*! * \brief Gets the geometry representing the entity * \return A constant reference to the physics geometry diff --git a/SDK/src/NDK/Components/CollisionComponent2D.cpp b/SDK/src/NDK/Components/CollisionComponent2D.cpp index 5cdfd1589..84582c261 100644 --- a/SDK/src/NDK/Components/CollisionComponent2D.cpp +++ b/SDK/src/NDK/Components/CollisionComponent2D.cpp @@ -17,28 +17,41 @@ namespace Ndk * \brief NDK class that represents a two-dimensional collision geometry */ + void CollisionComponent2D::Align(const Nz::Rectf& aabb) + { + const Nz::RigidBody2D* rigidBody = GetRigidBody(); + SetGeomOffset(aabb.GetCenter() - rigidBody->GetAABB().GetCenter() + rigidBody->GetPositionOffset()); + } + + /*! + * \brief Gets the collision box representing the entity + * \return The physics collision box + */ + Nz::Rectf CollisionComponent2D::GetAABB() const + { + return GetRigidBody()->GetAABB(); + } + + const Nz::Vector2f& CollisionComponent2D::GetGeomOffset() const + { + return GetRigidBody()->GetPositionOffset(); + } + /*! * \brief Sets geometry for the entity * * \param geom Geometry used for collisions - * - * \remark Produces a NazaraAssert if the entity has no physics component and has no static body */ void CollisionComponent2D::SetGeom(Nz::Collider2DRef geom) { m_geom = std::move(geom); - if (m_entity->HasComponent()) - { - // We update the geometry of the PhysiscsObject linked to the PhysicsComponent2D - PhysicsComponent2D& physComponent = m_entity->GetComponent(); - physComponent.GetRigidBody()->SetGeom(m_geom); - } - else - { - NazaraAssert(m_staticBody, "An entity without physics component should have a static body"); - m_staticBody->SetGeom(m_geom); - } + GetRigidBody()->SetGeom(m_geom); + } + + void CollisionComponent2D::SetGeomOffset(const Nz::Vector2f& geomOffset) + { + GetRigidBody()->SetPositionOffset(geomOffset); } /*! @@ -47,7 +60,6 @@ namespace Ndk * \remark Produces a NazaraAssert if entity is invalid * \remark Produces a NazaraAssert if entity is not linked to a world, or the world has no physics system */ - void CollisionComponent2D::InitializeStaticBody() { NazaraAssert(m_entity, "Invalid entity"); @@ -67,7 +79,34 @@ namespace Ndk matrix.MakeIdentity(); m_staticBody->SetPosition(Nz::Vector2f(matrix.GetTranslation())); + } + Nz::RigidBody2D* CollisionComponent2D::GetRigidBody() + { + if (m_entity->HasComponent()) + { + PhysicsComponent2D& physComponent = m_entity->GetComponent(); + return physComponent.GetRigidBody(); + } + else + { + NazaraAssert(m_staticBody, "An entity without physics component should have a static body"); + return m_staticBody.get(); + } + } + + const Nz::RigidBody2D* CollisionComponent2D::GetRigidBody() const + { + if (m_entity->HasComponent()) + { + PhysicsComponent2D& physComponent = m_entity->GetComponent(); + return physComponent.GetRigidBody(); + } + else + { + NazaraAssert(m_staticBody, "An entity without physics component should have a static body"); + return m_staticBody.get(); + } } /*! diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index be90acc92..bc40ef9c0 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -32,7 +32,7 @@ namespace Nz RigidBody2D(PhysWorld2D* world, float mass); RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom); RigidBody2D(const RigidBody2D& object); - RigidBody2D(RigidBody2D&& object); + RigidBody2D(RigidBody2D&& object) noexcept; ~RigidBody2D(); void AddForce(const Vector2f& force, CoordSys coordSys = CoordSys_Global); @@ -60,6 +60,7 @@ namespace Nz Vector2f GetMassCenter(CoordSys coordSys = CoordSys_Local) const; float GetMomentOfInertia() const; Vector2f GetPosition() const; + inline const Vector2f& GetPositionOffset() const; RadianAnglef GetRotation() const; inline std::size_t GetShapeCount() const; std::size_t GetShapeIndex(cpShape* shape) const; @@ -87,6 +88,7 @@ namespace Nz void SetMassCenter(const Vector2f& center, CoordSys coordSys = CoordSys_Local); void SetMomentOfInertia(float moment); void SetPosition(const Vector2f& position); + void SetPositionOffset(const Vector2f& offset); void SetRotation(const RadianAnglef& rotation); void SetSurfaceVelocity(const Vector2f& surfaceVelocity); void SetSurfaceVelocity(std::size_t shapeIndex, const Vector2f& surfaceVelocity); @@ -114,6 +116,7 @@ namespace Nz static void CopyBodyData(cpBody* from, cpBody* to); static void CopyShapeData(cpShape* from, cpShape* to); + Vector2f m_positionOffset; VelocityFunc m_velocityFunc; std::vector m_shapes; Collider2DRef m_geom; diff --git a/include/Nazara/Physics2D/RigidBody2D.inl b/include/Nazara/Physics2D/RigidBody2D.inl index a654c03e7..272c8fe30 100644 --- a/include/Nazara/Physics2D/RigidBody2D.inl +++ b/include/Nazara/Physics2D/RigidBody2D.inl @@ -17,6 +17,11 @@ namespace Nz return GetMassCenter(coordSys); } + inline const Vector2f& RigidBody2D::GetPositionOffset() const + { + return m_positionOffset; + } + inline std::size_t RigidBody2D::GetShapeCount() const { return m_shapes.size(); diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index cc181930f..a4876a1e6 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -19,6 +19,7 @@ namespace Nz } RigidBody2D::RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom) : + m_positionOffset(Vector2f::Zero()), m_geom(), m_userData(nullptr), m_world(world), @@ -35,6 +36,7 @@ namespace Nz } RigidBody2D::RigidBody2D(const RigidBody2D& object) : + m_positionOffset(object.m_positionOffset), m_geom(object.m_geom), m_userData(object.m_userData), m_world(object.m_world), @@ -59,9 +61,10 @@ namespace Nz } } - RigidBody2D::RigidBody2D(RigidBody2D&& object) : + RigidBody2D::RigidBody2D(RigidBody2D&& object) noexcept : OnRigidBody2DMove(std::move(object.OnRigidBody2DMove)), OnRigidBody2DRelease(std::move(object.OnRigidBody2DRelease)), + m_positionOffset(std::move(object.m_positionOffset)), m_shapes(std::move(object.m_shapes)), m_geom(std::move(object.m_geom)), m_handle(object.m_handle), @@ -260,7 +263,7 @@ namespace Nz Vector2f RigidBody2D::GetPosition() const { - cpVect pos = cpBodyGetPosition(m_handle); + cpVect pos = cpBodyLocalToWorld(m_handle, cpv(-m_positionOffset.x, -m_positionOffset.y)); return Vector2f(static_cast(pos.x), static_cast(pos.y)); } @@ -467,7 +470,9 @@ namespace Nz void RigidBody2D::SetPosition(const Vector2f& position) { - cpBodySetPosition(m_handle, cpv(position.x, position.y)); + cpVect oldPosition = cpBodyGetPosition(m_handle); + + cpBodySetPosition(m_handle, cpBodyLocalToWorld(m_handle, cpv(position.x - oldPosition.x + m_positionOffset.x, position.y - oldPosition.y + m_positionOffset.y))); if (m_isStatic) { m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) @@ -477,6 +482,13 @@ namespace Nz } } + void RigidBody2D::SetPositionOffset(const Vector2f& offset) + { + Nz::Vector2f position = GetPosition(); + m_positionOffset = offset; + SetPosition(position); + } + void RigidBody2D::SetRotation(const RadianAnglef& rotation) { cpBodySetAngle(m_handle, rotation.value); @@ -573,6 +585,7 @@ namespace Nz m_geom = std::move(object.m_geom); m_gravityFactor = object.m_gravityFactor; m_mass = object.m_mass; + m_positionOffset = object.m_positionOffset; m_shapes = std::move(object.m_shapes); m_userData = object.m_userData; m_velocityFunc = std::move(object.m_velocityFunc); @@ -653,9 +666,10 @@ namespace Nz void RigidBody2D::CopyBodyData(cpBody* from, cpBody* to) { + cpBodySetCenterOfGravity(to, cpBodyGetCenterOfGravity(from)); + cpBodySetAngle(to, cpBodyGetAngle(from)); cpBodySetAngularVelocity(to, cpBodyGetAngularVelocity(from)); - cpBodySetCenterOfGravity(to, cpBodyGetCenterOfGravity(from)); cpBodySetForce(to, cpBodyGetForce(from)); cpBodySetPosition(to, cpBodyGetPosition(from)); cpBodySetTorque(to, cpBodyGetTorque(from)); From ce43b633b9aa2e7d3f75d67ab7bf9b52a5f071f9 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 19:02:27 +0100 Subject: [PATCH 35/77] Physics3D/Collider3D: Update ForEachPolygon signature --- ChangeLog.md | 1 + include/Nazara/Physics3D/Collider3D.hpp | 2 +- src/Nazara/Physics3D/Collider3D.cpp | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 410312517..39ead0d94 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -174,6 +174,7 @@ Nazara Engine: - Signal now implement a copy constructor and copy assignation operator for convenience - Fixed ENet UnreliableFragment packets sent as Unreliable (and such being incomplete upon reception) - ENet DisconnectLater now reflects libenet behavior (and is waiting for unreliable commands to be sent before disconnecting for good) +- ⚠ Collider3D::ForEachPolygon now takes a void(Vector3f\*, std::size_t) callback (instead of void(float\*, std::size_t)) Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Physics3D/Collider3D.hpp b/include/Nazara/Physics3D/Collider3D.hpp index a7a59a2d1..9dbfe126c 100644 --- a/include/Nazara/Physics3D/Collider3D.hpp +++ b/include/Nazara/Physics3D/Collider3D.hpp @@ -54,7 +54,7 @@ namespace Nz virtual void ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const; virtual float ComputeVolume() const; - virtual void ForEachPolygon(const std::function& callback) const; + virtual void ForEachPolygon(const std::function& callback) const; NewtonCollision* GetHandle(PhysWorld3D* world) const; virtual ColliderType3D GetType() const = 0; diff --git a/src/Nazara/Physics3D/Collider3D.cpp b/src/Nazara/Physics3D/Collider3D.cpp index 4dc2f6821..be7ceb6be 100644 --- a/src/Nazara/Physics3D/Collider3D.cpp +++ b/src/Nazara/Physics3D/Collider3D.cpp @@ -114,12 +114,14 @@ namespace Nz return volume; } - void Collider3D::ForEachPolygon(const std::function& callback) const + void Collider3D::ForEachPolygon(const std::function& callback) const { auto newtCallback = [](void* const userData, int vertexCount, const dFloat* const faceArray, int /*faceId*/) { + static_assert(sizeof(Vector3f) == 3 * sizeof(float), "Vector3 is expected to contain 3 floats without padding"); + const auto& cb = *static_cast>(userData); - cb(faceArray, vertexCount); + cb(reinterpret_cast(faceArray), vertexCount); }; // Check for existing collision handles, and create a temporary one if none is available From 11e98918ab2fe7c0e8d0a7b6f5a85c4d88c16293 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 19:03:56 +0100 Subject: [PATCH 36/77] Physics2D/Collider2D: Add ForEachPolygon method --- ChangeLog.md | 1 + include/Nazara/Physics2D/Collider2D.hpp | 4 +- src/Nazara/Physics2D/Collider2D.cpp | 69 ++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 39ead0d94..6027f226d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -175,6 +175,7 @@ Nazara Engine: - Fixed ENet UnreliableFragment packets sent as Unreliable (and such being incomplete upon reception) - ENet DisconnectLater now reflects libenet behavior (and is waiting for unreliable commands to be sent before disconnecting for good) - ⚠ Collider3D::ForEachPolygon now takes a void(Vector3f\*, std::size_t) callback (instead of void(float\*, std::size_t)) +- Added Collider2D::ForEachPolygon Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp index cc2f62eac..e817457b8 100644 --- a/include/Nazara/Physics2D/Collider2D.hpp +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -41,9 +41,11 @@ namespace Nz Collider2D(Collider2D&&) = delete; virtual ~Collider2D(); - virtual Nz::Vector2f ComputeCenterOfMass() const = 0; + virtual Vector2f ComputeCenterOfMass() const = 0; virtual float ComputeMomentOfInertia(float mass) const = 0; + virtual void ForEachPolygon(const std::function& callback) const; + inline UInt32 GetCategoryMask() const; inline UInt32 GetCollisionGroup() const; inline unsigned int GetCollisionId() const; diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 75f5fe332..f997f29f6 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -3,14 +3,81 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include #include -#include +#include +#include +#include namespace Nz { Collider2D::~Collider2D() = default; + void Collider2D::ForEachPolygon(const std::function& callback) const + { + // Currently, the only way to get only the polygons of a shape is to create a temporary cpSpace containing only this shape + // A better way to do this would be to reimplement this function in every subclass type in the very same way chipmunk does + + PhysWorld2D physWorld; + RigidBody2D rigidBody(&physWorld, 0.f); + + std::vector shapeVector; + rigidBody.SetGeom(const_cast(this), false, false); //< Won't be used for writing, but still ugly + + PhysWorld2D::DebugDrawOptions drawCallbacks; + drawCallbacks.circleCallback = [&](const Vector2f& origin, const RadianAnglef& /*rotation*/, float radius, Nz::Color /*outlineColor*/, Nz::Color /*fillColor*/, void* /*userData*/) + { + constexpr std::size_t circleVerticesCount = 20; + + std::array vertices; + + RadianAnglef angleBetweenVertices = 2.f * float(M_PI) / vertices.size(); + for (std::size_t i = 0; i < vertices.size(); ++i) + { + RadianAnglef angle = float(i) * angleBetweenVertices; + std::pair sincos = angle.GetSinCos(); + + vertices[i] = origin + Vector2f(radius * sincos.first, radius * sincos.second); + } + + callback(vertices.data(), vertices.size()); + }; + + drawCallbacks.polygonCallback = [&](const Vector2f* vertices, std::size_t vertexCount, float radius, Nz::Color /*outlineColor*/, Nz::Color /*fillColor*/, void* /*userData*/) + { + //TODO: Handle radius + callback(vertices, vertexCount); + }; + + drawCallbacks.segmentCallback = [&](const Vector2f& first, const Vector2f& second, Nz::Color /*color*/, void* /*userData*/) + { + std::array vertices = { first, second }; + + callback(vertices.data(), vertices.size()); + }; + + drawCallbacks.thickSegmentCallback = [&](const Vector2f& first, const Vector2f& second, float thickness, Nz::Color /*outlineColor*/, Nz::Color /*fillColor*/, void* /*userData*/) + { + static std::pair sincos = Nz::DegreeAnglef(90.f).GetSinCos(); + + Vector2f normal = Vector2f::Normalize(second - first); + Vector2f thicknessNormal(sincos.second * normal.x - sincos.first * normal.y, + sincos.first * normal.x + sincos.second * normal.y); + + std::array vertices; + vertices[0] = first + thickness * thicknessNormal; + vertices[1] = first - thickness * thicknessNormal; + vertices[2] = second - thickness * thicknessNormal; + vertices[3] = second + thickness * thicknessNormal; + + callback(vertices.data(), vertices.size()); + }; + + physWorld.DebugDraw(drawCallbacks, true, false, false); + } + std::size_t Collider2D::GenerateShapes(RigidBody2D* body, std::vector* shapes) const { std::size_t shapeCount = CreateShapes(body, shapes); From 1f5a82d1784712e2dbc2b0d0060c280dc2b3eace Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 19:04:13 +0100 Subject: [PATCH 37/77] Physics2D/Collider2D: Fix CircleCollider2D center of mass --- src/Nazara/Physics2D/Collider2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index f997f29f6..3a67797bd 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -142,7 +142,7 @@ namespace Nz Nz::Vector2f CircleCollider2D::ComputeCenterOfMass() const { - return m_offset + Nz::Vector2f(m_radius, m_radius); + return m_offset; } float CircleCollider2D::ComputeMomentOfInertia(float mass) const From e00d0baa005436603464c4275123ffb39aa509e2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 19:05:25 +0100 Subject: [PATCH 38/77] SDK/DebugSystem: Add support for Collider2D --- ChangeLog.md | 4 +- SDK/include/NDK/Components/DebugComponent.hpp | 2 +- SDK/include/NDK/Systems/DebugSystem.hpp | 1 + SDK/src/NDK/Systems/DebugSystem.cpp | 106 +++++++++++++++--- 4 files changed, 94 insertions(+), 19 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6027f226d..44ab35911 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -175,7 +175,7 @@ Nazara Engine: - Fixed ENet UnreliableFragment packets sent as Unreliable (and such being incomplete upon reception) - ENet DisconnectLater now reflects libenet behavior (and is waiting for unreliable commands to be sent before disconnecting for good) - ⚠ Collider3D::ForEachPolygon now takes a void(Vector3f\*, std::size_t) callback (instead of void(float\*, std::size_t)) -- Added Collider2D::ForEachPolygon +- Added Collider2D::ForEachPolygon method Nazara Development Kit: - Added ImageWidget (#139) @@ -219,7 +219,7 @@ Nazara Development Kit: - Fix GraphicsComponent bounding volume not taking local matrix in account - ⚠️ Rewrote all render queue system, which should be more efficient, take scissor box into account - ⚠️ All widgets are now bound to a scissor box when rendering -- Add DebugComponent (a component able to show aabb/obb/collision mesh) +- Add DebugComponent (a component able to show aabb/obb/collision mesh 2D and 3D) - ⚠️ TextAreaWidget now support text selection (WIP) - ⚠️ TextAreaWidget::GetHoveredGlyph now returns a two-dimensional position instead of a single glyph position - Fixed Entity::OnEntityDestruction signal not being properly moved and thus not being called. diff --git a/SDK/include/NDK/Components/DebugComponent.hpp b/SDK/include/NDK/Components/DebugComponent.hpp index 206f85724..0777a9812 100644 --- a/SDK/include/NDK/Components/DebugComponent.hpp +++ b/SDK/include/NDK/Components/DebugComponent.hpp @@ -16,7 +16,7 @@ namespace Ndk { enum class DebugDraw { - //TODO: Collider2D + Collider2D, Collider3D, GraphicsAABB, GraphicsOBB, diff --git a/SDK/include/NDK/Systems/DebugSystem.hpp b/SDK/include/NDK/Systems/DebugSystem.hpp index 3dd186f36..0cb4839b7 100644 --- a/SDK/include/NDK/Systems/DebugSystem.hpp +++ b/SDK/include/NDK/Systems/DebugSystem.hpp @@ -26,6 +26,7 @@ namespace Ndk private: Nz::InstancedRenderableRef GenerateBox(Nz::Boxf box); + Nz::InstancedRenderableRef GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* origin); Nz::InstancedRenderableRef GenerateCollision3DMesh(Entity* entity); Nz::MaterialRef GetCollisionMaterial(); diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index 063a25d77..21a184981 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -8,10 +8,12 @@ #include #include #include +#include #include #include #include #include +#include namespace Ndk { @@ -227,17 +229,26 @@ namespace Ndk { switch (option) { + case DebugDraw::Collider2D: + { + const Nz::Boxf& obb = entityGfx.GetAABB(); + + Nz::Vector3f origin; + Nz::InstancedRenderableRef renderable = GenerateCollision2DMesh(entity, &origin); + if (renderable) + entityGfx.Attach(renderable, Nz::Matrix4f::Translate(origin - entityNode.GetPosition()), DebugDrawOrder); + + entityDebug.UpdateDebugRenderable(option, std::move(renderable)); + break; + } + case DebugDraw::Collider3D: { const Nz::Boxf& obb = entityGfx.GetAABB(); Nz::InstancedRenderableRef renderable = GenerateCollision3DMesh(entity); if (renderable) - { - renderable->SetPersistent(false); - entityGfx.Attach(renderable, Nz::Matrix4f::Translate(obb.GetCenter() - entityNode.GetPosition()), DebugDrawOrder); - } entityDebug.UpdateDebugRenderable(option, std::move(renderable)); break; @@ -305,6 +316,73 @@ namespace Ndk return model; } + + Nz::InstancedRenderableRef DebugSystem::GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* origin) + { + if (entity->HasComponent()) + { + CollisionComponent2D& entityCollision = entity->GetComponent(); + const Nz::Collider2DRef& geom = entityCollision.GetGeom(); + + std::vector vertices; + std::vector indices; + + geom->ForEachPolygon([&](const Nz::Vector2f* polygonVertices, std::size_t vertexCount) + { + std::size_t firstIndex = vertices.size(); + + // Don't reserve and let the vector handle its own capacity + for (std::size_t i = 0; i < vertexCount; ++i) + vertices.emplace_back(*polygonVertices++); + + for (std::size_t i = 0; i < vertexCount - 1; ++i) + { + indices.push_back(firstIndex + i); + indices.push_back(firstIndex + i + 1); + } + + indices.push_back(firstIndex + vertexCount - 1); + indices.push_back(firstIndex); + }); + + Nz::IndexBufferRef indexBuffer = Nz::IndexBuffer::New(vertices.size() > 0xFFFF, Nz::UInt32(indices.size()), Nz::DataStorage_Hardware, 0); + Nz::IndexMapper indexMapper(indexBuffer, Nz::BufferAccess_WriteOnly); + + Nz::IndexIterator indexPtr = indexMapper.begin(); + for (std::size_t index : indices) + *indexPtr++ = static_cast(index); + + indexMapper.Unmap(); + + Nz::VertexBufferRef vertexBuffer = Nz::VertexBuffer::New(Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ), Nz::UInt32(vertices.size()), Nz::DataStorage_Hardware, 0); + vertexBuffer->Fill(vertices.data(), 0, Nz::UInt32(vertices.size())); + + Nz::MeshRef mesh = Nz::Mesh::New(); + mesh->CreateStatic(); + + Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(vertexBuffer, indexBuffer); + subMesh->SetPrimitiveMode(Nz::PrimitiveMode_LineList); + subMesh->SetMaterialIndex(0); + subMesh->GenerateAABB(); + + mesh->SetMaterialCount(1); + mesh->AddSubMesh(subMesh); + + Nz::ModelRef model = Nz::Model::New(); + model->SetMesh(mesh); + model->SetMaterial(0, GetCollisionMaterial()); + + // Find center of mass + if (entity->HasComponent()) + *origin = entity->GetComponent().GetMassCenter(Nz::CoordSys_Global); + else + *origin = entity->GetComponent().GetPosition(Nz::CoordSys_Global); + + return model; + } + else + return nullptr; + } Nz::InstancedRenderableRef DebugSystem::GenerateCollision3DMesh(Entity* entity) { @@ -315,16 +393,12 @@ namespace Ndk std::vector vertices; std::vector indices; - - geom->ForEachPolygon([&](const float* polygonVertices, std::size_t vertexCount) + + geom->ForEachPolygon([&](const Nz::Vector3f* polygonVertices, std::size_t vertexCount) { std::size_t firstIndex = vertices.size(); - - for (std::size_t i = 0; i < vertexCount; ++i) - { - const float* vertexData = &polygonVertices[i * 3]; - vertices.emplace_back(vertexData[0], vertexData[1], vertexData[2]); - } + vertices.resize(firstIndex + vertexCount); + std::copy(polygonVertices, polygonVertices + vertexCount, &vertices[firstIndex]); for (std::size_t i = 0; i < vertexCount - 1; ++i) { @@ -378,7 +452,7 @@ namespace Ndk m_globalAabbMaterial->EnableDepthBuffer(true); m_globalAabbMaterial->SetDiffuseColor(Nz::Color::Orange); m_globalAabbMaterial->SetFaceFilling(Nz::FaceFilling_Line); - m_globalAabbMaterial->SetLineWidth(2.f); + //m_globalAabbMaterial->SetLineWidth(2.f); } return m_globalAabbMaterial; @@ -393,7 +467,7 @@ namespace Ndk m_localAabbMaterial->EnableDepthBuffer(true); m_localAabbMaterial->SetDiffuseColor(Nz::Color::Red); m_localAabbMaterial->SetFaceFilling(Nz::FaceFilling_Line); - m_localAabbMaterial->SetLineWidth(2.f); + //m_localAabbMaterial->SetLineWidth(2.f); } return m_localAabbMaterial; @@ -408,7 +482,7 @@ namespace Ndk m_collisionMaterial->EnableDepthBuffer(true); m_collisionMaterial->SetDiffuseColor(Nz::Color::Blue); m_collisionMaterial->SetFaceFilling(Nz::FaceFilling_Line); - m_collisionMaterial->SetLineWidth(2.f); + //m_collisionMaterial->SetLineWidth(2.f); } return m_collisionMaterial; @@ -423,7 +497,7 @@ namespace Ndk m_obbMaterial->EnableDepthBuffer(true); m_obbMaterial->SetDiffuseColor(Nz::Color::Green); m_obbMaterial->SetFaceFilling(Nz::FaceFilling_Line); - m_obbMaterial->SetLineWidth(2.f); + //m_obbMaterial->SetLineWidth(2.f); } return m_obbMaterial; From 00ca0248c6e6ebc72ff5f5e1ff9be64bf052fcac Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 19:05:41 +0100 Subject: [PATCH 39/77] Fix unit tests (WIP) --- tests/Engine/Physics2D/RigidBody2D.cpp | 33 +++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/tests/Engine/Physics2D/RigidBody2D.cpp b/tests/Engine/Physics2D/RigidBody2D.cpp index 7eae99908..e554746d8 100644 --- a/tests/Engine/Physics2D/RigidBody2D.cpp +++ b/tests/Engine/Physics2D/RigidBody2D.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world); @@ -93,6 +94,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") std::vector tmp; tmp.push_back(CreateBody(world)); tmp.push_back(CreateBody(world)); + world.Step(1.f); THEN("They should be valid") @@ -112,11 +114,14 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); float mass = 1.f; - Nz::RigidBody2D body(&world, mass, box); + Nz::RigidBody2D body(&world, mass); + body.SetGeom(box, true, false); + bool userData = false; body.SetUserdata(&userData); Nz::Vector2f position = Nz::Vector2f::Zero(); + body.SetPosition(position); world.Step(1.f); @@ -126,7 +131,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") { CHECK(body.GetAABB() == aabb); CHECK(body.GetAngularVelocity() == 0.f); - CHECK(body.GetMassCenter() == Nz::Vector2f::Zero()); + CHECK(body.GetMassCenter(Nz::CoordSys_Global) == position); CHECK(body.GetGeom() == box); CHECK(body.GetMass() == Approx(mass)); CHECK(body.GetPosition() == position); @@ -150,7 +155,7 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") { aabb.Translate(velocity); CHECK(body.GetAABB() == aabb); - CHECK(body.GetMassCenter() == Nz::Vector2f::Zero()); + CHECK(body.GetMassCenter(Nz::CoordSys_Global) == position); CHECK(body.GetPosition() == position); CHECK(body.GetVelocity() == velocity); } @@ -211,7 +216,9 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") float radius = 5.f; Nz::Collider2DRef circle = Nz::CircleCollider2D::New(radius, position); float mass = 1.f; - Nz::RigidBody2D body(&world, mass, circle); + Nz::RigidBody2D body(&world, mass); + body.SetGeom(circle, true, false); + world.Step(1.f); WHEN("We ask for the aabb of the circle") @@ -240,7 +247,9 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::CompoundCollider2DRef compound = Nz::CompoundCollider2D::New(colliders); float mass = 1.f; - Nz::RigidBody2D body(&world, mass, compound); + Nz::RigidBody2D body(&world, mass); + body.SetGeom(compound, true, false); + world.Step(1.f); WHEN("We ask for the aabb of the compound") @@ -267,7 +276,9 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::SparsePtr sparsePtr(vertices.data()); Nz::ConvexCollider2DRef convex = Nz::ConvexCollider2D::New(sparsePtr, vertices.size()); float mass = 1.f; - Nz::RigidBody2D body(&world, mass, convex); + Nz::RigidBody2D body(&world, mass); + body.SetGeom(convex, true, false); + world.Step(1.f); WHEN("We ask for the aabb of the convex") @@ -289,7 +300,9 @@ SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") Nz::Vector2f positionB(1.f, -4.f); Nz::Collider2DRef segment = Nz::SegmentCollider2D::New(positionA, positionB, 0.f); float mass = 1.f; - Nz::RigidBody2D body(&world, mass, segment); + Nz::RigidBody2D body(&world, mass); + body.SetGeom(segment, true, false); + world.Step(1.f); WHEN("We ask for the aabb of the segment") @@ -309,7 +322,11 @@ Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world) Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); float mass = 1.f; - return Nz::RigidBody2D(&world, mass, box); + + Nz::RigidBody2D body(&world, mass, box); + body.SetPosition(Nz::Vector2f::Zero()); + + return body; } void EQUALITY(const Nz::RigidBody2D& left, const Nz::RigidBody2D& right) From c05d39ed28bafaf0231b6edbf304ba426d35e386 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 19:09:46 +0100 Subject: [PATCH 40/77] Fix some indentation shit --- src/Nazara/Platform/Win32/InputImpl.cpp | 2 +- src/Nazara/Platform/Win32/WindowImpl.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Platform/Win32/InputImpl.cpp b/src/Nazara/Platform/Win32/InputImpl.cpp index f44594fa4..79a8b6a3c 100644 --- a/src/Nazara/Platform/Win32/InputImpl.cpp +++ b/src/Nazara/Platform/Win32/InputImpl.cpp @@ -292,5 +292,5 @@ namespace Nz } else NazaraError("Invalid window handle"); - } + } } diff --git a/src/Nazara/Platform/Win32/WindowImpl.cpp b/src/Nazara/Platform/Win32/WindowImpl.cpp index 1e5135168..27b4fa889 100644 --- a/src/Nazara/Platform/Win32/WindowImpl.cpp +++ b/src/Nazara/Platform/Win32/WindowImpl.cpp @@ -71,8 +71,8 @@ namespace Nz win32Mode.dmBitsPerPel = mode.bitsPerPixel; win32Mode.dmPelsHeight = mode.height; win32Mode.dmPelsWidth = mode.width; - win32Mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; - win32Mode.dmSize = sizeof(DEVMODE); + win32Mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + win32Mode.dmSize = sizeof(DEVMODE); if (ChangeDisplaySettings(&win32Mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { From 1880f88e8f5836c1d1b298166e00a2d73d864097 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 20:33:29 +0100 Subject: [PATCH 41/77] Fix unit tests --- tests/SDK/NDK/Systems/PhysicsSystem2D.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp index d94797065..770f1e190 100644 --- a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp +++ b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp @@ -6,7 +6,7 @@ #include #include -Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf AABB); +Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf& AABB); SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") { @@ -80,6 +80,8 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB); Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent(); Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent(); + physicsComponent2D.SetMassCenter(Nz::Vector2f::Zero()); + physicsComponent2D.SetPosition(position); world.GetSystem().SetFixedUpdateRate(30.f); @@ -124,6 +126,8 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB); Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent(); Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent(); + physicsComponent2D.SetMassCenter(Nz::Vector2f::Zero()); + physicsComponent2D.SetPosition(position); world.GetSystem().SetFixedUpdateRate(30.f); @@ -145,7 +149,7 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") } } -Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf AABB) +Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf& AABB) { Ndk::EntityHandle entity = world.CreateEntity(); Ndk::NodeComponent& nodeComponent = entity->AddComponent(); From 59dffe1a7bab7b2d2e818fc0adef78cca7c53f11 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 21:02:31 +0100 Subject: [PATCH 42/77] CollisionComponent2D: Rename Align to Center (and make it take a vector) --- .../NDK/Components/CollisionComponent2D.hpp | 4 +-- .../NDK/Components/CollisionComponent2D.cpp | 28 +++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/SDK/include/NDK/Components/CollisionComponent2D.hpp b/SDK/include/NDK/Components/CollisionComponent2D.hpp index 140846d62..ef8043629 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.hpp +++ b/SDK/include/NDK/Components/CollisionComponent2D.hpp @@ -28,12 +28,12 @@ namespace Ndk CollisionComponent2D(const CollisionComponent2D& collision); ~CollisionComponent2D() = default; - void Align(const Nz::Rectf& aabb); - Nz::Rectf GetAABB() const; const Nz::Collider2DRef& GetGeom() const; const Nz::Vector2f& GetGeomOffset() const; + void Recenter(const Nz::Vector2f& origin); + void SetGeom(Nz::Collider2DRef geom); void SetGeomOffset(const Nz::Vector2f& geomOffset); diff --git a/SDK/src/NDK/Components/CollisionComponent2D.cpp b/SDK/src/NDK/Components/CollisionComponent2D.cpp index 84582c261..fddbe8842 100644 --- a/SDK/src/NDK/Components/CollisionComponent2D.cpp +++ b/SDK/src/NDK/Components/CollisionComponent2D.cpp @@ -17,12 +17,6 @@ namespace Ndk * \brief NDK class that represents a two-dimensional collision geometry */ - void CollisionComponent2D::Align(const Nz::Rectf& aabb) - { - const Nz::RigidBody2D* rigidBody = GetRigidBody(); - SetGeomOffset(aabb.GetCenter() - rigidBody->GetAABB().GetCenter() + rigidBody->GetPositionOffset()); - } - /*! * \brief Gets the collision box representing the entity * \return The physics collision box @@ -32,11 +26,28 @@ namespace Ndk return GetRigidBody()->GetAABB(); } + /*! + * \brief Gets the position offset between the actual rigid body center of mass position and the origin of the geometry + * \return Position offset + */ const Nz::Vector2f& CollisionComponent2D::GetGeomOffset() const { return GetRigidBody()->GetPositionOffset(); } + /*! + * \brief Convenience function to align center of geometry to a specific point + * + * \param geomOffset Position offset + * + * \remark This does not change the center of mass + */ + void CollisionComponent2D::Recenter(const Nz::Vector2f& origin) + { + const Nz::RigidBody2D* rigidBody = GetRigidBody(); + SetGeomOffset(origin - rigidBody->GetAABB().GetCenter() + rigidBody->GetPositionOffset()); + } + /*! * \brief Sets geometry for the entity * @@ -49,6 +60,11 @@ namespace Ndk GetRigidBody()->SetGeom(m_geom); } + /*! + * \brief Sets the position offset between the actual rigid body center of mass position and the origin of the geometry + * + * \param geomOffset Position offset + */ void CollisionComponent2D::SetGeomOffset(const Nz::Vector2f& geomOffset) { GetRigidBody()->SetPositionOffset(geomOffset); From ae20ad6b65606c989977b209da7e82f6ec90857c Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 21:02:50 +0100 Subject: [PATCH 43/77] Sdk/DebugSystem: Take position offset into account --- SDK/src/NDK/Systems/DebugSystem.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index 21a184981..df429dd1d 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -232,11 +232,12 @@ namespace Ndk case DebugDraw::Collider2D: { const Nz::Boxf& obb = entityGfx.GetAABB(); + CollisionComponent2D& entityCollision2D = entity->GetComponent(); Nz::Vector3f origin; Nz::InstancedRenderableRef renderable = GenerateCollision2DMesh(entity, &origin); if (renderable) - entityGfx.Attach(renderable, Nz::Matrix4f::Translate(origin - entityNode.GetPosition()), DebugDrawOrder); + entityGfx.Attach(renderable, Nz::Matrix4f::Translate(origin - entityNode.GetPosition() + entityCollision2D.GetGeomOffset()), DebugDrawOrder); entityDebug.UpdateDebugRenderable(option, std::move(renderable)); break; From 4821eb14a7e27710129dbbe1dc27255666b2e10f Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 26 Mar 2019 22:01:10 +0100 Subject: [PATCH 44/77] Physics2D: Fix some last stuffs --- ChangeLog.md | 2 ++ .../NDK/Components/CollisionComponent2D.hpp | 4 +++- .../NDK/Components/CollisionComponent2D.inl | 10 +++++----- SDK/include/NDK/Systems/DebugSystem.hpp | 2 +- SDK/src/NDK/Components/PhysicsComponent2D.cpp | 11 ++++++++++- SDK/src/NDK/Systems/DebugSystem.cpp | 15 +++++++++------ SDK/src/NDK/Systems/PhysicsSystem2D.cpp | 8 +++----- 7 files changed, 33 insertions(+), 19 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 44ab35911..d2c5b2d83 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -176,6 +176,7 @@ Nazara Engine: - ENet DisconnectLater now reflects libenet behavior (and is waiting for unreliable commands to be sent before disconnecting for good) - ⚠ Collider3D::ForEachPolygon now takes a void(Vector3f\*, std::size_t) callback (instead of void(float\*, std::size_t)) - Added Collider2D::ForEachPolygon method +- Added RigidBody::[Get|Set]PositionOffset allowing set an offset between body logic position and body physics position (center of mass position) Nazara Development Kit: - Added ImageWidget (#139) @@ -248,6 +249,7 @@ Nazara Development Kit: - Add missing `recomputeMoment` parameter to PhysicsComponent2D::SetMass - Added possibility of disabling synchronization between PhysicsComponent2D and NodeComponent - Fixed GraphicsComponent not invalidating render queue on material change (causing crashes or visual errors) +- Added CollisionComponent2D::SetGeomOffset and CollisionComponent2D::Recenter # 0.4: diff --git a/SDK/include/NDK/Components/CollisionComponent2D.hpp b/SDK/include/NDK/Components/CollisionComponent2D.hpp index ef8043629..a5da3b8c2 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.hpp +++ b/SDK/include/NDK/Components/CollisionComponent2D.hpp @@ -20,8 +20,9 @@ namespace Ndk class NDK_API CollisionComponent2D : public Component { - friend class PhysicsSystem2D; friend class ConstraintComponent2D; + friend class PhysicsComponent2D; + friend class PhysicsSystem2D; public: CollisionComponent2D(Nz::Collider2DRef geom = Nz::Collider2DRef()); @@ -47,6 +48,7 @@ namespace Ndk Nz::RigidBody2D* GetRigidBody(); const Nz::RigidBody2D* GetRigidBody() const; Nz::RigidBody2D* GetStaticBody(); + const Nz::RigidBody2D* GetStaticBody() const; void OnAttached() override; void OnComponentAttached(BaseComponent& component) override; diff --git a/SDK/include/NDK/Components/CollisionComponent2D.inl b/SDK/include/NDK/Components/CollisionComponent2D.inl index 010780443..1bc9f0978 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.inl +++ b/SDK/include/NDK/Components/CollisionComponent2D.inl @@ -52,13 +52,13 @@ namespace Ndk return *this; } - /*! - * \brief Gets the static body used by the entity - * \return A pointer to the entity - */ - inline Nz::RigidBody2D* CollisionComponent2D::GetStaticBody() { return m_staticBody.get(); } + + inline const Nz::RigidBody2D* CollisionComponent2D::GetStaticBody() const + { + return m_staticBody.get(); + } } diff --git a/SDK/include/NDK/Systems/DebugSystem.hpp b/SDK/include/NDK/Systems/DebugSystem.hpp index 0cb4839b7..362b59f32 100644 --- a/SDK/include/NDK/Systems/DebugSystem.hpp +++ b/SDK/include/NDK/Systems/DebugSystem.hpp @@ -26,7 +26,7 @@ namespace Ndk private: Nz::InstancedRenderableRef GenerateBox(Nz::Boxf box); - Nz::InstancedRenderableRef GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* origin); + Nz::InstancedRenderableRef GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* offset); Nz::InstancedRenderableRef GenerateCollision3DMesh(Entity* entity); Nz::MaterialRef GetCollisionMaterial(); diff --git a/SDK/src/NDK/Components/PhysicsComponent2D.cpp b/SDK/src/NDK/Components/PhysicsComponent2D.cpp index 62cd922a4..f9feaff6e 100644 --- a/SDK/src/NDK/Components/PhysicsComponent2D.cpp +++ b/SDK/src/NDK/Components/PhysicsComponent2D.cpp @@ -31,9 +31,17 @@ namespace Ndk Nz::PhysWorld2D& world = entityWorld->GetSystem().GetPhysWorld(); + Nz::Vector2f positionOffset; + Nz::Collider2DRef geom; if (m_entity->HasComponent()) - geom = m_entity->GetComponent().GetGeom(); + { + const CollisionComponent2D& entityCollision = m_entity->GetComponent(); + geom = entityCollision.GetGeom(); + positionOffset = entityCollision.GetStaticBody()->GetPositionOffset(); //< Calling GetGeomOffset would retrieve current component which is not yet initialized + } + else + positionOffset = Nz::Vector2f::Zero(); Nz::Matrix4f matrix; if (m_entity->HasComponent()) @@ -42,6 +50,7 @@ namespace Ndk matrix.MakeIdentity(); m_object = std::make_unique(&world, 1.f, geom); + m_object->SetPositionOffset(positionOffset); m_object->SetPosition(Nz::Vector2f(matrix.GetTranslation())); m_object->SetUserdata(reinterpret_cast(static_cast(m_entity->GetId()))); } diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index df429dd1d..54295f611 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -234,10 +234,10 @@ namespace Ndk const Nz::Boxf& obb = entityGfx.GetAABB(); CollisionComponent2D& entityCollision2D = entity->GetComponent(); - Nz::Vector3f origin; - Nz::InstancedRenderableRef renderable = GenerateCollision2DMesh(entity, &origin); + Nz::Vector3f offset; + Nz::InstancedRenderableRef renderable = GenerateCollision2DMesh(entity, &offset); if (renderable) - entityGfx.Attach(renderable, Nz::Matrix4f::Translate(origin - entityNode.GetPosition() + entityCollision2D.GetGeomOffset()), DebugDrawOrder); + entityGfx.Attach(renderable, Nz::Matrix4f::Translate(offset), DebugDrawOrder); entityDebug.UpdateDebugRenderable(option, std::move(renderable)); break; @@ -318,7 +318,7 @@ namespace Ndk return model; } - Nz::InstancedRenderableRef DebugSystem::GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* origin) + Nz::InstancedRenderableRef DebugSystem::GenerateCollision2DMesh(Entity* entity, Nz::Vector3f* offset) { if (entity->HasComponent()) { @@ -375,9 +375,12 @@ namespace Ndk // Find center of mass if (entity->HasComponent()) - *origin = entity->GetComponent().GetMassCenter(Nz::CoordSys_Global); + { + const PhysicsComponent2D& entityPhys = entity->GetComponent(); + *offset = entityPhys.GetMassCenter(Nz::CoordSys_Global) - entityPhys.GetPosition(); // GetPosition already takes GetGeomOffset into account + } else - *origin = entity->GetComponent().GetPosition(Nz::CoordSys_Global); + *offset = entityCollision.GetGeomOffset(); return model; } diff --git a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp index 6579bb1fb..dac509128 100644 --- a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp +++ b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp @@ -213,7 +213,7 @@ namespace Ndk Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys_Global)); // To move static objects and ensure their collisions, we have to specify them a velocity - // (/!\: the physical motor does not apply the speed on static objects) + // (/!\: the physical engine does not apply the speed on static objects) if (newPosition != oldPosition) { body->SetPosition(newPosition); @@ -222,8 +222,7 @@ namespace Ndk else body->SetVelocity(Nz::Vector2f::Zero()); -/* - if (newRotation != oldRotation) + /*if (newRotation != oldRotation) { Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate(); Nz::EulerAnglesf angles = transition.ToEulerAngles(); @@ -235,8 +234,7 @@ namespace Ndk physObj->SetAngularVelocity(angularVelocity); } else - physObj->SetAngularVelocity(Nz::Vector3f::Zero()); -*/ + physObj->SetAngularVelocity(Nz::Vector3f::Zero());*/ } } From 4ff43f2f72ccc211198a105f6652ceadb26becf1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 27 Mar 2019 23:10:37 +0100 Subject: [PATCH 45/77] Sdk/DebugSystem: Fix collision 2D offset --- SDK/src/NDK/Systems/DebugSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index 54295f611..f2175e559 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -377,7 +377,7 @@ namespace Ndk if (entity->HasComponent()) { const PhysicsComponent2D& entityPhys = entity->GetComponent(); - *offset = entityPhys.GetMassCenter(Nz::CoordSys_Global) - entityPhys.GetPosition(); // GetPosition already takes GetGeomOffset into account + *offset = entityPhys.GetMassCenter(Nz::CoordSys_Local) + entityCollision.GetGeomOffset(); } else *offset = entityCollision.GetGeomOffset(); From b2da8d6c91af5f5d4ec4e5cc1afe85a5ddd5555f Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 27 Mar 2019 23:13:14 +0100 Subject: [PATCH 46/77] Fix compilation --- include/Nazara/Utility/AbstractAtlas.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/Nazara/Utility/AbstractAtlas.hpp b/include/Nazara/Utility/AbstractAtlas.hpp index bb6c77c2f..fc84cfa0e 100644 --- a/include/Nazara/Utility/AbstractAtlas.hpp +++ b/include/Nazara/Utility/AbstractAtlas.hpp @@ -22,6 +22,8 @@ namespace Nz { public: AbstractAtlas() = default; + AbstractAtlas(const AbstractAtlas&) = delete; + AbstractAtlas(AbstractAtlas&&) noexcept = default; virtual ~AbstractAtlas(); virtual void Clear() = 0; @@ -31,6 +33,9 @@ namespace Nz virtual UInt32 GetStorage() const = 0; virtual bool Insert(const Image& image, Rectui* rect, bool* flipped, unsigned int* layerIndex) = 0; + AbstractAtlas& operator=(const AbstractAtlas&) = delete; + AbstractAtlas& operator=(AbstractAtlas&&) noexcept = default; + // Signals: NazaraSignal(OnAtlasCleared, const AbstractAtlas* /*atlas*/); NazaraSignal(OnAtlasLayerChange, const AbstractAtlas* /*atlas*/, AbstractImage* /*oldLayer*/, AbstractImage* /*newLayer*/); From 5b48012deeaef1cfe26584b2dec50cb10d39f036 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 28 Mar 2019 00:02:22 +0100 Subject: [PATCH 47/77] Fix unit test --- tests/Engine/Network/IpAddress.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Engine/Network/IpAddress.cpp b/tests/Engine/Network/IpAddress.cpp index abcb65909..0c36e2a96 100644 --- a/tests/Engine/Network/IpAddress.cpp +++ b/tests/Engine/Network/IpAddress.cpp @@ -40,7 +40,7 @@ SCENARIO("IpAddress", "[NETWORK][IPADDRESS]") Nz::IpAddress google(8, 8, 8, 8); THEN("Google (DNS) is 8.8.8.8") { - CHECK(Nz::IpAddress::ResolveAddress(google) == "google-public-dns-a.google.com"); + CHECK(Nz::IpAddress::ResolveAddress(google) == "dns.google"); } } } From 0ca823f9a695f2d78fe4b8c6de7491635c37db7e Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 31 Mar 2019 16:31:02 +0200 Subject: [PATCH 48/77] Graphics: Remove sprite limit --- .../Nazara/Graphics/DeferredGeometryPass.hpp | 10 +- .../Nazara/Graphics/DepthRenderTechnique.hpp | 10 +- src/Nazara/Graphics/DeferredGeometryPass.cpp | 186 ++++++++------- src/Nazara/Graphics/DepthRenderTechnique.cpp | 188 +++++++++------- .../Graphics/ForwardRenderTechnique.cpp | 211 ++++++++++-------- 5 files changed, 347 insertions(+), 258 deletions(-) diff --git a/include/Nazara/Graphics/DeferredGeometryPass.hpp b/include/Nazara/Graphics/DeferredGeometryPass.hpp index 3c7890bfe..043378642 100644 --- a/include/Nazara/Graphics/DeferredGeometryPass.hpp +++ b/include/Nazara/Graphics/DeferredGeometryPass.hpp @@ -51,8 +51,16 @@ namespace Nz int textureOverlay; }; + struct SpriteBatch + { + std::size_t spriteCount; + const Material* material; + const Texture* overlayTexture; + Recti scissorRect; + }; + mutable std::unordered_map m_shaderUniforms; - mutable std::vector> m_spriteChains; + mutable std::vector m_spriteBatches; Buffer m_vertexBuffer; RenderStates m_clearStates; ShaderRef m_clearShader; diff --git a/include/Nazara/Graphics/DepthRenderTechnique.hpp b/include/Nazara/Graphics/DepthRenderTechnique.hpp index f8f7bc4e3..5ae883352 100644 --- a/include/Nazara/Graphics/DepthRenderTechnique.hpp +++ b/include/Nazara/Graphics/DepthRenderTechnique.hpp @@ -61,8 +61,16 @@ namespace Nz int textureOverlay; }; + struct SpriteBatch + { + std::size_t spriteCount; + const Material* material; + const Texture* overlayTexture; + Recti scissorRect; + }; + mutable std::unordered_map m_shaderUniforms; - mutable std::vector> m_spriteChains; + mutable std::vector m_spriteBatches; Buffer m_vertexBuffer; RenderStates m_clearStates; ShaderRef m_clearShader; diff --git a/src/Nazara/Graphics/DeferredGeometryPass.cpp b/src/Nazara/Graphics/DeferredGeometryPass.cpp index dbd500ea4..0129c4980 100644 --- a/src/Nazara/Graphics/DeferredGeometryPass.cpp +++ b/src/Nazara/Graphics/DeferredGeometryPass.cpp @@ -29,8 +29,8 @@ namespace Nz Vector2f uv; }; - UInt32 s_maxQuads = std::numeric_limits::max() / 6; - UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + constexpr UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + constexpr UInt32 s_maxQuadPerDraw = s_vertexBufferSize / sizeof(VertexLayout_XYZ_Color_UV); } /*! @@ -468,62 +468,9 @@ namespace Nz const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); - Renderer::SetIndexBuffer(&s_quadIndexBuffer); - Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); - Renderer::SetVertexBuffer(&m_spriteBuffer); + const std::size_t maxSpriteCount = std::min(s_maxQuadPerDraw, m_spriteBuffer.GetVertexCount() / 4); const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); - const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); - - m_spriteChains.clear(); - - auto Commit = [&]() - { - std::size_t spriteChainCount = m_spriteChains.size(); - if (spriteChainCount > 0) - { - std::size_t spriteChain = 0; // Which chain of sprites are we treating - std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain - - do - { - // We open the buffer in writing mode - BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); - VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); - - std::size_t spriteCount = 0; - - do - { - const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first; - std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second; - std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset); - - std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); - vertices += count * 4; - - spriteCount += count; - spriteChainOffset += count; - - // Have we treated the entire chain ? - if (spriteChainOffset == currentChainSpriteCount) - { - spriteChain++; - spriteChainOffset = 0; - } - } - while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); - - vertexMapper.Unmap(); - - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); - } - while (spriteChain < spriteChainCount); - } - - m_spriteChains.clear(); - }; - const Material* lastMaterial = nullptr; const MaterialPipeline* lastPipeline = nullptr; const Shader* lastShader = nullptr; @@ -533,18 +480,19 @@ namespace Nz const MaterialPipeline::Instance* pipelineInstance = nullptr; - for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) + Renderer::SetIndexBuffer(&s_quadIndexBuffer); + Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); + Renderer::SetVertexBuffer(&m_spriteBuffer); + + auto Draw = [&]() { - const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; - - if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + unsigned int firstIndex = 0; + for (const auto& batch : m_spriteBatches) { - Commit(); - - const MaterialPipeline* pipeline = basicSprites.material->GetPipeline(); - if (lastPipeline != pipeline) + const MaterialPipeline* pipeline = batch.material->GetPipeline(); + if (pipeline != lastPipeline) { - pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); const Shader* shader = pipelineInstance->uberInstance->GetShader(); if (shader != lastShader) @@ -566,33 +514,105 @@ namespace Nz lastPipeline = pipeline; } - if (lastMaterial != basicSprites.material) + if (batch.material != lastMaterial) { - basicSprites.material->Apply(*pipelineInstance); + batch.material->Apply(*pipelineInstance); - Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); + Renderer::SetTextureSampler(overlayTextureUnit, batch.material->GetDiffuseSampler()); - lastMaterial = basicSprites.material; + lastMaterial = batch.material; } + if (batch.overlayTexture != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, batch.overlayTexture); + lastOverlay = batch.overlayTexture; + } + + if (batch.material->IsScissorTestEnabled() && batch.scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(batch.scissorRect); + lastScissorRect = batch.scissorRect; + } + + unsigned int indexCount = batch.spriteCount * 6; + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount); + firstIndex += indexCount; + } + }; + + m_spriteBatches.clear(); + { + BufferMapper vertexMapper; + VertexStruct_XYZ_Color_UV* vertices = nullptr; + + std::size_t remainingSprite = maxSpriteCount; + + const Material* lastMaterial = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) + { const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); - if (overlayTexture != lastOverlay) - { - Renderer::SetTexture(overlayTextureUnit, overlayTexture); - lastOverlay = overlayTexture; - } + const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; - if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + const VertexStruct_XYZ_Color_UV* spriteVertices = basicSprites.vertices; + std::size_t spriteCount = basicSprites.spriteCount; + + for (;;) { - Renderer::SetScissorRect(scissorRect); - lastScissorRect = scissorRect; + if (m_spriteBatches.empty() || basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + m_spriteBatches.emplace_back(); + SpriteBatch& newBatch = m_spriteBatches.back(); + newBatch.material = basicSprites.material; + newBatch.overlayTexture = overlayTexture; + newBatch.scissorRect = scissorRect; + newBatch.spriteCount = 0; + + lastMaterial = basicSprites.material; + lastOverlay = overlayTexture; + lastScissorRect = scissorRect; + } + + SpriteBatch& currentBatch = m_spriteBatches.back(); + + if (!vertices) + { + vertexMapper.Map(m_spriteBuffer, BufferAccess_DiscardAndWrite); + vertices = static_cast(vertexMapper.GetPointer()); + } + + std::size_t processedSpriteCount = std::min(remainingSprite, spriteCount); + std::size_t processedVertices = processedSpriteCount * 4; + + std::memcpy(vertices, spriteVertices, processedVertices * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += processedVertices; + spriteVertices += processedVertices; + + currentBatch.spriteCount += processedSpriteCount; + spriteCount -= processedSpriteCount; + + remainingSprite -= processedSpriteCount; + if (remainingSprite == 0) + { + vertexMapper.Unmap(); + vertices = nullptr; + + Draw(); + + remainingSprite = maxSpriteCount; + m_spriteBatches.clear(); + } + + if (spriteCount == 0) + break; } } - - m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); } - Commit(); + Draw(); } const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const @@ -631,12 +651,12 @@ namespace Nz { ErrorFlags flags(ErrorFlag_ThrowException, true); - s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); + s_quadIndexBuffer.Reset(true, s_maxQuadPerDraw * 6, DataStorage_Hardware, 0); BufferMapper mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); - UInt16* indices = static_cast(mapper.GetPointer()); + UInt32* indices = static_cast(mapper.GetPointer()); - for (unsigned int i = 0; i < s_maxQuads; ++i) + for (UInt32 i = 0; i < s_maxQuadPerDraw; ++i) { *indices++ = i * 4 + 0; *indices++ = i * 4 + 2; diff --git a/src/Nazara/Graphics/DepthRenderTechnique.cpp b/src/Nazara/Graphics/DepthRenderTechnique.cpp index 5435d7497..531b9988a 100644 --- a/src/Nazara/Graphics/DepthRenderTechnique.cpp +++ b/src/Nazara/Graphics/DepthRenderTechnique.cpp @@ -31,8 +31,8 @@ namespace Nz Vector2f uv; }; - unsigned int s_maxQuads = std::numeric_limits::max() / 6; - unsigned int s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + constexpr UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + constexpr UInt32 s_maxQuadPerDraw = s_vertexBufferSize / sizeof(VertexLayout_XYZ_Color_UV); } /*! @@ -46,7 +46,7 @@ namespace Nz */ DepthRenderTechnique::DepthRenderTechnique() : - m_vertexBuffer(BufferType_Vertex) + m_vertexBuffer(BufferType_Vertex) { ErrorFlags flags(ErrorFlag_ThrowException, true); @@ -148,12 +148,12 @@ namespace Nz { ErrorFlags flags(ErrorFlag_ThrowException, true); - s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); + s_quadIndexBuffer.Reset(true, s_maxQuadPerDraw * 6, DataStorage_Hardware, 0); BufferMapper mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); - UInt16* indices = static_cast(mapper.GetPointer()); + UInt32* indices = static_cast(mapper.GetPointer()); - for (unsigned int i = 0; i < s_maxQuads; ++i) + for (UInt32 i = 0; i < s_maxQuadPerDraw; ++i) { *indices++ = i * 4 + 0; *indices++ = i * 4 + 2; @@ -486,62 +486,9 @@ namespace Nz const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); - Renderer::SetIndexBuffer(&s_quadIndexBuffer); - Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); - Renderer::SetVertexBuffer(&m_spriteBuffer); + const std::size_t maxSpriteCount = std::min(s_maxQuadPerDraw, m_spriteBuffer.GetVertexCount() / 4); const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); - const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); - - m_spriteChains.clear(); - - auto Commit = [&]() - { - std::size_t spriteChainCount = m_spriteChains.size(); - if (spriteChainCount > 0) - { - std::size_t spriteChain = 0; // Which chain of sprites are we treating - std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain - - do - { - // We open the buffer in writing mode - BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); - VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); - - std::size_t spriteCount = 0; - - do - { - const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first; - std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second; - std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset); - - std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); - vertices += count * 4; - - spriteCount += count; - spriteChainOffset += count; - - // Have we treated the entire chain ? - if (spriteChainOffset == currentChainSpriteCount) - { - spriteChain++; - spriteChainOffset = 0; - } - } - while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); - - vertexMapper.Unmap(); - - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); - } - while (spriteChain < spriteChainCount); - } - - m_spriteChains.clear(); - }; - const Material* lastMaterial = nullptr; const MaterialPipeline* lastPipeline = nullptr; const Shader* lastShader = nullptr; @@ -551,18 +498,19 @@ namespace Nz const MaterialPipeline::Instance* pipelineInstance = nullptr; - for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) + Renderer::SetIndexBuffer(&s_quadIndexBuffer); + Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); + Renderer::SetVertexBuffer(&m_spriteBuffer); + + auto Draw = [&]() { - const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; - - if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + unsigned int firstIndex = 0; + for (const auto& batch : m_spriteBatches) { - Commit(); - - const MaterialPipeline* pipeline = basicSprites.material->GetPipeline(); - if (lastPipeline != pipeline) + const MaterialPipeline* pipeline = batch.material->GetPipeline(); + if (pipeline != lastPipeline) { - pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); const Shader* shader = pipelineInstance->uberInstance->GetShader(); if (shader != lastShader) @@ -582,33 +530,105 @@ namespace Nz lastPipeline = pipeline; } - if (lastMaterial != basicSprites.material) + if (batch.material != lastMaterial) { - basicSprites.material->Apply(*pipelineInstance); + batch.material->Apply(*pipelineInstance); - Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); + Renderer::SetTextureSampler(overlayTextureUnit, batch.material->GetDiffuseSampler()); - lastMaterial = basicSprites.material; + lastMaterial = batch.material; } + if (batch.overlayTexture != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, batch.overlayTexture); + lastOverlay = batch.overlayTexture; + } + + if (batch.material->IsScissorTestEnabled() && batch.scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(batch.scissorRect); + lastScissorRect = batch.scissorRect; + } + + unsigned int indexCount = batch.spriteCount * 6; + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount); + firstIndex += indexCount; + } + }; + + m_spriteBatches.clear(); + { + BufferMapper vertexMapper; + VertexStruct_XYZ_Color_UV* vertices = nullptr; + + std::size_t remainingSprite = maxSpriteCount; + + const Material* lastMaterial = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) + { const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); - if (overlayTexture != lastOverlay) - { - Renderer::SetTexture(overlayTextureUnit, overlayTexture); - lastOverlay = overlayTexture; - } + const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; - if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + const VertexStruct_XYZ_Color_UV* spriteVertices = basicSprites.vertices; + std::size_t spriteCount = basicSprites.spriteCount; + + for (;;) { - Renderer::SetScissorRect(scissorRect); - lastScissorRect = scissorRect; + if (m_spriteBatches.empty() || basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + m_spriteBatches.emplace_back(); + SpriteBatch& newBatch = m_spriteBatches.back(); + newBatch.material = basicSprites.material; + newBatch.overlayTexture = overlayTexture; + newBatch.scissorRect = scissorRect; + newBatch.spriteCount = 0; + + lastMaterial = basicSprites.material; + lastOverlay = overlayTexture; + lastScissorRect = scissorRect; + } + + SpriteBatch& currentBatch = m_spriteBatches.back(); + + if (!vertices) + { + vertexMapper.Map(m_spriteBuffer, BufferAccess_DiscardAndWrite); + vertices = static_cast(vertexMapper.GetPointer()); + } + + std::size_t processedSpriteCount = std::min(remainingSprite, spriteCount); + std::size_t processedVertices = processedSpriteCount * 4; + + std::memcpy(vertices, spriteVertices, processedVertices * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += processedVertices; + spriteVertices += processedVertices; + + currentBatch.spriteCount += processedSpriteCount; + spriteCount -= processedSpriteCount; + + remainingSprite -= processedSpriteCount; + if (remainingSprite == 0) + { + vertexMapper.Unmap(); + vertices = nullptr; + + Draw(); + + remainingSprite = maxSpriteCount; + m_spriteBatches.clear(); + } + + if (spriteCount == 0) + break; } } - - m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); } - Commit(); + Draw(); } /*! diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 934d54d6d..77098ecf5 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -32,8 +32,8 @@ namespace Nz Vector2f uv; }; - UInt32 s_maxQuads = std::numeric_limits::max() / 6; - UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + constexpr UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + constexpr UInt32 s_maxQuadPerDraw = s_vertexBufferSize / sizeof(VertexLayout_XYZ_Color_UV); } /*! @@ -175,12 +175,12 @@ namespace Nz { ErrorFlags flags(ErrorFlag_ThrowException, true); - s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); + s_quadIndexBuffer.Reset(true, s_maxQuadPerDraw * 6, DataStorage_Hardware, 0); BufferMapper mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); - UInt16* indices = static_cast(mapper.GetPointer()); + UInt32* indices = static_cast(mapper.GetPointer()); - for (unsigned int i = 0; i < s_maxQuads; ++i) + for (UInt32 i = 0; i < s_maxQuadPerDraw; ++i) { *indices++ = i * 4 + 0; *indices++ = i * 4 + 2; @@ -618,52 +618,9 @@ namespace Nz const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + const std::size_t maxSpriteCount = std::min(s_maxQuadPerDraw, m_spriteBuffer.GetVertexCount() / 4); + const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); - const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); - - m_spriteBatches.clear(); - { - BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); - VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); - - std::size_t remainingSprite = maxSpriteCount; - - const Material* lastMaterial = nullptr; - const Texture* lastOverlay = nullptr; - Recti lastScissorRect = Recti(-1, -1); - - for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) - { - const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); - const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; - if (basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) - { - m_spriteBatches.emplace_back(); - SpriteBatch& newBatch = m_spriteBatches.back(); - newBatch.material = basicSprites.material; - newBatch.overlayTexture = overlayTexture; - newBatch.scissorRect = scissorRect; - newBatch.spriteCount = 0; - - lastMaterial = basicSprites.material; - lastOverlay = overlayTexture; - lastScissorRect = scissorRect; - } - - SpriteBatch& currentBatch = m_spriteBatches.back(); - - std::size_t spriteCount = std::min(remainingSprite, basicSprites.spriteCount); - std::memcpy(vertices, basicSprites.vertices, spriteCount * 4 * sizeof(VertexStruct_XYZ_Color_UV)); - vertices += spriteCount * 4; - - currentBatch.spriteCount += spriteCount; - - remainingSprite -= spriteCount; - if (remainingSprite == 0) - break; - } - } - const Material* lastMaterial = nullptr; const MaterialPipeline* lastPipeline = nullptr; const Shader* lastShader = nullptr; @@ -677,59 +634,135 @@ namespace Nz Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetVertexBuffer(&m_spriteBuffer); - unsigned int firstIndex = 0; - for (const auto& batch : m_spriteBatches) + auto Draw = [&]() { - const MaterialPipeline* pipeline = batch.material->GetPipeline(); - if (pipeline != lastPipeline) + unsigned int firstIndex = 0; + for (const auto& batch : m_spriteBatches) { - pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); - - const Shader* shader = pipelineInstance->uberInstance->GetShader(); - if (shader != lastShader) + const MaterialPipeline* pipeline = batch.material->GetPipeline(); + if (pipeline != lastPipeline) { - // Index of uniforms in the shader - shaderUniforms = GetShaderUniforms(shader); + pipelineInstance = &batch.material->GetPipeline()->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); - // Ambient color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position of the camera - shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + shaderUniforms = GetShaderUniforms(shader); - // Overlay texture unit - shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); + // Ambient color of the scene + shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + // Position of the camera + shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - lastShader = shader; + // Overlay texture unit + shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); + + lastShader = shader; + } + + lastPipeline = pipeline; } - lastPipeline = pipeline; - } + if (batch.material != lastMaterial) + { + batch.material->Apply(*pipelineInstance); - if (batch.material != lastMaterial) + Renderer::SetTextureSampler(overlayTextureUnit, batch.material->GetDiffuseSampler()); + + lastMaterial = batch.material; + } + + if (batch.overlayTexture != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, batch.overlayTexture); + lastOverlay = batch.overlayTexture; + } + + if (batch.material->IsScissorTestEnabled() && batch.scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(batch.scissorRect); + lastScissorRect = batch.scissorRect; + } + + unsigned int indexCount = batch.spriteCount * 6; + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount); + firstIndex += indexCount; + } + }; + + m_spriteBatches.clear(); + { + BufferMapper vertexMapper; + VertexStruct_XYZ_Color_UV* vertices = nullptr; + + std::size_t remainingSprite = maxSpriteCount; + + const Material* lastMaterial = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) { - batch.material->Apply(*pipelineInstance); + const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); + const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; - Renderer::SetTextureSampler(overlayTextureUnit, batch.material->GetDiffuseSampler()); + const VertexStruct_XYZ_Color_UV* spriteVertices = basicSprites.vertices; + std::size_t spriteCount = basicSprites.spriteCount; + + for (;;) + { + if (m_spriteBatches.empty() || basicSprites.material != lastMaterial || overlayTexture != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + m_spriteBatches.emplace_back(); + SpriteBatch& newBatch = m_spriteBatches.back(); + newBatch.material = basicSprites.material; + newBatch.overlayTexture = overlayTexture; + newBatch.scissorRect = scissorRect; + newBatch.spriteCount = 0; - lastMaterial = batch.material; + lastMaterial = basicSprites.material; + lastOverlay = overlayTexture; + lastScissorRect = scissorRect; + } + + SpriteBatch& currentBatch = m_spriteBatches.back(); + + if (!vertices) + { + vertexMapper.Map(m_spriteBuffer, BufferAccess_DiscardAndWrite); + vertices = static_cast(vertexMapper.GetPointer()); + } + + std::size_t processedSpriteCount = std::min(remainingSprite, spriteCount); + std::size_t processedVertices = processedSpriteCount * 4; + + std::memcpy(vertices, spriteVertices, processedVertices * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += processedVertices; + spriteVertices += processedVertices; + + currentBatch.spriteCount += processedSpriteCount; + spriteCount -= processedSpriteCount; + + remainingSprite -= processedSpriteCount; + if (remainingSprite == 0) + { + vertexMapper.Unmap(); + vertices = nullptr; + + Draw(); + + remainingSprite = maxSpriteCount; + m_spriteBatches.clear(); + } + + if (spriteCount == 0) + break; + } } - - if (batch.overlayTexture != lastOverlay) - { - Renderer::SetTexture(overlayTextureUnit, batch.overlayTexture); - lastOverlay = batch.overlayTexture; - } - - if (batch.material->IsScissorTestEnabled() && batch.scissorRect != lastScissorRect) - { - Renderer::SetScissorRect(batch.scissorRect); - lastScissorRect = batch.scissorRect; - } - - unsigned int indexCount = batch.spriteCount * 6; - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, firstIndex, indexCount); - firstIndex += indexCount; } + + Draw(); } const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const From 3efb54ea3c38487074dcf9a26534b67472508809 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 3 Apr 2019 21:14:17 +0200 Subject: [PATCH 49/77] Physics2D/RigidBody2D: Fix SetPosition --- src/Nazara/Physics2D/RigidBody2D.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index a4876a1e6..e4c29b19a 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -470,9 +470,8 @@ namespace Nz void RigidBody2D::SetPosition(const Vector2f& position) { - cpVect oldPosition = cpBodyGetPosition(m_handle); - - cpBodySetPosition(m_handle, cpBodyLocalToWorld(m_handle, cpv(position.x - oldPosition.x + m_positionOffset.x, position.y - oldPosition.y + m_positionOffset.y))); + // Use cpTransformVect to rotate/scale the position offset + cpBodySetPosition(m_handle, cpvadd(cpv(position.x, position.y), cpTransformVect(m_handle->transform, cpv(m_positionOffset.x, m_positionOffset.y)))); if (m_isStatic) { m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) From 5e724b9c047166928ebb0f403842823fb602ef45 Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 3 Apr 2019 21:14:40 +0200 Subject: [PATCH 50/77] SDK/PhysicsSystem2D: Fix crash when raycast doesn't hit --- SDK/src/NDK/Systems/PhysicsSystem2D.cpp | 36 ++++++++++++++----------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp index dac509128..1273d66bc 100644 --- a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp +++ b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp @@ -86,14 +86,17 @@ namespace Ndk bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result) { Nz::PhysWorld2D::NearestQueryResult queryResult; - bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &queryResult); + if (GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &queryResult)) + { + result->nearestBody = GetEntityFromBody(*queryResult.nearestBody); + result->closestPoint = std::move(queryResult.closestPoint); + result->fraction = std::move(queryResult.fraction); + result->distance = queryResult.distance; - result->nearestBody = GetEntityFromBody(*queryResult.nearestBody); - result->closestPoint = std::move(queryResult.closestPoint); - result->fraction = std::move(queryResult.fraction); - result->distance = queryResult.distance; - - return res; + return true; + } + else + return false; } bool PhysicsSystem2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos) @@ -108,7 +111,7 @@ namespace Ndk std::move(hitResult.hitPos), std::move(hitResult.hitNormal), hitResult.fraction - }); + }); } return res; @@ -117,14 +120,17 @@ namespace Ndk bool PhysicsSystem2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo) { Nz::PhysWorld2D::RaycastHit queryResult; - bool res = GetPhysWorld().RaycastQueryFirst(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult); + if (GetPhysWorld().RaycastQueryFirst(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult)) + { + hitInfo->body = GetEntityFromBody(*queryResult.nearestBody); + hitInfo->hitPos = std::move(queryResult.hitPos); + hitInfo->hitNormal = std::move(queryResult.hitNormal); + hitInfo->fraction = queryResult.fraction; - hitInfo->body = GetEntityFromBody(*queryResult.nearestBody); - hitInfo->hitPos = std::move(queryResult.hitPos); - hitInfo->hitNormal = std::move(queryResult.hitNormal); - hitInfo->fraction = queryResult.fraction; - - return res; + return true; + } + else + return false; } void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies) From 2f5e9e481b7b278e9b2b0230c288999af86845fb Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 3 Apr 2019 22:15:53 +0200 Subject: [PATCH 51/77] Fix unit tests --- tests/Engine/Network/IpAddress.cpp | 2 +- tests/SDK/NDK/Systems/RenderSystem.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/Engine/Network/IpAddress.cpp b/tests/Engine/Network/IpAddress.cpp index 0c36e2a96..abcb65909 100644 --- a/tests/Engine/Network/IpAddress.cpp +++ b/tests/Engine/Network/IpAddress.cpp @@ -40,7 +40,7 @@ SCENARIO("IpAddress", "[NETWORK][IPADDRESS]") Nz::IpAddress google(8, 8, 8, 8); THEN("Google (DNS) is 8.8.8.8") { - CHECK(Nz::IpAddress::ResolveAddress(google) == "dns.google"); + CHECK(Nz::IpAddress::ResolveAddress(google) == "google-public-dns-a.google.com"); } } } diff --git a/tests/SDK/NDK/Systems/RenderSystem.cpp b/tests/SDK/NDK/Systems/RenderSystem.cpp index 329818f74..e30fa3a03 100644 --- a/tests/SDK/NDK/Systems/RenderSystem.cpp +++ b/tests/SDK/NDK/Systems/RenderSystem.cpp @@ -90,17 +90,17 @@ SCENARIO("RenderSystem", "[NDK][RenderSystem]") { CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed); CHECK(physicsComponent2D.GetRotation() == angularSpeed); - CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(1.f, 4.f, 2.f, 1.f)); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(2.5f, 4.5f, 2.f, 1.f)); CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetAABB()); world.Update(1.f); CHECK(physicsComponent2D.GetRotation() == 2.f * angularSpeed); - CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(2.f, 2.f, 1.f, 2.f)); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(3.f, 4.0f, 1.f, 2.f)); CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetAABB()); world.Update(1.f); CHECK(physicsComponent2D.GetRotation() == 3.f * angularSpeed); - CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(3.f, 3.f, 2.f, 1.f)); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(2.5f, 4.5f, 2.f, 1.f)); CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetAABB()); world.Update(1.f); From ac4904867941dbe7d141010768c66c71542590ae Mon Sep 17 00:00:00 2001 From: Lynix Date: Wed, 3 Apr 2019 22:16:11 +0200 Subject: [PATCH 52/77] Fix crash when debug drawing Collider2D with no CollisionComponent2D --- SDK/src/NDK/Systems/DebugSystem.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp index f2175e559..d8c61b9bc 100644 --- a/SDK/src/NDK/Systems/DebugSystem.cpp +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -231,9 +231,6 @@ namespace Ndk { case DebugDraw::Collider2D: { - const Nz::Boxf& obb = entityGfx.GetAABB(); - CollisionComponent2D& entityCollision2D = entity->GetComponent(); - Nz::Vector3f offset; Nz::InstancedRenderableRef renderable = GenerateCollision2DMesh(entity, &offset); if (renderable) From 713a70dd1099eadee8777c9f4734d5d25c3e2dcc Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 6 Apr 2019 15:09:05 +0200 Subject: [PATCH 53/77] Renderer/TextureSampler: Set default texture sampler to Clamp --- ChangeLog.md | 1 + src/Nazara/Renderer/TextureSampler.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index d2c5b2d83..3f22ba700 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -177,6 +177,7 @@ Nazara Engine: - ⚠ Collider3D::ForEachPolygon now takes a void(Vector3f\*, std::size_t) callback (instead of void(float\*, std::size_t)) - Added Collider2D::ForEachPolygon method - Added RigidBody::[Get|Set]PositionOffset allowing set an offset between body logic position and body physics position (center of mass position) +- ⚠ Default TextureSampler WrapMode is now Clamp (instead of Repeat) Nazara Development Kit: - Added ImageWidget (#139) diff --git a/src/Nazara/Renderer/TextureSampler.cpp b/src/Nazara/Renderer/TextureSampler.cpp index 4f1f9233f..3d24e5d1d 100644 --- a/src/Nazara/Renderer/TextureSampler.cpp +++ b/src/Nazara/Renderer/TextureSampler.cpp @@ -389,5 +389,5 @@ namespace Nz UInt8 TextureSampler::s_defaultAnisotropyLevel = 1; SamplerFilter TextureSampler::s_defaultFilterMode = SamplerFilter_Trilinear; - SamplerWrap TextureSampler::s_defaultWrapMode = SamplerWrap_Repeat; + SamplerWrap TextureSampler::s_defaultWrapMode = SamplerWrap_Clamp; } From 793c5abfe3652ea566d6b0ac3d622d55b53a8604 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 7 Apr 2019 21:35:10 +0200 Subject: [PATCH 54/77] SDK: Add LifetimeComponent and LifetimeSystem --- ChangeLog.md | 1 + .../NDK/Components/LifetimeComponent.hpp | 40 +++++++++++++++++++ .../NDK/Components/LifetimeComponent.inl | 24 +++++++++++ SDK/include/NDK/Systems/LifetimeSystem.hpp | 29 ++++++++++++++ SDK/include/NDK/Systems/LifetimeSystem.inl | 3 ++ SDK/src/NDK/Components/LifetimeComponent.cpp | 10 +++++ SDK/src/NDK/Sdk.cpp | 4 ++ SDK/src/NDK/Systems/LifetimeSystem.cpp | 27 +++++++++++++ SDK/src/NDK/World.cpp | 2 + 9 files changed, 140 insertions(+) create mode 100644 SDK/include/NDK/Components/LifetimeComponent.hpp create mode 100644 SDK/include/NDK/Components/LifetimeComponent.inl create mode 100644 SDK/include/NDK/Systems/LifetimeSystem.hpp create mode 100644 SDK/include/NDK/Systems/LifetimeSystem.inl create mode 100644 SDK/src/NDK/Components/LifetimeComponent.cpp create mode 100644 SDK/src/NDK/Systems/LifetimeSystem.cpp diff --git a/ChangeLog.md b/ChangeLog.md index 3f22ba700..a700b072b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -251,6 +251,7 @@ Nazara Development Kit: - Added possibility of disabling synchronization between PhysicsComponent2D and NodeComponent - Fixed GraphicsComponent not invalidating render queue on material change (causing crashes or visual errors) - Added CollisionComponent2D::SetGeomOffset and CollisionComponent2D::Recenter +- Added LifetimeComponent and LifetimeSystem # 0.4: diff --git a/SDK/include/NDK/Components/LifetimeComponent.hpp b/SDK/include/NDK/Components/LifetimeComponent.hpp new file mode 100644 index 000000000..72004a90d --- /dev/null +++ b/SDK/include/NDK/Components/LifetimeComponent.hpp @@ -0,0 +1,40 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#pragma once + +#ifndef NDK_COMPONENTS_LIFETIMECOMPONENT_HPP +#define NDK_COMPONENTS_LIFETIMECOMPONENT_HPP + +#include + +namespace Ndk +{ + class LifetimeComponent; + + using LifetimeComponentHandle = Nz::ObjectHandle; + + class NDK_API LifetimeComponent : public Component + { + friend class LifetimeSystem; + + public: + inline LifetimeComponent(float lifetime); + LifetimeComponent(const LifetimeComponent&) = default; + ~LifetimeComponent() = default; + + inline float GetRemainingTime() const; + + static ComponentIndex componentIndex; + + private: + inline bool UpdateLifetime(float elapsedTime); + + float m_lifetime; + }; +} + +#include + +#endif // NDK_COMPONENTS_LIFETIMECOMPONENT_HPP diff --git a/SDK/include/NDK/Components/LifetimeComponent.inl b/SDK/include/NDK/Components/LifetimeComponent.inl new file mode 100644 index 000000000..145e160ba --- /dev/null +++ b/SDK/include/NDK/Components/LifetimeComponent.inl @@ -0,0 +1,24 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include + +namespace Ndk +{ + inline LifetimeComponent::LifetimeComponent(float lifetime) : + m_lifetime(lifetime) + { + } + + inline float Ndk::LifetimeComponent::GetRemainingTime() const + { + return m_lifetime; + } + + inline bool LifetimeComponent::UpdateLifetime(float elapsedTime) + { + m_lifetime -= elapsedTime; + return m_lifetime < 0.f; + } +} diff --git a/SDK/include/NDK/Systems/LifetimeSystem.hpp b/SDK/include/NDK/Systems/LifetimeSystem.hpp new file mode 100644 index 000000000..9957c1b53 --- /dev/null +++ b/SDK/include/NDK/Systems/LifetimeSystem.hpp @@ -0,0 +1,29 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#pragma once + +#ifndef NDK_SYSTEMS_LIFETIMESYSTEM_HPP +#define NDK_SYSTEMS_LIFETIMESYSTEM_HPP + +#include + +namespace Ndk +{ + class NDK_API LifetimeSystem : public System + { + public: + LifetimeSystem(); + ~LifetimeSystem() = default; + + static SystemIndex systemIndex; + + private: + void OnUpdate(float elapsedTime) override; + }; +} + +#include + +#endif // NDK_SYSTEMS_LIFETIMESYSTEM_HPP diff --git a/SDK/include/NDK/Systems/LifetimeSystem.inl b/SDK/include/NDK/Systems/LifetimeSystem.inl new file mode 100644 index 000000000..5302ce8d0 --- /dev/null +++ b/SDK/include/NDK/Systems/LifetimeSystem.inl @@ -0,0 +1,3 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp diff --git a/SDK/src/NDK/Components/LifetimeComponent.cpp b/SDK/src/NDK/Components/LifetimeComponent.cpp new file mode 100644 index 000000000..5ffa6da82 --- /dev/null +++ b/SDK/src/NDK/Components/LifetimeComponent.cpp @@ -0,0 +1,10 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include + +namespace Ndk +{ + ComponentIndex LifetimeComponent::componentIndex; +} diff --git a/SDK/src/NDK/Sdk.cpp b/SDK/src/NDK/Sdk.cpp index 90d07c738..341e6f0d5 100644 --- a/SDK/src/NDK/Sdk.cpp +++ b/SDK/src/NDK/Sdk.cpp @@ -17,11 +17,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -88,6 +90,7 @@ namespace Ndk // Shared components InitializeComponent("NdkColl2"); InitializeComponent("NdkColl3"); + InitializeComponent("NdkLiftm"); InitializeComponent("NdkNode"); InitializeComponent("NdkPhys2"); InitializeComponent("NdkPhys3"); @@ -110,6 +113,7 @@ namespace Ndk BaseSystem::Initialize(); // Shared systems + InitializeSystem(); InitializeSystem(); InitializeSystem(); InitializeSystem(); diff --git a/SDK/src/NDK/Systems/LifetimeSystem.cpp b/SDK/src/NDK/Systems/LifetimeSystem.cpp new file mode 100644 index 000000000..d575ebdc4 --- /dev/null +++ b/SDK/src/NDK/Systems/LifetimeSystem.cpp @@ -0,0 +1,27 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequisites.hpp + +#include +#include + +namespace Ndk +{ + LifetimeSystem::LifetimeSystem() + { + Requires(); + } + + void LifetimeSystem::OnUpdate(float elapsedTime) + { + for (const Ndk::EntityHandle& entity : GetEntities()) + { + auto& lifetime = entity->GetComponent(); + + if (lifetime.UpdateLifetime(elapsedTime)) + entity->Kill(); + } + } + + SystemIndex LifetimeSystem::systemIndex; +} diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index bfbe0140c..579985297 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ namespace Ndk void World::AddDefaultSystems() { + AddSystem(); AddSystem(); AddSystem(); AddSystem(); From d234d2084db47c204350328b7bbc98527bd35ce7 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 7 Apr 2019 21:36:08 +0200 Subject: [PATCH 55/77] SDK/StateMachine: Fixed ignored transitiions --- ChangeLog.md | 1 + SDK/include/NDK/StateMachine.inl | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index a700b072b..0a890109b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -178,6 +178,7 @@ Nazara Engine: - Added Collider2D::ForEachPolygon method - Added RigidBody::[Get|Set]PositionOffset allowing set an offset between body logic position and body physics position (center of mass position) - ⚠ Default TextureSampler WrapMode is now Clamp (instead of Repeat) +- Fixed StateMachine ignoring transitions made in Enter/Leave events of states Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/include/NDK/StateMachine.inl b/SDK/include/NDK/StateMachine.inl index 1b2a625ab..ba2a74928 100644 --- a/SDK/include/NDK/StateMachine.inl +++ b/SDK/include/NDK/StateMachine.inl @@ -159,8 +159,13 @@ namespace Ndk */ inline bool StateMachine::Update(float elapsedTime) { - for (StateTransition& transition : m_transitions) + // Use a classic for instead of a range-for because some state may push/pop on enter/leave, adding new transitions as we iterate + // (range-for is a problem here because it doesn't handle mutable containers) + + for (std::size_t i = 0; i < m_transitions.size(); ++i) { + StateTransition& transition = m_transitions[i]; + switch (transition.type) { case TransitionType::Pop: From 9d195c275081d1868cadab638deb06e1a983d48f Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 7 Apr 2019 21:36:16 +0200 Subject: [PATCH 56/77] Regenerate global headers --- SDK/include/NDK/Components.hpp | 1 + SDK/include/NDK/Systems.hpp | 1 + SDK/include/NDK/Widgets.hpp | 1 + 3 files changed, 3 insertions(+) diff --git a/SDK/include/NDK/Components.hpp b/SDK/include/NDK/Components.hpp index 97c15fc7c..cc8c37d93 100644 --- a/SDK/include/NDK/Components.hpp +++ b/SDK/include/NDK/Components.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/SDK/include/NDK/Systems.hpp b/SDK/include/NDK/Systems.hpp index 80571ef45..e9a60f0c3 100644 --- a/SDK/include/NDK/Systems.hpp +++ b/SDK/include/NDK/Systems.hpp @@ -6,6 +6,7 @@ #define NDK_SYSTEMS_GLOBAL_HPP #include +#include #include #include #include diff --git a/SDK/include/NDK/Widgets.hpp b/SDK/include/NDK/Widgets.hpp index 26917a4c9..a4b74b2d6 100644 --- a/SDK/include/NDK/Widgets.hpp +++ b/SDK/include/NDK/Widgets.hpp @@ -5,6 +5,7 @@ #ifndef NDK_WIDGETS_GLOBAL_HPP #define NDK_WIDGETS_GLOBAL_HPP +#include #include #include #include From e665ea537321e3e3df9fe8b0add087d678afc258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Fri, 12 Apr 2019 15:29:15 +0200 Subject: [PATCH 57/77] Graphics/Material: Fix Configure resetting textures --- ChangeLog.md | 1 + include/Nazara/Graphics/Material.inl | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 0a890109b..4476c6eb3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -179,6 +179,7 @@ Nazara Engine: - Added RigidBody::[Get|Set]PositionOffset allowing set an offset between body logic position and body physics position (center of mass position) - ⚠ Default TextureSampler WrapMode is now Clamp (instead of Repeat) - Fixed StateMachine ignoring transitions made in Enter/Leave events of states +- Fixed Material::Configure resetting textures Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Graphics/Material.inl b/include/Nazara/Graphics/Material.inl index 32a59b1bb..66c34e19c 100644 --- a/include/Nazara/Graphics/Material.inl +++ b/include/Nazara/Graphics/Material.inl @@ -119,6 +119,14 @@ namespace Nz { m_pipelineInfo = pipelineInfo; + // Temp and dirty fix for pipeline overriding has*Map + m_pipelineInfo.hasAlphaMap = m_alphaMap.IsValid(); + m_pipelineInfo.hasDiffuseMap = m_diffuseMap.IsValid(); + m_pipelineInfo.hasEmissiveMap = m_emissiveMap.IsValid(); + m_pipelineInfo.hasHeightMap = m_heightMap.IsValid(); + m_pipelineInfo.hasNormalMap = m_normalMap.IsValid(); + m_pipelineInfo.hasSpecularMap = m_specularMap.IsValid(); + InvalidatePipeline(); } From 0582cbfc265ca8864326723d64565e28e27acda4 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 13 Apr 2019 13:09:53 +0200 Subject: [PATCH 58/77] Utility: Replace UInt32 by TextStyleFlags --- ChangeLog.md | 2 ++ SDK/src/NDK/Lua/LuaBinding_Utility.cpp | 4 ++-- include/Nazara/Utility/Enums.hpp | 24 ++++++++++++------- include/Nazara/Utility/Font.hpp | 15 ++++++------ include/Nazara/Utility/FontData.hpp | 5 ++-- include/Nazara/Utility/SimpleTextDrawer.hpp | 10 ++++---- src/Nazara/Utility/Font.cpp | 16 ++++++------- src/Nazara/Utility/Formats/FreeTypeLoader.cpp | 8 +++---- src/Nazara/Utility/SimpleTextDrawer.cpp | 8 +++---- 9 files changed, 52 insertions(+), 40 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 4476c6eb3..5b65ee66d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -180,6 +180,8 @@ Nazara Engine: - ⚠ Default TextureSampler WrapMode is now Clamp (instead of Repeat) - Fixed StateMachine ignoring transitions made in Enter/Leave events of states - Fixed Material::Configure resetting textures +- ⚠ Renamed TextStyleFlags enum to TextStyle, introduced Flags specialization of TextStyle as TextStyleFlags +- ⚠ Font, FontData and SimpleTextDrawer now use a proper TextStyleFlags instead of a UInt32 Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp index 43ea4a8c7..a98bd4ed7 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp @@ -126,7 +126,7 @@ namespace Ndk case 2: { unsigned int characterSize = lua.Check(&argIndex); - Nz::UInt32 style = lua.Check(&argIndex); + Nz::TextStyleFlags style = lua.Check(&argIndex); lua.Push(instance->GetCachedGlyphCount(characterSize, style)); return 1; @@ -146,7 +146,7 @@ namespace Ndk font.BindMethod("IsValid", &Nz::Font::IsValid); - font.BindMethod("Precache", (bool(Nz::Font::*)(unsigned int, Nz::UInt32, const Nz::String&) const) &Nz::Font::Precache); + font.BindMethod("Precache", (bool(Nz::Font::*)(unsigned int, Nz::TextStyleFlags, const Nz::String&) const) &Nz::Font::Precache); font.BindMethod("SetGlyphBorder", &Nz::Font::SetGlyphBorder); font.BindMethod("SetMinimumStepSize", &Nz::Font::SetMinimumStepSize); diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index d6fee2127..f4d343acc 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -329,18 +329,26 @@ namespace Nz TextAlign_Max = TextAlign_Right }; - enum TextStyleFlags + enum TextStyle { - TextStyle_Regular = 0x0, + TextStyle_Bold, + TextStyle_Italic, + TextStyle_StrikeThrough, + TextStyle_Underlined, - TextStyle_Bold = 0x1, - TextStyle_Italic = 0x2, - TextStyle_StrikeThrough = 0x4, - TextStyle_Underlined = 0x8, - - TextStyle_Max = TextStyle_Underlined*2-1 + TextStyle_Max = TextStyle_Underlined }; + template<> + struct EnumAsFlags + { + static constexpr TextStyle max = TextStyle_Max; + }; + + using TextStyleFlags = Flags; + + constexpr TextStyleFlags TextStyle_Regular = 0; + enum VertexComponent { VertexComponent_Unused = -1, diff --git a/include/Nazara/Utility/Font.hpp b/include/Nazara/Utility/Font.hpp index be67c92e7..bac5db49c 100644 --- a/include/Nazara/Utility/Font.hpp +++ b/include/Nazara/Utility/Font.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -58,14 +59,14 @@ namespace Nz bool Create(FontData* data); void Destroy(); - bool ExtractGlyph(unsigned int characterSize, char32_t character, UInt32 style, FontGlyph* glyph) const; + bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* glyph) const; const std::shared_ptr& GetAtlas() const; - std::size_t GetCachedGlyphCount(unsigned int characterSize, UInt32 style) const; + std::size_t GetCachedGlyphCount(unsigned int characterSize, TextStyleFlags style) const; std::size_t GetCachedGlyphCount() const; String GetFamilyName() const; int GetKerning(unsigned int characterSize, char32_t first, char32_t second) const; - const Glyph& GetGlyph(unsigned int characterSize, UInt32 style, char32_t character) const; + const Glyph& GetGlyph(unsigned int characterSize, TextStyleFlags style, char32_t character) const; unsigned int GetGlyphBorder() const; unsigned int GetMinimumStepSize() const; const SizeInfo& GetSizeInfo(unsigned int characterSize) const; @@ -73,8 +74,8 @@ namespace Nz bool IsValid() const; - bool Precache(unsigned int characterSize, UInt32 style, char32_t character) const; - bool Precache(unsigned int characterSize, UInt32 style, const String& characterSet) const; + bool Precache(unsigned int characterSize, TextStyleFlags style, char32_t character) const; + bool Precache(unsigned int characterSize, TextStyleFlags style, const String& characterSet) const; void SetAtlas(const std::shared_ptr& atlas); void SetGlyphBorder(unsigned int borderSize); @@ -130,11 +131,11 @@ namespace Nz private: using GlyphMap = std::unordered_map; - UInt64 ComputeKey(unsigned int characterSize, UInt32 style) const; + UInt64 ComputeKey(unsigned int characterSize, TextStyleFlags style) const; void OnAtlasCleared(const AbstractAtlas* atlas); void OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer); void OnAtlasRelease(const AbstractAtlas* atlas); - const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, UInt32 style, char32_t character) const; + const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, TextStyleFlags style, char32_t character) const; static bool Initialize(); static void Uninitialize(); diff --git a/include/Nazara/Utility/FontData.hpp b/include/Nazara/Utility/FontData.hpp index efd2e6d94..a3ac4901a 100644 --- a/include/Nazara/Utility/FontData.hpp +++ b/include/Nazara/Utility/FontData.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace Nz { @@ -21,7 +22,7 @@ namespace Nz FontData() = default; virtual ~FontData(); - virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, UInt32 style, FontGlyph* dst) = 0; + virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* dst) = 0; virtual String GetFamilyName() const = 0; virtual String GetStyleName() const = 0; @@ -35,7 +36,7 @@ namespace Nz virtual float QueryUnderlinePosition(unsigned int characterSize) const = 0; virtual float QueryUnderlineThickness(unsigned int characterSize) const = 0; - virtual bool SupportsStyle(UInt32 style) const = 0; + virtual bool SupportsStyle(TextStyleFlags style) const = 0; }; } diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp index d3c3bd9cc..c41a5d8be 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.hpp +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -38,20 +38,20 @@ namespace Nz std::size_t GetGlyphCount() const override; const Line& GetLine(std::size_t index) const override; std::size_t GetLineCount() const override; - UInt32 GetStyle() const; + TextStyleFlags GetStyle() const; const String& GetText() const; void SetCharacterSize(unsigned int characterSize); void SetColor(const Color& color); void SetFont(Font* font); - void SetStyle(UInt32 style); + void SetStyle(TextStyleFlags style); void SetText(const String& str); SimpleTextDrawer& operator=(const SimpleTextDrawer& drawer); SimpleTextDrawer& operator=(SimpleTextDrawer&& drawer); - static SimpleTextDrawer Draw(const String& str, unsigned int characterSize, UInt32 style = TextStyle_Regular, const Color& color = Color::White); - static SimpleTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, UInt32 style = TextStyle_Regular, const Color& color = Color::White); + static SimpleTextDrawer Draw(const String& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); + static SimpleTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); private: void ClearGlyphs() const; @@ -76,8 +76,8 @@ namespace Nz mutable Rectf m_workingBounds; mutable Recti m_bounds; String m_text; + TextStyleFlags m_style; mutable UInt32 m_previousCharacter; - UInt32 m_style; mutable Vector2ui m_drawPos; mutable bool m_colorUpdated; mutable bool m_glyphUpdated; diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp index 731557628..0ccc09269 100644 --- a/src/Nazara/Utility/Font.cpp +++ b/src/Nazara/Utility/Font.cpp @@ -109,7 +109,7 @@ namespace Nz } } - bool Font::ExtractGlyph(unsigned int characterSize, char32_t character, UInt32 style, FontGlyph* glyph) const + bool Font::ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* glyph) const { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -127,7 +127,7 @@ namespace Nz return m_atlas; } - std::size_t Font::GetCachedGlyphCount(unsigned int characterSize, UInt32 style) const + std::size_t Font::GetCachedGlyphCount(unsigned int characterSize, TextStyleFlags style) const { UInt64 key = ComputeKey(characterSize, style); auto it = m_glyphes.find(key); @@ -187,7 +187,7 @@ namespace Nz return it->second; // Présent dans le cache, tout va bien } - const Font::Glyph& Font::GetGlyph(unsigned int characterSize, UInt32 style, char32_t character) const + const Font::Glyph& Font::GetGlyph(unsigned int characterSize, TextStyleFlags style, char32_t character) const { UInt64 key = ComputeKey(characterSize, style); return PrecacheGlyph(m_glyphes[key], characterSize, style, character); @@ -256,13 +256,13 @@ namespace Nz return m_data != nullptr; } - bool Font::Precache(unsigned int characterSize, UInt32 style, char32_t character) const + bool Font::Precache(unsigned int characterSize, TextStyleFlags style, char32_t character) const { UInt64 key = ComputeKey(characterSize, style); return PrecacheGlyph(m_glyphes[key], characterSize, style, character).valid; } - bool Font::Precache(unsigned int characterSize, UInt32 style, const String& characterSet) const + bool Font::Precache(unsigned int characterSize, TextStyleFlags style, const String& characterSet) const { ///TODO: Itération UTF-8 => UTF-32 sans allocation de buffer (Exposer utf8cpp ?) std::u32string set = characterSet.GetUtf32String(); @@ -399,7 +399,7 @@ namespace Nz s_defaultMinimumStepSize = minimumStepSize; } - UInt64 Font::ComputeKey(unsigned int characterSize, UInt32 style) const + UInt64 Font::ComputeKey(unsigned int characterSize, TextStyleFlags style) const { // On prend le pas en compte UInt64 sizePart = static_cast((characterSize/m_minimumStepSize)*m_minimumStepSize); @@ -471,7 +471,7 @@ namespace Nz NazaraError("Atlas has been released while in use"); } - const Font::Glyph& Font::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, UInt32 style, char32_t character) const + const Font::Glyph& Font::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, TextStyleFlags style, char32_t character) const { auto it = glyphMap.find(character); if (it != glyphMap.end()) // Si le glyphe n'est pas déjà chargé @@ -492,7 +492,7 @@ namespace Nz glyph.requireFauxBold = false; glyph.requireFauxItalic = false; - UInt32 supportedStyle = style; + TextStyleFlags supportedStyle = style; if (style & TextStyle_Bold && !m_data->SupportsStyle(TextStyle_Bold)) { glyph.requireFauxBold = true; diff --git a/src/Nazara/Utility/Formats/FreeTypeLoader.cpp b/src/Nazara/Utility/Formats/FreeTypeLoader.cpp index 2cd2c51e3..9f890385f 100644 --- a/src/Nazara/Utility/Formats/FreeTypeLoader.cpp +++ b/src/Nazara/Utility/Formats/FreeTypeLoader.cpp @@ -25,7 +25,7 @@ namespace Nz FT_Library s_library; std::shared_ptr s_libraryOwner; - float s_invScaleFactor = 1.f / (1 << 6); // 1/64 + constexpr float s_invScaleFactor = 1.f / (1 << 6); // 1/64 extern "C" unsigned long FT_StreamRead(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count) @@ -96,7 +96,7 @@ namespace Nz return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0; } - bool ExtractGlyph(unsigned int characterSize, char32_t character, UInt32 style, FontGlyph* dst) override + bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* dst) override { #ifdef NAZARA_DEBUG if (!dst) @@ -118,7 +118,7 @@ namespace Nz const FT_Pos boldStrength = 2 << 6; - bool embolden = (style & TextStyle_Bold); + bool embolden = (style & TextStyle_Bold) != 0; dst->advance = (embolden) ? boldStrength >> 6 : 0; @@ -312,7 +312,7 @@ namespace Nz m_args.stream = &m_stream; } - bool SupportsStyle(UInt32 style) const override + bool SupportsStyle(TextStyleFlags style) const override { ///TODO return style == TextStyle_Regular || style == TextStyle_Bold; diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 89accf012..ec684a8e0 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -120,7 +120,7 @@ namespace Nz return m_lines.size(); } - UInt32 SimpleTextDrawer::GetStyle() const + TextStyleFlags SimpleTextDrawer::GetStyle() const { return m_style; } @@ -159,7 +159,7 @@ namespace Nz } } - void SimpleTextDrawer::SetStyle(UInt32 style) + void SimpleTextDrawer::SetStyle(TextStyleFlags style) { m_style = style; @@ -207,7 +207,7 @@ namespace Nz return *this; } - SimpleTextDrawer SimpleTextDrawer::Draw(const String& str, unsigned int characterSize, UInt32 style, const Color& color) + SimpleTextDrawer SimpleTextDrawer::Draw(const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color) { SimpleTextDrawer drawer; drawer.SetCharacterSize(characterSize); @@ -218,7 +218,7 @@ namespace Nz return drawer; } - SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, UInt32 style, const Color& color) + SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color) { SimpleTextDrawer drawer; drawer.SetCharacterSize(characterSize); From 080b76a23c974c2afa65247b1c1e07ce1519cbe1 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sat, 13 Apr 2019 13:39:19 +0200 Subject: [PATCH 59/77] Utility/Font: Fix bold not working since last commit --- src/Nazara/Utility/Font.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp index 0ccc09269..0628a4337 100644 --- a/src/Nazara/Utility/Font.cpp +++ b/src/Nazara/Utility/Font.cpp @@ -405,7 +405,7 @@ namespace Nz UInt64 sizePart = static_cast((characterSize/m_minimumStepSize)*m_minimumStepSize); // Ainsi que le style (uniquement le gras et l'italique, les autres sont gérés par un TextDrawer) - UInt64 stylePart = 0; + TextStyleFlags stylePart = 0; if (style & TextStyle_Bold) stylePart |= TextStyle_Bold; @@ -413,7 +413,7 @@ namespace Nz if (style & TextStyle_Italic) stylePart |= TextStyle_Italic; - return (stylePart << 32) | sizePart; + return (static_cast(stylePart) << 32) | sizePart; } void Font::OnAtlasCleared(const AbstractAtlas* atlas) From 8c7d886f73e472e7f352a512dd445873273660ee Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 15 Apr 2019 14:16:57 +0200 Subject: [PATCH 60/77] Math/Algorithm: Reenable constexpr --- ChangeLog.md | 1 + include/Nazara/Math/Algorithm.hpp | 18 ++++----- include/Nazara/Math/Algorithm.inl | 61 ++++++------------------------- 3 files changed, 22 insertions(+), 58 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5b65ee66d..f35121273 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -182,6 +182,7 @@ Nazara Engine: - Fixed Material::Configure resetting textures - ⚠ Renamed TextStyleFlags enum to TextStyle, introduced Flags specialization of TextStyle as TextStyleFlags - ⚠ Font, FontData and SimpleTextDrawer now use a proper TextStyleFlags instead of a UInt32 +- Almost all Math algorithms are now constexpr Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Math/Algorithm.hpp b/include/Nazara/Math/Algorithm.hpp index dd9cb4d5a..7bd77437d 100644 --- a/include/Nazara/Math/Algorithm.hpp +++ b/include/Nazara/Math/Algorithm.hpp @@ -35,15 +35,15 @@ namespace Nz { - template /*constexpr*/ T Approach(T value, T objective, T increment); + template constexpr T Approach(T value, T objective, T increment); template constexpr T Clamp(T value, T min, T max); - template /*constexpr*/ std::size_t CountBits(T value); + template constexpr std::size_t CountBits(T value); template constexpr T FromDegrees(T degrees); template constexpr T FromRadians(T radians); template constexpr T DegreeToRadian(T degrees); - template /*constexpr*/ T GetNearestPowerOfTwo(T number); - /*constexpr*/ unsigned int GetNumberLength(signed char number); - /*constexpr*/ unsigned int GetNumberLength(unsigned char number); + template constexpr T GetNearestPowerOfTwo(T number); + constexpr unsigned int GetNumberLength(signed char number); + constexpr unsigned int GetNumberLength(unsigned char number); unsigned int GetNumberLength(int number); /*constexpr*/ unsigned int GetNumberLength(unsigned int number); unsigned int GetNumberLength(long long number); @@ -53,12 +53,12 @@ namespace Nz unsigned int GetNumberLength(long double number, UInt8 precision = NAZARA_CORE_DECIMAL_DIGITS); template /*constexpr*/ unsigned int IntegralLog2(T number); template /*constexpr*/ unsigned int IntegralLog2Pot(T pot); - template /*constexpr*/ T IntegralPow(T base, unsigned int exponent); + template constexpr T IntegralPow(T base, unsigned int exponent); template constexpr T Lerp(const T& from, const T& to, const T2& interpolation); template constexpr T MultiplyAdd(T x, T y, T z); - template /*constexpr*/ T NormalizeAngle(T angle); - template /*constexpr*/ bool NumberEquals(T a, T b); - template /*constexpr*/ bool NumberEquals(T a, T b, T maxDifference); + template constexpr T NormalizeAngle(T angle); + template constexpr bool NumberEquals(T a, T b); + template constexpr bool NumberEquals(T a, T b, T maxDifference); String NumberToString(long long number, UInt8 radix = 10); template constexpr T RadianToDegree(T radians); long long StringToNumber(String str, UInt8 radix = 10, bool* ok = nullptr); diff --git a/include/Nazara/Math/Algorithm.inl b/include/Nazara/Math/Algorithm.inl index b393d38e6..5a7bfb8fc 100644 --- a/include/Nazara/Math/Algorithm.inl +++ b/include/Nazara/Math/Algorithm.inl @@ -98,13 +98,13 @@ namespace Nz return 0; } - template /*constexpr*/ std::enable_if_t::value, bool> NumberEquals(T a, T b, T maxDifference) + template constexpr std::enable_if_t::value, bool> NumberEquals(T a, T b, T maxDifference) { T diff = std::abs(a - b); return diff <= maxDifference; } - template /*constexpr*/ std::enable_if_t::value || (!std::is_integral::value && !std::is_floating_point::value), bool> NumberEquals(T a, T b, T maxDifference) + template constexpr std::enable_if_t::value || (!std::is_integral::value && !std::is_floating_point::value), bool> NumberEquals(T a, T b, T maxDifference) { if (b > a) std::swap(a, b); @@ -113,7 +113,7 @@ namespace Nz return diff <= maxDifference; } - template /*constexpr*/ std::enable_if_t::value && std::is_integral::value, bool> NumberEquals(T a, T b, T maxDifference) + template constexpr std::enable_if_t::value && std::is_integral::value, bool> NumberEquals(T a, T b, T maxDifference) { if (b > a) std::swap(a, b); @@ -132,10 +132,8 @@ namespace Nz * \param objective Target value * \param increment One step value */ - template - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline T Approach(T value, T objective, T increment) + constexpr inline T Approach(T value, T objective, T increment) { if (value < objective) return std::min(value + increment, objective); @@ -154,7 +152,6 @@ namespace Nz * \param min Minimum of the interval * \param max Maximum of the interval */ - template constexpr T Clamp(T value, T min, T max) { @@ -168,10 +165,8 @@ namespace Nz * * \param value The value to count bits */ - template - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline std::size_t CountBits(T value) + constexpr inline std::size_t CountBits(T value) { // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan std::size_t count = 0; @@ -191,7 +186,6 @@ namespace Nz * * \param degrees Angle in degree (this is expected between 0..360) */ - template constexpr T DegreeToRadian(T degrees) { @@ -205,7 +199,6 @@ namespace Nz * * \param degrees Convert degree to NAZARA_MATH_ANGLE_RADIAN unit */ - template constexpr T FromDegrees(T degrees) { @@ -223,7 +216,6 @@ namespace Nz * * \param radians Convert radian to NAZARA_MATH_ANGLE_RADIAN unit */ - template constexpr T FromRadians(T radians) { @@ -241,10 +233,8 @@ namespace Nz * * \param number Number to get nearest power */ - template - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline T GetNearestPowerOfTwo(T number) + constexpr inline T GetNearestPowerOfTwo(T number) { T x = 1; while (x < number) @@ -260,9 +250,7 @@ namespace Nz * * \param number Number to get number of digits */ - - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline unsigned int GetNumberLength(signed char number) + constexpr inline unsigned int GetNumberLength(signed char number) { // Char is expected to be 1 byte static_assert(sizeof(number) == 1, "Signed char must be one byte-sized"); @@ -288,9 +276,7 @@ namespace Nz * * \param number Number to get number of digits */ - - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline unsigned int GetNumberLength(unsigned char number) + constexpr inline unsigned int GetNumberLength(unsigned char number) { // Char is expected to be 1 byte static_assert(sizeof(number) == 1, "Unsigned char must be one byte-sized"); @@ -310,7 +296,6 @@ namespace Nz * * \param number Number to get number of digits */ - inline unsigned int GetNumberLength(int number) { if (number == 0) @@ -326,7 +311,6 @@ namespace Nz * * \param number Number to get number of digits */ - //TODO: Mark as constexpr when supported by all major compilers /*constexpr*/ inline unsigned int GetNumberLength(unsigned int number) { @@ -343,7 +327,6 @@ namespace Nz * * \param number Number to get number of digits */ - inline unsigned int GetNumberLength(long long number) { if (number == 0) @@ -359,7 +342,6 @@ namespace Nz * * \param number Number to get number of digits */ - //TODO: Mark as constexpr when supported by all major compilers /*constexpr*/ inline unsigned int GetNumberLength(unsigned long long number) { @@ -377,7 +359,6 @@ namespace Nz * \param number Number to get number of digits * \param precision Number of digit after the dot */ - inline unsigned int GetNumberLength(float number, UInt8 precision) { // The imprecision of floats need a cast (log10(9.99999) = 0.99999) @@ -392,7 +373,6 @@ namespace Nz * \param number Number to get number of digits * \param precision Number of digit after the dot */ - inline unsigned int GetNumberLength(double number, UInt8 precision) { // The imprecision of floats need a cast (log10(9.99999) = 0.99999) @@ -407,7 +387,6 @@ namespace Nz * \param number Number to get number of digits * \param precision Number of digit after the dot */ - inline unsigned int GetNumberLength(long double number, UInt8 precision) { // The imprecision of floats need a cast (log10(9.99999) = 0.99999) @@ -423,7 +402,6 @@ namespace Nz * * \remark If number is 0, 0 is returned */ - template //TODO: Mark as constexpr when supported by all major compilers /*constexpr*/ inline unsigned int IntegralLog2(T number) @@ -442,7 +420,6 @@ namespace Nz * \remark Only works for power of two * \remark If number is 0, 0 is returned */ - template //TODO: Mark as constexpr when supported by all major compilers /*constexpr*/ inline unsigned int IntegralLog2Pot(T pot) @@ -458,10 +435,8 @@ namespace Nz * \param base Base of the exponentation * \param exponent Power for the base */ - - //TODO: Mark as constexpr when supported by all major compilers template - /*constexpr*/ T IntegralPow(T base, unsigned int exponent) + constexpr T IntegralPow(T base, unsigned int exponent) { T r = 1; for (unsigned int i = 0; i < exponent; ++i) @@ -484,7 +459,6 @@ namespace Nz * * \see Lerp */ - template constexpr T Lerp(const T& from, const T& to, const T2& interpolation) { @@ -540,10 +514,8 @@ namespace Nz * * \param angle Angle to normalize */ - template - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline T NormalizeAngle(T angle) + constexpr inline T NormalizeAngle(T angle) { #if NAZARA_MATH_ANGLE_RADIAN const T limit = T(M_PI); @@ -567,10 +539,8 @@ namespace Nz * \param a First value * \param b Second value */ - template - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline bool NumberEquals(T a, T b) + constexpr inline bool NumberEquals(T a, T b) { return NumberEquals(a, b, std::numeric_limits::epsilon()); } @@ -584,10 +554,8 @@ namespace Nz * \param b Second value * \param maxDifference Epsilon of comparison (expected to be positive) */ - template - //TODO: Mark as constexpr when supported by all major compilers - /*constexpr*/ inline bool NumberEquals(T a, T b, T maxDifference) + constexpr inline bool NumberEquals(T a, T b, T maxDifference) { return Detail::NumberEquals(a, b, maxDifference); } @@ -603,7 +571,6 @@ namespace Nz * \remark radix is meant to be between 2 and 36, other values are potentially undefined behavior * \remark With NAZARA_MATH_SAFE, a NazaraError is produced and String() is returned */ - inline String NumberToString(long long number, UInt8 radix) { #if NAZARA_MATH_SAFE @@ -651,7 +618,6 @@ namespace Nz * * \param radians Angle in radian (this is expected between 0..2*pi) */ - template constexpr T RadianToDegree(T radians) { @@ -670,7 +636,6 @@ namespace Nz * \remark radix is meant to be between 2 and 36, other values are potentially undefined behavior * \remark With NAZARA_MATH_SAFE, a NazaraError is produced and 0 is returned */ - inline long long StringToNumber(String str, UInt8 radix, bool* ok) { #if NAZARA_MATH_SAFE @@ -727,7 +692,6 @@ namespace Nz * * \param angle Convert degree from NAZARA_MATH_ANGLE_RADIAN unit to degrees */ - template constexpr T ToDegrees(T angle) { @@ -745,7 +709,6 @@ namespace Nz * * \param angle Convert degree from NAZARA_MATH_ANGLE_RADIAN unit to radians */ - template constexpr T ToRadians(T angle) { From e61faae0897c2899194b51d1e64d4b932ca931ec Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 15 Apr 2019 16:25:40 +0200 Subject: [PATCH 61/77] Physics2D/PhysWorld2D: Fix multiple calls to RegisterCallbacks with the same collision id --- ChangeLog.md | 1 + SDK/src/NDK/Systems/PhysicsSystem2D.cpp | 2 +- include/Nazara/Physics2D/PhysWorld2D.hpp | 8 +-- src/Nazara/Physics2D/PhysWorld2D.cpp | 71 ++++++++++++++++++------ 4 files changed, 61 insertions(+), 21 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index f35121273..37cb5f5c0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -183,6 +183,7 @@ Nazara Engine: - ⚠ Renamed TextStyleFlags enum to TextStyle, introduced Flags specialization of TextStyle as TextStyleFlags - ⚠ Font, FontData and SimpleTextDrawer now use a proper TextStyleFlags instead of a UInt32 - Almost all Math algorithms are now constexpr +- PhysWorld2D: Fixed callbacks not properly replacing each others when registering twice with the same collisionId (pair) Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp index 1273d66bc..8cce2e9aa 100644 --- a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp +++ b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp @@ -287,7 +287,7 @@ namespace Ndk void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks) { - Nz::PhysWorld2D::Callback worldCallbacks{}; + Nz::PhysWorld2D::Callback worldCallbacks; if (callbacks.endCallback) { diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp index 42e9288a1..86de8f003 100644 --- a/include/Nazara/Physics2D/PhysWorld2D.hpp +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -69,8 +69,8 @@ namespace Nz void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies); - void RegisterCallbacks(unsigned int collisionId, const Callback& callbacks); - void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks); + void RegisterCallbacks(unsigned int collisionId, Callback callbacks); + void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks); void SetDamping(float dampingValue); void SetGravity(const Vector2f& gravity); @@ -91,7 +91,7 @@ namespace Nz ContactPreSolveCallback preSolveCallback = nullptr; ContactPostSolveCallback postSolveCallback = nullptr; ContactStartCallback startCallback = nullptr; - void* userdata; + void* userdata = nullptr; }; struct DebugDrawOptions @@ -130,7 +130,7 @@ namespace Nz NazaraSignal(OnPhysWorld2DPostStep, const PhysWorld2D* /*physWorld*/, float /*invStepCount*/); private: - void InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks); + void InitCallbacks(cpCollisionHandler* handler, Callback callbacks); using PostStep = std::function; diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 7383510f8..319a10582 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -273,14 +273,14 @@ namespace Nz cpSpaceBBQuery(m_handle, cpBBNew(boundingBox.x, boundingBox.y, boundingBox.x + boundingBox.width, boundingBox.y + boundingBox.height), filter, callback, bodies); } - void PhysWorld2D::RegisterCallbacks(unsigned int collisionId, const Callback& callbacks) + void PhysWorld2D::RegisterCallbacks(unsigned int collisionId, Callback callbacks) { - InitCallbacks(cpSpaceAddWildcardHandler(m_handle, collisionId), callbacks); + InitCallbacks(cpSpaceAddWildcardHandler(m_handle, collisionId), std::move(callbacks)); } - void PhysWorld2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks) + void PhysWorld2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks) { - InitCallbacks(cpSpaceAddCollisionHandler(m_handle, collisionIdA, collisionIdB), callbacks); + InitCallbacks(cpSpaceAddCollisionHandler(m_handle, collisionIdA, collisionIdB), std::move(callbacks)); } void PhysWorld2D::SetDamping(float dampingValue) @@ -341,15 +341,20 @@ namespace Nz cpSpaceUseSpatialHash(m_handle, cpFloat(cellSize), int(entityCount)); } - void PhysWorld2D::InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks) + void PhysWorld2D::InitCallbacks(cpCollisionHandler* handler, Callback callbacks) { - auto it = m_callbacks.emplace(handler, std::make_unique(callbacks)).first; + auto it = m_callbacks.find(handler); + if (it == m_callbacks.end()) + it = m_callbacks.emplace(handler, std::make_unique(std::move(callbacks))).first; + else + it->second = std::make_unique(std::move(callbacks)); - handler->userData = it->second.get(); + Callback* callbackFunctions = it->second.get(); + handler->userData = callbackFunctions; - if (callbacks.startCallback) + if (callbackFunctions->startCallback) { - handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void *data) -> cpBool + handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void*) -> cpBool { cpBody* firstBody; cpBody* secondBody; @@ -372,10 +377,19 @@ namespace Nz return cpFalse; }; } - - if (callbacks.endCallback) + else { - handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void *data) + handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void*) -> cpBool + { + cpBool retA = cpArbiterCallWildcardBeginA(arb, space); + cpBool retB = cpArbiterCallWildcardBeginB(arb, space); + return retA && retB; + }; + } + + if (callbackFunctions->endCallback) + { + handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void*) { cpBody* firstBody; cpBody* secondBody; @@ -394,10 +408,18 @@ namespace Nz cpArbiterCallWildcardSeparateB(arb, space); }; } - - if (callbacks.preSolveCallback) + else { - handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void *data) -> cpBool + handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void*) + { + cpArbiterCallWildcardSeparateA(arb, space); + cpArbiterCallWildcardSeparateB(arb, space); + }; + } + + if (callbackFunctions->preSolveCallback) + { + handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) -> cpBool { cpBody* firstBody; cpBody* secondBody; @@ -420,8 +442,17 @@ namespace Nz return cpFalse; }; } + else + { + handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) -> cpBool + { + cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space); + cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space); + return retA && retB; + }; + } - if (callbacks.postSolveCallback) + if (callbackFunctions->postSolveCallback) { handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void *data) { @@ -442,6 +473,14 @@ namespace Nz cpArbiterCallWildcardPostSolveB(arb, space); }; } + else + { + handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) + { + cpArbiterCallWildcardPostSolveA(arb, space); + cpArbiterCallWildcardPostSolveB(arb, space); + }; + } } void PhysWorld2D::OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer) From 8a8c233840d5d94754137e820d4b129185c377c6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 15 Apr 2019 16:26:30 +0200 Subject: [PATCH 62/77] Oops --- src/Nazara/Physics2D/PhysWorld2D.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 319a10582..57ea8113e 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -354,7 +354,7 @@ namespace Nz if (callbackFunctions->startCallback) { - handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void*) -> cpBool + handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void* data) -> cpBool { cpBody* firstBody; cpBody* secondBody; @@ -389,7 +389,7 @@ namespace Nz if (callbackFunctions->endCallback) { - handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void*) + handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void* data) { cpBody* firstBody; cpBody* secondBody; From 79b0bd644ce5ee41654b32f6d35c5bd5734d29f6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Apr 2019 01:46:26 +0200 Subject: [PATCH 63/77] Add text outlines! --- ChangeLog.md | 4 + SDK/src/NDK/Lua/LuaBinding_Utility.cpp | 7 +- examples/Tut01/main.cpp | 6 +- include/Nazara/Graphics/TextSprite.hpp | 27 +++- include/Nazara/Utility/AbstractTextDrawer.hpp | 1 + include/Nazara/Utility/Font.hpp | 15 +- include/Nazara/Utility/FontData.hpp | 3 +- include/Nazara/Utility/SimpleTextDrawer.hpp | 8 + src/Nazara/Graphics/TextSprite.cpp | 75 +++++---- src/Nazara/Utility/Font.cpp | 104 ++++++------- src/Nazara/Utility/Formats/FreeTypeLoader.cpp | 103 +++++++++---- src/Nazara/Utility/SimpleTextDrawer.cpp | 145 +++++++++++++----- 12 files changed, 332 insertions(+), 166 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 37cb5f5c0..6f9dfa1e3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -184,6 +184,10 @@ Nazara Engine: - ⚠ Font, FontData and SimpleTextDrawer now use a proper TextStyleFlags instead of a UInt32 - Almost all Math algorithms are now constexpr - PhysWorld2D: Fixed callbacks not properly replacing each others when registering twice with the same collisionId (pair) +- ⚠ **Font, FontData and SimpleTextDrawer now supports text outlining.** +- Fixed TextSprite not handling multiple textures well +- ⚠ TextSprite will now use multiple render layers by itself (the current one and the one right before, ex: [-1, 0] if base layer is 0) if you use text outlines. +- ⚠ SimpleTextDrawer no longer supports faux bold rendering Nazara Development Kit: - Added ImageWidget (#139) diff --git a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp index a98bd4ed7..262620b12 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp @@ -123,12 +123,13 @@ namespace Ndk lua.Push(instance->GetCachedGlyphCount()); return 1; - case 2: + case 3: { unsigned int characterSize = lua.Check(&argIndex); Nz::TextStyleFlags style = lua.Check(&argIndex); + float outlineThickness = lua.Check(&argIndex); - lua.Push(instance->GetCachedGlyphCount(characterSize, style)); + lua.Push(instance->GetCachedGlyphCount(characterSize, style, outlineThickness)); return 1; } } @@ -146,7 +147,7 @@ namespace Ndk font.BindMethod("IsValid", &Nz::Font::IsValid); - font.BindMethod("Precache", (bool(Nz::Font::*)(unsigned int, Nz::TextStyleFlags, const Nz::String&) const) &Nz::Font::Precache); + font.BindMethod("Precache", (bool(Nz::Font::*)(unsigned int, Nz::TextStyleFlags, float, const Nz::String&) const) &Nz::Font::Precache); font.BindMethod("SetGlyphBorder", &Nz::Font::SetGlyphBorder); font.BindMethod("SetMinimumStepSize", &Nz::Font::SetMinimumStepSize); diff --git a/examples/Tut01/main.cpp b/examples/Tut01/main.cpp index 9d53b7b5e..4570cec08 100644 --- a/examples/Tut01/main.cpp +++ b/examples/Tut01/main.cpp @@ -29,9 +29,13 @@ int main(int argc, char* argv[]) viewer.SetTarget(&mainWindow); viewer.SetProjectionType(Nz::ProjectionType_Orthogonal); + Nz::SimpleTextDrawer textDrawer; + textDrawer.SetCharacterSize(72); + textDrawer.SetOutlineThickness(4.f); + textDrawer.SetText("Hello world !"); Nz::TextSpriteRef textSprite = Nz::TextSprite::New(); - textSprite->Update(Nz::SimpleTextDrawer::Draw("Hello world !", 72)); + textSprite->Update(textDrawer); Ndk::EntityHandle text = world.CreateEntity(); Ndk::NodeComponent& nodeComponent = text->AddComponent(); diff --git a/include/Nazara/Graphics/TextSprite.hpp b/include/Nazara/Graphics/TextSprite.hpp index d86d999ad..3811fea95 100644 --- a/include/Nazara/Graphics/TextSprite.hpp +++ b/include/Nazara/Graphics/TextSprite.hpp @@ -59,6 +59,31 @@ namespace Nz void OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer); void UpdateData(InstanceData* instanceData) const override; + struct RenderKey + { + Texture* texture; + int renderOrder; + + bool operator==(const RenderKey& rhs) const + { + return texture == rhs.texture && renderOrder == rhs.renderOrder; + } + + bool operator!=(const RenderKey& rhs) const + { + return !operator==(rhs); + } + }; + + struct HashRenderKey + { + std::size_t operator()(const RenderKey& key) const + { + // Since renderOrder will be very small, this will be enough + return std::hash()(key.texture) + key.renderOrder; + } + }; + struct RenderIndices { unsigned int first; @@ -74,7 +99,7 @@ namespace Nz }; std::unordered_map m_atlases; - mutable std::unordered_map m_renderInfos; + mutable std::unordered_map m_renderInfos; mutable std::vector m_localVertices; Color m_color; Recti m_localBounds; diff --git a/include/Nazara/Utility/AbstractTextDrawer.hpp b/include/Nazara/Utility/AbstractTextDrawer.hpp index c52051a5c..0b45d422d 100644 --- a/include/Nazara/Utility/AbstractTextDrawer.hpp +++ b/include/Nazara/Utility/AbstractTextDrawer.hpp @@ -44,6 +44,7 @@ namespace Nz Vector2f corners[4]; AbstractImage* atlas; bool flipped; + int renderOrder; }; struct Line diff --git a/include/Nazara/Utility/Font.hpp b/include/Nazara/Utility/Font.hpp index bac5db49c..70cbf6150 100644 --- a/include/Nazara/Utility/Font.hpp +++ b/include/Nazara/Utility/Font.hpp @@ -59,14 +59,14 @@ namespace Nz bool Create(FontData* data); void Destroy(); - bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* glyph) const; + bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, float outlineThickness, FontGlyph* glyph) const; const std::shared_ptr& GetAtlas() const; - std::size_t GetCachedGlyphCount(unsigned int characterSize, TextStyleFlags style) const; + std::size_t GetCachedGlyphCount(unsigned int characterSize, TextStyleFlags style, float outlineThickness) const; std::size_t GetCachedGlyphCount() const; String GetFamilyName() const; int GetKerning(unsigned int characterSize, char32_t first, char32_t second) const; - const Glyph& GetGlyph(unsigned int characterSize, TextStyleFlags style, char32_t character) const; + const Glyph& GetGlyph(unsigned int characterSize, TextStyleFlags style, float outlineThickness, char32_t character) const; unsigned int GetGlyphBorder() const; unsigned int GetMinimumStepSize() const; const SizeInfo& GetSizeInfo(unsigned int characterSize) const; @@ -74,8 +74,8 @@ namespace Nz bool IsValid() const; - bool Precache(unsigned int characterSize, TextStyleFlags style, char32_t character) const; - bool Precache(unsigned int characterSize, TextStyleFlags style, const String& characterSet) const; + bool Precache(unsigned int characterSize, TextStyleFlags style, float outlineThickness, char32_t character) const; + bool Precache(unsigned int characterSize, TextStyleFlags style, float outlineThickness, const String& characterSet) const; void SetAtlas(const std::shared_ptr& atlas); void SetGlyphBorder(unsigned int borderSize); @@ -107,6 +107,7 @@ namespace Nz bool requireFauxItalic; bool flipped; bool valid; + float fauxOutlineThickness; int advance; unsigned int layerIndex; }; @@ -131,11 +132,11 @@ namespace Nz private: using GlyphMap = std::unordered_map; - UInt64 ComputeKey(unsigned int characterSize, TextStyleFlags style) const; + UInt64 ComputeKey(unsigned int characterSize, TextStyleFlags style, float outlineThickness) const; void OnAtlasCleared(const AbstractAtlas* atlas); void OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer); void OnAtlasRelease(const AbstractAtlas* atlas); - const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, TextStyleFlags style, char32_t character) const; + const Glyph& PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, TextStyleFlags style, float outlineThickness, char32_t character) const; static bool Initialize(); static void Uninitialize(); diff --git a/include/Nazara/Utility/FontData.hpp b/include/Nazara/Utility/FontData.hpp index a3ac4901a..88838a3b7 100644 --- a/include/Nazara/Utility/FontData.hpp +++ b/include/Nazara/Utility/FontData.hpp @@ -22,7 +22,7 @@ namespace Nz FontData() = default; virtual ~FontData(); - virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* dst) = 0; + virtual bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, float outlineThickness, FontGlyph* dst) = 0; virtual String GetFamilyName() const = 0; virtual String GetStyleName() const = 0; @@ -36,6 +36,7 @@ namespace Nz virtual float QueryUnderlinePosition(unsigned int characterSize) const = 0; virtual float QueryUnderlineThickness(unsigned int characterSize) const = 0; + virtual bool SupportsOutline(float outlineThickness) const = 0; virtual bool SupportsStyle(TextStyleFlags style) const = 0; }; } diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp index c41a5d8be..5b4225805 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.hpp +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -38,12 +38,16 @@ namespace Nz std::size_t GetGlyphCount() const override; const Line& GetLine(std::size_t index) const override; std::size_t GetLineCount() const override; + const Color& GetOutlineColor() const; + float GetOutlineThickness() const; TextStyleFlags GetStyle() const; const String& GetText() const; void SetCharacterSize(unsigned int characterSize); void SetColor(const Color& color); void SetFont(Font* font); + void SetOutlineColor(const Color& color); + void SetOutlineThickness(float thickness); void SetStyle(TextStyleFlags style); void SetText(const String& str); @@ -51,7 +55,9 @@ namespace Nz SimpleTextDrawer& operator=(SimpleTextDrawer&& drawer); static SimpleTextDrawer Draw(const String& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); + static SimpleTextDrawer Draw(const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor); static SimpleTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); + static SimpleTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor); private: void ClearGlyphs() const; @@ -72,6 +78,7 @@ namespace Nz mutable std::vector m_glyphs; mutable std::vector m_lines; Color m_color; + Color m_outlineColor; FontRef m_font; mutable Rectf m_workingBounds; mutable Recti m_bounds; @@ -81,6 +88,7 @@ namespace Nz mutable Vector2ui m_drawPos; mutable bool m_colorUpdated; mutable bool m_glyphUpdated; + float m_outlineThickness; unsigned int m_characterSize; }; } diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index 8cc4961cf..a694bb563 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -30,13 +30,13 @@ namespace Nz { for (auto& pair : m_renderInfos) { - Texture* overlay = pair.first; + const RenderKey& key = pair.first; RenderIndices& indices = pair.second; if (indices.count > 0) { const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(instanceData.data.data()); - renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, scissorRect, overlay); + renderQueue->AddSprites(instanceData.renderOrder + key.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, scissorRect, key.texture); } } } @@ -101,15 +101,16 @@ namespace Nz } std::size_t glyphCount = drawer.GetGlyphCount(); - m_localVertices.resize(glyphCount * 4); // Reset glyph count for every texture to zero for (auto& pair : m_renderInfos) pair.second.count = 0; // Count glyph count for each texture - Texture* lastTexture = nullptr; + RenderKey lastRenderKey { nullptr, 0 }; unsigned int* count = nullptr; + + std::size_t visibleGlyphCount = 0; for (std::size_t i = 0; i < glyphCount; ++i) { const AbstractTextDrawer::Glyph& glyph = drawer.GetGlyph(i); @@ -117,19 +118,23 @@ namespace Nz continue; Texture* texture = static_cast(glyph.atlas); - if (lastTexture != texture) + RenderKey renderKey{ texture, glyph.renderOrder }; + if (lastRenderKey != renderKey) { - auto it = m_renderInfos.find(texture); + auto it = m_renderInfos.find(renderKey); if (it == m_renderInfos.end()) - it = m_renderInfos.insert(std::make_pair(texture, RenderIndices{0U, 0U})).first; + it = m_renderInfos.insert(std::make_pair(renderKey, RenderIndices{0U, 0U})).first; count = &it->second.count; - lastTexture = texture; + lastRenderKey = renderKey; } (*count)++; + visibleGlyphCount++; } + m_localVertices.resize(visibleGlyphCount * 4); + // Attributes indices and reinitialize glyph count to zero to use it as a counter in the next loop // This is because the 1st glyph can use texture A, the 2nd glyph can use texture B and the 3th glyph C can use texture A again // so we need a counter to know where to write informations @@ -140,7 +145,7 @@ namespace Nz { RenderIndices& indices = infoIt->second; if (indices.count == 0) - m_renderInfos.erase(infoIt++); //< No glyph uses this texture, remove from indices + infoIt = m_renderInfos.erase(infoIt); //< No glyph uses this texture, remove from indices else { indices.first = index; @@ -151,7 +156,7 @@ namespace Nz } } - lastTexture = nullptr; + lastRenderKey = { nullptr, 0 }; RenderIndices* indices = nullptr; for (unsigned int i = 0; i < glyphCount; ++i) { @@ -160,10 +165,11 @@ namespace Nz continue; Texture* texture = static_cast(glyph.atlas); - if (lastTexture != texture) + RenderKey renderKey{ texture, glyph.renderOrder }; + if (lastRenderKey != renderKey) { - indices = &m_renderInfos[texture]; //< We changed texture, adjust the pointer - lastTexture = texture; + indices = &m_renderInfos[renderKey]; //< We changed texture, adjust the pointer + lastRenderKey = renderKey; } // First, compute the uv coordinates from our atlas rect @@ -185,9 +191,10 @@ namespace Nz for (unsigned int j = 0; j < 4; ++j) { // Remember that indices->count is a counter here, not a count value - m_localVertices[indices->count * 4 + j].color = glyph.color; - m_localVertices[indices->count * 4 + j].position.Set(glyph.corners[j]); - m_localVertices[indices->count * 4 + j].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); + std::size_t offset = (indices->first + indices->count) * 4 + j; + m_localVertices[offset].color = glyph.color; + m_localVertices[offset].position.Set(glyph.corners[j]); + m_localVertices[offset].uv.Set(uvRect.GetCorner((glyph.flipped) ? flippedCorners[j] : normalCorners[j])); } // Increment the counter, go to next glyph @@ -236,13 +243,12 @@ namespace Nz } /*! - * \brief Handle the invalidation of an atlas layer + * \brief Handle the size change of an atlas layer * * \param atlas Atlas being invalidated * \param oldLayer Pointer to the previous layer * \param newLayer Pointer to the new layer */ - void TextSprite::OnAtlasLayerChange(const AbstractAtlas* atlas, AbstractImage* oldLayer, AbstractImage* newLayer) { NazaraUnused(atlas); @@ -255,33 +261,38 @@ namespace Nz } #endif + if (!oldLayer) + return; + + assert(newLayer); + // The texture of an atlas have just been recreated (size change) // we have to adjust the coordinates of the texture and the rendering texture Texture* oldTexture = static_cast(oldLayer); Texture* newTexture = static_cast(newLayer); - // It is possible that we don't use the texture (the atlas warning us for each of its layers) - auto it = m_renderInfos.find(oldTexture); - if (it != m_renderInfos.end()) + Vector2ui oldSize(oldTexture->GetSize()); + Vector2ui newSize(newTexture->GetSize()); + Vector2f scale = Vector2f(oldSize) / Vector2f(newSize); // ratio of the old one to the new one + + // It is possible we actually use that texture multiple times, check them all + for (auto it = m_renderInfos.begin(); it != m_renderInfos.end(); ++it) { - // We indeed use this texture, we have to update its coordinates - RenderIndices indices = std::move(it->second); + const RenderKey& renderKey = it->first; + const RenderIndices& indices = it->second; - Vector2ui oldSize(oldTexture->GetSize()); - Vector2ui newSize(newTexture->GetSize()); - Vector2f scale = Vector2f(oldSize) / Vector2f(newSize); // ratio of the old one to the new one - - // Now we will iterate through each coordinates of the concerned texture to multiply them by the ratio - SparsePtr texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XYZ_Color_UV)); + // Adjust texture coordinates by size ratio + SparsePtr texCoordPtr(&m_localVertices[indices.first].uv, sizeof(VertexStruct_XY_Color_UV)); for (unsigned int i = 0; i < indices.count; ++i) { for (unsigned int j = 0; j < 4; ++j) - m_localVertices[i*4 + j].uv *= scale; + m_localVertices[i * 4 + j].uv *= scale; } - // We get rid off the old texture and we set the new one at the place (same for indices) + // Erase and re-insert with the new texture handle m_renderInfos.erase(it); - m_renderInfos.insert(std::make_pair(newTexture, std::move(indices))); + m_renderInfos.insert(std::make_pair(RenderKey{ newTexture, renderKey.renderOrder }, indices)); + it = m_renderInfos.begin(); //< std::unordered_map::insert may invalidate all iterators, start from the beginning... } } diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp index 0628a4337..c0868c346 100644 --- a/src/Nazara/Utility/Font.cpp +++ b/src/Nazara/Utility/Font.cpp @@ -109,7 +109,7 @@ namespace Nz } } - bool Font::ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* glyph) const + bool Font::ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, float outlineThickness, FontGlyph* glyph) const { #if NAZARA_UTILITY_SAFE if (!IsValid()) @@ -119,7 +119,7 @@ namespace Nz } #endif - return m_data->ExtractGlyph(characterSize, character, style, glyph); + return m_data->ExtractGlyph(characterSize, character, style, outlineThickness, glyph); } const std::shared_ptr& Font::GetAtlas() const @@ -127,9 +127,9 @@ namespace Nz return m_atlas; } - std::size_t Font::GetCachedGlyphCount(unsigned int characterSize, TextStyleFlags style) const + std::size_t Font::GetCachedGlyphCount(unsigned int characterSize, TextStyleFlags style, float outlineThickness) const { - UInt64 key = ComputeKey(characterSize, style); + UInt64 key = ComputeKey(characterSize, style, outlineThickness); auto it = m_glyphes.find(key); if (it == m_glyphes.end()) return 0; @@ -169,28 +169,27 @@ namespace Nz } #endif - // On utilise un cache car la méthode interne QueryKerning peut se révéler coûteuse (car pouvant induire un changement de taille) + // Use a cache as QueryKerning may be costly (may induce an internal size change) auto& map = m_kerningCache[characterSize]; - UInt64 key = (static_cast(first) << 32) | second; // Combinaison de deux caractères 32 bits dans un nombre 64 bits + UInt64 key = (static_cast(first) << 32) | second; auto it = map.find(key); if (it == map.end()) { - // Absent du cache: on va demander l'information à la police int kerning = m_data->QueryKerning(characterSize, first, second); map.insert(std::make_pair(key, kerning)); return kerning; } else - return it->second; // Présent dans le cache, tout va bien + return it->second; } - const Font::Glyph& Font::GetGlyph(unsigned int characterSize, TextStyleFlags style, char32_t character) const + const Font::Glyph& Font::GetGlyph(unsigned int characterSize, TextStyleFlags style, float outlineThickness, char32_t character) const { - UInt64 key = ComputeKey(characterSize, style); - return PrecacheGlyph(m_glyphes[key], characterSize, style, character); + UInt64 key = ComputeKey(characterSize, style, outlineThickness); + return PrecacheGlyph(m_glyphes[key], characterSize, style, outlineThickness, character); } unsigned int Font::GetGlyphBorder() const @@ -224,11 +223,11 @@ namespace Nz sizeInfo.underlineThickness = m_data->QueryUnderlineThickness(characterSize); FontGlyph glyph; - if (m_data->ExtractGlyph(characterSize, ' ', TextStyle_Regular, &glyph)) + if (m_data->ExtractGlyph(characterSize, ' ', TextStyle_Regular, 0.f, &glyph)) sizeInfo.spaceAdvance = glyph.advance; else { - NazaraWarning("Failed to extract space character from font, using half the size"); + NazaraWarning("Failed to extract space character from font, using half the character size"); sizeInfo.spaceAdvance = characterSize/2; } @@ -256,13 +255,13 @@ namespace Nz return m_data != nullptr; } - bool Font::Precache(unsigned int characterSize, TextStyleFlags style, char32_t character) const + bool Font::Precache(unsigned int characterSize, TextStyleFlags style, float outlineThickness, char32_t character) const { - UInt64 key = ComputeKey(characterSize, style); - return PrecacheGlyph(m_glyphes[key], characterSize, style, character).valid; + UInt64 key = ComputeKey(characterSize, style, outlineThickness); + return PrecacheGlyph(m_glyphes[key], characterSize, style, outlineThickness, character).valid; } - bool Font::Precache(unsigned int characterSize, TextStyleFlags style, const String& characterSet) const + bool Font::Precache(unsigned int characterSize, TextStyleFlags style, float outlineThickness, const String& characterSet) const { ///TODO: Itération UTF-8 => UTF-32 sans allocation de buffer (Exposer utf8cpp ?) std::u32string set = characterSet.GetUtf32String(); @@ -272,10 +271,10 @@ namespace Nz return false; } - UInt64 key = ComputeKey(characterSize, style); + UInt64 key = ComputeKey(characterSize, style, outlineThickness); auto& glyphMap = m_glyphes[key]; for (char32_t character : set) - PrecacheGlyph(glyphMap, characterSize, style, character); + PrecacheGlyph(glyphMap, characterSize, style, outlineThickness, character); return true; } @@ -317,13 +316,7 @@ namespace Nz { if (m_minimumStepSize != minimumStepSize) { - #if NAZARA_UTILITY_SAFE - if (minimumStepSize == 0) - { - NazaraError("Minimum step size cannot be zero as it implies division by zero"); - return; - } - #endif + NazaraAssert(minimumStepSize != 0, "Minimum step size cannot be zero"); m_minimumStepSize = minimumStepSize; ClearGlyphCache(); @@ -399,21 +392,21 @@ namespace Nz s_defaultMinimumStepSize = minimumStepSize; } - UInt64 Font::ComputeKey(unsigned int characterSize, TextStyleFlags style) const + UInt64 Font::ComputeKey(unsigned int characterSize, TextStyleFlags style, float outlineThickness) const { - // On prend le pas en compte - UInt64 sizePart = static_cast((characterSize/m_minimumStepSize)*m_minimumStepSize); - - // Ainsi que le style (uniquement le gras et l'italique, les autres sont gérés par un TextDrawer) - TextStyleFlags stylePart = 0; + // Adjust size to step size + UInt64 sizeStylePart = static_cast((characterSize/m_minimumStepSize)*m_minimumStepSize); + sizeStylePart = std::min(sizeStylePart, Nz::IntegralPow(2, 30)); //< 2^30 should be more than enough as a max size + sizeStylePart <<= 2; + // Store bold and italic flags (other style are handled directly by a TextDrawer) if (style & TextStyle_Bold) - stylePart |= TextStyle_Bold; + sizeStylePart |= 1 << 0; if (style & TextStyle_Italic) - stylePart |= TextStyle_Italic; + sizeStylePart |= 1 << 1; - return (static_cast(stylePart) << 32) | sizePart; + return (sizeStylePart << 32) | reinterpret_cast(outlineThickness); } void Font::OnAtlasCleared(const AbstractAtlas* atlas) @@ -471,13 +464,13 @@ namespace Nz NazaraError("Atlas has been released while in use"); } - const Font::Glyph& Font::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, TextStyleFlags style, char32_t character) const + const Font::Glyph& Font::PrecacheGlyph(GlyphMap& glyphMap, unsigned int characterSize, TextStyleFlags style, float outlineThickness, char32_t character) const { auto it = glyphMap.find(character); - if (it != glyphMap.end()) // Si le glyphe n'est pas déjà chargé + if (it != glyphMap.end()) return it->second; - Glyph& glyph = glyphMap[character]; // Insertion du glyphe + Glyph& glyph = glyphMap[character]; //< Insert a new glyph glyph.valid = false; #if NAZARA_UTILITY_SAFE @@ -488,7 +481,8 @@ namespace Nz } #endif - // On vérifie que le style demandé est supporté par la police (dans le cas contraire il devra être simulé au rendu) + // Check if requested style is supported by our font (otherwise it will need to be simulated) + glyph.fauxOutlineThickness = 0.f; glyph.requireFauxBold = false; glyph.requireFauxItalic = false; @@ -505,12 +499,18 @@ namespace Nz supportedStyle &= ~TextStyle_Italic; } - // Est-ce que la police supporte le style demandé ? - if (style == supportedStyle) + float supportedOutlineThickness = outlineThickness; + if (outlineThickness > 0.f && !m_data->SupportsOutline(outlineThickness)) + { + glyph.fauxOutlineThickness = supportedOutlineThickness; + supportedOutlineThickness = 0.f; + } + + // Does font support requested style? + if (style == supportedStyle && outlineThickness == supportedOutlineThickness) { - // On extrait le glyphe depuis la police FontGlyph fontGlyph; - if (ExtractGlyph(characterSize, character, style, &fontGlyph)) + if (ExtractGlyph(characterSize, character, style, outlineThickness, &fontGlyph)) { if (fontGlyph.image.IsValid()) { @@ -523,21 +523,20 @@ namespace Nz glyph.atlasRect.height = 0; } - // Insertion du rectangle dans l'un des atlas - if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose + // Insert rectangle (if not empty) into our atlas + if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) { - // Bordure (pour éviter le débordement lors du filtrage) + // Add a small border to prevent GPU to sample another glyph pixel glyph.atlasRect.width += m_glyphBorder*2; glyph.atlasRect.height += m_glyphBorder*2; - // Insertion du rectangle dans l'atlas virtuel if (!m_atlas->Insert(fontGlyph.image, &glyph.atlasRect, &glyph.flipped, &glyph.layerIndex)) { NazaraError("Failed to insert glyph into atlas"); return glyph; } - // Compensation de la bordure (centrage du glyphe) + // Recenter and remove glyph border glyph.atlasRect.x += m_glyphBorder; glyph.atlasRect.y += m_glyphBorder; glyph.atlasRect.width -= m_glyphBorder*2; @@ -549,16 +548,13 @@ namespace Nz glyph.valid = true; } else - { NazaraWarning("Failed to extract glyph \"" + String::Unicode(character) + "\""); - } } else { - // La police ne supporte pas le style demandé, nous allons donc précharger le glyphe supportant le style "minimum" supporté - // et copier ses données - UInt64 newKey = ComputeKey(characterSize, supportedStyle); - const Glyph& referenceGlyph = PrecacheGlyph(m_glyphes[newKey], characterSize, supportedStyle, character); + // Font doesn't support request style, precache the minimal supported version and copy its data + UInt64 newKey = ComputeKey(characterSize, supportedStyle, supportedOutlineThickness); + const Glyph& referenceGlyph = PrecacheGlyph(m_glyphes[newKey], characterSize, supportedStyle, supportedOutlineThickness, character); if (referenceGlyph.valid) { glyph.aabb = referenceGlyph.aabb; diff --git a/src/Nazara/Utility/Formats/FreeTypeLoader.cpp b/src/Nazara/Utility/Formats/FreeTypeLoader.cpp index 9f890385f..05814a903 100644 --- a/src/Nazara/Utility/Formats/FreeTypeLoader.cpp +++ b/src/Nazara/Utility/Formats/FreeTypeLoader.cpp @@ -6,7 +6,9 @@ #include #include FT_FREETYPE_H #include FT_BITMAP_H +#include FT_STROKER_H #include FT_OUTLINE_H +#include #include #include #include @@ -24,8 +26,10 @@ namespace Nz class FreeTypeLibrary; FT_Library s_library; + FT_Stroker s_stroker; std::shared_ptr s_libraryOwner; - constexpr float s_invScaleFactor = 1.f / (1 << 6); // 1/64 + constexpr float s_scaleFactor = 1 << 6; + constexpr float s_invScaleFactor = 1.f / s_scaleFactor; extern "C" unsigned long FT_StreamRead(FT_Stream stream, unsigned long offset, unsigned char* buffer, unsigned long count) @@ -66,9 +70,23 @@ namespace Nz // pour ne libérer FreeType que lorsque plus personne ne l'utilise public: - FreeTypeLibrary() = default; + FreeTypeLibrary() + { + if (FT_Stroker_New(s_library, &s_stroker) != 0) + { + NazaraWarning("Failed to load FreeType stroker, outline will not be possible"); + s_stroker = nullptr; //< Just in case + } + } + ~FreeTypeLibrary() { + if (s_stroker) + { + FT_Stroker_Done(s_stroker); + s_stroker = nullptr; + } + FT_Done_FreeType(s_library); s_library = nullptr; } @@ -96,7 +114,7 @@ namespace Nz return FT_Open_Face(s_library, &m_args, -1, nullptr) == 0; } - bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, FontGlyph* dst) override + bool ExtractGlyph(unsigned int characterSize, char32_t character, TextStyleFlags style, float outlineThickness, FontGlyph* dst) override { #ifdef NAZARA_DEBUG if (!dst) @@ -114,61 +132,85 @@ namespace Nz return false; } - FT_GlyphSlot& glyph = m_face->glyph; + FT_GlyphSlot glyphSlot = m_face->glyph; + + FT_Glyph glyph; + if (FT_Get_Glyph(glyphSlot, &glyph) != 0) + { + NazaraError("Failed to extract glyph"); + return false; + } + CallOnExit destroyGlyph([&]() { FT_Done_Glyph(glyph); }); const FT_Pos boldStrength = 2 << 6; bool embolden = (style & TextStyle_Bold) != 0; + bool hasOutlineFormat = (glyph->format == FT_GLYPH_FORMAT_OUTLINE); dst->advance = (embolden) ? boldStrength >> 6 : 0; - if (embolden && glyph->format == FT_GLYPH_FORMAT_OUTLINE) + if (hasOutlineFormat) { - // http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline_Embolden - FT_Outline_Embolden(&glyph->outline, boldStrength); - embolden = false; + if (embolden) + { + // FT_Glyph can be casted to FT_OutlineGlyph if format is FT_GLYPH_FORMAT_OUTLINE + FT_OutlineGlyph outlineGlyph = reinterpret_cast(glyph); + if (FT_Outline_Embolden(&outlineGlyph->outline, boldStrength) != 0) + { + NazaraError("Failed to embolden glyph"); + return false; + } + } + + if (outlineThickness > 0.f) + { + FT_Stroker_Set(s_stroker, static_cast(s_scaleFactor * outlineThickness), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); + if (FT_Glyph_Stroke(&glyph, s_stroker, 1) != 0) + { + NazaraError("Failed to outline glyph"); + return false; + } + } } - // http://www.freetype.org/freetype2/docs/reference/ft2-glyph_management.html#FT_Glyph_To_Bitmap - // Conversion du glyphe vers le format bitmap - // Cette fonction ne fait rien dans le cas où le glyphe est déjà un bitmap - if (FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL) != 0) + if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, 1) != 0) { NazaraError("Failed to convert glyph to bitmap"); return false; } + FT_Bitmap& bitmap = reinterpret_cast(glyph)->bitmap; + // Dans le cas où nous voulons des caractères gras mais que nous n'avons pas pu agir plus tôt // nous demandons à FreeType d'agir directement sur le bitmap généré if (embolden) { // http://www.freetype.org/freetype2/docs/reference/ft2-bitmap_handling.html#FT_Bitmap_Embolden - // "If you want to embolden the bitmap owned by a FT_GlyphSlot_Rec, you should call FT_GlyphSlot_Own_Bitmap on the slot first" - FT_GlyphSlot_Own_Bitmap(glyph); - FT_Bitmap_Embolden(s_library, &glyph->bitmap, boldStrength, boldStrength); + FT_Bitmap_Embolden(s_library, &bitmap, boldStrength, boldStrength); } - dst->advance += glyph->metrics.horiAdvance >> 6; - dst->aabb.x = glyph->metrics.horiBearingX >> 6; - dst->aabb.y = -(glyph->metrics.horiBearingY >> 6); // Inversion du repère - dst->aabb.width = glyph->metrics.width >> 6; - dst->aabb.height = glyph->metrics.height >> 6; + int outlineThicknessInt = static_cast(outlineThickness * 2.f + 0.5f); //< round it + dst->advance += glyphSlot->metrics.horiAdvance >> 6; + dst->aabb.x = glyphSlot->metrics.horiBearingX >> 6; + dst->aabb.y = -(glyphSlot->metrics.horiBearingY >> 6); // Inversion du repère + dst->aabb.width = (glyphSlot->metrics.width >> 6) + outlineThicknessInt; + dst->aabb.height = (glyphSlot->metrics.height >> 6) + outlineThicknessInt; - unsigned int width = glyph->bitmap.width; - unsigned int height = glyph->bitmap.rows; + unsigned int width = bitmap.width; + unsigned int height = bitmap.rows; if (width > 0 && height > 0) { dst->image.Create(ImageType_2D, PixelFormatType_A8, width, height); UInt8* pixels = dst->image.GetPixels(); - const UInt8* data = glyph->bitmap.buffer; + const UInt8* data = bitmap.buffer; // Selon la documentation FreeType, le glyphe peut être encodé en format A8 (huit bits d'alpha par pixel) // ou au format A1 (un bit d'alpha par pixel). // Cependant dans un cas comme dans l'autre, il nous faut gérer le pitch (les données peuvent ne pas être contigues) // ainsi que le padding dans le cas du format A1 (Chaque ligne prends un nombre fixe d'octets) - if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) + if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { // Format A1 for (unsigned int y = 0; y < height; ++y) @@ -176,20 +218,20 @@ namespace Nz for (unsigned int x = 0; x < width; ++x) *pixels++ = (data[x/8] & ((1 << (7 - x%8)) ? 255 : 0)); - data += glyph->bitmap.pitch; + data += bitmap.pitch; } } else { // Format A8 - if (glyph->bitmap.pitch == static_cast(width*sizeof(UInt8))) // Pouvons-nous copier directement ? - dst->image.Update(glyph->bitmap.buffer); + if (bitmap.pitch == static_cast(width*sizeof(UInt8))) // Pouvons-nous copier directement ? + dst->image.Update(bitmap.buffer); //< Small optimization else { for (unsigned int y = 0; y < height; ++y) { std::memcpy(pixels, data, width*sizeof(UInt8)); - data += glyph->bitmap.pitch; + data += bitmap.pitch; pixels += width*sizeof(UInt8); } } @@ -312,6 +354,11 @@ namespace Nz m_args.stream = &m_stream; } + bool SupportsOutline(float /*outlineThickness*/) const override + { + return s_stroker != 0; + } + bool SupportsStyle(TextStyleFlags style) const override { ///TODO diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index ec684a8e0..17c2a9b6d 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -10,9 +10,11 @@ namespace Nz { SimpleTextDrawer::SimpleTextDrawer() : m_color(Color::White), + m_outlineColor(Color::Black), m_style(TextStyle_Regular), m_colorUpdated(true), m_glyphUpdated(true), + m_outlineThickness(0.f), m_characterSize(24) { SetFont(Font::GetDefault()); @@ -24,6 +26,8 @@ namespace Nz m_style(drawer.m_style), m_colorUpdated(false), m_glyphUpdated(false), + m_outlineColor(drawer.m_outlineColor), + m_outlineThickness(drawer.m_outlineThickness), m_characterSize(drawer.m_characterSize) { SetFont(drawer.m_font); @@ -120,6 +124,16 @@ namespace Nz return m_lines.size(); } + const Color& SimpleTextDrawer::GetOutlineColor() const + { + return m_outlineColor; + } + + float SimpleTextDrawer::GetOutlineThickness() const + { + return m_outlineThickness; + } + TextStyleFlags SimpleTextDrawer::GetStyle() const { return m_style; @@ -159,6 +173,22 @@ namespace Nz } } + void SimpleTextDrawer::SetOutlineColor(const Color& color) + { + m_outlineColor = color; + + m_glyphUpdated = false; + } + + void SimpleTextDrawer::SetOutlineThickness(float thickness) + { + NazaraAssert(thickness >= 0.f, "Thickness must be zero or positive"); + + m_outlineThickness = thickness; + + m_glyphUpdated = false; + } + void SimpleTextDrawer::SetStyle(TextStyleFlags style) { m_style = style; @@ -177,6 +207,8 @@ namespace Nz { m_characterSize = drawer.m_characterSize; m_color = drawer.m_color; + m_outlineColor = drawer.m_outlineColor; + m_outlineThickness = drawer.m_outlineThickness; m_style = drawer.m_style; m_text = drawer.m_text; @@ -198,6 +230,8 @@ namespace Nz m_glyphs = std::move(drawer.m_glyphs); m_glyphUpdated = std::move(drawer.m_glyphUpdated); m_font = std::move(drawer.m_font); + m_outlineColor = std::move(drawer.m_outlineColor); + m_outlineThickness = std::move(drawer.m_outlineThickness); m_style = std::move(drawer.m_style); m_text = std::move(drawer.m_text); @@ -218,6 +252,19 @@ namespace Nz return drawer; } + SimpleTextDrawer SimpleTextDrawer::Draw(const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor) + { + SimpleTextDrawer drawer; + drawer.SetCharacterSize(characterSize); + drawer.SetColor(color); + drawer.SetOutlineColor(outlineColor); + drawer.SetOutlineThickness(outlineThickness); + drawer.SetStyle(style); + drawer.SetText(str); + + return drawer; + } + SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color) { SimpleTextDrawer drawer; @@ -230,6 +277,20 @@ namespace Nz return drawer; } + SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor) + { + SimpleTextDrawer drawer; + drawer.SetCharacterSize(characterSize); + drawer.SetColor(color); + drawer.SetFont(font); + drawer.SetOutlineColor(outlineColor); + drawer.SetOutlineThickness(outlineThickness); + drawer.SetStyle(style); + drawer.SetText(str); + + return drawer; + } + void SimpleTextDrawer::ClearGlyphs() const { m_bounds.MakeZero(); @@ -278,7 +339,7 @@ namespace Nz const Font::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize); - m_glyphs.reserve(m_glyphs.size() + characters.size()); + m_glyphs.reserve(m_glyphs.size() + characters.size() * (m_outlineThickness > 0.f) ? 2 : 1); for (char32_t character : characters) { if (m_previousCharacter != 0) @@ -304,51 +365,57 @@ namespace Nz break; } + auto GenerateGlyph = [this](Glyph& glyph, char32_t character, float outlineThickness, Nz::Color color, int renderOrder, int* advance) + { + const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, outlineThickness, character); + if (fontGlyph.valid && fontGlyph.fauxOutlineThickness <= 0.f) + { + glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex); + glyph.atlasRect = fontGlyph.atlasRect; + glyph.color = color; + glyph.flipped = fontGlyph.flipped; + glyph.renderOrder = renderOrder; + + glyph.bounds.Set(fontGlyph.aabb); + glyph.bounds.x += m_drawPos.x; + glyph.bounds.y += m_drawPos.y; + + // Faux bold and faux outline thickness are not supported + + // We "lean" the glyph to simulate italics style + float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f; + float italicTop = italic * glyph.bounds.y; + float italicBottom = italic * glyph.bounds.GetMaximum().y; + + glyph.corners[0].Set(glyph.bounds.x - italicTop - outlineThickness, glyph.bounds.y - outlineThickness); + glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop - outlineThickness, glyph.bounds.y - outlineThickness); + glyph.corners[2].Set(glyph.bounds.x - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness); + glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness); + + if (advance) + *advance = fontGlyph.advance; + + return true; + } + else + return false; + }; + Glyph glyph; if (!whitespace) { - const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, character); - if (!fontGlyph.valid) + if (!GenerateGlyph(glyph, character, 0.f, m_color, 0, &advance)) continue; // Glyph failed to load, just skip it (can't do much) - advance = fontGlyph.advance; - - glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex); - glyph.atlasRect = fontGlyph.atlasRect; - glyph.color = m_color; - glyph.flipped = fontGlyph.flipped; - - glyph.bounds.Set(fontGlyph.aabb); - glyph.bounds.x += m_drawPos.x; - glyph.bounds.y += m_drawPos.y; - - if (fontGlyph.requireFauxBold) + if (m_outlineThickness > 0.f) { - // Let's simulate bold by enlarging the glyph (not a neat idea, but should work) - Vector2f center = glyph.bounds.GetCenter(); - - // Enlarge by 10% - glyph.bounds.width *= 1.1f; - glyph.bounds.height *= 1.1f; - - // Replace it at the correct height - Vector2f offset(glyph.bounds.GetCenter() - center); - glyph.bounds.x -= offset.x; - glyph.bounds.y -= offset.y; - - // Adjust advance (+10%) - advance += advance / 10; + Glyph outlineGlyph; + if (GenerateGlyph(outlineGlyph, character, m_outlineThickness, m_outlineColor, -1, nullptr)) + { + m_lines.back().bounds.ExtendTo(outlineGlyph.bounds); + m_glyphs.push_back(outlineGlyph); + } } - - // We "lean" the glyph to simulate italics style - float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f; - float italicTop = italic * glyph.bounds.y; - float italicBottom = italic * glyph.bounds.GetMaximum().y; - - glyph.corners[0].Set(glyph.bounds.x - italicTop, glyph.bounds.y); - glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop, glyph.bounds.y); - glyph.corners[2].Set(glyph.bounds.x - italicBottom, glyph.bounds.y + glyph.bounds.height); - glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom, glyph.bounds.y + glyph.bounds.height); } else { From 17236880d24b04b2a7e71162bf85d4c62de0388a Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 16 Apr 2019 01:46:49 +0200 Subject: [PATCH 64/77] SDK/ImageWidget: Fixed sprite not following widget position --- SDK/src/NDK/Widgets/ImageWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SDK/src/NDK/Widgets/ImageWidget.cpp b/SDK/src/NDK/Widgets/ImageWidget.cpp index 8a766419b..0a1cfdc81 100644 --- a/SDK/src/NDK/Widgets/ImageWidget.cpp +++ b/SDK/src/NDK/Widgets/ImageWidget.cpp @@ -12,7 +12,7 @@ namespace Ndk BaseWidget(parent) { m_entity = CreateEntity(); - m_entity->AddComponent(); + m_entity->AddComponent().SetParent(this); auto& gfx = m_entity->AddComponent(); m_sprite = Nz::Sprite::New(); From 57264a56501baec1e122f67cb66d8c36ceca391c Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 22 Apr 2019 17:05:15 +0200 Subject: [PATCH 65/77] SimpleTextDrawer: Don't regenerate glyphs on outline color update --- src/Nazara/Utility/SimpleTextDrawer.cpp | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 17c2a9b6d..86ba50764 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -177,7 +177,7 @@ namespace Nz { m_outlineColor = color; - m_glyphUpdated = false; + m_colorUpdated = false; } void SimpleTextDrawer::SetOutlineThickness(float thickness) @@ -430,7 +430,7 @@ namespace Nz } m_lines.back().bounds.ExtendTo(glyph.bounds); - + switch (character) { case '\n': @@ -515,8 +515,22 @@ namespace Nz void SimpleTextDrawer::UpdateGlyphColor() const { - for (Glyph& glyph : m_glyphs) - glyph.color = m_color; + if (m_outlineThickness > 0.f) + { + for (std::size_t glyphIndex = 0; glyphIndex < m_glyphs.size(); ++glyphIndex) + { + Glyph& glyph = m_glyphs[glyphIndex]; + if (glyphIndex % 2 == 0) + glyph.color = m_outlineColor; + else + glyph.color = m_color; + } + } + else + { + for (Glyph& glyph : m_glyphs) + glyph.color = m_color; + } m_colorUpdated = true; } From 408d37a27a37147d2f363410aafe3de195838495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 24 Apr 2019 13:46:02 +0200 Subject: [PATCH 66/77] Network/IpAddress: Fix problem with some IPv6 --- src/Nazara/Network/Win32/IpAddressImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/Win32/IpAddressImpl.cpp b/src/Nazara/Network/Win32/IpAddressImpl.cpp index 853dae840..38da48b4b 100644 --- a/src/Nazara/Network/Win32/IpAddressImpl.cpp +++ b/src/Nazara/Network/Win32/IpAddressImpl.cpp @@ -157,7 +157,7 @@ namespace Nz IpAddress::IPv6 ipv6; for (unsigned int i = 0; i < 8; ++i) - ipv6[i] = rawIpV6[i * 2] << 8 | rawIpV6[i * 2 + 1]; + ipv6[i] = Nz::UInt16(rawIpV6[i * 2]) << 8 | rawIpV6[i * 2 + 1]; return IpAddress(ipv6, ntohs(addressv6->sin6_port)); } From 278ff2679550fa219143fe6c464cab6963c6d737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Wed, 24 Apr 2019 14:29:55 +0200 Subject: [PATCH 67/77] Forgot to fix this for Linux too --- src/Nazara/Network/Posix/IpAddressImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nazara/Network/Posix/IpAddressImpl.cpp b/src/Nazara/Network/Posix/IpAddressImpl.cpp index d00d58068..4abaaee94 100644 --- a/src/Nazara/Network/Posix/IpAddressImpl.cpp +++ b/src/Nazara/Network/Posix/IpAddressImpl.cpp @@ -63,7 +63,7 @@ namespace Nz IpAddress::IPv6 ipv6; for (unsigned int i = 0; i < 8; ++i) - ipv6[i] = rawIpV6[i * 2] << 8 | rawIpV6[i * 2 + 1]; + ipv6[i] = Nz::UInt16(rawIpV6[i * 2]) << 8 | rawIpV6[i * 2 + 1]; return ipv6; } From 3871a8373a8de35cc7a297ba168e4e03a99ef2c2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 25 Apr 2019 21:06:49 +0200 Subject: [PATCH 68/77] Assimp: Add support for animated meshes (WIP) Doesn't work at all for animations --- plugins/Assimp/Plugin.cpp | 265 +++++++++++++++++++++++++++++++++++++- 1 file changed, 260 insertions(+), 5 deletions(-) diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index b91337f9a..5295d2f5a 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -25,11 +25,14 @@ SOFTWARE. #include #include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -77,7 +80,7 @@ bool IsSupported(const String& extension) return (aiIsExtensionSupported(dotExt.GetConstBuffer()) == AI_TRUE); } -Ternary Check(Stream& /*stream*/, const MeshParams& parameters) +Ternary CheckAnimation(Stream& /*stream*/, const AnimationParams& parameters) { bool skip; if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip) @@ -86,7 +89,102 @@ Ternary Check(Stream& /*stream*/, const MeshParams& parameters) return Ternary_Unknown; } -MeshRef Load(Stream& stream, const MeshParams& parameters) +AnimationRef LoadAnimation(Stream& stream, const AnimationParams& parameters) +{ + Nz::String streamPath = stream.GetPath(); + + FileIOUserdata userdata; + userdata.originalFilePath = (!streamPath.IsEmpty()) ? streamPath.GetConstBuffer() : StreamPath; + userdata.originalStream = &stream; + + aiFileIO fileIO; + fileIO.CloseProc = StreamCloser; + fileIO.OpenProc = StreamOpener; + fileIO.UserData = reinterpret_cast(&userdata); + + unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_Debone + | aiProcess_FindInvalidData | aiProcess_FixInfacingNormals + | aiProcess_FlipWindingOrder | aiProcess_GenSmoothNormals + | aiProcess_GenUVCoords | aiProcess_JoinIdenticalVertices + | aiProcess_LimitBoneWeights | aiProcess_MakeLeftHanded + | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes + | aiProcess_RemoveComponent | aiProcess_RemoveRedundantMaterials + | aiProcess_SortByPType | aiProcess_SplitLargeMeshes + | aiProcess_TransformUVCoords | aiProcess_Triangulate; + + aiPropertyStore* properties = aiCreatePropertyStore(); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, ~aiComponent_ANIMATIONS); + + const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, 0, &fileIO, properties); + aiReleasePropertyStore(properties); + + if (!scene) + { + NazaraError("Assimp failed to import file: " + Nz::String(aiGetErrorString())); + return nullptr; + } + + if (!scene->HasAnimations()) + { + NazaraError("File has no animation"); + return nullptr; + } + + aiAnimation* animation = scene->mAnimations[0]; + + unsigned int maxFrameCount = 0; + for (unsigned int i = 0; i < animation->mNumChannels; ++i) + { + aiNodeAnim* nodeAnim = animation->mChannels[i]; + + maxFrameCount = std::max({ maxFrameCount, nodeAnim->mNumPositionKeys, nodeAnim->mNumRotationKeys, nodeAnim->mNumScalingKeys }); + } + + AnimationRef anim = Animation::New(); + + anim->CreateSkeletal(maxFrameCount, animation->mNumChannels); + + Sequence sequence; + sequence.firstFrame = 0; + sequence.frameCount = maxFrameCount; + sequence.frameRate = animation->mTicksPerSecond; + + anim->AddSequence(sequence); + + SequenceJoint* sequenceJoints = anim->GetSequenceJoints(); + + Quaternionf rotationQuat = Quaternionf::Identity(); + + for (unsigned int i = 0; i < animation->mNumChannels; ++i) + { + aiNodeAnim* nodeAnim = animation->mChannels[i]; + for (unsigned int j = 0; j < nodeAnim->mNumPositionKeys; ++j) + { + SequenceJoint& sequenceJoint = sequenceJoints[i*animation->mNumChannels + j]; + + aiQuaternion rotation = nodeAnim->mRotationKeys[j].mValue; + aiVector3D position = nodeAnim->mPositionKeys[j].mValue; + + sequenceJoint.position = Vector3f(position.x, position.y, position.z); + sequenceJoint.rotation = Quaternionf(rotation.w, rotation.x, rotation.y, rotation.z); + sequenceJoint.scale.Set(1.f); + } + } + + return anim; +} + +Ternary CheckMesh(Stream& /*stream*/, const MeshParams& parameters) +{ + bool skip; + if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip) + return Ternary_False; + + return Ternary_Unknown; +} + +MeshRef LoadMesh(Stream& stream, const MeshParams& parameters) { Nz::String streamPath = stream.GetPath(); @@ -183,7 +281,162 @@ MeshRef Load(Stream& stream, const MeshParams& parameters) ProcessJoints(scene->mRootNode, skeleton, joints); - return nullptr; + // aiMaterial index in scene => Material index and data in Mesh + std::unordered_map> materials; + + for (unsigned int i = 0; i < scene->mNumMeshes; ++i) + { + aiMesh* iMesh = scene->mMeshes[i]; + if (iMesh->HasBones()) + { + // For now, process only skeletal meshes + } + + unsigned int indexCount = iMesh->mNumFaces * 3; + unsigned int vertexCount = iMesh->mNumVertices; + + // Index buffer + bool largeIndices = (vertexCount > std::numeric_limits::max()); + + IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, parameters.indexBufferFlags); + + IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); + IndexIterator index = indexMapper.begin(); + + for (unsigned int j = 0; j < iMesh->mNumFaces; ++j) + { + aiFace& face = iMesh->mFaces[j]; + if (face.mNumIndices != 3) + NazaraWarning("Assimp plugin: This face is not a triangle!"); + + *index++ = face.mIndices[0]; + *index++ = face.mIndices[1]; + *index++ = face.mIndices[2]; + } + indexMapper.Unmap(); + + // Make sure the normal/tangent matrix won't rescale our vectors + Nz::Matrix4f normalTangentMatrix = parameters.matrix; + if (normalTangentMatrix.HasScale()) + normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); + + VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.storage, parameters.vertexBufferFlags | BufferUsage_Dynamic); + BufferMapper vertexMapper(vertexBuffer, BufferAccess_ReadWrite); + SkeletalMeshVertex* vertices = static_cast(vertexMapper.GetPointer()); + + for (std::size_t i = 0; i < vertexCount; ++i) + { + aiVector3D normal = iMesh->mNormals[i]; + aiVector3D position = iMesh->mVertices[i]; + aiVector3D tangent = iMesh->mTangents[i]; + aiVector3D uv = iMesh->mTextureCoords[0][i]; + + vertices[i].weightCount = 0; + vertices[i].normal = normalTangentMatrix.Transform({ normal.x, normal.y, normal.z }, 0.f); + vertices[i].position = parameters.matrix * Vector3f(position.x, position.y, position.z); + vertices[i].tangent = normalTangentMatrix.Transform({ tangent.x, tangent.y, tangent.z }, 0.f); + vertices[i].uv = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale; + } + + for (unsigned int i = 0; i < iMesh->mNumBones; ++i) + { + aiBone* bone = iMesh->mBones[i]; + for (unsigned int j = 0; j < bone->mNumWeights; ++j) + { + aiVertexWeight& vertexWeight = bone->mWeights[j]; + SkeletalMeshVertex& vertex = vertices[vertexWeight.mVertexId]; + + std::size_t weightIndex = vertex.weightCount++; + vertex.jointIndexes[weightIndex] = i; + vertex.weights[weightIndex] = vertexWeight.mWeight; + } + } + + // Submesh + SkeletalMeshRef subMesh = SkeletalMesh::New(vertexBuffer, indexBuffer); + subMesh->SetMaterialIndex(iMesh->mMaterialIndex); + + auto matIt = materials.find(iMesh->mMaterialIndex); + if (matIt == materials.end()) + { + ParameterList matData; + aiMaterial* aiMat = scene->mMaterials[iMesh->mMaterialIndex]; + + auto ConvertColor = [&](const char* aiKey, unsigned int aiType, unsigned int aiIndex, const char* colorKey) + { + aiColor4D color; + if (aiGetMaterialColor(aiMat, aiKey, aiType, aiIndex, &color) == aiReturn_SUCCESS) + { + matData.SetParameter(colorKey, Color(static_cast(color.r * 255), static_cast(color.g * 255), static_cast(color.b * 255), static_cast(color.a * 255))); + } + }; + + auto ConvertTexture = [&](aiTextureType aiType, const char* textureKey, const char* wrapKey = nullptr) + { + aiString path; + aiTextureMapMode mapMode[3]; + if (aiGetMaterialTexture(aiMat, aiType, 0, &path, nullptr, nullptr, nullptr, nullptr, &mapMode[0], nullptr) == aiReturn_SUCCESS) + { + matData.SetParameter(textureKey, stream.GetDirectory() + String(path.data, path.length)); + + if (wrapKey) + { + SamplerWrap wrap = SamplerWrap_Default; + switch (mapMode[0]) + { + case aiTextureMapMode_Clamp: + case aiTextureMapMode_Decal: + wrap = SamplerWrap_Clamp; + break; + + case aiTextureMapMode_Mirror: + wrap = SamplerWrap_MirroredRepeat; + break; + + case aiTextureMapMode_Wrap: + wrap = SamplerWrap_Repeat; + break; + + default: + NazaraWarning("Assimp texture map mode 0x" + String::Number(mapMode[0], 16) + " not handled"); + break; + } + + matData.SetParameter(wrapKey, static_cast(wrap)); + } + } + }; + + ConvertColor(AI_MATKEY_COLOR_AMBIENT, MaterialData::AmbientColor); + ConvertColor(AI_MATKEY_COLOR_DIFFUSE, MaterialData::DiffuseColor); + ConvertColor(AI_MATKEY_COLOR_SPECULAR, MaterialData::SpecularColor); + + ConvertTexture(aiTextureType_DIFFUSE, MaterialData::DiffuseTexturePath, MaterialData::DiffuseWrap); + ConvertTexture(aiTextureType_EMISSIVE, MaterialData::EmissiveTexturePath); + ConvertTexture(aiTextureType_HEIGHT, MaterialData::HeightTexturePath); + ConvertTexture(aiTextureType_NORMALS, MaterialData::NormalTexturePath); + ConvertTexture(aiTextureType_OPACITY, MaterialData::AlphaTexturePath); + ConvertTexture(aiTextureType_SPECULAR, MaterialData::SpecularTexturePath, MaterialData::SpecularWrap); + + aiString name; + if (aiGetMaterialString(aiMat, AI_MATKEY_NAME, &name) == aiReturn_SUCCESS) + matData.SetParameter(MaterialData::Name, String(name.data, name.length)); + + int iValue; + if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) + matData.SetParameter(MaterialData::FaceCulling, !iValue); + + matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first; + } + + subMesh->SetMaterialIndex(matIt->first); + + mesh->AddSubMesh(subMesh); + } + + mesh->SetMaterialCount(std::max(UInt32(materials.size()), 1)); + for (const auto& pair : materials) + mesh->SetMaterialData(pair.second.first, pair.second.second); } else { @@ -385,12 +638,14 @@ extern "C" { NAZARA_EXPORT int PluginLoad() { - Nz::MeshLoader::RegisterLoader(IsSupported, Check, Load); + Nz::AnimationLoader::RegisterLoader(IsSupported, CheckAnimation, LoadAnimation); + Nz::MeshLoader::RegisterLoader(IsSupported, CheckMesh, LoadMesh); return 1; } NAZARA_EXPORT void PluginUnload() { - Nz::MeshLoader::UnregisterLoader(IsSupported, Check, Load); + Nz::AnimationLoader::RegisterLoader(IsSupported, CheckAnimation, LoadAnimation); + Nz::MeshLoader::UnregisterLoader(IsSupported, CheckMesh, LoadMesh); } } From aec88aafa24768a26a52b221700638e74f1628b3 Mon Sep 17 00:00:00 2001 From: Apjue Date: Fri, 26 Apr 2019 21:47:24 +0200 Subject: [PATCH 69/77] Fix Nazara version & fake tab --- include/Nazara/Prerequisites.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Nazara/Prerequisites.hpp b/include/Nazara/Prerequisites.hpp index ddb2796fc..ca3fa889d 100644 --- a/include/Nazara/Prerequisites.hpp +++ b/include/Nazara/Prerequisites.hpp @@ -77,7 +77,7 @@ // Nazara version macro #define NAZARA_VERSION_MAJOR 0 -#define NAZARA_VERSION_MINOR 3 +#define NAZARA_VERSION_MINOR 4 #define NAZARA_VERSION_PATCH 0 #include @@ -136,7 +136,7 @@ // Détection 64 bits #if !defined(NAZARA_PLATFORM_x64) && (defined(_WIN64) || defined(__amd64__) || defined(__x86_64__) || defined(__ia64__) || defined(__ia64) || \ - defined(_M_IA64) || defined(__itanium__) || defined(__MINGW64__) || defined(_M_AMD64) || defined (_M_X64)) + defined(_M_IA64) || defined(__itanium__) || defined(__MINGW64__) || defined(_M_AMD64) || defined (_M_X64)) #define NAZARA_PLATFORM_x64 #endif From 1244ef13034c18afba114c0785171bc726318a5f Mon Sep 17 00:00:00 2001 From: Apjue Date: Fri, 26 Apr 2019 21:51:43 +0200 Subject: [PATCH 70/77] Fix french comment --- include/Nazara/Prerequisites.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Nazara/Prerequisites.hpp b/include/Nazara/Prerequisites.hpp index ca3fa889d..2414aba95 100644 --- a/include/Nazara/Prerequisites.hpp +++ b/include/Nazara/Prerequisites.hpp @@ -134,7 +134,7 @@ #define NAZARA_CORE_API #endif -// Détection 64 bits +// Detect 64 bits #if !defined(NAZARA_PLATFORM_x64) && (defined(_WIN64) || defined(__amd64__) || defined(__x86_64__) || defined(__ia64__) || defined(__ia64) || \ defined(_M_IA64) || defined(__itanium__) || defined(__MINGW64__) || defined(_M_AMD64) || defined (_M_X64)) #define NAZARA_PLATFORM_x64 From 1a8a5e612ea096a9976fc51434e8469c8a47943a Mon Sep 17 00:00:00 2001 From: Apjue Date: Sun, 12 May 2019 16:07:21 +0200 Subject: [PATCH 71/77] Set start project --- build/scripts/common.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/build/scripts/common.lua b/build/scripts/common.lua index f5f50a9f8..4270fb6dd 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -58,6 +58,7 @@ function NazaraBuild:Execute() workspace("NazaraEngine") platforms(platformData) + startproject "DemoFirstScene" location(_ACTION) do From 73c0dbbd30ffdc3403b94164be7d008b33e3b2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 13 May 2019 14:05:48 +0200 Subject: [PATCH 72/77] Add vector test --- tests/SDK/NDK/EntityOwner.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/SDK/NDK/EntityOwner.cpp b/tests/SDK/NDK/EntityOwner.cpp index 2d240a6d0..b7ce87e15 100644 --- a/tests/SDK/NDK/EntityOwner.cpp +++ b/tests/SDK/NDK/EntityOwner.cpp @@ -105,4 +105,25 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]") } } } + + GIVEN("A vector of EntityOwner") + { + Ndk::World world(false); + + std::vector entityOwners; + for (std::size_t i = 1; i <= 10; ++i) + { + for (const Ndk::EntityHandle& entity : world.CreateEntities(10 * i)) + entityOwners.emplace_back(entity); + + entityOwners.clear(); + world.Refresh(); + + std::size_t aliveEntities = 0; + for (const Ndk::EntityHandle& entity : world.GetEntities()) + aliveEntities++; + + CHECK(aliveEntities == 0); + } + } } From b88c9b2cecdef930be98eea368d2f29a84972067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Leclercq?= Date: Mon, 13 May 2019 16:50:19 +0200 Subject: [PATCH 73/77] Sdk/World: Fix entity kill and invalidation bug --- ChangeLog.md | 1 + SDK/include/NDK/World.hpp | 10 ++++++++-- SDK/include/NDK/World.inl | 10 +++++----- SDK/src/NDK/World.cpp | 18 ++++++++++-------- tests/SDK/NDK/World.cpp | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 15 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6f9dfa1e3..c9628ed0c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -262,6 +262,7 @@ Nazara Development Kit: - Fixed GraphicsComponent not invalidating render queue on material change (causing crashes or visual errors) - Added CollisionComponent2D::SetGeomOffset and CollisionComponent2D::Recenter - Added LifetimeComponent and LifetimeSystem +- Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction). # 0.4: diff --git a/SDK/include/NDK/World.hpp b/SDK/include/NDK/World.hpp index 98e6d87ac..891c3df11 100644 --- a/SDK/include/NDK/World.hpp +++ b/SDK/include/NDK/World.hpp @@ -98,6 +98,12 @@ namespace Ndk inline void InvalidateSystemOrder(); void ReorderSystems(); + struct DoubleBitset + { + Nz::Bitset front; + Nz::Bitset back; + }; + struct EntityBlock { EntityBlock(Entity&& e) : @@ -119,9 +125,9 @@ namespace Ndk std::vector> m_waitingEntities; EntityList m_aliveEntities; ProfilerData m_profilerData; - Nz::Bitset m_dirtyEntities; + DoubleBitset m_dirtyEntities; Nz::Bitset m_freeEntityIds; - Nz::Bitset m_killedEntities; + DoubleBitset m_killedEntities; bool m_orderedSystemsUpdated; bool m_isProfilerEnabled; }; diff --git a/SDK/include/NDK/World.inl b/SDK/include/NDK/World.inl index 860454a0d..1c3e446e1 100644 --- a/SDK/include/NDK/World.inl +++ b/SDK/include/NDK/World.inl @@ -308,7 +308,7 @@ namespace Ndk inline void World::KillEntity(Entity* entity) { if (IsEntityValid(entity)) - m_killedEntities.UnboundedSet(entity->GetId(), true); + m_killedEntities.front.UnboundedSet(entity->GetId(), true); } /*! @@ -343,7 +343,7 @@ namespace Ndk */ inline bool World::IsEntityDying(EntityId id) const { - return m_killedEntities.UnboundedTest(id); + return m_killedEntities.front.UnboundedTest(id); } /*! @@ -467,13 +467,13 @@ namespace Ndk inline void World::Invalidate() { - m_dirtyEntities.Resize(m_entityBlocks.size(), false); - m_dirtyEntities.Set(true); // Activation of all bits + m_dirtyEntities.front.Resize(m_entityBlocks.size(), false); + m_dirtyEntities.front.Set(true); // Activation of all bits } inline void World::Invalidate(EntityId id) { - m_dirtyEntities.UnboundedSet(id, true); + m_dirtyEntities.front.UnboundedSet(id, true); } inline void World::InvalidateSystemOrder() diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index 579985297..d8a1ec0e3 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -135,9 +135,9 @@ namespace Ndk m_waitingEntities.clear(); m_aliveEntities.Clear(); - m_dirtyEntities.Clear(); + m_dirtyEntities.front.Clear(); m_freeEntityIds.Clear(); - m_killedEntities.Clear(); + m_killedEntities.front.Clear(); } /*! @@ -210,7 +210,8 @@ namespace Ndk } // Handle killed entities before last call - for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i)) + std::swap(m_killedEntities.front, m_killedEntities.back); + for (std::size_t i = m_killedEntities.back.FindFirst(); i != m_killedEntities.back.npos; i = m_killedEntities.back.FindNext(i)) { NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range"); @@ -220,12 +221,13 @@ namespace Ndk entity->Destroy(); // Send back the identifier of the entity to the free queue - m_freeEntityIds.UnboundedSet(entity->GetId()); + m_freeEntityIds.UnboundedSet(i); } - m_killedEntities.Reset(); + m_killedEntities.back.Clear(); // Handle of entities which need an update from the systems - for (std::size_t i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i)) + std::swap(m_dirtyEntities.front, m_dirtyEntities.back); + for (std::size_t i = m_dirtyEntities.back.FindFirst(); i != m_dirtyEntities.back.npos; i = m_dirtyEntities.back.FindNext(i)) { NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range"); @@ -236,7 +238,7 @@ namespace Ndk continue; Nz::Bitset<>& removedComponents = entity->GetRemovedComponentBits(); - for (std::size_t j = removedComponents.FindFirst(); j != m_dirtyEntities.npos; j = removedComponents.FindNext(j)) + for (std::size_t j = removedComponents.FindFirst(); j != m_dirtyEntities.back.npos; j = removedComponents.FindNext(j)) entity->DestroyComponent(static_cast(j)); removedComponents.Reset(); @@ -262,7 +264,7 @@ namespace Ndk } } } - m_dirtyEntities.Reset(); + m_dirtyEntities.back.Clear(); } /*! diff --git a/tests/SDK/NDK/World.cpp b/tests/SDK/NDK/World.cpp index 185717609..f98a7e2e1 100644 --- a/tests/SDK/NDK/World.cpp +++ b/tests/SDK/NDK/World.cpp @@ -126,4 +126,37 @@ SCENARIO("World", "[NDK][WORLD]") } } } + + GIVEN("An empty world") + { + Ndk::World world(false); + + WHEN("We create two entities") + { + Ndk::EntityHandle a = world.CreateEntity(); + REQUIRE(a->GetId() == 0); + Ndk::EntityHandle b = world.CreateEntity(); + REQUIRE(b->GetId() == 1); + + b->OnEntityDestruction.Connect([a](Ndk::Entity*) + { + REQUIRE(a.IsValid()); + a->Kill(); + }); + + THEN("We kill the second entity which will kill the first one") + { + b->Kill(); + world.Refresh(); + + AND_THEN("Both entities should be dead next refresh") + { + world.Refresh(); + + REQUIRE_FALSE(a.IsValid()); + REQUIRE_FALSE(b.IsValid()); + } + } + } + } } From dcfd2ad8f9015cc28ef923f8ecb848ea1d1c3800 Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 27 May 2019 22:42:37 +0200 Subject: [PATCH 74/77] Physics2D/PhysWorld2D: Add RaycastQuery and RegionQuery overloads taking a callback --- ChangeLog.md | 2 ++ SDK/include/NDK/Systems/PhysicsSystem2D.hpp | 2 ++ SDK/src/NDK/Systems/PhysicsSystem2D.cpp | 21 +++++++++++++ include/Nazara/Physics2D/PhysWorld2D.hpp | 2 ++ src/Nazara/Physics2D/PhysWorld2D.cpp | 35 +++++++++++++++++++++ 5 files changed, 62 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index c9628ed0c..100ee3c89 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -188,6 +188,7 @@ Nazara Engine: - Fixed TextSprite not handling multiple textures well - ⚠ TextSprite will now use multiple render layers by itself (the current one and the one right before, ex: [-1, 0] if base layer is 0) if you use text outlines. - ⚠ SimpleTextDrawer no longer supports faux bold rendering +- Added PhysWorld2D::[RaycastQuery, RegionQuery] overloads taking a callback Nazara Development Kit: - Added ImageWidget (#139) @@ -263,6 +264,7 @@ Nazara Development Kit: - Added CollisionComponent2D::SetGeomOffset and CollisionComponent2D::Recenter - Added LifetimeComponent and LifetimeSystem - Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction). +- Added PhysicsSystem2D::[RaycastQuery, RegionQuery] overloads taking a callback # 0.4: diff --git a/SDK/include/NDK/Systems/PhysicsSystem2D.hpp b/SDK/include/NDK/Systems/PhysicsSystem2D.hpp index a919abbd5..35579862a 100644 --- a/SDK/include/NDK/Systems/PhysicsSystem2D.hpp +++ b/SDK/include/NDK/Systems/PhysicsSystem2D.hpp @@ -51,9 +51,11 @@ namespace Ndk bool NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody = nullptr); bool NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result); + void RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback); bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos); bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr); + void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback); void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies); void RegisterCallbacks(unsigned int collisionId, Callback callbacks); diff --git a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp index 8cce2e9aa..891b5b8a3 100644 --- a/SDK/src/NDK/Systems/PhysicsSystem2D.cpp +++ b/SDK/src/NDK/Systems/PhysicsSystem2D.cpp @@ -99,6 +99,19 @@ namespace Ndk return false; } + void PhysicsSystem2D::RaycastQuery(const Nz::Vector2f & from, const Nz::Vector2f & to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback) + { + return GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, [this, &callback](const Nz::PhysWorld2D::RaycastHit& hitInfo) + { + callback({ + GetEntityFromBody(*hitInfo.nearestBody), + hitInfo.hitPos, + hitInfo.hitNormal, + hitInfo.fraction + }); + }); + } + bool PhysicsSystem2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos) { std::vector queryResult; @@ -133,6 +146,14 @@ namespace Ndk return false; } + void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback) + { + return GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, [this, &callback](Nz::RigidBody2D* body) + { + callback(GetEntityFromBody(*body)); + }); + } + void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies) { std::vector queryResult; diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp index 86de8f003..8d3afe07c 100644 --- a/include/Nazara/Physics2D/PhysWorld2D.hpp +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -64,9 +64,11 @@ namespace Nz bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody = nullptr); bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result); + void RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback); bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos); bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr); + void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback); void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies); void RegisterCallbacks(unsigned int collisionId, Callback callbacks); diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 57ea8113e..1390bc84f 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -205,6 +205,27 @@ namespace Nz } } + void PhysWorld2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback) + { + using CallbackType = const std::function; + + auto cpCallback = [](cpShape* shape, cpVect point, cpVect normal, cpFloat alpha, void* data) + { + CallbackType& callback = *static_cast(data); + + RaycastHit hitInfo; + hitInfo.fraction = float(alpha); + hitInfo.hitNormal.Set(Nz::Vector2(normal.x, normal.y)); + hitInfo.hitPos.Set(Nz::Vector2(point.x, point.y)); + hitInfo.nearestBody = static_cast(cpShapeGetUserData(shape)); + + callback(hitInfo); + }; + + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + cpSpaceSegmentQuery(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, cpCallback, const_cast(static_cast(&callback))); + } + bool PhysWorld2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos) { using ResultType = decltype(hitInfos); @@ -259,6 +280,20 @@ namespace Nz } } + void PhysWorld2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function& callback) + { + using CallbackType = const std::function; + + auto cpCallback = [](cpShape* shape, void* data) + { + CallbackType& callback = *static_cast(data); + callback(static_cast(cpShapeGetUserData(shape))); + }; + + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + cpSpaceBBQuery(m_handle, cpBBNew(boundingBox.x, boundingBox.y, boundingBox.x + boundingBox.width, boundingBox.y + boundingBox.height), filter, cpCallback, const_cast(static_cast(&callback))); + } + void PhysWorld2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies) { using ResultType = decltype(bodies); From 29718db08575e4c7d35d77d51097398fe860a616 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 13 Jun 2019 19:05:25 +0200 Subject: [PATCH 75/77] SDK/TextAreaWidget: Add TextOutline property --- ChangeLog.md | 19 ++++++++-------- SDK/include/NDK/Widgets/TextAreaWidget.hpp | 4 ++++ SDK/include/NDK/Widgets/TextAreaWidget.inl | 26 +++++++++++++++++++++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 100ee3c89..ea46c15c8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -55,7 +55,7 @@ Nazara Engine: - Fix RigidBody3D copy constructor not copying all physics states (angular/linear damping/velocity, mass center, position and rotation) - Add RigidBody3D simulation control (via EnableSimulation and IsSimulationEnabled), which allows to disable physics and collisions at will. - Fix some uninitialized values (found by Valgrind) in Network module -- Fix possible infinite recursion when outputting a Thread::Id object +- Fix possible infinite recursion when outputting a Thread::Id object - ⚠️ Replaced implicit conversion from a Nz::String to a std::string by an explicit method ToStdString() - Fix LuaInstance movement constructor/assignment operator which was corrupting Lua memory - Fix potential bug on SocketImpl::Connect (used by TcpClient::Connect) on POSIX platforms @@ -112,7 +112,7 @@ Nazara Engine: - Fixed SocketPoller not be able to recover from some errors (like invalid sockets and such) - Add LuaImplQuery implementation for std::vector - Fixed LuaState::PushGlobal & LuaState::PushField to copy the object before moving it -- ⚠️ Replaced currentBitPos and currentByte fields by [read|write][BitPos][Byte] to handle properly bit reading/writing. +- ⚠️ Replaced currentBitPos and currentByte fields by [read|write][BitPos][Byte] to handle properly bit reading/writing. - InstancedRenderable::SetMaterial methods are now public. - Fixed Model copy constructor not copying materials - ⚠️ Added InstancedRenderable::Clone() method @@ -148,8 +148,8 @@ Nazara Engine: - ⚠️ CullingList now handles full and partial visibility testing - Added math class Angle, capable of handling both degrees and radians angles and converting them to euler angles/quaternions to improve 2D interface. - ⚠️ AbstractSocket::OnStateChange has been replaced by OnStateChanged, which is now called after state has been changed (with oldState and newState as parameters). -- ⚠️ TcpClient::WaitForconnected now returns the new socket state. -- Added TcpClient::PollForConnected +- ⚠️ TcpClient::WaitForconnected now returns the new socket state. +- Added TcpClient::PollForConnected - ⚠️ Use of the new Angle class instead of floating point angle - It is now possible to set elasticity/friction/surface bodies of 2D colliders and change it at runtime on RigidBody2D - ObjectHandle were remade and should be way more optimized now @@ -188,7 +188,7 @@ Nazara Engine: - Fixed TextSprite not handling multiple textures well - ⚠ TextSprite will now use multiple render layers by itself (the current one and the one right before, ex: [-1, 0] if base layer is 0) if you use text outlines. - ⚠ SimpleTextDrawer no longer supports faux bold rendering -- Added PhysWorld2D::[RaycastQuery, RegionQuery] overloads taking a callback +- Added PhysWorld2D::[RaycastQuery, RegionQuery] overloads taking a callback Nazara Development Kit: - Added ImageWidget (#139) @@ -265,6 +265,7 @@ Nazara Development Kit: - Added LifetimeComponent and LifetimeSystem - Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction). - Added PhysicsSystem2D::[RaycastQuery, RegionQuery] overloads taking a callback +- Added TextAreaWidget support for outline # 0.4: @@ -352,8 +353,8 @@ Nazara Engine: - Added [Nz::TcpClient::SendMultiple](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_tcp_client.html#a495c32beb46ed9192699a3b82d358035) method, allowing to send multiple buffers at once. - Added [Nz::PlacementDestroy](https://nazara.digitalpulsesoftware.net/doc/namespace_nz.html#a27c8667def991fc896c5beff3e62668a). (ea985fa76586762f008e4054938db3234eeaf0cb) - Added [Nz::String::Format](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#a4b699982e7f9ea38f6d44b43ac1e2040) and [Nz::String::FormatVA](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_string.html#abe0fcbce11224b157ac756b60e8dee92) static methods. (cc6e4127dc6c61799a64404770992cef0804ad34). -- Added [Nz::ParticleGroup::GetBuffer](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_particle_mapper.html#aefe1b251efc8c9b8668842275561be0c) method. (4dc85789b59e50d964c83321dbd4b6485c04bef6) -- Added Nz::ParticleMapper::GetPointer method. (1f4e6c2d1594b7bb9dd6f4ea5480fdd16cf5f208) +- Added [Nz::ParticleGroup::GetBuffer](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_particle_mapper.html#aefe1b251efc8c9b8668842275561be0c) method. (4dc85789b59e50d964c83321dbd4b6485c04bef6) +- Added Nz::ParticleMapper::GetPointer method. (1f4e6c2d1594b7bb9dd6f4ea5480fdd16cf5f208) - ⚠️ Structures provied by ParticleStruct header now have a float life. (472d964d587d906764ad1e05bfcc9ab1bf979483) - Fixed scale property of Nz::TextSprite not affecting its bounding volume. (52b29bac775823294c4ad7de70f4dc3f4adfa743) - ⚠️ Nz:MeshParams::flipUVs has been replaced by texCoordOffset and texCoordScale. (a1a7d908adc060fd7a43491c903dfe3b501d98e5) @@ -380,7 +381,7 @@ Nazara Engine: - All noises classes now uses std::mt19937 as a random number generator, to ensure the same results on every machine. (1f5ea9839016964c173d919263827dee69ecb65d) Nazara Development Kit: -- **Added basic widgets**. (c8a12083b3133e946bf60dd060331a4b4631f8d8) +- **Added basic widgets**. (c8a12083b3133e946bf60dd060331a4b4631f8d8) - VelocitySystem will no longer affect entities with PhysicsComponent2D. (a6853234412c744cdcb28344f02f7b0c92704d77) - Fixed EulerAngles constructor in Lua. (d55149a0a70f6230b6f1c3fb50e37dc82a2feb9f) - Fixed Component::OnDetached not being called on entity destruction. (5b777eb4853639d7aeb232ca46d17f0d432f47ca) @@ -391,7 +392,7 @@ Nazara Engine: Nazara Engine: - Nazara binaries are now compiled with Run-Time Type-Information. (a70acdc8f44010627a65282fd3099202116d3e13) -- Nazara demos are now compiled with relative dependencies on Linux. +- Nazara demos are now compiled with relative dependencies on Linux. (d6fbb4c408d48c4a768fad7b43460c76a0df1777) - Added [**Nz::BitCount**](https://nazara.digitalpulsesoftware.net/doc/group__core.html#ga6bfbcff78eb6cfbe3ddaedcfc8c04196) function. (82e31a3ec8449da6618f41690164c2e1d883edb4) - Added [**Nz::Bitset::AppendBits**](https://nazara.digitalpulsesoftware.net/doc/class_nz_1_1_bitset.html#a5ca8f365006c86d6d699d02471904f7e) method. (b018a400499a2356c4455a40d9f6a6c12b3cb36b) diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.hpp b/SDK/include/NDK/Widgets/TextAreaWidget.hpp index 9a5d33335..d215603eb 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.hpp +++ b/SDK/include/NDK/Widgets/TextAreaWidget.hpp @@ -49,6 +49,8 @@ namespace Ndk inline std::size_t GetGlyphIndex(const Nz::Vector2ui& cursorPosition); inline const Nz::String& GetText() const; inline const Nz::Color& GetTextColor() const; + inline const Nz::Color& GetTextOulineColor() const; + inline float GetTextOulineThickness() const; Nz::Vector2ui GetHoveredGlyph(float x, float y) const; @@ -70,6 +72,8 @@ namespace Ndk inline void SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition); inline void SetText(const Nz::String& text); inline void SetTextColor(const Nz::Color& text); + inline void SetTextOutlineColor(const Nz::Color& color); + inline void SetTextOutlineThickness(float thickness); inline void Write(const Nz::String& text); inline void Write(const Nz::String& text, const Nz::Vector2ui& glyphPosition); diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.inl b/SDK/include/NDK/Widgets/TextAreaWidget.inl index e4c9f2c30..0c931cebd 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.inl +++ b/SDK/include/NDK/Widgets/TextAreaWidget.inl @@ -102,6 +102,16 @@ namespace Ndk return m_drawer.GetColor(); } + inline const Nz::Color& TextAreaWidget::GetTextOulineColor() const + { + return m_drawer.GetOutlineColor(); + } + + inline float TextAreaWidget::GetTextOulineThickness() const + { + return m_drawer.GetOutlineThickness(); + } + inline bool TextAreaWidget::HasSelection() const { return m_cursorPositionBegin != m_cursorPositionEnd; @@ -241,7 +251,21 @@ namespace Ndk { m_drawer.SetColor(text); - m_textSprite->Update(m_drawer); + UpdateDisplayText(); + } + + inline void TextAreaWidget::SetTextOutlineColor(const Nz::Color& color) + { + m_drawer.SetOutlineColor(color); + + UpdateDisplayText(); + } + + inline void TextAreaWidget::SetTextOutlineThickness(float thickness) + { + m_drawer.SetOutlineThickness(thickness); + + UpdateDisplayText(); } inline void TextAreaWidget::Write(const Nz::String& text) From 6e7fd326db12fef4717c61f7cd7d13fe733249f5 Mon Sep 17 00:00:00 2001 From: Lynix Date: Thu, 13 Jun 2019 19:06:09 +0200 Subject: [PATCH 76/77] SDK/BaseWidget: Fix possible crash when disabling background --- ChangeLog.md | 1 + SDK/src/NDK/BaseWidget.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index ea46c15c8..b2f71d16d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -266,6 +266,7 @@ Nazara Development Kit: - Fixed a subtle bug regarding entities invalidation and kill (ex: if an entity #2 kills entity #1 during Entity::Destroy callbacks, entity #1 will survive destruction). - Added PhysicsSystem2D::[RaycastQuery, RegionQuery] overloads taking a callback - Added TextAreaWidget support for outline +- Fixed possible crash when disabling BaseWidget background # 0.4: diff --git a/SDK/src/NDK/BaseWidget.cpp b/SDK/src/NDK/BaseWidget.cpp index 89ca6bb9c..499a7aa2b 100644 --- a/SDK/src/NDK/BaseWidget.cpp +++ b/SDK/src/NDK/BaseWidget.cpp @@ -89,6 +89,7 @@ namespace Ndk } else { + DestroyEntity(m_backgroundEntity); m_backgroundEntity.Reset(); m_backgroundSprite.Reset(); } @@ -185,7 +186,7 @@ namespace Ndk void BaseWidget::Layout() { - if (m_backgroundEntity) + if (m_backgroundSprite) m_backgroundSprite->SetSize(m_size.x, m_size.y); UpdatePositionAndSize(); From c23248c56433e6ef9823448b74381e75a88d04ac Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 16 Jun 2019 15:40:24 +0200 Subject: [PATCH 77/77] PhysWorld2D: Fix possible stack overflow when using wildcard collision handler --- src/Nazara/Physics2D/PhysWorld2D.cpp | 30 ++++------------------------ thirdparty/src/chipmunk/chipmunk.c | 2 +- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 1390bc84f..6e0c9c22a 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -403,11 +403,7 @@ namespace Nz const Callback* customCallbacks = static_cast(data); if (customCallbacks->startCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata)) - { - cpBool retA = cpArbiterCallWildcardBeginA(arb, space); - cpBool retB = cpArbiterCallWildcardBeginB(arb, space); - return retA && retB; - } + return cpTrue; else return cpFalse; }; @@ -416,9 +412,7 @@ namespace Nz { handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void*) -> cpBool { - cpBool retA = cpArbiterCallWildcardBeginA(arb, space); - cpBool retB = cpArbiterCallWildcardBeginB(arb, space); - return retA && retB; + return cpTrue; }; } @@ -438,17 +432,12 @@ namespace Nz const Callback* customCallbacks = static_cast(data); customCallbacks->endCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata); - - cpArbiterCallWildcardSeparateA(arb, space); - cpArbiterCallWildcardSeparateB(arb, space); }; } else { handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void*) { - cpArbiterCallWildcardSeparateA(arb, space); - cpArbiterCallWildcardSeparateB(arb, space); }; } @@ -468,11 +457,7 @@ namespace Nz const Callback* customCallbacks = static_cast(data); if (customCallbacks->preSolveCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata)) - { - cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space); - cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space); - return retA && retB; - } + return cpTrue; else return cpFalse; }; @@ -481,9 +466,7 @@ namespace Nz { handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) -> cpBool { - cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space); - cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space); - return retA && retB; + return cpTrue; }; } @@ -503,17 +486,12 @@ namespace Nz const Callback* customCallbacks = static_cast(data); customCallbacks->postSolveCallback(*world, arbiter, *firstRigidBody, *secondRigidBody, customCallbacks->userdata); - - cpArbiterCallWildcardPostSolveA(arb, space); - cpArbiterCallWildcardPostSolveB(arb, space); }; } else { handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void* data) { - cpArbiterCallWildcardPostSolveA(arb, space); - cpArbiterCallWildcardPostSolveB(arb, space); }; } } diff --git a/thirdparty/src/chipmunk/chipmunk.c b/thirdparty/src/chipmunk/chipmunk.c index 503265cf6..a6cc9d6d4 100644 --- a/thirdparty/src/chipmunk/chipmunk.c +++ b/thirdparty/src/chipmunk/chipmunk.c @@ -89,7 +89,7 @@ cpAreaForSegment(cpVect a, cpVect b, cpFloat r) } cpFloat -cpMomentForPoly(cpFloat m, const int count, const cpVect *verts, cpVect offset, cpFloat r) +cpMomentForPoly(cpFloat m, int count, const cpVect *verts, cpVect offset, cpFloat r) { // TODO account for radius. if(count == 2) return cpMomentForSegment(m, verts[0], verts[1], 0.0f);