diff --git a/SDK/include/NDK/Algorithm.hpp b/SDK/include/NDK/Algorithm.hpp index c98e63c6c..ece1d5d37 100644 --- a/SDK/include/NDK/Algorithm.hpp +++ b/SDK/include/NDK/Algorithm.hpp @@ -16,6 +16,8 @@ namespace Ndk template constexpr SystemIndex GetSystemIndex(); template ComponentIndex InitializeComponent(const char (&name)[N]); template SystemIndex InitializeSystem(); + template bool IsComponent(C& component); + template bool IsSystem(S& system); } #include diff --git a/SDK/include/NDK/Algorithm.inl b/SDK/include/NDK/Algorithm.inl index 2f2586868..e79e3a901 100644 --- a/SDK/include/NDK/Algorithm.inl +++ b/SDK/include/NDK/Algorithm.inl @@ -44,4 +44,16 @@ namespace Ndk SystemType::systemIndex = SystemType::RegisterSystem(); return SystemType::systemIndex; } + + template + bool IsComponent(C& component) + { + return component.GetIndex() == GetComponentIndex(); + } + + template + bool IsSystem(S& system) + { + return system.GetIndex() == GetSystemIndex(); + } } diff --git a/SDK/include/NDK/BaseComponent.hpp b/SDK/include/NDK/BaseComponent.hpp index 53a6121ec..4e9b53328 100644 --- a/SDK/include/NDK/BaseComponent.hpp +++ b/SDK/include/NDK/BaseComponent.hpp @@ -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(); diff --git a/SDK/include/NDK/BaseComponent.inl b/SDK/include/NDK/BaseComponent.inl index 0ac1678e0..b8637b457 100644 --- a/SDK/include/NDK/BaseComponent.inl +++ b/SDK/include/NDK/BaseComponent.inl @@ -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 diff --git a/SDK/include/NDK/BaseSystem.hpp b/SDK/include/NDK/BaseSystem.hpp index 9204f0fe0..2e8201c80 100644 --- a/SDK/include/NDK/BaseSystem.hpp +++ b/SDK/include/NDK/BaseSystem.hpp @@ -51,16 +51,23 @@ namespace Ndk template void Requires(); void RequiresComponent(ComponentIndex index); + template void RequiresAny(); + template 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 m_entityBits; NzBitset<> m_excludedComponents; mutable NzBitset<> m_filterResult; + NzBitset<> m_requiredAnyComponents; NzBitset<> m_requiredComponents; SystemIndex m_systemIndex; World* m_world; diff --git a/SDK/include/NDK/BaseSystem.inl b/SDK/include/NDK/BaseSystem.inl index 7c688138b..fec06ef9a 100644 --- a/SDK/include/NDK/BaseSystem.inl +++ b/SDK/include/NDK/BaseSystem.inl @@ -87,11 +87,31 @@ namespace Ndk m_requiredComponents.UnboundedSet(index); } + template + void BaseSystem::RequiresAny() + { + static_assert(std::is_base_of(), "ComponentType is not a component"); + + RequiresAnyComponent(GetComponentIndex()); + } + + template + void BaseSystem::RequiresAny() + { + RequiresAny(); + RequiresAny(); + } + + 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 } - } diff --git a/SDK/include/NDK/Component.inl b/SDK/include/NDK/Component.inl index 4715e8d7d..b016fd8be 100644 --- a/SDK/include/NDK/Component.inl +++ b/SDK/include/NDK/Component.inl @@ -20,7 +20,7 @@ namespace Ndk BaseComponent* Component::Clone() const { ///FIXME: Pas encore supporté par GCC (4.9.2) - //static_assert(std::is_trivially_copy_constructible::value, "ComponentType should be copy-constructible"); + //static_assert(std::is_trivially_copy_constructible::value, "ComponentType must be copy-constructible"); return new ComponentType(static_cast(*this)); } @@ -29,7 +29,7 @@ namespace Ndk ComponentIndex Component::RegisterComponent(ComponentId id) { // Il faut que notre composant possède un constructeur par défaut (pour la factory) - static_assert(std::is_default_constructible::value, "ComponentType should be default-constructible"); + static_assert(std::is_default_constructible::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); } diff --git a/SDK/include/NDK/Components/CollisionComponent.hpp b/SDK/include/NDK/Components/CollisionComponent.hpp new file mode 100644 index 000000000..c421f127a --- /dev/null +++ b/SDK/include/NDK/Components/CollisionComponent.hpp @@ -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 +#include +#include + +class NzPhysObject; + +namespace Ndk +{ + class Entity; + + class NDK_API CollisionComponent : public Component + { + 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 m_staticBody; + NzPhysGeomRef m_geom; + bool m_bodyUpdated; + }; +} + +#include + +#endif // NDK_COMPONENTS_COLLISIONCOMPONENT_HPP diff --git a/SDK/include/NDK/Components/CollisionComponent.inl b/SDK/include/NDK/Components/CollisionComponent.inl new file mode 100644 index 000000000..2f748c1d6 --- /dev/null +++ b/SDK/include/NDK/Components/CollisionComponent.inl @@ -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 +#include +#include +#include + +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(); + } +} diff --git a/SDK/include/NDK/Components/PhysicsComponent.hpp b/SDK/include/NDK/Components/PhysicsComponent.hpp new file mode 100644 index 000000000..4385735f9 --- /dev/null +++ b/SDK/include/NDK/Components/PhysicsComponent.hpp @@ -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 +#include +#include + +namespace Ndk +{ + class Entity; + + class NDK_API PhysicsComponent : public Component + { + 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 m_object; + }; +} + +#include + +#endif // NDK_COMPONENTS_PHYSICSCOMPONENT_HPP diff --git a/SDK/include/NDK/Components/PhysicsComponent.inl b/SDK/include/NDK/Components/PhysicsComponent.inl new file mode 100644 index 000000000..fec47f8f5 --- /dev/null +++ b/SDK/include/NDK/Components/PhysicsComponent.inl @@ -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 + +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(); + } +} diff --git a/SDK/include/NDK/Entity.inl b/SDK/include/NDK/Entity.inl index 72936bee9..c3935b0bf 100644 --- a/SDK/include/NDK/Entity.inl +++ b/SDK/include/NDK/Entity.inl @@ -80,6 +80,11 @@ namespace Ndk return HasComponent(index); } + inline bool Entity::IsValid() const + { + return m_valid; + } + template void Entity::RemoveComponent() { diff --git a/SDK/include/NDK/EntityList.hpp b/SDK/include/NDK/EntityList.hpp new file mode 100644 index 000000000..753189580 --- /dev/null +++ b/SDK/include/NDK/EntityList.hpp @@ -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 +#include +#include + +namespace Ndk +{ + class NDK_API EntityList + { + public: + using Container = std::vector; + + 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 m_entities; + NzBitset m_entityBits; + }; +} + +#include + +#endif // NDK_ENTITYLIST_HPP diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl new file mode 100644 index 000000000..e7cd2bb3b --- /dev/null +++ b/SDK/include/NDK/EntityList.inl @@ -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 +#include + +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(); + } +} diff --git a/SDK/include/NDK/Systems/PhysicsSystem.hpp b/SDK/include/NDK/Systems/PhysicsSystem.hpp new file mode 100644 index 000000000..227ee1f9d --- /dev/null +++ b/SDK/include/NDK/Systems/PhysicsSystem.hpp @@ -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 +#include +#include + +namespace Ndk +{ + class NDK_API PhysicsSystem : public System + { + 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 + +#endif // NDK_SYSTEMS_PHYSICSSYSTEM_HPP diff --git a/SDK/include/NDK/Systems/PhysicsSystem.inl b/SDK/include/NDK/Systems/PhysicsSystem.inl new file mode 100644 index 000000000..78d396282 --- /dev/null +++ b/SDK/include/NDK/Systems/PhysicsSystem.inl @@ -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; + } +} diff --git a/SDK/src/NDK/BaseComponent.cpp b/SDK/src/NDK/BaseComponent.cpp index 3c90cef21..1a0b85168 100644 --- a/SDK/src/NDK/BaseComponent.cpp +++ b/SDK/src/NDK/BaseComponent.cpp @@ -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::s_entries; std::unordered_map BaseComponent::s_idToIndex; } diff --git a/SDK/src/NDK/BaseSystem.cpp b/SDK/src/NDK/BaseSystem.cpp index 6c60f435c..5aa9aac30 100644 --- a/SDK/src/NDK/BaseSystem.cpp +++ b/SDK/src/NDK/BaseSystem.cpp @@ -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; } diff --git a/SDK/src/NDK/Components/CollisionComponent.cpp b/SDK/src/NDK/Components/CollisionComponent.cpp new file mode 100644 index 000000000..929b087eb --- /dev/null +++ b/SDK/src/NDK/Components/CollisionComponent.cpp @@ -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 +#include +#include +#include +#include +#include + +namespace Ndk +{ + void CollisionComponent::SetGeom(NzPhysGeomRef geom) + { + m_geom = std::move(geom); + + if (m_entity->HasComponent()) + { + // On met à jour la géométrie du PhysObject associé au PhysicsComponent + PhysicsComponent& physComponent = m_entity->GetComponent(); + 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(), "World must have a physics system"); + NzPhysWorld& physWorld = entityWorld->GetSystem().GetWorld(); + + m_staticBody.reset(new NzPhysObject(&physWorld, m_geom)); + m_staticBody->EnableAutoSleep(false); + } + + void CollisionComponent::OnAttached() + { + if (!m_entity->HasComponent()) + InitializeStaticBody(); + } + + void CollisionComponent::OnComponentAttached(BaseComponent& component) + { + if (IsComponent(component)) + m_staticBody.reset(); + } + + void CollisionComponent::OnComponentDetached(BaseComponent& component) + { + if (IsComponent(component)) + InitializeStaticBody(); + } + + void CollisionComponent::OnDetached() + { + m_staticBody.reset(); + } + + ComponentIndex CollisionComponent::componentIndex; +} diff --git a/SDK/src/NDK/Components/PhysicsComponent.cpp b/SDK/src/NDK/Components/PhysicsComponent.cpp new file mode 100644 index 000000000..6c70dbff7 --- /dev/null +++ b/SDK/src/NDK/Components/PhysicsComponent.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + void PhysicsComponent::OnAttached() + { + World* entityWorld = m_entity->GetWorld(); + NazaraAssert(entityWorld->HasSystem(), "World must have a physics system"); + + NzPhysWorld& world = entityWorld->GetSystem().GetWorld(); + + NzPhysGeomRef geom; + if (m_entity->HasComponent()) + geom = m_entity->GetComponent().GetGeom(); + + NzMatrix4f matrix; + if (m_entity->HasComponent()) + matrix = m_entity->GetComponent().GetTransformMatrix(); + else + matrix.MakeIdentity(); + + m_object.reset(new NzPhysObject(&world, geom, matrix)); + m_object->SetMass(1.f); + } + + void PhysicsComponent::OnComponentAttached(BaseComponent& component) + { + if (IsComponent(component)) + { + NazaraAssert(m_object, "Invalid object"); + m_object->SetGeom(static_cast(component).GetGeom()); + } + } + + void PhysicsComponent::OnComponentDetached(BaseComponent& component) + { + if (IsComponent(component)) + { + NazaraAssert(m_object, "Invalid object"); + m_object->SetGeom(NzNullGeom::New()); + } + } + + void PhysicsComponent::OnDetached() + { + m_object.reset(); + } + + ComponentIndex PhysicsComponent::componentIndex; +} diff --git a/SDK/src/NDK/Entity.cpp b/SDK/src/NDK/Entity.cpp index f7074c9b8..e6bd09ce0 100644 --- a/SDK/src/NDK/Entity.cpp +++ b/SDK/src/NDK/Entity.cpp @@ -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&& component) + BaseComponent& Entity::AddComponent(std::unique_ptr&& 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); diff --git a/SDK/src/NDK/Sdk.cpp b/SDK/src/NDK/Sdk.cpp index 6d2bff6d4..456332a88 100644 --- a/SDK/src/NDK/Sdk.cpp +++ b/SDK/src/NDK/Sdk.cpp @@ -13,10 +13,13 @@ #include #include #include +#include #include #include +#include #include #include +#include #include namespace Ndk @@ -49,12 +52,15 @@ namespace Ndk BaseSystem::Initialize(); // Composants + InitializeComponent("NdkColli"); InitializeComponent("NdkList"); InitializeComponent("NdkNode"); + InitializeComponent("NdkPhys"); InitializeComponent("NdkVeloc"); // Systèmes InitializeSystem(); + InitializeSystem(); InitializeSystem(); NazaraNotice("Initialized: SDK"); diff --git a/SDK/src/NDK/Systems/ListenerSystem.cpp b/SDK/src/NDK/Systems/ListenerSystem.cpp index e7a90c5a9..d7cede524 100644 --- a/SDK/src/NDK/Systems/ListenerSystem.cpp +++ b/SDK/src/NDK/Systems/ListenerSystem.cpp @@ -6,6 +6,7 @@ #include #include #include +#include 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(); 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()) + { + const VelocityComponent& velocity = entity->GetComponent(); + NzAudio::SetListenerVelocity(velocity.linearVelocity); + } + activeListenerCount++; } diff --git a/SDK/src/NDK/Systems/PhysicsSystem.cpp b/SDK/src/NDK/Systems/PhysicsSystem.cpp new file mode 100644 index 000000000..a54c776a2 --- /dev/null +++ b/SDK/src/NDK/Systems/PhysicsSystem.cpp @@ -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 +#include +#include +#include +#include + +namespace Ndk +{ + PhysicsSystem::PhysicsSystem() + { + Requires(); + RequiresAny(); + } + + 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(); + PhysicsComponent& phys = entity->GetComponent(); + + 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(); + NodeComponent& node = entity->GetComponent(); + + 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()) ? m_staticObjects : m_dynamicObjects; + entities.Remove(entity); + } + + auto& entities = (entity->HasComponent()) ? m_dynamicObjects : m_staticObjects; + entities.Insert(entity); + } + + SystemIndex PhysicsSystem::systemIndex; +} diff --git a/SDK/src/NDK/Systems/VelocitySystem.cpp b/SDK/src/NDK/Systems/VelocitySystem.cpp index 415889e20..a3968a053 100644 --- a/SDK/src/NDK/Systems/VelocitySystem.cpp +++ b/SDK/src/NDK/Systems/VelocitySystem.cpp @@ -4,6 +4,7 @@ #include #include +#include #include namespace Ndk @@ -11,6 +12,7 @@ namespace Ndk VelocitySystem::VelocitySystem() { Requires(); + Excludes(); } void VelocitySystem::Update(float elapsedTime) diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index c1a91fa10..98d75e6f3 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace Ndk @@ -18,6 +19,7 @@ namespace Ndk void World::AddDefaultSystems() { AddSystem(); + AddSystem(); AddSystem(); } @@ -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 + // 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 + { + // Elle ne doit pas en faire partie, si elle en faisait partie nous devons la retirer if (partOfSystem) - system->RemoveEntity(&entity); - else - system->AddEntity(&entity); + system->RemoveEntity(entity); } } } diff --git a/include/Nazara/Core/Bitset.hpp b/include/Nazara/Core/Bitset.hpp index c359181cc..bc1df0e27 100644 --- a/include/Nazara/Core/Bitset.hpp +++ b/include/Nazara/Core/Bitset.hpp @@ -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 T To() const; NzString ToString() const; diff --git a/include/Nazara/Core/Bitset.inl b/include/Nazara/Core/Bitset.inl index bcd0187ff..a02c16550 100644 --- a/include/Nazara/Core/Bitset.inl +++ b/include/Nazara/Core/Bitset.inl @@ -309,7 +309,7 @@ bool NzBitset::Test(unsigned int bit) const } template -bool NzBitset::TestAll() +bool NzBitset::TestAll() const { // Cas particulier du dernier bloc Block lastBlockMask = GetLastBlockMask(); @@ -325,7 +325,7 @@ bool NzBitset::TestAll() } template -bool NzBitset::TestAny() +bool NzBitset::TestAny() const { if (m_blocks.empty()) return false; @@ -340,7 +340,7 @@ bool NzBitset::TestAny() } template -bool NzBitset::TestNone() +bool NzBitset::TestNone() const { return !TestAny(); } diff --git a/include/Nazara/Physics/Geom.hpp b/include/Nazara/Physics/Geom.hpp index 5c851ee30..81319d713 100644 --- a/include/Nazara/Physics/Geom.hpp +++ b/include/Nazara/Physics/Geom.hpp @@ -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 -#include #include +#include +#include +#include +#include +#include #include #include #include #include +#include ///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; +using NzPhysGeomConstRef = NzObjectRef; +using NzPhysGeomLibrary = NzObjectLibrary; +using NzPhysGeomListener = NzObjectListenerWrapper; +using NzPhysGeomRef = NzObjectRef; + +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 m_handles; + + static NzPhysGeomLibrary::LibraryMap s_library; }; -class NAZARA_API NzBoxGeom : public NzBaseGeom +class NzBoxGeom; + +using NzBoxGeomConstListener = NzObjectListenerWrapper; +using NzBoxGeomConstRef = NzObjectRef; +using NzBoxGeomListener = NzObjectListenerWrapper; +using NzBoxGeomRef = NzObjectRef; + +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 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; +using NzCapsuleGeomConstRef = NzObjectRef; +using NzCapsuleGeomListener = NzObjectListenerWrapper; +using NzCapsuleGeomRef = NzObjectRef; + +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 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; +using NzCompoundGeomConstRef = NzObjectRef; +using NzCompoundGeomListener = NzObjectListenerWrapper; +using NzCompoundGeomRef = NzObjectRef; + +class NAZARA_API NzCompoundGeom : public NzPhysGeom { public: - NzCompoundGeom(NzPhysWorld* physWorld, NzBaseGeom** geoms, unsigned int geomCount); + NzCompoundGeom(NzPhysGeom** geoms, unsigned int geomCount); + const std::vector& GetGeoms() const; nzGeomType GetType() const override; + + template static NzCompoundGeomRef New(Args&&... args); + + private: + NewtonCollision* CreateHandle(NzPhysWorld* world) const override; + + std::vector m_geoms; }; -class NAZARA_API NzConeGeom : public NzBaseGeom +class NzConeGeom; + +using NzConeGeomConstListener = NzObjectListenerWrapper; +using NzConeGeomConstRef = NzObjectRef; +using NzConeGeomListener = NzObjectListenerWrapper; +using NzConeGeomRef = NzObjectRef; + +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 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; +using NzConvexHullGeomConstRef = NzObjectRef; +using NzConvexHullGeomListener = NzObjectListenerWrapper; +using NzConvexHullGeomRef = NzObjectRef; + +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 static NzConvexHullGeomRef New(Args&&... args); + + private: + NewtonCollision* CreateHandle(NzPhysWorld* world) const override; + + std::vector m_vertices; + NzMatrix4f m_matrix; + float m_tolerance; + unsigned int m_vertexStride; }; -class NAZARA_API NzCylinderGeom : public NzBaseGeom +class NzCylinderGeom; + +using NzCylinderGeomConstListener = NzObjectListenerWrapper; +using NzCylinderGeomConstRef = NzObjectRef; +using NzCylinderGeomListener = NzObjectListenerWrapper; +using NzCylinderGeomRef = NzObjectRef; + +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 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; +using NzNullGeomConstRef = NzObjectRef; +using NzNullGeomListener = NzObjectListenerWrapper; +using NzNullGeomRef = NzObjectRef; + +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 static NzNullGeomRef New(Args&&... args); private: - NzVector3f m_radius; + NewtonCollision* CreateHandle(NzPhysWorld* world) const override; }; +class NzSphereGeom; + +using NzSphereGeomConstListener = NzObjectListenerWrapper; +using NzSphereGeomConstRef = NzObjectRef; +using NzSphereGeomListener = NzObjectListenerWrapper; +using NzSphereGeomRef = NzObjectRef; + +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 static NzSphereGeomRef New(Args&&... args); + + private: + NewtonCollision* CreateHandle(NzPhysWorld* world) const override; + + NzVector3f m_position; + float m_radius; +}; + +#include + #endif // NAZARA_PHYSWORLD_HPP diff --git a/include/Nazara/Physics/Geom.inl b/include/Nazara/Physics/Geom.inl new file mode 100644 index 000000000..6254feea8 --- /dev/null +++ b/include/Nazara/Physics/Geom.inl @@ -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 +#include + +template +NzBoxGeomRef NzBoxGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzBoxGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzCapsuleGeomRef NzCapsuleGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzCapsuleGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzCompoundGeomRef NzCompoundGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzCompoundGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzConeGeomRef NzConeGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzConeGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzConvexHullGeomRef NzConvexHullGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzConvexHullGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzCylinderGeomRef NzCylinderGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzCylinderGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzNullGeomRef NzNullGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzNullGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +template +NzSphereGeomRef NzSphereGeom::New(Args&&... args) +{ + std::unique_ptr object(new NzSphereGeom(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); +} + +#include diff --git a/include/Nazara/Physics/PhysObject.hpp b/include/Nazara/Physics/PhysObject.hpp index 10e0bece9..e2cf7f82e 100644 --- a/include/Nazara/Physics/PhysObject.hpp +++ b/include/Nazara/Physics/PhysObject.hpp @@ -13,16 +13,18 @@ #include #include #include +#include -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; }; diff --git a/include/Nazara/Utility/IndexMapper.hpp b/include/Nazara/Utility/IndexMapper.hpp index e06d1826f..6df36f8db 100644 --- a/include/Nazara/Utility/IndexMapper.hpp +++ b/include/Nazara/Utility/IndexMapper.hpp @@ -9,6 +9,7 @@ #include #include +#include class NzIndexBuffer; class NzIndexIterator; diff --git a/src/Nazara/Physics/Geom.cpp b/src/Nazara/Physics/Geom.cpp index 8bb344ba4..0651921af 100644 --- a/src/Nazara/Physics/Geom.cpp +++ b/src/Nazara/Physics/Geom.cpp @@ -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 - return NzBoxf(scale*min, scale*max); + // 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 geoms(primitiveCount); + std::vector 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; } +NewtonCollision* NzCapsuleGeom::CreateHandle(NzPhysWorld* world) const +{ + return NewtonCreateCapsule(world->GetHandle(), m_radius, m_length, 0, m_matrix); +} + /******************************* CompoundGeom ********************************/ -NzCompoundGeom::NzCompoundGeom(NzPhysWorld* physWorld, NzBaseGeom** geoms, unsigned int geomCount) : -NzBaseGeom(physWorld) +NzCompoundGeom::NzCompoundGeom(NzPhysGeom** geoms, unsigned int geomCount) { - m_collision = NewtonCreateCompoundCollision(physWorld->GetHandle(), 0); - NewtonCompoundCollisionBeginAddRemove(m_collision); - + m_geoms.reserve(geomCount); 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()); - } + m_geoms.emplace_back(geoms[i]); +} - NewtonCompoundCollisionEndAddRemove(m_collision); +const std::vector& 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(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(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(vertices); + + m_vertices.resize(vertexCount); + if (stride != sizeof(NzVector3f)) + { + for (unsigned int i = 0; i < vertexCount; ++i) + m_vertices[i] = *reinterpret_cast(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(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)); +} diff --git a/src/Nazara/Physics/PhysObject.cpp b/src/Nazara/Physics/PhysObject.cpp index bde930811..b33acb226 100644 --- a/src/Nazara/Physics/PhysObject.cpp +++ b/src/Nazara/Physics/PhysObject.cpp @@ -3,56 +3,70 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include -#include #include #include +#include #include 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() { - NewtonDestroyBody(m_world->GetHandle(), m_body); - - if (m_ownsGeom) - delete m_geom; + if (m_body) + NewtonDestroyBody(m_world->GetHandle(), m_body); } void NzPhysObject::AddForce(const NzVector3f& force, nzCoordSys coordSys) @@ -64,7 +78,7 @@ void NzPhysObject::AddForce(const NzVector3f& force, nzCoordSys coordSys) break; case nzCoordSys_Local: - m_forceAccumulator += GetRotation()*force; + m_forceAccumulator += GetRotation() * force; break; } @@ -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::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);