Former-commit-id: 6e7a2cff46d6e077a3ee4434dd9f1a4a7fd00bb5
This commit is contained in:
Lynix 2015-05-04 11:02:08 +02:00
commit 385b7fc3fd
34 changed files with 1569 additions and 192 deletions

View File

@ -16,6 +16,8 @@ namespace Ndk
template<typename SystemType> constexpr SystemIndex GetSystemIndex();
template<typename ComponentType, unsigned int N> ComponentIndex InitializeComponent(const char (&name)[N]);
template<typename SystemType> SystemIndex InitializeSystem();
template<typename ComponentType, typename C> bool IsComponent(C& component);
template<typename SystemType, typename S> bool IsSystem(S& system);
}
#include <Ndk/Algorithm.inl>

View File

@ -44,4 +44,16 @@ namespace Ndk
SystemType::systemIndex = SystemType::RegisterSystem();
return SystemType::systemIndex;
}
template<typename ComponentType, typename C>
bool IsComponent(C& component)
{
return component.GetIndex() == GetComponentIndex<ComponentType>();
}
template<typename SystemType, typename S>
bool IsSystem(S& system)
{
return system.GetIndex() == GetSystemIndex<SystemType>();
}
}

View File

@ -14,8 +14,11 @@
namespace Ndk
{
class Entity;
class NDK_API BaseComponent
{
friend Entity;
friend class Sdk;
public:
@ -35,10 +38,17 @@ namespace Ndk
protected:
ComponentIndex m_componentIndex;
Entity* m_entity;
static ComponentIndex RegisterComponent(ComponentId id, Factory factoryFunc);
private:
virtual void OnAttached();
virtual void OnComponentAttached(BaseComponent& component);
virtual void OnComponentDetached(BaseComponent& component);
virtual void OnDetached();
void SetEntity(Entity* entity);
static bool Initialize();
static void Uninitialize();

View File

@ -7,7 +7,8 @@
namespace Ndk
{
inline BaseComponent::BaseComponent(ComponentIndex index) :
m_componentIndex(index)
m_componentIndex(index),
m_entity(nullptr)
{
}
@ -35,6 +36,19 @@ namespace Ndk
return index;
}
inline void BaseComponent::SetEntity(Entity* entity)
{
if (m_entity != entity)
{
if (m_entity)
OnDetached();
m_entity = entity;
if (m_entity)
OnAttached();
}
}
inline bool BaseComponent::Initialize()
{
// Rien à faire

View File

@ -51,16 +51,23 @@ namespace Ndk
template<typename ComponentType1, typename ComponentType2, typename... Rest> void Requires();
void RequiresComponent(ComponentIndex index);
template<typename ComponentType> void RequiresAny();
template<typename ComponentType1, typename ComponentType2, typename... Rest> void RequiresAny();
void RequiresAnyComponent(ComponentIndex index);
private:
void AddEntity(Entity* entity);
virtual void OnEntityAdded(Entity* entity);
virtual void OnEntityRemoved(Entity* entity);
virtual void OnEntityValidation(Entity* entity, bool justAdded);
void RemoveEntity(Entity* entity);
void SetWorld(World& world);
void ValidateEntity(Entity* entity, bool justAdded);
static bool Initialize();
static void Uninitialize();
@ -68,6 +75,7 @@ namespace Ndk
NzBitset<nzUInt64> m_entityBits;
NzBitset<> m_excludedComponents;
mutable NzBitset<> m_filterResult;
NzBitset<> m_requiredAnyComponents;
NzBitset<> m_requiredComponents;
SystemIndex m_systemIndex;
World* m_world;

View File

@ -87,11 +87,31 @@ namespace Ndk
m_requiredComponents.UnboundedSet(index);
}
template<typename ComponentType>
void BaseSystem::RequiresAny()
{
static_assert(std::is_base_of<BaseComponent, ComponentType>(), "ComponentType is not a component");
RequiresAnyComponent(GetComponentIndex<ComponentType>());
}
template<typename ComponentType1, typename ComponentType2, typename... Rest>
void BaseSystem::RequiresAny()
{
RequiresAny<ComponentType1>();
RequiresAny<ComponentType2, Rest...>();
}
inline void BaseSystem::RequiresAnyComponent(ComponentIndex index)
{
m_requiredAnyComponents.UnboundedSet(index);
}
inline void BaseSystem::AddEntity(Entity* entity)
{
NazaraAssert(entity, "Invalid entity");
m_entities.push_back(entity->CreateHandle());
m_entities.emplace_back(entity);
m_entityBits.UnboundedSet(entity->GetId(), true);
entity->RegisterSystem(m_systemIndex);
@ -116,6 +136,14 @@ namespace Ndk
OnEntityRemoved(entity); // Et on appelle le callback
}
inline void BaseSystem::ValidateEntity(Entity* entity, bool justAdded)
{
NazaraAssert(entity, "Invalid entity");
NazaraAssert(HasEntity(entity), "Entity should be part of system");
OnEntityValidation(entity, justAdded);
}
inline void BaseSystem::SetWorld(World& world)
{
m_world = &world;
@ -132,5 +160,4 @@ namespace Ndk
{
// Rien à faire
}
}

View File

@ -20,7 +20,7 @@ namespace Ndk
BaseComponent* Component<ComponentType>::Clone() const
{
///FIXME: Pas encore supporté par GCC (4.9.2)
//static_assert(std::is_trivially_copy_constructible<ComponentType>::value, "ComponentType should be copy-constructible");
//static_assert(std::is_trivially_copy_constructible<ComponentType>::value, "ComponentType must be copy-constructible");
return new ComponentType(static_cast<const ComponentType&>(*this));
}
@ -29,7 +29,7 @@ namespace Ndk
ComponentIndex Component<ComponentType>::RegisterComponent(ComponentId id)
{
// Il faut que notre composant possède un constructeur par défaut (pour la factory)
static_assert(std::is_default_constructible<ComponentType>::value, "ComponentType should be default-constructible");
static_assert(std::is_default_constructible<ComponentType>::value, "ComponentType must be default-constructible");
// On utilise les lambda pour créer une fonction factory
auto factory = []() -> BaseComponent*
@ -37,8 +37,6 @@ namespace Ndk
return new ComponentType;
};
// Je ne sais pas si c'est un bug de GCC ou si c'est quelque chose que j'ai mal compris
// mais le fait est que ça ne compile pas si je ne précise pas Basecomponent::
return BaseComponent::RegisterComponent(id, factory);
}

View File

@ -0,0 +1,56 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#pragma once
#ifndef NDK_COMPONENTS_COLLISIONCOMPONENT_HPP
#define NDK_COMPONENTS_COLLISIONCOMPONENT_HPP
#include <Nazara/Physics/Geom.hpp>
#include <NDK/Component.hpp>
#include <memory>
class NzPhysObject;
namespace Ndk
{
class Entity;
class NDK_API CollisionComponent : public Component<CollisionComponent>
{
friend class PhysicsSystem;
friend class StaticCollisionSystem;
public:
CollisionComponent(NzPhysGeomRef geom = NzPhysGeomRef());
CollisionComponent(const CollisionComponent& collision);
~CollisionComponent() = default;
const NzPhysGeomRef& GetGeom() const;
void SetGeom(NzPhysGeomRef geom);
CollisionComponent& operator=(NzPhysGeomRef geom);
CollisionComponent& operator=(CollisionComponent&& collision) = default;
static ComponentIndex componentIndex;
private:
void InitializeStaticBody();
NzPhysObject* GetStaticBody();
void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override;
void OnComponentDetached(BaseComponent& component) override;
void OnDetached() override;
std::unique_ptr<NzPhysObject> m_staticBody;
NzPhysGeomRef m_geom;
bool m_bodyUpdated;
};
}
#include <NDK/Components/CollisionComponent.inl>
#endif // NDK_COMPONENTS_COLLISIONCOMPONENT_HPP

View File

@ -0,0 +1,40 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/Entity.hpp>
#include <NDK/World.hpp>
#include <NDK/Components/PhysicsComponent.hpp>
#include <NDK/Systems/PhysicsSystem.hpp>
namespace Ndk
{
inline CollisionComponent::CollisionComponent(NzPhysGeomRef geom) :
m_geom(std::move(geom)),
m_bodyUpdated(false)
{
}
inline CollisionComponent::CollisionComponent(const CollisionComponent& collision) :
m_geom(collision.m_geom),
m_bodyUpdated(false)
{
}
inline const NzPhysGeomRef& CollisionComponent::GetGeom() const
{
return m_geom;
}
inline CollisionComponent& CollisionComponent::operator=(NzPhysGeomRef geom)
{
SetGeom(geom);
return *this;
}
inline NzPhysObject* CollisionComponent::GetStaticBody()
{
return m_staticBody.get();
}
}

View File

@ -0,0 +1,72 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#pragma once
#ifndef NDK_COMPONENTS_PHYSICSCOMPONENT_HPP
#define NDK_COMPONENTS_PHYSICSCOMPONENT_HPP
#include <Nazara/Physics/PhysObject.hpp>
#include <NDK/Component.hpp>
#include <memory>
namespace Ndk
{
class Entity;
class NDK_API PhysicsComponent : public Component<PhysicsComponent>
{
friend class CollisionComponent;
friend class PhysicsSystem;
public:
PhysicsComponent() = default;
PhysicsComponent(const PhysicsComponent& physics);
~PhysicsComponent() = default;
void AddForce(const NzVector3f& force, nzCoordSys coordSys = nzCoordSys_Global);
void AddForce(const NzVector3f& force, const NzVector3f& point, nzCoordSys coordSys = nzCoordSys_Global);
void AddTorque(const NzVector3f& torque, nzCoordSys coordSys = nzCoordSys_Global);
void EnableAutoSleep(bool autoSleep);
NzBoxf GetAABB() const;
NzVector3f GetAngularVelocity() const;
float GetGravityFactor() const;
float GetMass() const;
NzVector3f GetMassCenter(nzCoordSys coordSys = nzCoordSys_Local) const;
const NzMatrix4f& GetMatrix() const;
NzVector3f GetPosition() const;
NzQuaternionf GetRotation() const;
NzVector3f GetVelocity() const;
bool IsAutoSleepEnabled() const;
bool IsMoveable() const;
bool IsSleeping() const;
void SetAngularVelocity(const NzVector3f& angularVelocity);
void SetGravityFactor(float gravityFactor);
void SetMass(float mass);
void SetMassCenter(const NzVector3f& center);
void SetPosition(const NzVector3f& position);
void SetRotation(const NzQuaternionf& rotation);
void SetVelocity(const NzVector3f& velocity);
static ComponentIndex componentIndex;
private:
NzPhysObject& GetPhysObject();
void OnAttached() override;
void OnComponentAttached(BaseComponent& component) override;
void OnComponentDetached(BaseComponent& component) override;
void OnDetached() override;
std::unique_ptr<NzPhysObject> m_object;
};
}
#include <NDK/Components/PhysicsComponent.inl>
#endif // NDK_COMPONENTS_PHYSICSCOMPONENT_HPP

View File

@ -0,0 +1,174 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Nazara/Core/Error.hpp>
namespace Ndk
{
inline PhysicsComponent::PhysicsComponent(const PhysicsComponent& physics)
{
// Pas de copie de l'objet physique (étant donné que nous n'allons le créer qu'une fois attaché à une entité)
NazaraUnused(physics);
}
inline void PhysicsComponent::AddForce(const NzVector3f& force, nzCoordSys coordSys)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->AddForce(force, coordSys);
}
inline void PhysicsComponent::AddForce(const NzVector3f& force, const NzVector3f& point, nzCoordSys coordSys)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->AddForce(force, point, coordSys);
}
inline void PhysicsComponent::AddTorque(const NzVector3f& torque, nzCoordSys coordSys)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->AddForce(torque, coordSys);
}
inline void PhysicsComponent::EnableAutoSleep(bool autoSleep)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->EnableAutoSleep(autoSleep);
}
inline NzBoxf PhysicsComponent::GetAABB() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetAABB();
}
inline NzVector3f PhysicsComponent::GetAngularVelocity() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetAngularVelocity();
}
inline float PhysicsComponent::GetGravityFactor() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetGravityFactor();
}
inline float PhysicsComponent::GetMass() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetMass();
}
inline NzVector3f PhysicsComponent::GetMassCenter(nzCoordSys coordSys) const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetMassCenter(coordSys);
}
inline const NzMatrix4f& PhysicsComponent::GetMatrix() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetMatrix();
}
inline NzVector3f PhysicsComponent::GetPosition() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetPosition();
}
inline NzQuaternionf PhysicsComponent::GetRotation() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetRotation();
}
inline NzVector3f PhysicsComponent::GetVelocity() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->GetVelocity();
}
inline bool PhysicsComponent::IsAutoSleepEnabled() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->IsAutoSleepEnabled();
}
inline bool PhysicsComponent::IsSleeping() const
{
NazaraAssert(m_object, "Invalid physics object");
return m_object->IsSleeping();
}
inline void PhysicsComponent::SetAngularVelocity(const NzVector3f& angularVelocity)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetAngularVelocity(angularVelocity);
}
inline void PhysicsComponent::SetGravityFactor(float gravityFactor)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetGravityFactor(gravityFactor);
}
inline void PhysicsComponent::SetMass(float mass)
{
NazaraAssert(m_object, "Invalid physics object");
NazaraAssert(mass > 0.f, "Mass should be positive");
m_object->SetMass(mass);
}
inline void PhysicsComponent::SetMassCenter(const NzVector3f& center)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetMassCenter(center);
}
inline void PhysicsComponent::SetPosition(const NzVector3f& position)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetPosition(position);
}
inline void PhysicsComponent::SetRotation(const NzQuaternionf& rotation)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetRotation(rotation);
}
inline void PhysicsComponent::SetVelocity(const NzVector3f& velocity)
{
NazaraAssert(m_object, "Invalid physics object");
m_object->SetVelocity(velocity);
}
inline NzPhysObject& PhysicsComponent::GetPhysObject()
{
return *m_object.get();
}
}

View File

@ -80,6 +80,11 @@ namespace Ndk
return HasComponent(index);
}
inline bool Entity::IsValid() const
{
return m_valid;
}
template<typename ComponentType>
void Entity::RemoveComponent()
{

View File

@ -0,0 +1,63 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#pragma once
#ifndef NDK_ENTITYLIST_HPP
#define NDK_ENTITYLIST_HPP
#include <Nazara/Core/Bitset.hpp>
#include <NDK/Prerequesites.hpp>
#include <NDK/EntityHandle.hpp>
namespace Ndk
{
class NDK_API EntityList
{
public:
using Container = std::vector<EntityHandle>;
EntityList() = default;
~EntityList() = default;
void Clear();
bool Has(const Entity* entity);
bool Has(EntityId entity);
void Insert(Entity* entity);
void Remove(Entity* entity);
// Interface STD
Container::iterator begin();
Container::const_iterator begin() const;
Container::const_iterator cbegin() const;
Container::const_iterator cend() const;
Container::const_reverse_iterator crbegin() const;
Container::const_reverse_iterator crend() const;
bool empty() const;
Container::iterator end();
Container::const_iterator end() const;
Container::reverse_iterator rbegin();
Container::const_reverse_iterator rbegin() const;
Container::reverse_iterator rend();
Container::const_reverse_iterator rend() const;
Container::size_type size() const;
private:
std::vector<EntityHandle> m_entities;
NzBitset<nzUInt64> m_entityBits;
};
}
#include <NDK/EntityList.inl>
#endif // NDK_ENTITYLIST_HPP

View File

@ -0,0 +1,117 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Nazara/Core/Error.hpp>
#include <algorithm>
namespace Ndk
{
inline void EntityList::Clear()
{
m_entities.clear();
m_entityBits.Clear();
}
inline bool EntityList::Has(const Entity* entity)
{
return entity && entity->IsValid() && Has(entity->GetId());
}
inline bool EntityList::Has(EntityId entity)
{
return m_entityBits.UnboundedTest(entity);
}
inline void EntityList::Insert(Entity* entity)
{
if (!Has(entity))
{
m_entities.emplace_back(entity);
m_entityBits.UnboundedSet(entity->GetId(), true);
}
}
inline void EntityList::Remove(Entity* entity)
{
if (Has(entity))
{
auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
NazaraAssert(it != m_entities.end(), "Entity should be part of the vector");
std::swap(*it, m_entities.back());
m_entities.pop_back(); // On le sort du vector
}
}
// Interface STD
inline EntityList::Container::iterator EntityList::begin()
{
return m_entities.begin();
}
inline EntityList::Container::const_iterator EntityList::begin() const
{
return m_entities.begin();
}
inline EntityList::Container::const_iterator EntityList::cbegin() const
{
return m_entities.cbegin();
}
inline EntityList::Container::const_iterator EntityList::cend() const
{
return m_entities.cend();
}
inline EntityList::Container::const_reverse_iterator EntityList::crbegin() const
{
return m_entities.crbegin();
}
inline EntityList::Container::const_reverse_iterator EntityList::crend() const
{
return m_entities.crend();
}
inline bool EntityList::empty() const
{
return m_entities.empty();
}
inline EntityList::Container::iterator EntityList::end()
{
return m_entities.end();
}
inline EntityList::Container::const_iterator EntityList::end() const
{
return m_entities.end();
}
inline EntityList::Container::reverse_iterator EntityList::rbegin()
{
return m_entities.rbegin();
}
inline EntityList::Container::const_reverse_iterator EntityList::rbegin() const
{
return m_entities.rbegin();
}
inline EntityList::Container::reverse_iterator EntityList::rend()
{
return m_entities.rend();
}
inline EntityList::Container::const_reverse_iterator EntityList::rend() const
{
return m_entities.rend();
}
inline EntityList::Container::size_type EntityList::size() const
{
return m_entities.size();
}
}

View File

@ -0,0 +1,41 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#pragma once
#ifndef NDK_SYSTEMS_PHYSICSSYSTEM_HPP
#define NDK_SYSTEMS_PHYSICSSYSTEM_HPP
#include <Nazara/Physics/PhysWorld.hpp>
#include <NDK/EntityList.hpp>
#include <NDK/System.hpp>
namespace Ndk
{
class NDK_API PhysicsSystem : public System<PhysicsSystem>
{
public:
PhysicsSystem();
PhysicsSystem(const PhysicsSystem& system);
~PhysicsSystem() = default;
NzPhysWorld& GetWorld();
const NzPhysWorld& GetWorld() const;
void Update(float elapsedTime);
static SystemIndex systemIndex;
private:
void OnEntityValidation(Entity* entity, bool justAdded) override;
EntityList m_dynamicObjects;
EntityList m_staticObjects;
NzPhysWorld m_world;
};
}
#include <NDK/Systems/PhysicsSystem.inl>
#endif // NDK_SYSTEMS_PHYSICSSYSTEM_HPP

View File

@ -0,0 +1,16 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
namespace Ndk
{
inline NzPhysWorld& PhysicsSystem::GetWorld()
{
return m_world;
}
inline const NzPhysWorld& PhysicsSystem::GetWorld() const
{
return m_world;
}
}

View File

@ -8,6 +8,24 @@ namespace Ndk
{
BaseComponent::~BaseComponent() = default;
void BaseComponent::OnAttached()
{
}
void BaseComponent::OnComponentAttached(BaseComponent& component)
{
NazaraUnused(component);
}
void BaseComponent::OnComponentDetached(BaseComponent& component)
{
NazaraUnused(component);
}
void BaseComponent::OnDetached()
{
}
std::vector<BaseComponent::ComponentEntry> BaseComponent::s_entries;
std::unordered_map<ComponentId, ComponentIndex> BaseComponent::s_idToIndex;
}

View File

@ -27,6 +27,13 @@ namespace Ndk
if (m_filterResult.TestAny())
return false; // Au moins un component exclu est présent
// Si nous avons une liste de composants nécessaires
if (m_requiredAnyComponents.TestAny())
{
if (!m_requiredAnyComponents.Intersects(components))
return false;
}
return true;
}
@ -40,5 +47,11 @@ namespace Ndk
NazaraUnused(entity);
}
void BaseSystem::OnEntityValidation(Entity* entity, bool justAdded)
{
NazaraUnused(entity);
NazaraUnused(justAdded);
}
SystemIndex BaseSystem::s_nextIndex;
}

View File

@ -0,0 +1,68 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/Components/CollisionComponent.hpp>
#include <Nazara/Physics/PhysObject.hpp>
#include <NDK/Algorithm.hpp>
#include <NDK/World.hpp>
#include <NDK/Components/PhysicsComponent.hpp>
#include <NDK/Systems/PhysicsSystem.hpp>
namespace Ndk
{
void CollisionComponent::SetGeom(NzPhysGeomRef geom)
{
m_geom = std::move(geom);
if (m_entity->HasComponent<PhysicsComponent>())
{
// On met à jour la géométrie du PhysObject associé au PhysicsComponent
PhysicsComponent& physComponent = m_entity->GetComponent<PhysicsComponent>();
physComponent.GetPhysObject().SetGeom(m_geom);
}
else
{
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
m_staticBody->SetGeom(m_geom);
}
}
void CollisionComponent::InitializeStaticBody()
{
NazaraAssert(m_entity, "Invalid entity");
World* entityWorld = m_entity->GetWorld();
NazaraAssert(entityWorld, "Entity must have world");
NazaraAssert(entityWorld->HasSystem<PhysicsSystem>(), "World must have a physics system");
NzPhysWorld& physWorld = entityWorld->GetSystem<PhysicsSystem>().GetWorld();
m_staticBody.reset(new NzPhysObject(&physWorld, m_geom));
m_staticBody->EnableAutoSleep(false);
}
void CollisionComponent::OnAttached()
{
if (!m_entity->HasComponent<PhysicsComponent>())
InitializeStaticBody();
}
void CollisionComponent::OnComponentAttached(BaseComponent& component)
{
if (IsComponent<PhysicsComponent>(component))
m_staticBody.reset();
}
void CollisionComponent::OnComponentDetached(BaseComponent& component)
{
if (IsComponent<PhysicsComponent>(component))
InitializeStaticBody();
}
void CollisionComponent::OnDetached()
{
m_staticBody.reset();
}
ComponentIndex CollisionComponent::componentIndex;
}

View File

@ -0,0 +1,60 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/Components/PhysicsComponent.hpp>
#include <Nazara/Physics/PhysObject.hpp>
#include <NDK/Algorithm.hpp>
#include <NDK/World.hpp>
#include <NDK/Components/CollisionComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Systems/PhysicsSystem.hpp>
namespace Ndk
{
void PhysicsComponent::OnAttached()
{
World* entityWorld = m_entity->GetWorld();
NazaraAssert(entityWorld->HasSystem<PhysicsSystem>(), "World must have a physics system");
NzPhysWorld& world = entityWorld->GetSystem<PhysicsSystem>().GetWorld();
NzPhysGeomRef geom;
if (m_entity->HasComponent<CollisionComponent>())
geom = m_entity->GetComponent<CollisionComponent>().GetGeom();
NzMatrix4f matrix;
if (m_entity->HasComponent<NodeComponent>())
matrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
else
matrix.MakeIdentity();
m_object.reset(new NzPhysObject(&world, geom, matrix));
m_object->SetMass(1.f);
}
void PhysicsComponent::OnComponentAttached(BaseComponent& component)
{
if (IsComponent<CollisionComponent>(component))
{
NazaraAssert(m_object, "Invalid object");
m_object->SetGeom(static_cast<CollisionComponent&>(component).GetGeom());
}
}
void PhysicsComponent::OnComponentDetached(BaseComponent& component)
{
if (IsComponent<CollisionComponent>(component))
{
NazaraAssert(m_object, "Invalid object");
m_object->SetGeom(NzNullGeom::New());
}
}
void PhysicsComponent::OnDetached()
{
m_object.reset();
}
ComponentIndex PhysicsComponent::componentIndex;
}

View File

@ -9,8 +9,11 @@
namespace Ndk
{
Entity::Entity(Entity&& entity) :
m_components(std::move(entity.m_components)),
m_handles(std::move(entity.m_handles)),
m_id(entity.m_id),
m_componentBits(std::move(entity.m_componentBits)),
m_systemBits(std::move(entity.m_systemBits)),
m_world(entity.m_world),
m_valid(entity.m_valid)
{
@ -23,24 +26,34 @@ namespace Ndk
Destroy();
}
BaseComponent& Entity::AddComponent(std::unique_ptr<BaseComponent>&& component)
BaseComponent& Entity::AddComponent(std::unique_ptr<BaseComponent>&& componentPtr)
{
NazaraAssert(component, "Component must be valid");
NazaraAssert(componentPtr, "Component must be valid");
ComponentIndex index = component->GetIndex();
ComponentIndex index = componentPtr->GetIndex();
// Nous nous assurons que le vecteur de component est suffisamment grand pour contenir le nouveau component
if (index >= m_components.size())
m_components.resize(index + 1);
// Affectation et retour du component
m_components[index] = std::move(component);
m_components[index] = std::move(componentPtr);
m_componentBits.UnboundedSet(index);
// On informe le monde que nous avons besoin d'une mise à jour
m_world->Invalidate(m_id);
return *m_components[index].get();
// On récupère le component et on informe les composants existants du nouvel arrivant
BaseComponent& component = *m_components[index].get();
component.SetEntity(this);
for (unsigned int i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
{
if (i != index)
m_components[index]->OnComponentAttached(component);
}
return component;
}
EntityHandle Entity::CreateHandle()
@ -53,15 +66,14 @@ namespace Ndk
m_world->KillEntity(this);
}
bool Entity::IsValid() const
{
return m_valid;
}
void Entity::RemoveAllComponents()
{
for (unsigned int i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
RemoveComponent(i);
NazaraAssert(m_componentBits.TestNone(), "All components should be gone");
m_components.clear();
m_componentBits.Clear();
// On informe le monde que nous avons besoin d'une mise à jour
m_world->Invalidate(m_id);
@ -72,6 +84,16 @@ namespace Ndk
///DOC: N'a aucun effet si le component n'est pas présent
if (HasComponent(index))
{
// On récupère le component et on informe les composants du détachement
BaseComponent& component = *m_components[index].get();
for (unsigned int i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
{
if (i != index)
m_components[index]->OnComponentDetached(component);
}
component.SetEntity(nullptr);
m_components[index].reset();
m_componentBits.Reset(index);

View File

@ -13,10 +13,13 @@
#include <Nazara/Utility/Utility.hpp>
#include <NDK/Algorithm.hpp>
#include <NDK/BaseSystem.hpp>
#include <NDK/Components/CollisionComponent.hpp>
#include <NDK/Components/ListenerComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent.hpp>
#include <NDK/Components/VelocityComponent.hpp>
#include <NDK/Systems/ListenerSystem.hpp>
#include <NDK/Systems/PhysicsSystem.hpp>
#include <NDK/Systems/VelocitySystem.hpp>
namespace Ndk
@ -49,12 +52,15 @@ namespace Ndk
BaseSystem::Initialize();
// Composants
InitializeComponent<CollisionComponent>("NdkColli");
InitializeComponent<ListenerComponent>("NdkList");
InitializeComponent<NodeComponent>("NdkNode");
InitializeComponent<PhysicsComponent>("NdkPhys");
InitializeComponent<VelocityComponent>("NdkVeloc");
// Systèmes
InitializeSystem<ListenerSystem>();
InitializeSystem<PhysicsSystem>();
InitializeSystem<VelocitySystem>();
NazaraNotice("Initialized: SDK");

View File

@ -6,6 +6,7 @@
#include <Nazara/Audio/Audio.hpp>
#include <NDK/Components/ListenerComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/VelocityComponent.hpp>
namespace Ndk
{
@ -16,6 +17,8 @@ namespace Ndk
void ListenerSystem::Update(float elapsedTime)
{
NazaraUnused(elapsedTime);
unsigned int activeListenerCount = 0;
for (const Ndk::EntityHandle& entity : GetEntities())
@ -25,10 +28,19 @@ namespace Ndk
if (!listener.IsActive())
continue;
// On récupère la position et la rotation pour les affecter au listener
const NodeComponent& node = entity->GetComponent<NodeComponent>();
NzAudio::SetListenerPosition(node.GetPosition(nzCoordSys_Global));
NzAudio::SetListenerRotation(node.GetRotation(nzCoordSys_Global));
// On vérifie la présence d'une donnée de vitesse, et on l'affecte
// (La vitesse du listener Audio ne le fait pas se déplacer, mais affecte par exemple l'effet Doppler)
if (entity->HasComponent<VelocityComponent>())
{
const VelocityComponent& velocity = entity->GetComponent<VelocityComponent>();
NzAudio::SetListenerVelocity(velocity.linearVelocity);
}
activeListenerCount++;
}

View File

@ -0,0 +1,93 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/Systems/PhysicsSystem.hpp>
#include <Nazara/Physics/PhysObject.hpp>
#include <NDK/Components/CollisionComponent.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent.hpp>
namespace Ndk
{
PhysicsSystem::PhysicsSystem()
{
Requires<NodeComponent>();
RequiresAny<CollisionComponent, PhysicsComponent>();
}
PhysicsSystem::PhysicsSystem(const PhysicsSystem& system) :
System(system),
m_world()
{
}
void PhysicsSystem::Update(float elapsedTime)
{
m_world.Step(elapsedTime);
for (const Ndk::EntityHandle& entity : m_dynamicObjects)
{
NodeComponent& node = entity->GetComponent<NodeComponent>();
PhysicsComponent& phys = entity->GetComponent<PhysicsComponent>();
NzPhysObject& physObj = phys.GetPhysObject();
node.SetRotation(physObj.GetRotation(), nzCoordSys_Global);
node.SetPosition(physObj.GetPosition(), nzCoordSys_Global);
}
float invElapsedTime = 1.f / elapsedTime;
for (const Ndk::EntityHandle& entity : m_staticObjects)
{
CollisionComponent& collision = entity->GetComponent<CollisionComponent>();
NodeComponent& node = entity->GetComponent<NodeComponent>();
NzPhysObject* physObj = collision.GetStaticBody();
NzQuaternionf oldRotation = physObj->GetRotation();
NzVector3f oldPosition = physObj->GetPosition();
NzQuaternionf newRotation = node.GetRotation(nzCoordSys_Global);
NzVector3f newPosition = node.GetPosition(nzCoordSys_Global);
// Pour déplacer des objets statiques et assurer les collisions, il faut leur définir une vitesse
// (note importante: le moteur physique n'applique pas la vitesse sur les objets statiques)
if (newPosition != oldPosition)
{
physObj->SetPosition(newPosition);
physObj->SetVelocity((newPosition - oldPosition) * invElapsedTime);
}
else
physObj->SetVelocity(NzVector3f::Zero());
if (newRotation != oldRotation)
{
NzQuaternionf transition = newRotation * oldRotation.GetConjugate();
NzEulerAnglesf angles = transition.ToEulerAngles();
NzVector3f angularVelocity(NzToRadians(angles.pitch * invElapsedTime),
NzToRadians(angles.yaw * invElapsedTime),
NzToRadians(angles.roll * invElapsedTime));
physObj->SetRotation(oldRotation);
physObj->SetAngularVelocity(angularVelocity);
}
else
physObj->SetAngularVelocity(NzVector3f::Zero());
}
}
void PhysicsSystem::OnEntityValidation(Entity* entity, bool justAdded)
{
// Si l'entité ne vient pas d'être ajoutée au système, il est possible qu'elle fasse partie du mauvais tableau
if (!justAdded)
{
// On prend le tableau inverse de celui dont l'entité devrait faire partie
auto& entities = (entity->HasComponent<PhysicsComponent>()) ? m_staticObjects : m_dynamicObjects;
entities.Remove(entity);
}
auto& entities = (entity->HasComponent<PhysicsComponent>()) ? m_dynamicObjects : m_staticObjects;
entities.Insert(entity);
}
SystemIndex PhysicsSystem::systemIndex;
}

View File

@ -4,6 +4,7 @@
#include <NDK/Systems/VelocitySystem.hpp>
#include <NDK/Components/NodeComponent.hpp>
#include <NDK/Components/PhysicsComponent.hpp>
#include <NDK/Components/VelocityComponent.hpp>
namespace Ndk
@ -11,6 +12,7 @@ namespace Ndk
VelocitySystem::VelocitySystem()
{
Requires<NodeComponent, VelocityComponent>();
Excludes<PhysicsComponent>();
}
void VelocitySystem::Update(float elapsedTime)

View File

@ -5,6 +5,7 @@
#include <NDK/World.hpp>
#include <Nazara/Core/Error.hpp>
#include <NDK/Systems/ListenerSystem.hpp>
#include <NDK/Systems/PhysicsSystem.hpp>
#include <NDK/Systems/VelocitySystem.hpp>
namespace Ndk
@ -18,6 +19,7 @@ namespace Ndk
void World::AddDefaultSystems()
{
AddSystem<ListenerSystem>();
AddSystem<PhysicsSystem>();
AddSystem<VelocitySystem>();
}
@ -121,25 +123,30 @@ namespace Ndk
{
NazaraAssert(i < m_entities.size(), "Entity index out of range");
Entity& entity = m_entities[i].entity;
Entity* entity = &m_entities[i].entity;
// Aucun intérêt de traiter une entité n'existant plus
if (entity.IsValid())
if (entity->IsValid())
{
for (auto& system : m_systems)
{
// L'entité est-elle enregistrée comme faisant partie du système ?
bool partOfSystem = system->HasEntity(&entity);
bool partOfSystem = system->HasEntity(entity);
// Doit-elle en faire partie ?
if (system->Filters(&entity) != partOfSystem)
if (system->Filters(entity))
{
// L'entité n'est pas dans l'état dans lequel elle devrait être vis-à-vis de ce système
// si elle en fait partie, nous devons l'en enlever, et inversément
if (partOfSystem)
system->RemoveEntity(&entity);
// L'entité doit faire partie du système, revalidons-là (événement système) ou ajoutons-la au système
if (!partOfSystem)
system->AddEntity(entity);
system->ValidateEntity(entity, !partOfSystem);
}
else
system->AddEntity(&entity);
{
// Elle ne doit pas en faire partie, si elle en faisait partie nous devons la retirer
if (partOfSystem)
system->RemoveEntity(entity);
}
}
}

View File

@ -63,9 +63,9 @@ class NzBitset
void Swap(NzBitset& bitset);
bool Test(unsigned int bit) const;
bool TestAll();
bool TestAny();
bool TestNone();
bool TestAll() const;
bool TestAny() const;
bool TestNone() const;
template<typename T> T To() const;
NzString ToString() const;

View File

@ -309,7 +309,7 @@ bool NzBitset<Block, Allocator>::Test(unsigned int bit) const
}
template<typename Block, class Allocator>
bool NzBitset<Block, Allocator>::TestAll()
bool NzBitset<Block, Allocator>::TestAll() const
{
// Cas particulier du dernier bloc
Block lastBlockMask = GetLastBlockMask();
@ -325,7 +325,7 @@ bool NzBitset<Block, Allocator>::TestAll()
}
template<typename Block, class Allocator>
bool NzBitset<Block, Allocator>::TestAny()
bool NzBitset<Block, Allocator>::TestAny() const
{
if (m_blocks.empty())
return false;
@ -340,7 +340,7 @@ bool NzBitset<Block, Allocator>::TestAny()
}
template<typename Block, class Allocator>
bool NzBitset<Block, Allocator>::TestNone()
bool NzBitset<Block, Allocator>::TestNone() const
{
return !TestAny();
}

View File

@ -1,4 +1,4 @@
// Copyright (C) 2015 Jérôme Leclercq
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Physics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@ -8,12 +8,17 @@
#define NAZARA_GEOM_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Core/PrimitiveList.hpp>
#include <Nazara/Core/NonCopyable.hpp>
#include <Nazara/Core/PrimitiveList.hpp>
#include <Nazara/Core/ObjectLibrary.hpp>
#include <Nazara/Core/ObjectListenerWrapper.hpp>
#include <Nazara/Core/ObjectRef.hpp>
#include <Nazara/Core/RefCounted.hpp>
#include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Physics/Enums.hpp>
#include <unordered_map>
///TODO: CollisionModifier
///TODO: HeightfieldGeom
@ -21,126 +26,246 @@
///TODO: SceneGeom
///TODO: TreeGeom
class NzPhysGeom;
class NzPhysWorld;
struct NewtonCollision;
class NAZARA_API NzBaseGeom : NzNonCopyable
using NzPhysGeomConstListener = NzObjectListenerWrapper<const NzPhysGeom>;
using NzPhysGeomConstRef = NzObjectRef<const NzPhysGeom>;
using NzPhysGeomLibrary = NzObjectLibrary<NzPhysGeom>;
using NzPhysGeomListener = NzObjectListenerWrapper<NzPhysGeom>;
using NzPhysGeomRef = NzObjectRef<NzPhysGeom>;
class NAZARA_API NzPhysGeom : public NzRefCounted, NzNonCopyable
{
public:
NzBaseGeom(NzPhysWorld* physWorld);
virtual ~NzBaseGeom();
NzPhysGeom() = default;
virtual ~NzPhysGeom();
virtual NzBoxf ComputeAABB(const NzVector3f& translation, const NzQuaternionf& rotation, const NzVector3f& scale) const;
virtual NzBoxf ComputeAABB(const NzMatrix4f& offsetMatrix = NzMatrix4f::Identity()) const;
NzBoxf ComputeAABB(const NzVector3f& translation, const NzQuaternionf& rotation, const NzVector3f& scale) const;
virtual NzBoxf ComputeAABB(const NzMatrix4f& offsetMatrix = NzMatrix4f::Identity(), const NzVector3f& scale = NzVector3f::Unit()) const;
virtual void ComputeInertialMatrix(NzVector3f* inertia, NzVector3f* center) const;
virtual float ComputeVolume() const;
NewtonCollision* GetHandle() const;
NewtonCollision* GetHandle(NzPhysWorld* world) const;
virtual nzGeomType GetType() const = 0;
NzPhysWorld* GetWorld() const;
static NzBaseGeom* Build(NzPhysWorld* physWorld, const NzPrimitiveList& list);
static NzPhysGeomRef Build(const NzPrimitiveList& list);
protected:
NewtonCollision* m_collision;
NzPhysWorld* m_world;
virtual NewtonCollision* CreateHandle(NzPhysWorld* world) const = 0;
mutable std::unordered_map<NzPhysWorld*, NewtonCollision*> m_handles;
static NzPhysGeomLibrary::LibraryMap s_library;
};
class NAZARA_API NzBoxGeom : public NzBaseGeom
class NzBoxGeom;
using NzBoxGeomConstListener = NzObjectListenerWrapper<const NzBoxGeom>;
using NzBoxGeomConstRef = NzObjectRef<const NzBoxGeom>;
using NzBoxGeomListener = NzObjectListenerWrapper<NzBoxGeom>;
using NzBoxGeomRef = NzObjectRef<NzBoxGeom>;
class NAZARA_API NzBoxGeom : public NzPhysGeom
{
public:
NzBoxGeom(NzPhysWorld* physWorld, const NzVector3f& lengths, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzBoxGeom(NzPhysWorld* physWorld, const NzVector3f& lengths, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzBoxGeom(const NzVector3f& lengths, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzBoxGeom(const NzVector3f& lengths, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzBoxf ComputeAABB(const NzMatrix4f& offsetMatrix = NzMatrix4f::Identity(), const NzVector3f& scale = NzVector3f::Unit()) const override;
float ComputeVolume() const override;
NzVector3f GetLengths() const;
nzGeomType GetType() const override;
template<typename... Args> static NzBoxGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
NzMatrix4f m_matrix;
NzVector3f m_lengths;
};
class NAZARA_API NzCapsuleGeom : public NzBaseGeom
class NzCapsuleGeom;
using NzCapsuleGeomConstListener = NzObjectListenerWrapper<const NzCapsuleGeom>;
using NzCapsuleGeomConstRef = NzObjectRef<const NzCapsuleGeom>;
using NzCapsuleGeomListener = NzObjectListenerWrapper<NzCapsuleGeom>;
using NzCapsuleGeomRef = NzObjectRef<NzCapsuleGeom>;
class NAZARA_API NzCapsuleGeom : public NzPhysGeom
{
public:
NzCapsuleGeom(NzPhysWorld* physWorld, float length, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzCapsuleGeom(NzPhysWorld* physWorld, float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzCapsuleGeom(float length, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzCapsuleGeom(float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
float GetLength() const;
float GetRadius() const;
nzGeomType GetType() const override;
template<typename... Args> static NzCapsuleGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
NzMatrix4f m_matrix;
float m_length;
float m_radius;
};
class NAZARA_API NzCompoundGeom : public NzBaseGeom
class NzCompoundGeom;
using NzCompoundGeomConstListener = NzObjectListenerWrapper<const NzCompoundGeom>;
using NzCompoundGeomConstRef = NzObjectRef<const NzCompoundGeom>;
using NzCompoundGeomListener = NzObjectListenerWrapper<NzCompoundGeom>;
using NzCompoundGeomRef = NzObjectRef<NzCompoundGeom>;
class NAZARA_API NzCompoundGeom : public NzPhysGeom
{
public:
NzCompoundGeom(NzPhysWorld* physWorld, NzBaseGeom** geoms, unsigned int geomCount);
NzCompoundGeom(NzPhysGeom** geoms, unsigned int geomCount);
const std::vector<NzPhysGeomRef>& GetGeoms() const;
nzGeomType GetType() const override;
template<typename... Args> static NzCompoundGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
std::vector<NzPhysGeomRef> m_geoms;
};
class NAZARA_API NzConeGeom : public NzBaseGeom
class NzConeGeom;
using NzConeGeomConstListener = NzObjectListenerWrapper<const NzConeGeom>;
using NzConeGeomConstRef = NzObjectRef<const NzConeGeom>;
using NzConeGeomListener = NzObjectListenerWrapper<NzConeGeom>;
using NzConeGeomRef = NzObjectRef<NzConeGeom>;
class NAZARA_API NzConeGeom : public NzPhysGeom
{
public:
NzConeGeom(NzPhysWorld* physWorld, float length, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzConeGeom(NzPhysWorld* physWorld, float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzConeGeom(float length, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzConeGeom(float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
float GetLength() const;
float GetRadius() const;
nzGeomType GetType() const override;
template<typename... Args> static NzConeGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
NzMatrix4f m_matrix;
float m_length;
float m_radius;
};
class NAZARA_API NzConvexHullGeom : public NzBaseGeom
class NzConvexHullGeom;
using NzConvexHullGeomConstListener = NzObjectListenerWrapper<const NzConvexHullGeom>;
using NzConvexHullGeomConstRef = NzObjectRef<const NzConvexHullGeom>;
using NzConvexHullGeomListener = NzObjectListenerWrapper<NzConvexHullGeom>;
using NzConvexHullGeomRef = NzObjectRef<NzConvexHullGeom>;
class NAZARA_API NzConvexHullGeom : public NzPhysGeom
{
public:
NzConvexHullGeom(NzPhysWorld* physWorld, const void* vertices, unsigned int vertexCount, unsigned int stride = sizeof(NzVector3f), float tolerance = 0.002f, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzConvexHullGeom(NzPhysWorld* physWorld, const void* vertices, unsigned int vertexCount, unsigned int stride, float tolerance, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzConvexHullGeom(const void* vertices, unsigned int vertexCount, unsigned int stride = sizeof(NzVector3f), float tolerance = 0.002f, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzConvexHullGeom(const void* vertices, unsigned int vertexCount, unsigned int stride, float tolerance, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
nzGeomType GetType() const override;
template<typename... Args> static NzConvexHullGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
std::vector<NzVector3f> m_vertices;
NzMatrix4f m_matrix;
float m_tolerance;
unsigned int m_vertexStride;
};
class NAZARA_API NzCylinderGeom : public NzBaseGeom
class NzCylinderGeom;
using NzCylinderGeomConstListener = NzObjectListenerWrapper<const NzCylinderGeom>;
using NzCylinderGeomConstRef = NzObjectRef<const NzCylinderGeom>;
using NzCylinderGeomListener = NzObjectListenerWrapper<NzCylinderGeom>;
using NzCylinderGeomRef = NzObjectRef<NzCylinderGeom>;
class NAZARA_API NzCylinderGeom : public NzPhysGeom
{
public:
NzCylinderGeom(NzPhysWorld* physWorld, float length, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzCylinderGeom(NzPhysWorld* physWorld, float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzCylinderGeom(float length, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzCylinderGeom(float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
float GetLength() const;
float GetRadius() const;
nzGeomType GetType() const override;
template<typename... Args> static NzCylinderGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
NzMatrix4f m_matrix;
float m_length;
float m_radius;
};
class NAZARA_API NzNullGeom : public NzBaseGeom
class NzNullGeom;
using NzNullGeomConstListener = NzObjectListenerWrapper<const NzNullGeom>;
using NzNullGeomConstRef = NzObjectRef<const NzNullGeom>;
using NzNullGeomListener = NzObjectListenerWrapper<NzNullGeom>;
using NzNullGeomRef = NzObjectRef<NzNullGeom>;
class NAZARA_API NzNullGeom : public NzPhysGeom
{
public:
NzNullGeom(NzPhysWorld* physWorld);
NzNullGeom();
nzGeomType GetType() const override;
};
class NAZARA_API NzSphereGeom : public NzBaseGeom
{
public:
NzSphereGeom(NzPhysWorld* physWorld, float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzSphereGeom(NzPhysWorld* physWorld, float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzVector3f GetRadius() const;
nzGeomType GetType() const override;
template<typename... Args> static NzNullGeomRef New(Args&&... args);
private:
NzVector3f m_radius;
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
};
class NzSphereGeom;
using NzSphereGeomConstListener = NzObjectListenerWrapper<const NzSphereGeom>;
using NzSphereGeomConstRef = NzObjectRef<const NzSphereGeom>;
using NzSphereGeomListener = NzObjectListenerWrapper<NzSphereGeom>;
using NzSphereGeomRef = NzObjectRef<NzSphereGeom>;
class NAZARA_API NzSphereGeom : public NzPhysGeom
{
public:
NzSphereGeom(float radius, const NzMatrix4f& transformMatrix = NzMatrix4f::Identity());
NzSphereGeom(float radius, const NzVector3f& translation, const NzQuaternionf& rotation = NzQuaternionf::Identity());
NzBoxf ComputeAABB(const NzMatrix4f& offsetMatrix = NzMatrix4f::Identity(), const NzVector3f& scale = NzVector3f::Unit()) const override;
float ComputeVolume() const override;
float GetRadius() const;
nzGeomType GetType() const override;
template<typename... Args> static NzSphereGeomRef New(Args&&... args);
private:
NewtonCollision* CreateHandle(NzPhysWorld* world) const override;
NzVector3f m_position;
float m_radius;
};
#include <Nazara/Physics/Geom.inl>
#endif // NAZARA_PHYSWORLD_HPP

View File

@ -0,0 +1,80 @@
// Copyright (C) 2015 Jérôme Leclercq
// This file is part of the "Nazara Engine - Physics module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <memory>
#include <Nazara/Physics/Debug.hpp>
template<typename... Args>
NzBoxGeomRef NzBoxGeom::New(Args&&... args)
{
std::unique_ptr<NzBoxGeom> object(new NzBoxGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzCapsuleGeomRef NzCapsuleGeom::New(Args&&... args)
{
std::unique_ptr<NzCapsuleGeom> object(new NzCapsuleGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzCompoundGeomRef NzCompoundGeom::New(Args&&... args)
{
std::unique_ptr<NzCompoundGeom> object(new NzCompoundGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzConeGeomRef NzConeGeom::New(Args&&... args)
{
std::unique_ptr<NzConeGeom> object(new NzConeGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzConvexHullGeomRef NzConvexHullGeom::New(Args&&... args)
{
std::unique_ptr<NzConvexHullGeom> object(new NzConvexHullGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzCylinderGeomRef NzCylinderGeom::New(Args&&... args)
{
std::unique_ptr<NzCylinderGeom> object(new NzCylinderGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzNullGeomRef NzNullGeom::New(Args&&... args)
{
std::unique_ptr<NzNullGeom> object(new NzNullGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
template<typename... Args>
NzSphereGeomRef NzSphereGeom::New(Args&&... args)
{
std::unique_ptr<NzSphereGeom> object(new NzSphereGeom(std::forward<Args>(args)...));
object->SetPersistent(false);
return object.release();
}
#include <Nazara/Physics/DebugOff.hpp>

View File

@ -13,16 +13,18 @@
#include <Nazara/Math/Matrix4.hpp>
#include <Nazara/Math/Quaternion.hpp>
#include <Nazara/Math/Vector3.hpp>
#include <Nazara/Physics/Geom.hpp>
class NzBaseGeom;
class NzPhysWorld;
struct NewtonBody;
class NAZARA_API NzPhysObject : NzNonCopyable
class NAZARA_API NzPhysObject
{
public:
NzPhysObject(NzPhysWorld* world, const NzMatrix4f& mat = NzMatrix4f::Identity());
NzPhysObject(NzPhysWorld* world, const NzBaseGeom* geom, const NzMatrix4f& mat = NzMatrix4f::Identity());
NzPhysObject(NzPhysWorld* world, NzPhysGeomRef geom, const NzMatrix4f& mat = NzMatrix4f::Identity());
NzPhysObject(const NzPhysObject& object);
NzPhysObject(NzPhysObject&& object);
~NzPhysObject();
void AddForce(const NzVector3f& force, nzCoordSys coordSys = nzCoordSys_Global);
@ -31,7 +33,9 @@ class NAZARA_API NzPhysObject : NzNonCopyable
void EnableAutoSleep(bool autoSleep);
NzBoxf GetAABB() const;
NzVector3f GetAngularVelocity() const;
const NzPhysGeomRef& GetGeom() const;
float GetGravityFactor() const;
NewtonBody* GetHandle() const;
float GetMass() const;
@ -45,11 +49,17 @@ class NAZARA_API NzPhysObject : NzNonCopyable
bool IsMoveable() const;
bool IsSleeping() const;
void SetAngularVelocity(const NzVector3f& angularVelocity);
void SetGeom(NzPhysGeomRef geom);
void SetGravityFactor(float gravityFactor);
void SetMass(float mass);
void SetMassCenter(const NzVector3f& center);
void SetPosition(const NzVector3f& position);
void SetRotation(const NzQuaternionf& rotation);
void SetVelocity(const NzVector3f& velocity);
NzPhysObject& operator=(const NzPhysObject& object);
NzPhysObject& operator=(NzPhysObject&& object);
private:
void UpdateBody();
@ -57,12 +67,11 @@ class NAZARA_API NzPhysObject : NzNonCopyable
static void TransformCallback(const NewtonBody* body, const float* matrix, int threadIndex);
NzMatrix4f m_matrix;
NzPhysGeomRef m_geom;
NzVector3f m_forceAccumulator;
NzVector3f m_torqueAccumulator;
NewtonBody* m_body;
const NzBaseGeom* m_geom;
NzPhysWorld* m_world;
bool m_ownsGeom;
float m_gravityFactor;
float m_mass;
};

View File

@ -9,6 +9,7 @@
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/IndexBuffer.hpp>
class NzIndexBuffer;
class NzIndexIterator;

View File

@ -10,62 +10,79 @@
namespace
{
NzBaseGeom* CreateGeomFromPrimitive(NzPhysWorld* physWorld, const NzPrimitive& primitive)
NzPhysGeomRef CreateGeomFromPrimitive(const NzPrimitive& primitive)
{
switch (primitive.type)
{
case nzPrimitiveType_Box:
return new NzBoxGeom(physWorld, primitive.box.lengths, primitive.matrix);
return NzBoxGeom::New(primitive.box.lengths, primitive.matrix);
case nzPrimitiveType_Cone:
return new NzConeGeom(physWorld, primitive.cone.length, primitive.cone.radius, primitive.matrix);
return NzConeGeom::New(primitive.cone.length, primitive.cone.radius, primitive.matrix);
case nzPrimitiveType_Plane:
return new NzBoxGeom(physWorld, NzVector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y), primitive.matrix);
return NzBoxGeom::New(NzVector3f(primitive.plane.size.x, 0.01f, primitive.plane.size.y), primitive.matrix);
///TODO: PlaneGeom?
case nzPrimitiveType_Sphere:
return new NzSphereGeom(physWorld, primitive.sphere.size, primitive.matrix.GetTranslation());
return NzSphereGeom::New(primitive.sphere.size, primitive.matrix.GetTranslation());
}
NazaraError("Primitive type not handled (0x" + NzString::Number(primitive.type, 16) + ')');
return nullptr;
return NzPhysGeomRef();
}
}
NzBaseGeom::NzBaseGeom(NzPhysWorld* physWorld) :
m_world(physWorld)
NzPhysGeom::~NzPhysGeom()
{
for (auto& pair : m_handles)
NewtonDestroyCollision(pair.second);
}
NzBaseGeom::~NzBaseGeom()
NzBoxf NzPhysGeom::ComputeAABB(const NzVector3f& translation, const NzQuaternionf& rotation, const NzVector3f& scale) const
{
NewtonDestroyCollision(m_collision);
return ComputeAABB(NzMatrix4f::Transform(translation, rotation), scale);
}
NzBoxf NzBaseGeom::ComputeAABB(const NzVector3f& translation, const NzQuaternionf& rotation, const NzVector3f& scale) const
NzBoxf NzPhysGeom::ComputeAABB(const NzMatrix4f& offsetMatrix, const NzVector3f& scale) const
{
NzVector3f min, max;
NewtonCollisionCalculateAABB(m_collision, NzMatrix4f::Transform(translation, rotation), min, max);
// Et on applique le scale à la fin
// Si nous n'avons aucune instance, nous en créons une temporaire
if (m_handles.empty())
{
NzPhysWorld world;
NewtonCollision* collision = CreateHandle(&world);
{
NewtonCollisionCalculateAABB(collision, offsetMatrix, min, max);
}
NewtonDestroyCollision(collision);
}
else // Sinon on utilise une instance au hasard (elles sont toutes identiques de toute façon)
NewtonCollisionCalculateAABB(m_handles.begin()->second, offsetMatrix, min, max);
return NzBoxf(scale * min, scale * max);
}
NzBoxf NzBaseGeom::ComputeAABB(const NzMatrix4f& offsetMatrix) const
{
NzVector3f min, max;
NewtonCollisionCalculateAABB(m_collision, offsetMatrix, min, max);
return NzBoxf(min, max);
}
void NzBaseGeom::ComputeInertialMatrix(NzVector3f* inertia, NzVector3f* center) const
void NzPhysGeom::ComputeInertialMatrix(NzVector3f* inertia, NzVector3f* center) const
{
float inertiaMatrix[3];
float origin[3];
NewtonConvexCollisionCalculateInertialMatrix(m_collision, inertiaMatrix, origin);
// Si nous n'avons aucune instance, nous en créons une temporaire
if (m_handles.empty())
{
NzPhysWorld world;
NewtonCollision* collision = CreateHandle(&world);
{
NewtonConvexCollisionCalculateInertialMatrix(collision, inertiaMatrix, origin);
}
NewtonDestroyCollision(collision);
}
else // Sinon on utilise une instance au hasard (elles sont toutes identiques de toute façon)
NewtonConvexCollisionCalculateInertialMatrix(m_handles.begin()->second, inertiaMatrix, origin);
if (inertia)
inertia->Set(inertiaMatrix);
@ -74,22 +91,37 @@ void NzBaseGeom::ComputeInertialMatrix(NzVector3f* inertia, NzVector3f* center)
center->Set(origin);
}
float NzBaseGeom::ComputeVolume() const
float NzPhysGeom::ComputeVolume() const
{
return NewtonConvexCollisionCalculateVolume(m_collision);
float volume;
// Si nous n'avons aucune instance, nous en créons une temporaire
if (m_handles.empty())
{
NzPhysWorld world;
NewtonCollision* collision = CreateHandle(&world);
{
volume = NewtonConvexCollisionCalculateVolume(collision);
}
NewtonDestroyCollision(collision);
}
else // Sinon on utilise une instance au hasard (elles sont toutes identiques de toute façon)
volume = NewtonConvexCollisionCalculateVolume(m_handles.begin()->second);
return volume;
}
NewtonCollision* NzBaseGeom::GetHandle() const
NewtonCollision* NzPhysGeom::GetHandle(NzPhysWorld* world) const
{
return m_collision;
auto it = m_handles.find(world);
if (it == m_handles.end())
it = m_handles.insert(std::make_pair(world, CreateHandle(world))).first;
return it->second;
}
NzPhysWorld* NzBaseGeom::GetWorld() const
{
return m_world;
}
NzBaseGeom* NzBaseGeom::Build(NzPhysWorld* physWorld, const NzPrimitiveList& list)
NzPhysGeomRef NzPhysGeom::Build(const NzPrimitiveList& list)
{
unsigned int primitiveCount = list.GetSize();
@ -103,31 +135,48 @@ NzBaseGeom* NzBaseGeom::Build(NzPhysWorld* physWorld, const NzPrimitiveList& lis
if (primitiveCount > 1)
{
std::vector<NzBaseGeom*> geoms(primitiveCount);
std::vector<NzPhysGeom*> geoms(primitiveCount);
for (unsigned int i = 0; i < primitiveCount; ++i)
geoms[i] = CreateGeomFromPrimitive(physWorld, list.GetPrimitive(i));
geoms[i] = CreateGeomFromPrimitive(list.GetPrimitive(i));
return new NzCompoundGeom(physWorld, &geoms[0], primitiveCount);
return NzCompoundGeom::New(&geoms[0], primitiveCount);
}
else
return CreateGeomFromPrimitive(physWorld, list.GetPrimitive(0));
return CreateGeomFromPrimitive(list.GetPrimitive(0));
}
NzPhysGeomLibrary::LibraryMap NzPhysGeom::s_library;
/********************************** BoxGeom **********************************/
NzBoxGeom::NzBoxGeom(NzPhysWorld* physWorld, const NzVector3f& lengths, const NzMatrix4f& transformMatrix) :
NzBaseGeom(physWorld),
NzBoxGeom::NzBoxGeom(const NzVector3f& lengths, const NzMatrix4f& transformMatrix) :
m_matrix(transformMatrix),
m_lengths(lengths)
{
m_collision = NewtonCreateBox(physWorld->GetHandle(), lengths.x, lengths.y, lengths.z, 0, transformMatrix);
}
NzBoxGeom::NzBoxGeom(NzPhysWorld* physWorld, const NzVector3f& lengths, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzBoxGeom(physWorld, lengths, NzMatrix4f::Transform(translation, rotation))
NzBoxGeom::NzBoxGeom(const NzVector3f& lengths, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzBoxGeom(lengths, NzMatrix4f::Transform(translation, rotation))
{
}
NzBoxf NzBoxGeom::ComputeAABB(const NzMatrix4f& offsetMatrix, const NzVector3f& scale) const
{
NzVector3f halfLengths(m_lengths * 0.5f);
NzBoxf aabb(-halfLengths.x, -halfLengths.y, -halfLengths.z, m_lengths.x, m_lengths.y, m_lengths.z);
aabb.Transform(offsetMatrix, true);
aabb *= scale;
return aabb;
}
float NzBoxGeom::ComputeVolume() const
{
return m_lengths.x * m_lengths.y * m_lengths.z;
}
NzVector3f NzBoxGeom::GetLengths() const
{
return m_lengths;
@ -138,18 +187,22 @@ nzGeomType NzBoxGeom::GetType() const
return nzGeomType_Box;
}
NewtonCollision* NzBoxGeom::CreateHandle(NzPhysWorld* world) const
{
return NewtonCreateBox(world->GetHandle(), m_lengths.x, m_lengths.y, m_lengths.z, 0, m_matrix);
}
/******************************** CapsuleGeom ********************************/
NzCapsuleGeom::NzCapsuleGeom(NzPhysWorld* physWorld, float length, float radius, const NzMatrix4f& transformMatrix) :
NzBaseGeom(physWorld),
NzCapsuleGeom::NzCapsuleGeom(float length, float radius, const NzMatrix4f& transformMatrix) :
m_matrix(transformMatrix),
m_length(length),
m_radius(radius)
{
m_collision = NewtonCreateCapsule(physWorld->GetHandle(), radius, length, 0, transformMatrix);
}
NzCapsuleGeom::NzCapsuleGeom(NzPhysWorld* physWorld, float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzCapsuleGeom(physWorld, length, radius, NzMatrix4f::Transform(translation, rotation))
NzCapsuleGeom::NzCapsuleGeom(float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzCapsuleGeom(length, radius, NzMatrix4f::Transform(translation, rotation))
{
}
@ -168,23 +221,23 @@ nzGeomType NzCapsuleGeom::GetType() const
return nzGeomType_Capsule;
}
/******************************* CompoundGeom ********************************/
NzCompoundGeom::NzCompoundGeom(NzPhysWorld* physWorld, NzBaseGeom** geoms, unsigned int geomCount) :
NzBaseGeom(physWorld)
NewtonCollision* NzCapsuleGeom::CreateHandle(NzPhysWorld* world) const
{
m_collision = NewtonCreateCompoundCollision(physWorld->GetHandle(), 0);
NewtonCompoundCollisionBeginAddRemove(m_collision);
for (unsigned int i = 0; i < geomCount; ++i)
{
if (geoms[i]->GetType() == nzGeomType_Compound)
NazaraError("Cannot add compound geoms to other compound geoms");
else
NewtonCompoundCollisionAddSubCollision(m_collision, geoms[i]->GetHandle());
return NewtonCreateCapsule(world->GetHandle(), m_radius, m_length, 0, m_matrix);
}
NewtonCompoundCollisionEndAddRemove(m_collision);
/******************************* CompoundGeom ********************************/
NzCompoundGeom::NzCompoundGeom(NzPhysGeom** geoms, unsigned int geomCount)
{
m_geoms.reserve(geomCount);
for (unsigned int i = 0; i < geomCount; ++i)
m_geoms.emplace_back(geoms[i]);
}
const std::vector<NzPhysGeomRef>& NzCompoundGeom::GetGeoms() const
{
return m_geoms;
}
nzGeomType NzCompoundGeom::GetType() const
@ -192,18 +245,38 @@ nzGeomType NzCompoundGeom::GetType() const
return nzGeomType_Compound;
}
NewtonCollision* NzCompoundGeom::CreateHandle(NzPhysWorld* world) const
{
NewtonCollision* compoundCollision = NewtonCreateCompoundCollision(world->GetHandle(), 0);
NewtonCompoundCollisionBeginAddRemove(compoundCollision);
for (const NzPhysGeomRef& geom : m_geoms)
{
if (geom->GetType() == nzGeomType_Compound)
{
NzCompoundGeom* compoundGeom = static_cast<NzCompoundGeom*>(geom.Get());
for (const NzPhysGeomRef& piece : compoundGeom->GetGeoms())
NewtonCompoundCollisionAddSubCollision(compoundCollision, piece->GetHandle(world));
}
else
NewtonCompoundCollisionAddSubCollision(compoundCollision, geom->GetHandle(world));
}
NewtonCompoundCollisionEndAddRemove(compoundCollision);
return compoundCollision;
}
/********************************* ConeGeom **********************************/
NzConeGeom::NzConeGeom(NzPhysWorld* physWorld, float length, float radius, const NzMatrix4f& transformMatrix) :
NzBaseGeom(physWorld),
NzConeGeom::NzConeGeom(float length, float radius, const NzMatrix4f& transformMatrix) :
m_matrix(transformMatrix),
m_length(length),
m_radius(radius)
{
m_collision = NewtonCreateCone(physWorld->GetHandle(), radius, length, 0, transformMatrix);
}
NzConeGeom::NzConeGeom(NzPhysWorld* physWorld, float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzConeGeom(physWorld, length, radius, NzMatrix4f::Transform(translation, rotation))
NzConeGeom::NzConeGeom(float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzConeGeom(length, radius, NzMatrix4f::Transform(translation, rotation))
{
}
@ -222,16 +295,32 @@ nzGeomType NzConeGeom::GetType() const
return nzGeomType_Cone;
}
/****************************** ConvexHullGeom *******************************/
NzConvexHullGeom::NzConvexHullGeom(NzPhysWorld* physWorld, const void* vertices, unsigned int vertexCount, unsigned int stride, float tolerance, const NzMatrix4f& transformMatrix) :
NzBaseGeom(physWorld)
NewtonCollision* NzConeGeom::CreateHandle(NzPhysWorld* world) const
{
m_collision = NewtonCreateConvexHull(physWorld->GetHandle(), vertexCount, reinterpret_cast<const float*>(vertices), stride, tolerance, 0, transformMatrix);
return NewtonCreateCone(world->GetHandle(), m_radius, m_length, 0, m_matrix);
}
NzConvexHullGeom::NzConvexHullGeom(NzPhysWorld* physWorld, const void* vertices, unsigned int vertexCount, unsigned int stride, float tolerance, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzConvexHullGeom(physWorld, vertices, vertexCount, stride, tolerance, NzMatrix4f::Transform(translation, rotation))
/****************************** ConvexHullGeom *******************************/
NzConvexHullGeom::NzConvexHullGeom(const void* vertices, unsigned int vertexCount, unsigned int stride, float tolerance, const NzMatrix4f& transformMatrix) :
m_matrix(transformMatrix),
m_tolerance(tolerance),
m_vertexStride(stride)
{
const nzUInt8* ptr = static_cast<const nzUInt8*>(vertices);
m_vertices.resize(vertexCount);
if (stride != sizeof(NzVector3f))
{
for (unsigned int i = 0; i < vertexCount; ++i)
m_vertices[i] = *reinterpret_cast<const NzVector3f*>(ptr + stride*i);
}
else // Fast path
std::memcpy(m_vertices.data(), vertices, vertexCount*sizeof(NzVector3f));
}
NzConvexHullGeom::NzConvexHullGeom(const void* vertices, unsigned int vertexCount, unsigned int stride, float tolerance, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzConvexHullGeom(vertices, vertexCount, stride, tolerance, NzMatrix4f::Transform(translation, rotation))
{
}
@ -240,18 +329,22 @@ nzGeomType NzConvexHullGeom::GetType() const
return nzGeomType_Compound;
}
NewtonCollision* NzConvexHullGeom::CreateHandle(NzPhysWorld* world) const
{
return NewtonCreateConvexHull(world->GetHandle(), m_vertices.size(), reinterpret_cast<const float*>(m_vertices.data()), sizeof(NzVector3f), m_tolerance, 0, m_matrix);
}
/******************************* CylinderGeom ********************************/
NzCylinderGeom::NzCylinderGeom(NzPhysWorld* physWorld, float length, float radius, const NzMatrix4f& transformMatrix) :
NzBaseGeom(physWorld),
NzCylinderGeom::NzCylinderGeom(float length, float radius, const NzMatrix4f& transformMatrix) :
m_matrix(transformMatrix),
m_length(length),
m_radius(radius)
{
m_collision = NewtonCreateCylinder(physWorld->GetHandle(), radius, length, 0, transformMatrix);
}
NzCylinderGeom::NzCylinderGeom(NzPhysWorld* physWorld, float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzCylinderGeom(physWorld, length, radius, NzMatrix4f::Transform(translation, rotation))
NzCylinderGeom::NzCylinderGeom(float length, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzCylinderGeom(length, radius, NzMatrix4f::Transform(translation, rotation))
{
}
@ -270,12 +363,15 @@ nzGeomType NzCylinderGeom::GetType() const
return nzGeomType_Cylinder;
}
NewtonCollision* NzCylinderGeom::CreateHandle(NzPhysWorld* world) const
{
return NewtonCreateCylinder(world->GetHandle(), m_radius, m_length, 0, m_matrix);
}
/********************************* NullGeom **********************************/
NzNullGeom::NzNullGeom(NzPhysWorld* physWorld) :
NzBaseGeom(physWorld)
NzNullGeom::NzNullGeom()
{
m_collision = NewtonCreateNull(physWorld->GetHandle());
}
nzGeomType NzNullGeom::GetType() const
@ -283,21 +379,39 @@ nzGeomType NzNullGeom::GetType() const
return nzGeomType_Null;
}
NewtonCollision* NzNullGeom::CreateHandle(NzPhysWorld* world) const
{
return NewtonCreateNull(world->GetHandle());
}
/******************************** SphereGeom *********************************/
NzSphereGeom::NzSphereGeom(NzPhysWorld* physWorld, float radius, const NzMatrix4f& transformMatrix) :
NzBaseGeom(physWorld),
NzSphereGeom::NzSphereGeom(float radius, const NzMatrix4f& transformMatrix) :
NzSphereGeom(radius, transformMatrix.GetTranslation())
{
}
NzSphereGeom::NzSphereGeom(float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
m_position(translation),
m_radius(radius)
{
m_collision = NewtonCreateSphere(physWorld->GetHandle(), radius, 0, transformMatrix);
NazaraUnused(rotation);
}
NzSphereGeom::NzSphereGeom(NzPhysWorld* physWorld, float radius, const NzVector3f& translation, const NzQuaternionf& rotation) :
NzSphereGeom(physWorld, radius, NzMatrix4f::Transform(translation, rotation))
NzBoxf NzSphereGeom::ComputeAABB(const NzMatrix4f& offsetMatrix, const NzVector3f& scale) const
{
NzVector3f size(m_radius * scale);
NzVector3f position(offsetMatrix.GetTranslation());
return NzBoxf(position - size, position + size);
}
NzVector3f NzSphereGeom::GetRadius() const
float NzSphereGeom::ComputeVolume() const
{
return M_PI * m_radius * m_radius * m_radius / 3.f;
}
float NzSphereGeom::GetRadius() const
{
return m_radius;
}
@ -306,3 +420,8 @@ nzGeomType NzSphereGeom::GetType() const
{
return nzGeomType_Sphere;
}
NewtonCollision* NzSphereGeom::CreateHandle(NzPhysWorld* world) const
{
return NewtonCreateSphere(world->GetHandle(), m_radius, 0, NzMatrix4f::Translate(m_position));
}

View File

@ -3,56 +3,70 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Physics/PhysObject.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <Nazara/Physics/Config.hpp>
#include <Nazara/Physics/Geom.hpp>
#include <Nazara/Physics/PhysWorld.hpp>
#include <Newton/Newton.h>
#include <algorithm>
#include <Nazara/Physics/Debug.hpp>
NzPhysObject::NzPhysObject(NzPhysWorld* world, const NzMatrix4f& mat) :
NzPhysObject(world, NzNullGeom::New(), mat)
{
}
NzPhysObject::NzPhysObject(NzPhysWorld* world, NzPhysGeomRef geom, const NzMatrix4f& mat) :
m_matrix(mat),
m_geom(std::move(geom)),
m_forceAccumulator(NzVector3f::Zero()),
m_torqueAccumulator(NzVector3f::Zero()),
m_world(world),
m_ownsGeom(true),
m_gravityFactor(1.f),
m_mass(0.f)
{
#if NAZARA_PHYSICS_SAFE
if (!world)
NazaraError("Invalid physics world"); ///TODO: Unexcepted
#endif
NazaraAssert(m_world, "Invalid world");
m_geom = new NzNullGeom(world);
m_body = NewtonCreateDynamicBody(world->GetHandle(), m_geom->GetHandle(), mat);
if (!m_geom)
m_geom = NzNullGeom::New();
m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix);
NewtonBodySetUserData(m_body, this);
}
NzPhysObject::NzPhysObject(NzPhysWorld* world, const NzBaseGeom* geom, const NzMatrix4f& mat) :
m_matrix(mat),
NzPhysObject::NzPhysObject(const NzPhysObject& object) :
m_matrix(object.m_matrix),
m_geom(object.m_geom),
m_forceAccumulator(NzVector3f::Zero()),
m_torqueAccumulator(NzVector3f::Zero()),
m_geom(geom),
m_world(world),
m_ownsGeom(false),
m_gravityFactor(1.f),
m_world(object.m_world),
m_gravityFactor(object.m_gravityFactor),
m_mass(0.f)
{
#if NAZARA_PHYSICS_SAFE
if (!world)
NazaraError("Invalid physics world"); ///TODO: Unexcepted
#endif
NazaraAssert(m_world, "Invalid world");
NazaraAssert(m_geom, "Invalid geometry");
m_body = NewtonCreateDynamicBody(world->GetHandle(), geom->GetHandle(), mat);
m_body = NewtonCreateDynamicBody(m_world->GetHandle(), m_geom->GetHandle(m_world), m_matrix);
NewtonBodySetUserData(m_body, this);
SetMass(object.m_mass);
}
NzPhysObject::NzPhysObject(NzPhysObject&& object) :
m_matrix(std::move(object.m_matrix)),
m_forceAccumulator(std::move(object.m_forceAccumulator)),
m_torqueAccumulator(std::move(object.m_torqueAccumulator)),
m_body(object.m_body),
m_geom(std::move(object.m_geom)),
m_world(object.m_world),
m_gravityFactor(object.m_gravityFactor),
m_mass(object.m_mass)
{
object.m_body = nullptr;
}
NzPhysObject::~NzPhysObject()
{
if (m_body)
NewtonDestroyBody(m_world->GetHandle(), m_body);
if (m_ownsGeom)
delete m_geom;
}
void NzPhysObject::AddForce(const NzVector3f& force, nzCoordSys coordSys)
@ -82,8 +96,7 @@ void NzPhysObject::AddForce(const NzVector3f& force, const NzVector3f& point, nz
break;
case nzCoordSys_Local:
AddForce(m_matrix.Transform(force, 0.f), m_matrix.Transform(point));
return;
return AddForce(m_matrix.Transform(force, 0.f), m_matrix.Transform(point), nzCoordSys_Global);
}
// On réveille le corps pour que le callback soit appelé et que les forces soient appliquées
@ -112,6 +125,14 @@ void NzPhysObject::EnableAutoSleep(bool autoSleep)
NewtonBodySetAutoSleep(m_body, autoSleep);
}
NzBoxf NzPhysObject::GetAABB() const
{
NzVector3f min, max;
NewtonBodyGetAABB(m_body, min, max);
return NzBoxf(min, max);
}
NzVector3f NzPhysObject::GetAngularVelocity() const
{
NzVector3f angularVelocity;
@ -120,6 +141,11 @@ NzVector3f NzPhysObject::GetAngularVelocity() const
return angularVelocity;
}
const NzPhysGeomRef& NzPhysObject::GetGeom() const
{
return m_geom;
}
float NzPhysObject::GetGravityFactor() const
{
return m_gravityFactor;
@ -191,6 +217,24 @@ bool NzPhysObject::IsSleeping() const
return NewtonBodyGetSleepState(m_body) != 0;
}
void NzPhysObject::SetAngularVelocity(const NzVector3f& angularVelocity)
{
NewtonBodySetOmega(m_body, angularVelocity);
}
void NzPhysObject::SetGeom(NzPhysGeomRef geom)
{
if (m_geom.Get() != geom)
{
if (geom)
m_geom = geom;
else
m_geom = NzNullGeom::New();
NewtonBodySetCollision(m_body, m_geom->GetHandle(m_world));
}
}
void NzPhysObject::SetGravityFactor(float gravityFactor)
{
m_gravityFactor = gravityFactor;
@ -237,13 +281,56 @@ void NzPhysObject::SetRotation(const NzQuaternionf& rotation)
UpdateBody();
}
void NzPhysObject::SetVelocity(const NzVector3f& velocity)
{
NewtonBodySetVelocity(m_body, velocity);
}
NzPhysObject& NzPhysObject::operator=(const NzPhysObject& object)
{
NzPhysObject physObj(object);
return operator=(std::move(physObj));
}
void NzPhysObject::UpdateBody()
{
NewtonBodySetMatrix(m_body, m_matrix);
if (NzNumberEquals(m_mass, 0.f))
{
// http://newtondynamics.com/wiki/index.php5?title=Can_i_dynamicly_move_a_TriMesh%3F
NzVector3f min, max;
NewtonBodyGetAABB(m_body, min, max);
NewtonWorldForEachBodyInAABBDo(m_world->GetHandle(), min, max, [](const NewtonBody* const body, void* const userData)
{
NazaraUnused(userData);
NewtonBodySetSleepState(body, 0);
}, nullptr);
}
/*for (std::set<PhysObjectListener*>::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
(*it)->PhysObjectOnUpdate(this);*/
}
NzPhysObject& NzPhysObject::operator=(NzPhysObject&& object)
{
if (m_body)
NewtonDestroyBody(m_world->GetHandle(), m_body);
m_body = object.m_body;
m_forceAccumulator = std::move(object.m_forceAccumulator);
m_geom = std::move(object.m_geom);
m_gravityFactor = object.m_gravityFactor;
m_mass = object.m_mass;
m_matrix = std::move(object.m_matrix);
m_torqueAccumulator = std::move(object.m_torqueAccumulator);
m_world = object.m_world;
object.m_body = nullptr;
return *this;
}
void NzPhysObject::ForceAndTorqueCallback(const NewtonBody* body, float timeStep, int threadIndex)
{
NazaraUnused(timeStep);