Merge remote-tracking branch 'refs/remotes/origin/master' into reflection-mapping

This commit is contained in:
Lynix 2017-03-18 17:23:12 +01:00
commit 62fd66a159
23 changed files with 427 additions and 39 deletions

View File

@ -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);

View File

@ -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));
}

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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));
}
}

View File

@ -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);
}