Merge remote-tracking branch 'refs/remotes/origin/master' into reflection-mapping
This commit is contained in:
commit
62fd66a159
|
|
@ -47,6 +47,7 @@ namespace Ndk
|
|||
virtual void OnComponentAttached(BaseComponent& component);
|
||||
virtual void OnComponentDetached(BaseComponent& component);
|
||||
virtual void OnDetached();
|
||||
virtual void OnEntityDestruction();
|
||||
|
||||
void SetEntity(Entity* entity);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Ndk
|
|||
inline void BaseWidget::AddChild(std::unique_ptr<BaseWidget>&& widget)
|
||||
{
|
||||
widget->Show(m_visible);
|
||||
widget->SetParent(this);
|
||||
m_children.emplace_back(std::move(widget));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ namespace Ndk
|
|||
void OnComponentAttached(BaseComponent& component) override;
|
||||
void OnComponentDetached(BaseComponent& component) override;
|
||||
void OnDetached() override;
|
||||
void OnEntityDestruction() override;
|
||||
|
||||
std::unique_ptr<Nz::RigidBody2D> m_object;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ namespace Ndk
|
|||
void OnComponentAttached(BaseComponent& component) override;
|
||||
void OnComponentDetached(BaseComponent& component) override;
|
||||
void OnDetached() override;
|
||||
void OnEntityDestruction() override;
|
||||
|
||||
std::unique_ptr<Nz::RigidBody3D> m_object;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <NDK/Algorithm.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
|
@ -65,6 +66,8 @@ namespace Ndk
|
|||
Entity& operator=(const Entity&) = delete;
|
||||
Entity& operator=(Entity&&) = delete;
|
||||
|
||||
NazaraSignal(OnEntityDestruction, Entity* /*entity*/);
|
||||
|
||||
private:
|
||||
Entity(World* world, EntityId id);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,15 @@ namespace Ndk
|
|||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when the entity is destroyed and we're still attached to it
|
||||
*
|
||||
* \remark This is always called before the entity proper destruction, and thus its components.
|
||||
*/
|
||||
void BaseComponent::OnEntityDestruction()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<BaseComponent::ComponentEntry> BaseComponent::s_entries;
|
||||
std::unordered_map<ComponentId, ComponentIndex> BaseComponent::s_idToIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,5 +88,11 @@ namespace Ndk
|
|||
m_object.reset();
|
||||
}
|
||||
|
||||
void PhysicsComponent2D::OnEntityDestruction()
|
||||
{
|
||||
// Kill rigidbody before entity destruction to force contact callbacks to be called while the entity is still valid
|
||||
m_object.reset();
|
||||
}
|
||||
|
||||
ComponentIndex PhysicsComponent2D::componentIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,5 +88,11 @@ namespace Ndk
|
|||
m_object.reset();
|
||||
}
|
||||
|
||||
void PhysicsComponent3D::OnEntityDestruction()
|
||||
{
|
||||
// Kill rigid body before entity destruction to force contact callbacks to be called while the entity is still valid
|
||||
m_object.reset();
|
||||
}
|
||||
|
||||
ComponentIndex PhysicsComponent3D::componentIndex;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ namespace Ndk
|
|||
m_enabled(entity.m_enabled),
|
||||
m_valid(entity.m_valid)
|
||||
{
|
||||
entity.m_world = nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -53,7 +54,8 @@ namespace Ndk
|
|||
|
||||
Entity::~Entity()
|
||||
{
|
||||
Destroy();
|
||||
if (m_world)
|
||||
Destroy();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -145,6 +147,17 @@ namespace Ndk
|
|||
|
||||
void Entity::Destroy()
|
||||
{
|
||||
OnEntityDestruction(this);
|
||||
OnEntityDestruction.Clear();
|
||||
|
||||
// We prepare components for entity destruction (some components needs this to handle some final callbacks while the entity is still valid)
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->OnEntityDestruction();
|
||||
|
||||
// Detach components while they're still attached to systems
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->SetEntity(nullptr);
|
||||
|
||||
// We alert each system
|
||||
for (std::size_t index = m_systemBits.FindFirst(); index != m_systemBits.npos; index = m_systemBits.FindNext(index))
|
||||
{
|
||||
|
|
@ -158,10 +171,7 @@ namespace Ndk
|
|||
}
|
||||
m_systemBits.Clear();
|
||||
|
||||
// We properly destroy each component
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->SetEntity(nullptr);
|
||||
|
||||
// Destroy components
|
||||
m_components.clear();
|
||||
m_componentBits.Reset();
|
||||
|
||||
|
|
|
|||
|
|
@ -185,12 +185,12 @@ namespace Ndk
|
|||
|
||||
NazaraAssert(entity.IsValid(), "Entity must be valid");
|
||||
|
||||
// Send back the identifier of the entity to the free queue
|
||||
m_freeIdList.push_back(entity.GetId());
|
||||
|
||||
// Destruction of the entity (invalidation of handle by the same way)
|
||||
entity.Destroy();
|
||||
|
||||
// Send back the identifier of the entity to the free queue
|
||||
m_freeIdList.push_back(entity.GetId());
|
||||
|
||||
// We take out the handle from the list of alive entities
|
||||
// With the idiom swap and pop
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
-- This file contains special configurations values, such as directories to extern libraries (Qt)
|
||||
-- Editing this file is not required to use/compile the engine, as default values should be enough
|
||||
|
||||
-- Additionnal compilation options
|
||||
--AdditionalCompilationOptions = "-fsanitize=address" -- Enable ASan
|
||||
|
||||
-- Builds Nazara extern libraries (such as lua/STB)
|
||||
BuildDependencies = true
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ ACTION.Function = function ()
|
|||
local exeFilterFunc
|
||||
if (os.is("windows")) then
|
||||
binFileMasks = {"**.dll"}
|
||||
libFileMasks = {"**.lib", "**.a"}
|
||||
libFileMasks = {"**.lib", "**.a", "**.pdb"}
|
||||
exeFileExt = ".exe"
|
||||
exeFilterFunc = function (filePath) return true end
|
||||
else
|
||||
|
|
|
|||
|
|
@ -505,11 +505,47 @@ function NazaraBuild:LoadConfig()
|
|||
end
|
||||
end
|
||||
|
||||
local AddStringOption = function (option, name, description)
|
||||
newoption({
|
||||
trigger = name,
|
||||
description = description
|
||||
})
|
||||
|
||||
local str = _OPTIONS[name]
|
||||
if (str) then
|
||||
configTable[option] = str
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
AddBoolOption("BuildDependencies", "with-extlibs", "Builds the extern libraries")
|
||||
AddBoolOption("BuildExamples", "with-examples", "Builds the examples")
|
||||
AddBoolOption("ServerMode", "server", "Excludes client-only modules/tools/examples")
|
||||
AddBoolOption("UniteModules", "united", "Builds all the modules as one united library")
|
||||
|
||||
-- AdditionalCompilationOptions
|
||||
do
|
||||
newoption({
|
||||
trigger = "compile-options",
|
||||
description = "Specify additionnal compilation options to be added to every generated project."
|
||||
})
|
||||
|
||||
configTable["AdditionalCompilationOptions"] = configTable["AdditionalCompilationOptions"] or ""
|
||||
if (_OPTIONS["compile-options"] ~= nil) then
|
||||
configTable["AdditionalCompilationOptions"] = configTable["AdditionalCompilationOptions"] .. ";" .. _OPTIONS["compile-options"]
|
||||
end
|
||||
|
||||
local configs = {}
|
||||
local paths = string.explode(configTable["AdditionalCompilationOptions"], ";")
|
||||
for k,v in pairs(paths) do
|
||||
if (#v > 0) then
|
||||
table.insert(configs, v)
|
||||
end
|
||||
end
|
||||
|
||||
configTable["AdditionalCompilationOptions"] = configs
|
||||
end
|
||||
|
||||
-- Configurations
|
||||
do
|
||||
newoption({
|
||||
|
|
@ -792,6 +828,8 @@ function NazaraBuild:PrepareGeneric()
|
|||
buildoptions("-ftree-vectorize")
|
||||
|
||||
filter({})
|
||||
|
||||
buildoptions(self.Config["AdditionalCompilationOptions"])
|
||||
end
|
||||
|
||||
function NazaraBuild:PrepareMainWorkspace()
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ namespace Nz
|
|||
SlotListIndex index;
|
||||
};
|
||||
|
||||
void Disconnect(const SlotPtr& slot);
|
||||
void Disconnect(const SlotPtr& slot) noexcept;
|
||||
|
||||
SlotList m_slots;
|
||||
mutable SlotListIndex m_slotIterator;
|
||||
|
|
@ -84,17 +84,17 @@ namespace Nz
|
|||
public:
|
||||
Connection() = default;
|
||||
Connection(const Connection& connection) = default;
|
||||
Connection(Connection&& connection) = default;
|
||||
Connection(Connection&& connection) noexcept;
|
||||
~Connection() = default;
|
||||
|
||||
template<typename... ConnectArgs>
|
||||
void Connect(BaseClass& signal, ConnectArgs&&... args);
|
||||
void Disconnect();
|
||||
void Disconnect() noexcept;
|
||||
|
||||
bool IsConnected() const;
|
||||
|
||||
Connection& operator=(const Connection& connection) = default;
|
||||
Connection& operator=(Connection&& connection) = default;
|
||||
Connection& operator=(Connection&& connection) noexcept;
|
||||
|
||||
private:
|
||||
Connection(const SlotPtr& slot);
|
||||
|
|
@ -113,12 +113,12 @@ namespace Nz
|
|||
ConnectionGuard(const Connection& connection);
|
||||
ConnectionGuard(const ConnectionGuard& connection) = delete;
|
||||
ConnectionGuard(Connection&& connection);
|
||||
ConnectionGuard(ConnectionGuard&& connection) = default;
|
||||
ConnectionGuard(ConnectionGuard&& connection) noexcept = default;
|
||||
~ConnectionGuard();
|
||||
|
||||
template<typename... ConnectArgs>
|
||||
void Connect(BaseClass& signal, ConnectArgs&&... args);
|
||||
void Disconnect();
|
||||
void Disconnect() noexcept;
|
||||
|
||||
Connection& GetConnection();
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ namespace Nz
|
|||
ConnectionGuard& operator=(const Connection& connection);
|
||||
ConnectionGuard& operator=(const ConnectionGuard& connection) = delete;
|
||||
ConnectionGuard& operator=(Connection&& connection);
|
||||
ConnectionGuard& operator=(ConnectionGuard&& connection);
|
||||
ConnectionGuard& operator=(ConnectionGuard&& connection) noexcept;
|
||||
|
||||
private:
|
||||
Connection m_connection;
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ namespace Nz
|
|||
*/
|
||||
|
||||
template<typename... Args>
|
||||
void Signal<Args...>::Disconnect(const SlotPtr& slot)
|
||||
void Signal<Args...>::Disconnect(const SlotPtr& slot) noexcept
|
||||
{
|
||||
NazaraAssert(slot, "Invalid slot pointer");
|
||||
NazaraAssert(slot->index < m_slots.size(), "Invalid slot index");
|
||||
|
|
@ -246,6 +246,18 @@ namespace Nz
|
|||
* \brief Core class that represents a connection attached to a signal
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Signal::Connection object with by move semantic
|
||||
*
|
||||
* \param connection Connection object to move
|
||||
*/
|
||||
template<typename... Args>
|
||||
Signal<Args...>::Connection::Connection(Connection&& connection) noexcept :
|
||||
m_ptr(std::move(connection.m_ptr))
|
||||
{
|
||||
connection.m_ptr.reset(); //< Fuck you GCC 4.9
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Signal::Connection object with a slot
|
||||
*
|
||||
|
|
@ -277,7 +289,7 @@ namespace Nz
|
|||
*/
|
||||
|
||||
template<typename... Args>
|
||||
void Signal<Args...>::Connection::Disconnect()
|
||||
void Signal<Args...>::Connection::Disconnect() noexcept
|
||||
{
|
||||
if (SlotPtr ptr = m_ptr.lock())
|
||||
ptr->signal->Disconnect(ptr);
|
||||
|
|
@ -294,6 +306,20 @@ namespace Nz
|
|||
return !m_ptr.expired();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Signal::ConnectionGuard object by move semantic
|
||||
*
|
||||
* \param connection Connection to move
|
||||
*/
|
||||
template<typename... Args>
|
||||
typename Signal<Args...>::Connection& Signal<Args...>::Connection::operator=(Connection&& connection) noexcept
|
||||
{
|
||||
m_ptr = std::move(connection.m_ptr);
|
||||
connection.m_ptr.reset(); //< Fuck you GCC 4.9
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \class Nz::Signal::ConnectionGuard
|
||||
* \brief Core class that represents a RAII for a connection attached to a signal
|
||||
|
|
@ -353,7 +379,7 @@ namespace Nz
|
|||
*/
|
||||
|
||||
template<typename... Args>
|
||||
void Signal<Args...>::ConnectionGuard::Disconnect()
|
||||
void Signal<Args...>::ConnectionGuard::Disconnect() noexcept
|
||||
{
|
||||
m_connection.Disconnect();
|
||||
}
|
||||
|
|
@ -406,8 +432,11 @@ namespace Nz
|
|||
template<typename... Args>
|
||||
typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(Connection&& connection)
|
||||
{
|
||||
m_connection.Disconnect();
|
||||
m_connection = std::move(connection);
|
||||
if (&connection != this)
|
||||
{
|
||||
m_connection.Disconnect();
|
||||
m_connection = std::move(connection);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -420,10 +449,13 @@ namespace Nz
|
|||
*/
|
||||
|
||||
template<typename... Args>
|
||||
typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(ConnectionGuard&& connection)
|
||||
typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(ConnectionGuard&& connection) noexcept
|
||||
{
|
||||
m_connection.Disconnect();
|
||||
m_connection = std::move(connection.m_connection);
|
||||
if (&connection != this)
|
||||
{
|
||||
m_connection.Disconnect();
|
||||
m_connection = std::move(connection.m_connection);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,13 +42,19 @@ namespace Nz
|
|||
|
||||
virtual float ComputeInertialMatrix(float mass) const = 0;
|
||||
|
||||
inline Nz::UInt32 GetCategoryMask() const;
|
||||
inline Nz::UInt32 GetCollisionGroup() const;
|
||||
inline unsigned int GetCollisionId() const;
|
||||
inline Nz::UInt32 GetCollisionMask() const;
|
||||
|
||||
virtual ColliderType2D GetType() const = 0;
|
||||
|
||||
inline bool IsTrigger() const;
|
||||
|
||||
inline void SetCollisionId(unsigned long typeId);
|
||||
inline void SetCategoryMask(Nz::UInt32 categoryMask);
|
||||
inline void SetCollisionGroup(Nz::UInt32 groupId);
|
||||
inline void SetCollisionId(unsigned int typeId);
|
||||
inline void SetCollisionMask(Nz::UInt32 mask);
|
||||
inline void SetTrigger(bool trigger);
|
||||
|
||||
Collider2D& operator=(const Collider2D&) = delete;
|
||||
|
|
@ -61,7 +67,10 @@ namespace Nz
|
|||
virtual std::vector<cpShape*> CreateShapes(RigidBody2D* body) const = 0;
|
||||
|
||||
bool m_trigger;
|
||||
Nz::UInt32 m_categoryMask;
|
||||
Nz::UInt32 m_collisionGroup;
|
||||
unsigned int m_collisionId;
|
||||
Nz::UInt32 m_collisionMask;
|
||||
|
||||
private:
|
||||
virtual std::vector<cpShape*> GenerateShapes(RigidBody2D* body) const;
|
||||
|
|
|
|||
|
|
@ -2,32 +2,66 @@
|
|||
// This file is part of the "Nazara Engine - Physics 2D module"
|
||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||
|
||||
#include <Nazara/Physics2D/Collider2D.hpp>
|
||||
#include <memory>
|
||||
#include <Nazara/Physics2D/Debug.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
inline Collider2D::Collider2D() :
|
||||
m_trigger(false),
|
||||
m_categoryMask(0xFFFFFFFF),
|
||||
m_collisionGroup(0),
|
||||
m_collisionId(0),
|
||||
m_trigger(false)
|
||||
m_collisionMask(0xFFFFFFFF)
|
||||
{
|
||||
}
|
||||
|
||||
inline Nz::UInt32 Collider2D::GetCategoryMask() const
|
||||
{
|
||||
return m_categoryMask;
|
||||
}
|
||||
|
||||
inline Nz::UInt32 Collider2D::GetCollisionGroup() const
|
||||
{
|
||||
return m_collisionGroup;
|
||||
}
|
||||
|
||||
inline unsigned int Collider2D::GetCollisionId() const
|
||||
{
|
||||
return m_collisionId;
|
||||
}
|
||||
|
||||
inline Nz::UInt32 Collider2D::GetCollisionMask() const
|
||||
{
|
||||
return m_collisionMask;
|
||||
}
|
||||
|
||||
inline bool Collider2D::IsTrigger() const
|
||||
{
|
||||
return m_trigger;
|
||||
}
|
||||
|
||||
inline void Collider2D::SetCollisionId(unsigned long typeId)
|
||||
inline void Collider2D::SetCategoryMask(Nz::UInt32 categoryMask)
|
||||
{
|
||||
m_categoryMask = categoryMask;
|
||||
}
|
||||
|
||||
inline void Collider2D::SetCollisionGroup(Nz::UInt32 groupId)
|
||||
{
|
||||
m_collisionGroup = groupId;
|
||||
}
|
||||
|
||||
inline void Collider2D::SetCollisionId(unsigned int typeId)
|
||||
{
|
||||
m_collisionId = typeId;
|
||||
}
|
||||
|
||||
inline void Collider2D::SetCollisionMask(Nz::UInt32 mask)
|
||||
{
|
||||
m_collisionMask = mask;
|
||||
}
|
||||
|
||||
inline void Collider2D::SetTrigger(bool trigger)
|
||||
{
|
||||
m_trigger = trigger;
|
||||
|
|
@ -108,4 +142,3 @@ namespace Nz
|
|||
}
|
||||
|
||||
#include <Nazara/Physics2D/DebugOff.hpp>
|
||||
#include "Collider2D.hpp"
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@
|
|||
#define NAZARA_PHYSWORLD2D_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <Nazara/Math/Vector2.hpp>
|
||||
#include <Nazara/Physics2D/Config.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
@ -18,10 +20,10 @@ struct cpSpace;
|
|||
|
||||
namespace Nz
|
||||
{
|
||||
class RigidBody2D;
|
||||
|
||||
class NAZARA_PHYSICS2D_API PhysWorld2D
|
||||
{
|
||||
friend RigidBody2D;
|
||||
|
||||
using ContactEndCallback = void(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata);
|
||||
using ContactPreSolveCallback = bool(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata);
|
||||
using ContactPostSolveCallback = void(*)(PhysWorld2D& world, RigidBody2D& bodyA, RigidBody2D& bodyB, void* userdata);
|
||||
|
|
@ -29,6 +31,8 @@ namespace Nz
|
|||
|
||||
public:
|
||||
struct Callback;
|
||||
struct NearestQueryResult;
|
||||
struct RaycastHit;
|
||||
|
||||
PhysWorld2D();
|
||||
PhysWorld2D(const PhysWorld2D&) = delete;
|
||||
|
|
@ -39,6 +43,12 @@ namespace Nz
|
|||
cpSpace* GetHandle() const;
|
||||
float GetStepSize() const;
|
||||
|
||||
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);
|
||||
|
||||
bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* 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 RegisterCallbacks(unsigned int collisionId, const Callback& callbacks);
|
||||
void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks);
|
||||
|
||||
|
|
@ -59,10 +69,47 @@ namespace Nz
|
|||
void* userdata;
|
||||
};
|
||||
|
||||
struct NearestQueryResult
|
||||
{
|
||||
Nz::RigidBody2D* nearestBody;
|
||||
Nz::Vector2f closestPoint;
|
||||
Nz::Vector2f fraction;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct RaycastHit
|
||||
{
|
||||
Nz::RigidBody2D* nearestBody;
|
||||
Nz::Vector2f hitPos;
|
||||
Nz::Vector2f hitNormal;
|
||||
float fraction;
|
||||
};
|
||||
|
||||
NazaraSignal(OnPhysWorld2DPreStep, const PhysWorld2D* /*physWorld*/);
|
||||
NazaraSignal(OnPhysWorld2DPostStep, const PhysWorld2D* /*physWorld*/);
|
||||
|
||||
private:
|
||||
void InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks);
|
||||
|
||||
using PostStep = std::function<void(Nz::RigidBody2D* body)>;
|
||||
|
||||
void OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer);
|
||||
void OnRigidBodyRelease(RigidBody2D* rigidBody);
|
||||
|
||||
void RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func);
|
||||
|
||||
struct PostStepContainer
|
||||
{
|
||||
NazaraSlot(RigidBody2D, OnRigidBody2DMove, onMovedSlot);
|
||||
NazaraSlot(RigidBody2D, OnRigidBody2DRelease, onReleaseSlot);
|
||||
|
||||
std::vector<PostStep> funcs;
|
||||
};
|
||||
|
||||
static_assert(std::is_nothrow_move_constructible<PostStepContainer>::value, "PostStepContainer should be noexcept MoveConstructible");
|
||||
|
||||
std::unordered_map<cpCollisionHandler*, std::unique_ptr<Callback>> m_callbacks;
|
||||
std::unordered_map<RigidBody2D*, PostStepContainer> m_rigidPostSteps;
|
||||
cpSpace* m_handle;
|
||||
float m_stepSize;
|
||||
float m_timestepAccumulator;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ namespace Nz
|
|||
|
||||
void AddForce(const Vector2f& force, CoordSys coordSys = CoordSys_Global);
|
||||
void AddForce(const Vector2f& force, const Vector2f& point, CoordSys coordSys = CoordSys_Global);
|
||||
void AddImpulse(const Vector2f& impulse, CoordSys coordSys = CoordSys_Global);
|
||||
void AddImpulse(const Vector2f& impulse, const Vector2f& point, CoordSys coordSys = CoordSys_Global);
|
||||
void AddTorque(float torque);
|
||||
|
||||
Rectf GetAABB() const;
|
||||
|
|
|
|||
|
|
@ -142,13 +142,15 @@ namespace Nz
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Wait until any registered socket switches to a ready state
|
||||
* \brief Wait until any registered socket switches to a ready state.
|
||||
*
|
||||
* Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready.
|
||||
* To query the ready state of the registered socket, use the IsReady function.
|
||||
*
|
||||
* \param msTimeout Maximum time to wait in milliseconds, 0 for infinity
|
||||
*
|
||||
* \return True if at least one socket registered to the poller is ready.
|
||||
*
|
||||
* \remark It is an error to try to unregister a non-registered socket from a SocketPoller.
|
||||
*
|
||||
* \see IsReady
|
||||
|
|
|
|||
|
|
@ -13,9 +13,12 @@ namespace Nz
|
|||
|
||||
std::vector<cpShape*> Collider2D::GenerateShapes(RigidBody2D* body) const
|
||||
{
|
||||
cpShapeFilter filter = cpShapeFilterNew(m_collisionGroup, m_categoryMask, m_collisionMask);
|
||||
|
||||
std::vector<cpShape*> shapes = CreateShapes(body);
|
||||
for (cpShape* shape : shapes)
|
||||
{
|
||||
cpShapeSetFilter(shape, filter);
|
||||
cpShapeSetCollisionType(shape, m_collisionId);
|
||||
cpShapeSetSensor(shape, (m_trigger) ? cpTrue : cpFalse);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,102 @@ namespace Nz
|
|||
return m_stepSize;
|
||||
}
|
||||
|
||||
bool PhysWorld2D::NearestBodyQuery(const Vector2f & from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody)
|
||||
{
|
||||
cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask);
|
||||
|
||||
if (cpShape* shape = cpSpacePointQueryNearest(m_handle, {from.x, from.y}, maxDistance, filter, nullptr))
|
||||
{
|
||||
if (nearestBody)
|
||||
*nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PhysWorld2D::NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result)
|
||||
{
|
||||
cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask);
|
||||
|
||||
if (result)
|
||||
{
|
||||
cpPointQueryInfo queryInfo;
|
||||
|
||||
if (cpShape* shape = cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, &queryInfo))
|
||||
{
|
||||
result->closestPoint.Set(queryInfo.point.x, queryInfo.point.y);
|
||||
result->distance = queryInfo.distance;
|
||||
result->fraction.Set(queryInfo.gradient.x, queryInfo.gradient.y);
|
||||
result->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpShape* shape = cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, nullptr))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PhysWorld2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos)
|
||||
{
|
||||
auto callback = [](cpShape* shape, cpVect point, cpVect normal, cpFloat alpha, void* data)
|
||||
{
|
||||
std::vector<RaycastHit>* results = reinterpret_cast<std::vector<RaycastHit>*>(data);
|
||||
|
||||
RaycastHit hitInfo;
|
||||
hitInfo.fraction = alpha;
|
||||
hitInfo.hitNormal.Set(normal.x, normal.y);
|
||||
hitInfo.hitPos.Set(point.x, point.y);
|
||||
hitInfo.nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||
|
||||
results->emplace_back(std::move(hitInfo));
|
||||
};
|
||||
|
||||
cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask);
|
||||
|
||||
std::size_t previousSize = hitInfos->size();
|
||||
cpSpaceSegmentQuery(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, callback, hitInfos);
|
||||
|
||||
return hitInfos->size() != previousSize;
|
||||
}
|
||||
|
||||
bool PhysWorld2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo)
|
||||
{
|
||||
cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask);
|
||||
|
||||
if (hitInfo)
|
||||
{
|
||||
cpSegmentQueryInfo queryInfo;
|
||||
|
||||
if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo))
|
||||
{
|
||||
hitInfo->fraction = queryInfo.alpha;
|
||||
hitInfo->hitNormal.Set(queryInfo.normal.x, queryInfo.normal.y);
|
||||
hitInfo->hitPos.Set(queryInfo.point.x, queryInfo.point.y);
|
||||
hitInfo->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(queryInfo.shape));
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, nullptr))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void PhysWorld2D::RegisterCallbacks(unsigned int collisionId, const Callback& callbacks)
|
||||
{
|
||||
InitCallbacks(cpSpaceAddWildcardHandler(m_handle, collisionId), callbacks);
|
||||
|
|
@ -63,7 +159,22 @@ namespace Nz
|
|||
|
||||
while (m_timestepAccumulator >= m_stepSize)
|
||||
{
|
||||
OnPhysWorld2DPreStep(this);
|
||||
|
||||
cpSpaceStep(m_handle, m_stepSize);
|
||||
|
||||
OnPhysWorld2DPostStep(this);
|
||||
if (!m_rigidPostSteps.empty())
|
||||
{
|
||||
for (const auto& pair : m_rigidPostSteps)
|
||||
{
|
||||
for (const auto& step : pair.second.funcs)
|
||||
step(pair.first);
|
||||
}
|
||||
|
||||
m_rigidPostSteps.clear();
|
||||
}
|
||||
|
||||
m_timestepAccumulator -= m_stepSize;
|
||||
}
|
||||
}
|
||||
|
|
@ -162,4 +273,41 @@ namespace Nz
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
void PhysWorld2D::OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer)
|
||||
{
|
||||
auto it = m_rigidPostSteps.find(oldPointer);
|
||||
if (it == m_rigidPostSteps.end())
|
||||
return; //< Shouldn't happen
|
||||
|
||||
m_rigidPostSteps.emplace(std::make_pair(newPointer, std::move(it->second)));
|
||||
m_rigidPostSteps.erase(oldPointer);
|
||||
}
|
||||
|
||||
void PhysWorld2D::OnRigidBodyRelease(RigidBody2D* rigidBody)
|
||||
{
|
||||
m_rigidPostSteps.erase(rigidBody);
|
||||
}
|
||||
|
||||
void PhysWorld2D::RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func)
|
||||
{
|
||||
// If space isn't locked, no need to wait
|
||||
if (!cpSpaceIsLocked(m_handle))
|
||||
{
|
||||
func(rigidBody);
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = m_rigidPostSteps.find(rigidBody);
|
||||
if (it == m_rigidPostSteps.end())
|
||||
{
|
||||
PostStepContainer postStep;
|
||||
postStep.onMovedSlot.Connect(rigidBody->OnRigidBody2DMove, this, &PhysWorld2D::OnRigidBodyMoved);
|
||||
postStep.onReleaseSlot.Connect(rigidBody->OnRigidBody2DRelease, this, &PhysWorld2D::OnRigidBodyRelease);
|
||||
|
||||
it = m_rigidPostSteps.insert(std::make_pair(rigidBody, std::move(postStep))).first;
|
||||
}
|
||||
|
||||
it->second.funcs.emplace_back(std::move(func));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ namespace Nz
|
|||
m_mass(object.m_mass)
|
||||
{
|
||||
cpBodySetUserData(m_handle, this);
|
||||
for (cpShape* shape : m_shapes)
|
||||
cpShapeSetUserData(shape, this);
|
||||
|
||||
object.m_handle = nullptr;
|
||||
|
||||
|
|
@ -93,6 +95,25 @@ namespace Nz
|
|||
}
|
||||
}
|
||||
|
||||
void RigidBody2D::AddImpulse(const Vector2f& impulse, CoordSys coordSys)
|
||||
{
|
||||
return AddImpulse(impulse, GetCenterOfGravity(coordSys), coordSys);
|
||||
}
|
||||
|
||||
void RigidBody2D::AddImpulse(const Vector2f& impulse, const Vector2f& point, CoordSys coordSys)
|
||||
{
|
||||
switch (coordSys)
|
||||
{
|
||||
case CoordSys_Global:
|
||||
cpBodyApplyImpulseAtWorldPoint(m_handle, cpv(impulse.x, impulse.y), cpv(point.x, point.y));
|
||||
break;
|
||||
|
||||
case CoordSys_Local:
|
||||
cpBodyApplyImpulseAtLocalPoint(m_handle, cpv(impulse.x, impulse.y), cpv(point.x, point.y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RigidBody2D::AddTorque(float torque)
|
||||
{
|
||||
cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + torque);
|
||||
|
|
@ -210,7 +231,10 @@ namespace Nz
|
|||
|
||||
cpSpace* space = m_world->GetHandle();
|
||||
for (cpShape* shape : m_shapes)
|
||||
{
|
||||
cpShapeSetUserData(shape, this);
|
||||
cpSpaceAddShape(space, shape);
|
||||
}
|
||||
|
||||
cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass));
|
||||
}
|
||||
|
|
@ -221,20 +245,26 @@ namespace Nz
|
|||
{
|
||||
if (mass > 0.f)
|
||||
{
|
||||
cpBodySetMass(m_handle, mass);
|
||||
cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass));
|
||||
m_world->RegisterPostStep(this, [mass](Nz::RigidBody2D* body)
|
||||
{
|
||||
cpBodySetMass(body->GetHandle(), mass);
|
||||
cpBodySetMoment(body->GetHandle(), body->GetGeom()->ComputeInertialMatrix(mass));
|
||||
});
|
||||
}
|
||||
else
|
||||
cpBodySetType(m_handle, CP_BODY_TYPE_STATIC);
|
||||
m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) { cpBodySetType(body->GetHandle(), CP_BODY_TYPE_STATIC); } );
|
||||
}
|
||||
else if (mass > 0.f)
|
||||
{
|
||||
if (cpBodyGetType(m_handle) == CP_BODY_TYPE_STATIC)
|
||||
m_world->RegisterPostStep(this, [mass](Nz::RigidBody2D* body)
|
||||
{
|
||||
cpBodySetType(m_handle, CP_BODY_TYPE_DYNAMIC);
|
||||
cpBodySetMass(m_handle, mass);
|
||||
cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass));
|
||||
}
|
||||
if (cpBodyGetType(body->GetHandle()) == CP_BODY_TYPE_STATIC)
|
||||
{
|
||||
cpBodySetType(body->GetHandle(), CP_BODY_TYPE_DYNAMIC);
|
||||
cpBodySetMass(body->GetHandle(), mass);
|
||||
cpBodySetMoment(body->GetHandle(), body->GetGeom()->ComputeInertialMatrix(mass));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
m_mass = mass;
|
||||
|
|
@ -290,6 +320,8 @@ namespace Nz
|
|||
m_world = object.m_world;
|
||||
|
||||
cpBodySetUserData(m_handle, this);
|
||||
for (cpShape* shape : m_shapes)
|
||||
cpShapeSetUserData(shape, this);
|
||||
|
||||
object.m_handle = nullptr;
|
||||
|
||||
|
|
@ -302,6 +334,7 @@ namespace Nz
|
|||
{
|
||||
m_handle = cpBodyNew(mass, moment);
|
||||
cpBodySetUserData(m_handle, this);
|
||||
|
||||
cpSpaceAddBody(m_world->GetHandle(), m_handle);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue