Merge branch 'enet_wip_nothing_to_see_here' of https://github.com/DigitalPulseSoftware/NazaraEngine into enet_wip_nothing_to_see_here
This commit is contained in:
commit
53f865c42c
|
|
@ -23,7 +23,6 @@ namespace Ndk
|
||||||
using Factory = std::function<BaseComponent*()>;
|
using Factory = std::function<BaseComponent*()>;
|
||||||
|
|
||||||
BaseComponent(ComponentIndex componentIndex);
|
BaseComponent(ComponentIndex componentIndex);
|
||||||
BaseComponent(const BaseComponent&) = default;
|
|
||||||
BaseComponent(BaseComponent&&) = default;
|
BaseComponent(BaseComponent&&) = default;
|
||||||
virtual ~BaseComponent();
|
virtual ~BaseComponent();
|
||||||
|
|
||||||
|
|
@ -34,10 +33,12 @@ namespace Ndk
|
||||||
|
|
||||||
inline static ComponentIndex GetMaxComponentIndex();
|
inline static ComponentIndex GetMaxComponentIndex();
|
||||||
|
|
||||||
BaseComponent& operator=(const BaseComponent&) = default;
|
BaseComponent& operator=(const BaseComponent&) = delete;
|
||||||
BaseComponent& operator=(BaseComponent&&) = default;
|
BaseComponent& operator=(BaseComponent&&) = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
BaseComponent(const BaseComponent&) = default;
|
||||||
|
|
||||||
ComponentIndex m_componentIndex;
|
ComponentIndex m_componentIndex;
|
||||||
EntityHandle m_entity;
|
EntityHandle m_entity;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <Nazara/Core/Bitset.hpp>
|
#include <Nazara/Core/Bitset.hpp>
|
||||||
#include <NDK/Entity.hpp>
|
#include <NDK/Entity.hpp>
|
||||||
|
#include <NDK/EntityList.hpp>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
|
|
@ -33,7 +34,7 @@ namespace Ndk
|
||||||
|
|
||||||
bool Filters(const Entity* entity) const;
|
bool Filters(const Entity* entity) const;
|
||||||
|
|
||||||
inline const std::vector<EntityHandle>& GetEntities() const;
|
inline const EntityList& GetEntities() const;
|
||||||
inline SystemIndex GetIndex() const;
|
inline SystemIndex GetIndex() const;
|
||||||
inline int GetUpdateOrder() const;
|
inline int GetUpdateOrder() const;
|
||||||
inline float GetUpdateRate() const;
|
inline float GetUpdateRate() const;
|
||||||
|
|
@ -84,12 +85,11 @@ namespace Ndk
|
||||||
static inline bool Initialize();
|
static inline bool Initialize();
|
||||||
static inline void Uninitialize();
|
static inline void Uninitialize();
|
||||||
|
|
||||||
std::vector<EntityHandle> m_entities;
|
|
||||||
Nz::Bitset<Nz::UInt64> m_entityBits;
|
|
||||||
Nz::Bitset<> m_excludedComponents;
|
Nz::Bitset<> m_excludedComponents;
|
||||||
mutable Nz::Bitset<> m_filterResult;
|
mutable Nz::Bitset<> m_filterResult;
|
||||||
Nz::Bitset<> m_requiredAnyComponents;
|
Nz::Bitset<> m_requiredAnyComponents;
|
||||||
Nz::Bitset<> m_requiredComponents;
|
Nz::Bitset<> m_requiredComponents;
|
||||||
|
EntityList m_entities;
|
||||||
SystemIndex m_systemIndex;
|
SystemIndex m_systemIndex;
|
||||||
World* m_world;
|
World* m_world;
|
||||||
bool m_updateEnabled;
|
bool m_updateEnabled;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ namespace Ndk
|
||||||
* \return A constant reference to the list of entities
|
* \return A constant reference to the list of entities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline const std::vector<EntityHandle>& BaseSystem::GetEntities() const
|
inline const EntityList& BaseSystem::GetEntities() const
|
||||||
{
|
{
|
||||||
return m_entities;
|
return m_entities;
|
||||||
}
|
}
|
||||||
|
|
@ -121,10 +121,7 @@ namespace Ndk
|
||||||
|
|
||||||
inline bool BaseSystem::HasEntity(const Entity* entity) const
|
inline bool BaseSystem::HasEntity(const Entity* entity) const
|
||||||
{
|
{
|
||||||
if (!entity)
|
return m_entities.Has(entity);
|
||||||
return false;
|
|
||||||
|
|
||||||
return m_entityBits.UnboundedTest(entity->GetId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -288,9 +285,7 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
NazaraAssert(entity, "Invalid entity");
|
NazaraAssert(entity, "Invalid entity");
|
||||||
|
|
||||||
m_entities.emplace_back(entity);
|
m_entities.Insert(entity);
|
||||||
m_entityBits.UnboundedSet(entity->GetId(), true);
|
|
||||||
|
|
||||||
entity->RegisterSystem(m_systemIndex);
|
entity->RegisterSystem(m_systemIndex);
|
||||||
|
|
||||||
OnEntityAdded(entity);
|
OnEntityAdded(entity);
|
||||||
|
|
@ -308,14 +303,7 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
NazaraAssert(entity, "Invalid entity");
|
NazaraAssert(entity, "Invalid entity");
|
||||||
|
|
||||||
auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
|
m_entities.Remove(entity);
|
||||||
NazaraAssert(it != m_entities.end(), "Entity is not part of this system");
|
|
||||||
|
|
||||||
// To avoid moving a lot of handles, we swap and pop
|
|
||||||
std::swap(*it, m_entities.back());
|
|
||||||
m_entities.pop_back(); // We get it out of the vector
|
|
||||||
|
|
||||||
m_entityBits.Reset(entity->GetId());
|
|
||||||
entity->UnregisterSystem(m_systemIndex);
|
entity->UnregisterSystem(m_systemIndex);
|
||||||
|
|
||||||
OnEntityRemoved(entity); // And we alert our callback
|
OnEntityRemoved(entity); // And we alert our callback
|
||||||
|
|
@ -360,7 +348,7 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Uninitializes the BaseSystem
|
* \brief Uninitialize the BaseSystem
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline void BaseSystem::Uninitialize()
|
inline void BaseSystem::Uninitialize()
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace Ndk
|
||||||
const Nz::Frustumf& GetFrustum() const override;
|
const Nz::Frustumf& GetFrustum() const override;
|
||||||
inline unsigned int GetLayer() const;
|
inline unsigned int GetLayer() const;
|
||||||
const Nz::Matrix4f& GetProjectionMatrix() const override;
|
const Nz::Matrix4f& GetProjectionMatrix() const override;
|
||||||
inline Nz::ProjectionType GetProjectionType() const;
|
Nz::ProjectionType GetProjectionType() const override;
|
||||||
inline const Nz::Vector2f& GetSize() const;
|
inline const Nz::Vector2f& GetSize() const;
|
||||||
const Nz::RenderTarget* GetTarget() const override;
|
const Nz::RenderTarget* GetTarget() const override;
|
||||||
inline const Nz::Rectf& GetTargetRegion() const;
|
inline const Nz::Rectf& GetTargetRegion() const;
|
||||||
|
|
|
||||||
|
|
@ -117,16 +117,6 @@ namespace Ndk
|
||||||
return m_layer;
|
return m_layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the projection type of the camera
|
|
||||||
* \return Projection type of the camera
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline Nz::ProjectionType CameraComponent::GetProjectionType() const
|
|
||||||
{
|
|
||||||
return m_projectionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the size of the camera
|
* \brief Gets the size of the camera
|
||||||
* \return Size of the camera
|
* \return Size of the camera
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ namespace Ndk
|
||||||
|
|
||||||
inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const;
|
inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const;
|
||||||
|
|
||||||
|
inline void UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix);
|
||||||
|
inline void UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder);
|
||||||
|
|
||||||
static ComponentIndex componentIndex;
|
static ComponentIndex componentIndex;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,32 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void GraphicsComponent::UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix)
|
||||||
|
{
|
||||||
|
for (auto& renderable : m_renderables)
|
||||||
|
{
|
||||||
|
if (renderable.renderable == instancedRenderable)
|
||||||
|
{
|
||||||
|
renderable.data.localMatrix = localMatrix;
|
||||||
|
|
||||||
|
InvalidateBoundingVolume();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void GraphicsComponent::UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder)
|
||||||
|
{
|
||||||
|
for (auto& renderable : m_renderables)
|
||||||
|
{
|
||||||
|
if (renderable.renderable == instancedRenderable)
|
||||||
|
{
|
||||||
|
renderable.data.renderOrder = renderOrder;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Invalidates the bounding volume
|
* \brief Invalidates the bounding volume
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,17 @@
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
class BaseComponent;
|
class BaseComponent;
|
||||||
|
class BaseSystem;
|
||||||
class Entity;
|
class Entity;
|
||||||
|
class EntityList;
|
||||||
class World;
|
class World;
|
||||||
|
|
||||||
using EntityHandle = Nz::ObjectHandle<Entity>;
|
using EntityHandle = Nz::ObjectHandle<Entity>;
|
||||||
|
|
||||||
class NDK_API Entity : public Nz::HandledObject<Entity>
|
class NDK_API Entity : public Nz::HandledObject<Entity>
|
||||||
{
|
{
|
||||||
friend class BaseSystem;
|
friend BaseSystem;
|
||||||
|
friend EntityList;
|
||||||
friend World;
|
friend World;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -78,13 +81,16 @@ namespace Ndk
|
||||||
|
|
||||||
inline Nz::Bitset<>& GetRemovedComponentBits();
|
inline Nz::Bitset<>& GetRemovedComponentBits();
|
||||||
|
|
||||||
|
inline void RegisterEntityList(EntityList* list);
|
||||||
inline void RegisterSystem(SystemIndex index);
|
inline void RegisterSystem(SystemIndex index);
|
||||||
|
|
||||||
inline void SetWorld(World* world) noexcept;
|
inline void SetWorld(World* world) noexcept;
|
||||||
|
|
||||||
|
inline void UnregisterEntityList(EntityList* list);
|
||||||
inline void UnregisterSystem(SystemIndex index);
|
inline void UnregisterSystem(SystemIndex index);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<BaseComponent>> m_components;
|
std::vector<std::unique_ptr<BaseComponent>> m_components;
|
||||||
|
std::vector<EntityList*> m_containedInLists;
|
||||||
Nz::Bitset<> m_componentBits;
|
Nz::Bitset<> m_componentBits;
|
||||||
Nz::Bitset<> m_removedComponentBits;
|
Nz::Bitset<> m_removedComponentBits;
|
||||||
Nz::Bitset<> m_systemBits;
|
Nz::Bitset<> m_systemBits;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <Nazara/Core/StringStream.hpp>
|
#include <Nazara/Core/StringStream.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
@ -257,11 +258,10 @@ namespace Ndk
|
||||||
return m_removedComponentBits;
|
return m_removedComponentBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
inline void Entity::RegisterEntityList(EntityList* list)
|
||||||
* \brief Registers a system for the entity
|
{
|
||||||
*
|
m_containedInLists.push_back(list);
|
||||||
* \param index Index of the system
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
inline void Entity::RegisterSystem(SystemIndex index)
|
inline void Entity::RegisterSystem(SystemIndex index)
|
||||||
{
|
{
|
||||||
|
|
@ -289,6 +289,16 @@ namespace Ndk
|
||||||
* \param index Index of the system
|
* \param index Index of the system
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
inline void Entity::UnregisterEntityList(EntityList* list)
|
||||||
|
{
|
||||||
|
auto it = std::find(m_containedInLists.begin(), m_containedInLists.end(), list);
|
||||||
|
assert(it != m_containedInLists.end());
|
||||||
|
|
||||||
|
// Swap and pop idiom
|
||||||
|
*it = m_containedInLists.back();
|
||||||
|
m_containedInLists.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
inline void Entity::UnregisterSystem(SystemIndex index)
|
inline void Entity::UnregisterSystem(SystemIndex index)
|
||||||
{
|
{
|
||||||
m_systemBits.UnboundedReset(index);
|
m_systemBits.UnboundedReset(index);
|
||||||
|
|
|
||||||
|
|
@ -15,46 +15,68 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
class NDK_API EntityList
|
class NDK_API EntityList
|
||||||
{
|
{
|
||||||
public:
|
friend Entity;
|
||||||
using Container = std::vector<EntityHandle>;
|
|
||||||
|
|
||||||
EntityList() = default;
|
public:
|
||||||
~EntityList() = default;
|
class iterator;
|
||||||
|
friend iterator;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
|
||||||
|
inline EntityList();
|
||||||
|
inline EntityList(const EntityList& entityList);
|
||||||
|
inline EntityList(EntityList&& entityList) noexcept;
|
||||||
|
inline ~EntityList();
|
||||||
|
|
||||||
inline void Clear();
|
inline void Clear();
|
||||||
|
|
||||||
inline bool Has(const Entity* entity);
|
inline bool Has(const Entity* entity) const;
|
||||||
inline bool Has(EntityId entity);
|
inline bool Has(EntityId entity) const;
|
||||||
|
|
||||||
inline void Insert(Entity* entity);
|
inline void Insert(Entity* entity);
|
||||||
|
|
||||||
inline void Remove(Entity* entity);
|
inline void Remove(Entity* entity);
|
||||||
|
|
||||||
// STL API
|
// STL API
|
||||||
inline Container::iterator begin();
|
inline iterator begin() const;
|
||||||
inline Container::const_iterator begin() const;
|
|
||||||
|
|
||||||
inline Container::const_iterator cbegin() const;
|
|
||||||
inline Container::const_iterator cend() const;
|
|
||||||
inline Container::const_reverse_iterator crbegin() const;
|
|
||||||
inline Container::const_reverse_iterator crend() const;
|
|
||||||
|
|
||||||
inline bool empty() const;
|
inline bool empty() const;
|
||||||
|
inline iterator end() const;
|
||||||
|
inline size_type size() const;
|
||||||
|
|
||||||
inline Container::iterator end();
|
inline EntityList& operator=(const EntityList& entityList);
|
||||||
inline Container::const_iterator end() const;
|
inline EntityList& operator=(EntityList&& entityList) noexcept;
|
||||||
|
|
||||||
inline Container::reverse_iterator rbegin();
|
|
||||||
inline Container::const_reverse_iterator rbegin() const;
|
|
||||||
|
|
||||||
inline Container::reverse_iterator rend();
|
|
||||||
inline Container::const_reverse_iterator rend() const;
|
|
||||||
|
|
||||||
inline Container::size_type size() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<EntityHandle> m_entities;
|
inline std::size_t FindNext(std::size_t currentId) const;
|
||||||
|
inline World* GetWorld() const;
|
||||||
|
inline void NotifyEntityDestruction(const Entity* entity);
|
||||||
|
|
||||||
Nz::Bitset<Nz::UInt64> m_entityBits;
|
Nz::Bitset<Nz::UInt64> m_entityBits;
|
||||||
|
World* m_world;
|
||||||
|
};
|
||||||
|
|
||||||
|
class NDK_API EntityList::iterator : public std::iterator<std::forward_iterator_tag, const EntityHandle>
|
||||||
|
{
|
||||||
|
friend EntityList;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline iterator(const iterator& iterator);
|
||||||
|
|
||||||
|
const EntityHandle& operator*() const;
|
||||||
|
|
||||||
|
inline iterator& operator=(const iterator& iterator);
|
||||||
|
inline iterator& operator++();
|
||||||
|
inline iterator operator++(int);
|
||||||
|
|
||||||
|
friend inline bool operator==(const iterator& lhs, const iterator& rhs);
|
||||||
|
friend inline bool operator!=(const iterator& lhs, const iterator& rhs);
|
||||||
|
|
||||||
|
friend inline void swap(iterator& lhs, iterator& rhs);
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline iterator(const EntityList* world, std::size_t nextId);
|
||||||
|
|
||||||
|
std::size_t m_nextEntityId;
|
||||||
|
const EntityList* m_list;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// This file is part of the "Nazara Development Kit"
|
// This file is part of the "Nazara Development Kit"
|
||||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#include <NDK/EntityList.hpp>
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
@ -14,24 +15,71 @@ namespace Ndk
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Clears the set from every entities
|
* \brief Construct a new entity list
|
||||||
*/
|
*/
|
||||||
|
inline EntityList::EntityList() :
|
||||||
inline void EntityList::Clear()
|
m_world(nullptr)
|
||||||
{
|
{
|
||||||
m_entities.clear();
|
|
||||||
m_entityBits.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Checks whether or not the set contains the entity
|
* \brief Construct a new entity list by copying another one
|
||||||
|
*/
|
||||||
|
inline EntityList::EntityList(const EntityList& entityList) :
|
||||||
|
m_entityBits(entityList.m_entityBits),
|
||||||
|
m_world(entityList.m_world)
|
||||||
|
{
|
||||||
|
for (const Ndk::EntityHandle& entity : *this)
|
||||||
|
entity->RegisterEntityList(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Construct a new entity list by moving a list into this one
|
||||||
|
*/
|
||||||
|
inline EntityList::EntityList(EntityList&& entityList) noexcept :
|
||||||
|
m_entityBits(std::move(entityList.m_entityBits)),
|
||||||
|
m_world(entityList.m_world)
|
||||||
|
{
|
||||||
|
for (const Ndk::EntityHandle& entity : *this)
|
||||||
|
{
|
||||||
|
entity->UnregisterEntityList(&entityList);
|
||||||
|
entity->RegisterEntityList(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline EntityList::~EntityList()
|
||||||
|
{
|
||||||
|
for (const Ndk::EntityHandle& entity : *this)
|
||||||
|
entity->UnregisterEntityList(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Clears the set from every entities
|
||||||
|
*
|
||||||
|
* \remark This resets the implicit world member, allowing you to insert entities from a different world than previously
|
||||||
|
*/
|
||||||
|
inline void EntityList::Clear()
|
||||||
|
{
|
||||||
|
for (const Ndk::EntityHandle& entity : *this)
|
||||||
|
entity->UnregisterEntityList(this);
|
||||||
|
|
||||||
|
m_entityBits.Clear();
|
||||||
|
m_world = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Checks whether or not the EntityList contains the entity
|
||||||
* \return true If it is the case
|
* \return true If it is the case
|
||||||
*
|
*
|
||||||
* \param entity Pointer to the entity
|
* \param entity Pointer to the entity
|
||||||
|
*
|
||||||
|
* \remark If the Insert function was called since the EntityList construction (or last call to Clear), the entity passed by parameter must belong to the same world as the previously inserted entities.
|
||||||
*/
|
*/
|
||||||
|
inline bool EntityList::Has(const Entity* entity) const
|
||||||
inline bool EntityList::Has(const Entity* entity)
|
|
||||||
{
|
{
|
||||||
|
NazaraAssert(!m_world || !entity || entity->GetWorld() == m_world, "Incompatible world");
|
||||||
|
|
||||||
return entity && entity->IsValid() && Has(entity->GetId());
|
return entity && entity->IsValid() && Has(entity->GetId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,8 +89,7 @@ namespace Ndk
|
||||||
*
|
*
|
||||||
* \param id Identifier of the entity
|
* \param id Identifier of the entity
|
||||||
*/
|
*/
|
||||||
|
inline bool EntityList::Has(EntityId entity) const
|
||||||
inline bool EntityList::Has(EntityId entity)
|
|
||||||
{
|
{
|
||||||
return m_entityBits.UnboundedTest(entity);
|
return m_entityBits.UnboundedTest(entity);
|
||||||
}
|
}
|
||||||
|
|
@ -50,17 +97,23 @@ namespace Ndk
|
||||||
/*!
|
/*!
|
||||||
* \brief Inserts the entity into the set
|
* \brief Inserts the entity into the set
|
||||||
*
|
*
|
||||||
* \param entity Pointer to the entity
|
* Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list.
|
||||||
|
*
|
||||||
|
* \param entity Valid pointer to an entity
|
||||||
*
|
*
|
||||||
* \remark If entity is already contained, no action is performed
|
* \remark If entity is already contained, no action is performed
|
||||||
|
* \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline void EntityList::Insert(Entity* entity)
|
inline void EntityList::Insert(Entity* entity)
|
||||||
{
|
{
|
||||||
|
NazaraAssert(entity, "Invalid entity");
|
||||||
|
|
||||||
if (!Has(entity))
|
if (!Has(entity))
|
||||||
{
|
{
|
||||||
m_entities.emplace_back(entity);
|
entity->RegisterEntityList(this);
|
||||||
|
|
||||||
m_entityBits.UnboundedSet(entity->GetId(), true);
|
m_entityBits.UnboundedSet(entity->GetId(), true);
|
||||||
|
m_world = entity->GetWorld();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,89 +123,138 @@ namespace Ndk
|
||||||
* \param entity Pointer to the entity
|
* \param entity Pointer to the entity
|
||||||
*
|
*
|
||||||
* \remark If entity is not contained, no action is performed
|
* \remark If entity is not contained, no action is performed
|
||||||
|
* \remark This function never resets the implicit world member, even if it empties the list. Use the Clear method if you want to reset it.
|
||||||
|
*
|
||||||
|
* \see Clear
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline void EntityList::Remove(Entity* entity)
|
inline void EntityList::Remove(Entity* entity)
|
||||||
{
|
{
|
||||||
if (Has(entity))
|
if (Has(entity))
|
||||||
{
|
{
|
||||||
auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
|
m_entityBits.Reset(entity->GetId());
|
||||||
NazaraAssert(it != m_entities.end(), "Entity should be part of the vector");
|
|
||||||
|
|
||||||
std::swap(*it, m_entities.back());
|
entity->UnregisterEntityList(this);
|
||||||
m_entities.pop_back(); // We get it out of the vector
|
|
||||||
m_entityBits.UnboundedSet(entity->GetId(), false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nz::Interface STD
|
// STL Interface
|
||||||
inline EntityList::Container::iterator EntityList::begin()
|
inline EntityList::iterator EntityList::begin() const
|
||||||
{
|
{
|
||||||
return m_entities.begin();
|
return EntityList::iterator(this, m_entityBits.FindFirst());
|
||||||
}
|
|
||||||
|
|
||||||
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
|
inline bool EntityList::empty() const
|
||||||
{
|
{
|
||||||
return m_entities.empty();
|
return !m_entityBits.TestAny();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::iterator EntityList::end()
|
inline EntityList::iterator EntityList::end() const
|
||||||
{
|
{
|
||||||
return m_entities.end();
|
return EntityList::iterator(this, m_entityBits.npos);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::const_iterator EntityList::end() const
|
inline EntityList::size_type EntityList::size() const
|
||||||
{
|
{
|
||||||
return m_entities.end();
|
return m_entityBits.Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::reverse_iterator EntityList::rbegin()
|
inline EntityList& EntityList::operator=(const EntityList& entityList)
|
||||||
{
|
{
|
||||||
return m_entities.rbegin();
|
m_entityBits = entityList.m_entityBits;
|
||||||
|
m_world = entityList.m_world;
|
||||||
|
|
||||||
|
for (const Ndk::EntityHandle& entity : *this)
|
||||||
|
entity->RegisterEntityList(this);
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::const_reverse_iterator EntityList::rbegin() const
|
inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept
|
||||||
{
|
{
|
||||||
return m_entities.rbegin();
|
m_entityBits = std::move(entityList.m_entityBits);
|
||||||
|
m_world = entityList.m_world;
|
||||||
|
|
||||||
|
for (const Ndk::EntityHandle& entity : *this)
|
||||||
|
{
|
||||||
|
entity->UnregisterEntityList(&entityList);
|
||||||
|
entity->RegisterEntityList(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::reverse_iterator EntityList::rend()
|
inline std::size_t EntityList::FindNext(std::size_t currentId) const
|
||||||
{
|
{
|
||||||
return m_entities.rend();
|
return m_entityBits.FindNext(currentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::const_reverse_iterator EntityList::rend() const
|
inline World* EntityList::GetWorld() const
|
||||||
{
|
{
|
||||||
return m_entities.rend();
|
return m_world;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline EntityList::Container::size_type EntityList::size() const
|
inline void EntityList::NotifyEntityDestruction(const Entity* entity)
|
||||||
{
|
{
|
||||||
return m_entities.size();
|
assert(Has(entity));
|
||||||
|
|
||||||
|
m_entityBits.Reset(entity->GetId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) :
|
||||||
|
m_nextEntityId(nextId),
|
||||||
|
m_list(list)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline EntityList::iterator::iterator(const iterator& iterator) :
|
||||||
|
m_nextEntityId(iterator.m_nextEntityId),
|
||||||
|
m_list(iterator.m_list)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline EntityList::iterator& EntityList::iterator::operator=(const iterator& iterator)
|
||||||
|
{
|
||||||
|
m_nextEntityId = iterator.m_nextEntityId;
|
||||||
|
m_list = iterator.m_list;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline EntityList::iterator& EntityList::iterator::operator++()
|
||||||
|
{
|
||||||
|
m_nextEntityId = m_list->FindNext(m_nextEntityId);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline EntityList::iterator EntityList::iterator::operator++(int)
|
||||||
|
{
|
||||||
|
std::size_t previousId = m_nextEntityId;
|
||||||
|
|
||||||
|
m_nextEntityId = m_list->FindNext(m_nextEntityId);
|
||||||
|
|
||||||
|
return iterator(m_list, previousId);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const EntityList::iterator& lhs, const EntityList::iterator& rhs)
|
||||||
|
{
|
||||||
|
NazaraAssert(lhs.m_list == rhs.m_list, "Cannot compare iterator coming from different lists");
|
||||||
|
|
||||||
|
return lhs.m_nextEntityId == rhs.m_nextEntityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(const EntityList::iterator& lhs, const EntityList::iterator& rhs)
|
||||||
|
{
|
||||||
|
return !operator==(lhs, rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void swap(EntityList::iterator& lhs, EntityList::iterator& rhs)
|
||||||
|
{
|
||||||
|
NazaraAssert(lhs.m_list == rhs.m_list, "Cannot compare iterator coming from different lists");
|
||||||
|
|
||||||
|
using std::swap;
|
||||||
|
|
||||||
|
swap(lhs.m_nextEntityId, rhs.m_nextEntityId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (C) 2017 Jérôme Leclercq
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
// This file is part of the "Nazara Development Kit"
|
// This file is part of the "Nazara Development Kit"
|
||||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <NDK/Prerequesites.hpp>
|
#include <NDK/Prerequesites.hpp>
|
||||||
#include <NDK/State.hpp>
|
#include <NDK/State.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
{
|
{
|
||||||
|
|
@ -25,14 +26,21 @@ namespace Ndk
|
||||||
|
|
||||||
inline const std::shared_ptr<State>& GetCurrentState() const;
|
inline const std::shared_ptr<State>& GetCurrentState() const;
|
||||||
|
|
||||||
|
inline bool IsTopState(const State* state) const;
|
||||||
|
|
||||||
|
inline std::shared_ptr<State> PopState();
|
||||||
|
inline bool PopStatesUntil(std::shared_ptr<State> state);
|
||||||
|
inline void PushState(std::shared_ptr<State> state);
|
||||||
|
|
||||||
|
inline void SetState(std::shared_ptr<State> state);
|
||||||
|
|
||||||
inline bool Update(float elapsedTime);
|
inline bool Update(float elapsedTime);
|
||||||
|
|
||||||
inline StateMachine& operator=(StateMachine&& fsm) = default;
|
inline StateMachine& operator=(StateMachine&& fsm) = default;
|
||||||
StateMachine& operator=(const StateMachine&) = delete;
|
StateMachine& operator=(const StateMachine&) = delete;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<State> m_currentState;
|
std::vector<std::shared_ptr<State>> m_states;
|
||||||
std::shared_ptr<State> m_nextState;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
#include <NDK/StateMachine.hpp>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
namespace Ndk
|
namespace Ndk
|
||||||
|
|
@ -11,7 +10,7 @@ namespace Ndk
|
||||||
/*!
|
/*!
|
||||||
* \ingroup NDK
|
* \ingroup NDK
|
||||||
* \class Ndk::StateMachine
|
* \class Ndk::StateMachine
|
||||||
* \brief NDK class that represents a state machine, to represent the multiple states of your program
|
* \brief NDK class that represents a state machine, to represent the multiple states of your program as a stack
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -23,61 +22,153 @@ namespace Ndk
|
||||||
* \remark Produces a NazaraAssert if nullptr is given
|
* \remark Produces a NazaraAssert if nullptr is given
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline StateMachine::StateMachine(std::shared_ptr<State> originalState) :
|
inline StateMachine::StateMachine(std::shared_ptr<State> originalState)
|
||||||
m_currentState(std::move(originalState))
|
|
||||||
{
|
{
|
||||||
NazaraAssert(m_currentState, "StateMachine must have a state to begin with");
|
NazaraAssert(originalState, "StateMachine must have a state to begin with");
|
||||||
m_currentState->Enter(*this);
|
PushState(std::move(originalState));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Destructs the object
|
* \brief Destructs the object
|
||||||
*
|
*
|
||||||
* \remark Calls "Leave" on the state
|
* \remark Calls "Leave" on all the states
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline StateMachine::~StateMachine()
|
inline StateMachine::~StateMachine()
|
||||||
{
|
{
|
||||||
m_currentState->Leave(*this);
|
for (std::shared_ptr<State>& state : m_states)
|
||||||
|
state->Leave(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Changes the current state of the machine
|
* \brief Replaces the current state on the top of the machine
|
||||||
*
|
*
|
||||||
* \param state Next state to represent
|
* \param state State to replace the top one if it is nullptr, no action is performed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline void StateMachine::ChangeState(std::shared_ptr<State> state)
|
inline void StateMachine::ChangeState(std::shared_ptr<State> state)
|
||||||
{
|
{
|
||||||
m_nextState = std::move(state);
|
if (state)
|
||||||
|
{
|
||||||
|
PopState();
|
||||||
|
PushState(std::move(state));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the current state of the machine
|
* \brief Gets the current state on the top of the machine
|
||||||
* \return A constant reference to the state
|
* \return A constant reference to the state
|
||||||
|
*
|
||||||
|
* \remark The stack is supposed to be non empty, otherwise it is undefined behaviour
|
||||||
|
*
|
||||||
|
* \see PopStatesUntil
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline const std::shared_ptr<State>& StateMachine::GetCurrentState() const
|
inline const std::shared_ptr<State>& StateMachine::GetCurrentState() const
|
||||||
{
|
{
|
||||||
return m_currentState;
|
return m_states.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Updates the state
|
* \brief Checks whether the state is on the top of the machine
|
||||||
* \return True if update is successful
|
* \return true If it is the case
|
||||||
|
*
|
||||||
|
* \param state State to compare the top with
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline bool StateMachine::IsTopState(const State* state) const
|
||||||
|
{
|
||||||
|
if (m_states.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return m_states.back().get() == state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Pops the state on the top of the machine
|
||||||
|
* \return Old state on the top, nullptr if stack was empty
|
||||||
|
*
|
||||||
|
* \remark This method can completely empty the stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline std::shared_ptr<State> StateMachine::PopState()
|
||||||
|
{
|
||||||
|
if (m_states.empty())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
m_states.back()->Leave(*this);
|
||||||
|
std::shared_ptr<State> oldTopState = std::move(m_states.back());
|
||||||
|
m_states.pop_back();
|
||||||
|
return oldTopState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Pops all the states of the machine until a specific one is reached
|
||||||
|
* \return true If that specific state is on top, false if stack is empty
|
||||||
|
*
|
||||||
|
* \param state State to find on the stack if it is nullptr, no action is performed
|
||||||
|
*
|
||||||
|
* \remark This method can completely empty the stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline bool StateMachine::PopStatesUntil(std::shared_ptr<State> state)
|
||||||
|
{
|
||||||
|
if (!state)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
while (!m_states.empty() && !IsTopState(state.get()))
|
||||||
|
PopState();
|
||||||
|
|
||||||
|
return !m_states.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Pushes a new state on the top of the machine
|
||||||
|
*
|
||||||
|
* \param state Next state to represent if it is nullptr, it performs no action
|
||||||
|
*
|
||||||
|
* \remark Produces a NazaraAssert if the same state is pushed two times on the stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline void StateMachine::PushState(std::shared_ptr<State> state)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
NazaraAssert(std::find(m_states.begin(), m_states.end(), state) == m_states.end(), "The same state was pushed two times");
|
||||||
|
|
||||||
|
m_states.push_back(std::move(state));
|
||||||
|
m_states.back()->Enter(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Pops every states of the machine to put a new one
|
||||||
|
*
|
||||||
|
* \param state State to reset the stack with if it is nullptr, no action is performed
|
||||||
|
*/
|
||||||
|
|
||||||
|
inline void StateMachine::SetState(std::shared_ptr<State> state)
|
||||||
|
{
|
||||||
|
if (state)
|
||||||
|
{
|
||||||
|
while (!m_states.empty())
|
||||||
|
PopState();
|
||||||
|
|
||||||
|
PushState(std::move(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Updates all the states
|
||||||
|
* \return true If update is successful for everyone of them
|
||||||
*
|
*
|
||||||
* \param elapsedTime Delta time used for the update
|
* \param elapsedTime Delta time used for the update
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline bool StateMachine::Update(float elapsedTime)
|
inline bool StateMachine::Update(float elapsedTime)
|
||||||
{
|
{
|
||||||
if (m_nextState)
|
return std::all_of(m_states.begin(), m_states.end(), [=](std::shared_ptr<State>& state) {
|
||||||
{
|
return state->Update(*this, elapsedTime);
|
||||||
m_currentState->Leave(*this);
|
});
|
||||||
m_currentState = std::move(m_nextState);
|
|
||||||
m_currentState->Enter(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_currentState->Update(*this, elapsedTime);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ namespace Ndk
|
||||||
|
|
||||||
std::unique_ptr<Nz::AbstractRenderTechnique> m_renderTechnique;
|
std::unique_ptr<Nz::AbstractRenderTechnique> m_renderTechnique;
|
||||||
std::vector<GraphicsComponentCullingList::VolumeEntry> m_volumeEntries;
|
std::vector<GraphicsComponentCullingList::VolumeEntry> m_volumeEntries;
|
||||||
EntityList m_cameras;
|
std::vector<EntityHandle> m_cameras;
|
||||||
EntityList m_drawables;
|
EntityList m_drawables;
|
||||||
EntityList m_directionalLights;
|
EntityList m_directionalLights;
|
||||||
EntityList m_lights;
|
EntityList m_lights;
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include <Nazara/Core/Bitset.hpp>
|
#include <Nazara/Core/Bitset.hpp>
|
||||||
#include <Nazara/Core/HandledObject.hpp>
|
#include <Nazara/Core/HandledObject.hpp>
|
||||||
#include <NDK/Entity.hpp>
|
#include <NDK/Entity.hpp>
|
||||||
|
#include <NDK/EntityList.hpp>
|
||||||
#include <NDK/System.hpp>
|
#include <NDK/System.hpp>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -28,7 +29,7 @@ namespace Ndk
|
||||||
friend Entity;
|
friend Entity;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using EntityList = std::vector<EntityHandle>;
|
using EntityVector = std::vector<EntityHandle>;
|
||||||
|
|
||||||
inline World(bool addDefaultSystems = true);
|
inline World(bool addDefaultSystems = true);
|
||||||
World(const World&) = delete;
|
World(const World&) = delete;
|
||||||
|
|
@ -41,21 +42,21 @@ namespace Ndk
|
||||||
template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args);
|
template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args);
|
||||||
|
|
||||||
const EntityHandle& CreateEntity();
|
const EntityHandle& CreateEntity();
|
||||||
inline EntityList CreateEntities(unsigned int count);
|
inline EntityVector CreateEntities(unsigned int count);
|
||||||
|
|
||||||
void Clear() noexcept;
|
void Clear() noexcept;
|
||||||
const EntityHandle& CloneEntity(EntityId id);
|
const EntityHandle& CloneEntity(EntityId id);
|
||||||
|
|
||||||
const EntityHandle& GetEntity(EntityId id);
|
inline const EntityHandle& GetEntity(EntityId id);
|
||||||
inline const EntityList& GetEntities();
|
inline const EntityList& GetEntities() const;
|
||||||
inline BaseSystem& GetSystem(SystemIndex index);
|
inline BaseSystem& GetSystem(SystemIndex index);
|
||||||
template<typename SystemType> SystemType& GetSystem();
|
template<typename SystemType> SystemType& GetSystem();
|
||||||
|
|
||||||
inline bool HasSystem(SystemIndex index) const;
|
inline bool HasSystem(SystemIndex index) const;
|
||||||
template<typename SystemType> bool HasSystem() const;
|
template<typename SystemType> bool HasSystem() const;
|
||||||
|
|
||||||
void KillEntity(Entity* entity);
|
inline void KillEntity(Entity* entity);
|
||||||
inline void KillEntities(const EntityList& list);
|
inline void KillEntities(const EntityVector& list);
|
||||||
|
|
||||||
inline bool IsEntityValid(const Entity* entity) const;
|
inline bool IsEntityValid(const Entity* entity) const;
|
||||||
inline bool IsEntityIdValid(EntityId id) const;
|
inline bool IsEntityIdValid(EntityId id) const;
|
||||||
|
|
@ -79,19 +80,22 @@ namespace Ndk
|
||||||
struct EntityBlock
|
struct EntityBlock
|
||||||
{
|
{
|
||||||
EntityBlock(Entity&& e) :
|
EntityBlock(Entity&& e) :
|
||||||
entity(std::move(e))
|
entity(std::move(e)),
|
||||||
|
handle(&entity)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityBlock(EntityBlock&& block) = default;
|
EntityBlock(EntityBlock&& block) = default;
|
||||||
|
|
||||||
Entity entity;
|
Entity entity;
|
||||||
std::size_t aliveIndex;
|
EntityHandle handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::unique_ptr<BaseSystem>> m_systems;
|
std::vector<std::unique_ptr<BaseSystem>> m_systems;
|
||||||
std::vector<BaseSystem*> m_orderedSystems;
|
std::vector<BaseSystem*> m_orderedSystems;
|
||||||
std::vector<EntityBlock> m_entities;
|
std::vector<EntityBlock> m_entities;
|
||||||
|
std::vector<EntityBlock*> m_entityBlocks;
|
||||||
|
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
|
||||||
std::vector<EntityId> m_freeIdList;
|
std::vector<EntityId> m_freeIdList;
|
||||||
EntityList m_aliveEntities;
|
EntityList m_aliveEntities;
|
||||||
Nz::Bitset<Nz::UInt64> m_dirtyEntities;
|
Nz::Bitset<Nz::UInt64> m_dirtyEntities;
|
||||||
|
|
|
||||||
|
|
@ -82,9 +82,9 @@ namespace Ndk
|
||||||
* \param count Number of entities to create
|
* \param count Number of entities to create
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline World::EntityList World::CreateEntities(unsigned int count)
|
inline World::EntityVector World::CreateEntities(unsigned int count)
|
||||||
{
|
{
|
||||||
EntityList list;
|
EntityVector list;
|
||||||
list.reserve(count);
|
list.reserve(count);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < count; ++i)
|
for (unsigned int i = 0; i < count; ++i)
|
||||||
|
|
@ -98,7 +98,7 @@ namespace Ndk
|
||||||
* \return A constant reference to the entities
|
* \return A constant reference to the entities
|
||||||
*/
|
*/
|
||||||
|
|
||||||
inline const World::EntityList& World::GetEntities()
|
inline const EntityList& World::GetEntities() const
|
||||||
{
|
{
|
||||||
return m_aliveEntities;
|
return m_aliveEntities;
|
||||||
}
|
}
|
||||||
|
|
@ -164,18 +164,53 @@ namespace Ndk
|
||||||
return HasSystem(index);
|
return HasSystem(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Marks an entity for deletion
|
||||||
|
*
|
||||||
|
* \param Pointer to the entity
|
||||||
|
*
|
||||||
|
* \remark If the entity pointer is invalid, nothing is done
|
||||||
|
* \remark For safety, entities are not killed until the next world update
|
||||||
|
*/
|
||||||
|
inline void World::KillEntity(Entity* entity)
|
||||||
|
{
|
||||||
|
if (IsEntityValid(entity))
|
||||||
|
m_killedEntities.UnboundedSet(entity->GetId(), true);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Kills a set of entities
|
* \brief Kills a set of entities
|
||||||
*
|
*
|
||||||
|
* This function has the same effect as calling KillEntity for every entity contained in the vector
|
||||||
|
*
|
||||||
* \param list Set of entities to kill
|
* \param list Set of entities to kill
|
||||||
*/
|
*/
|
||||||
|
inline void World::KillEntities(const EntityVector& list)
|
||||||
inline void World::KillEntities(const EntityList& list)
|
|
||||||
{
|
{
|
||||||
for (const EntityHandle& entity : list)
|
for (const EntityHandle& entity : list)
|
||||||
KillEntity(entity);
|
KillEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Gets an entity
|
||||||
|
* \return A constant reference to a handle of the entity
|
||||||
|
*
|
||||||
|
* \param id Identifier of the entity
|
||||||
|
*
|
||||||
|
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a reference to a handle from a world update to another
|
||||||
|
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
|
||||||
|
*/
|
||||||
|
inline const EntityHandle& World::GetEntity(EntityId id)
|
||||||
|
{
|
||||||
|
if (IsEntityIdValid(id))
|
||||||
|
return m_entityBlocks[id]->handle;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NazaraError("Invalid ID");
|
||||||
|
return EntityHandle::InvalidHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Checks whether or not an entity is valid
|
* \brief Checks whether or not an entity is valid
|
||||||
* \return true If it is the case
|
* \return true If it is the case
|
||||||
|
|
@ -197,7 +232,7 @@ namespace Ndk
|
||||||
|
|
||||||
inline bool World::IsEntityIdValid(EntityId id) const
|
inline bool World::IsEntityIdValid(EntityId id) const
|
||||||
{
|
{
|
||||||
return id < m_entities.size() && m_entities[id].entity.IsValid();
|
return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -266,10 +301,12 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
m_aliveEntities = std::move(world.m_aliveEntities);
|
m_aliveEntities = std::move(world.m_aliveEntities);
|
||||||
m_dirtyEntities = std::move(world.m_dirtyEntities);
|
m_dirtyEntities = std::move(world.m_dirtyEntities);
|
||||||
|
m_entityBlocks = std::move(world.m_entityBlocks);
|
||||||
m_freeIdList = std::move(world.m_freeIdList);
|
m_freeIdList = std::move(world.m_freeIdList);
|
||||||
m_killedEntities = std::move(world.m_killedEntities);
|
m_killedEntities = std::move(world.m_killedEntities);
|
||||||
m_orderedSystems = std::move(world.m_orderedSystems);
|
m_orderedSystems = std::move(world.m_orderedSystems);
|
||||||
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
||||||
|
m_waitingEntities = std::move(world.m_waitingEntities);
|
||||||
|
|
||||||
m_entities = std::move(world.m_entities);
|
m_entities = std::move(world.m_entities);
|
||||||
for (EntityBlock& block : m_entities)
|
for (EntityBlock& block : m_entities)
|
||||||
|
|
@ -284,7 +321,7 @@ namespace Ndk
|
||||||
|
|
||||||
inline void World::Invalidate()
|
inline void World::Invalidate()
|
||||||
{
|
{
|
||||||
m_dirtyEntities.Resize(m_entities.size(), false);
|
m_dirtyEntities.Resize(m_entityBlocks.size(), false);
|
||||||
m_dirtyEntities.Set(true); // Activation of all bits
|
m_dirtyEntities.Set(true); // Activation of all bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,17 @@ namespace Ndk
|
||||||
return m_projectionMatrix;
|
return m_projectionMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Gets the projection type of the camera
|
||||||
|
* \return Projection type of the camera
|
||||||
|
*/
|
||||||
|
Nz::ProjectionType CameraComponent::GetProjectionType() const
|
||||||
|
{
|
||||||
|
return m_projectionType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the target of the camera
|
* \brief Gets the target of the camera
|
||||||
* \return A constant reference to the render target of the camera
|
* \return A constant reference to the render target of the camera
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,9 @@ namespace Ndk
|
||||||
Entity::Entity(Entity&& entity) :
|
Entity::Entity(Entity&& entity) :
|
||||||
HandledObject(std::move(entity)),
|
HandledObject(std::move(entity)),
|
||||||
m_components(std::move(entity.m_components)),
|
m_components(std::move(entity.m_components)),
|
||||||
|
m_containedInLists(std::move(entity.m_containedInLists)),
|
||||||
m_componentBits(std::move(entity.m_componentBits)),
|
m_componentBits(std::move(entity.m_componentBits)),
|
||||||
|
m_removedComponentBits(std::move(entity.m_removedComponentBits)),
|
||||||
m_systemBits(std::move(entity.m_systemBits)),
|
m_systemBits(std::move(entity.m_systemBits)),
|
||||||
m_id(entity.m_id),
|
m_id(entity.m_id),
|
||||||
m_world(entity.m_world),
|
m_world(entity.m_world),
|
||||||
|
|
@ -175,9 +177,15 @@ namespace Ndk
|
||||||
m_components.clear();
|
m_components.clear();
|
||||||
m_componentBits.Reset();
|
m_componentBits.Reset();
|
||||||
|
|
||||||
// And then free every handle
|
// Free every handle
|
||||||
UnregisterAllHandles();
|
UnregisterAllHandles();
|
||||||
|
|
||||||
|
// Remove from every list
|
||||||
|
for (EntityList* list : m_containedInLists)
|
||||||
|
list->NotifyEntityDestruction(this);
|
||||||
|
|
||||||
|
m_containedInLists.clear();
|
||||||
|
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright (C) 2017 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Development Kit"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||||
|
|
||||||
|
#include <NDK/EntityList.hpp>
|
||||||
|
#include <NDK/World.hpp>
|
||||||
|
|
||||||
|
namespace Ndk
|
||||||
|
{
|
||||||
|
const EntityHandle& EntityList::iterator::operator*() const
|
||||||
|
{
|
||||||
|
return m_list->GetWorld()->GetEntity(static_cast<EntityId>(m_nextEntityId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -48,12 +48,14 @@ namespace Ndk
|
||||||
{
|
{
|
||||||
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
|
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
|
||||||
|
|
||||||
m_cameras.Remove(entity);
|
for (auto it = m_cameras.begin(); it != m_cameras.end(); ++it)
|
||||||
m_directionalLights.Remove(entity);
|
{
|
||||||
m_drawables.Remove(entity);
|
if (it->GetObject() == entity)
|
||||||
m_lights.Remove(entity);
|
{
|
||||||
m_particleGroups.Remove(entity);
|
m_cameras.erase(it);
|
||||||
m_pointSpotLights.Remove(entity);
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (entity->HasComponent<GraphicsComponent>())
|
if (entity->HasComponent<GraphicsComponent>())
|
||||||
{
|
{
|
||||||
|
|
@ -74,14 +76,23 @@ namespace Ndk
|
||||||
|
|
||||||
if (entity->HasComponent<CameraComponent>() && entity->HasComponent<NodeComponent>())
|
if (entity->HasComponent<CameraComponent>() && entity->HasComponent<NodeComponent>())
|
||||||
{
|
{
|
||||||
m_cameras.Insert(entity);
|
m_cameras.emplace_back(entity);
|
||||||
std::sort(m_cameras.begin(), m_cameras.end(), [](const EntityHandle& handle1, const EntityHandle& handle2)
|
std::sort(m_cameras.begin(), m_cameras.end(), [](const EntityHandle& handle1, const EntityHandle& handle2)
|
||||||
{
|
{
|
||||||
return handle1->GetComponent<CameraComponent>().GetLayer() < handle2->GetComponent<CameraComponent>().GetLayer();
|
return handle1->GetComponent<CameraComponent>().GetLayer() < handle2->GetComponent<CameraComponent>().GetLayer();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
m_cameras.Remove(entity);
|
{
|
||||||
|
for (auto it = m_cameras.begin(); it != m_cameras.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->GetObject() == entity)
|
||||||
|
{
|
||||||
|
m_cameras.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (entity->HasComponent<GraphicsComponent>() && entity->HasComponent<NodeComponent>())
|
if (entity->HasComponent<GraphicsComponent>() && entity->HasComponent<NodeComponent>())
|
||||||
{
|
{
|
||||||
|
|
@ -181,7 +192,7 @@ namespace Ndk
|
||||||
GraphicsComponent& graphicsComponent = drawable->GetComponent<GraphicsComponent>();
|
GraphicsComponent& graphicsComponent = drawable->GetComponent<GraphicsComponent>();
|
||||||
graphicsComponent.EnsureBoundingVolumeUpdate();
|
graphicsComponent.EnsureBoundingVolumeUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool forceInvalidation = false;
|
bool forceInvalidation = false;
|
||||||
|
|
||||||
std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation);
|
std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation);
|
||||||
|
|
|
||||||
|
|
@ -60,29 +60,51 @@ namespace Ndk
|
||||||
const EntityHandle& World::CreateEntity()
|
const EntityHandle& World::CreateEntity()
|
||||||
{
|
{
|
||||||
EntityId id;
|
EntityId id;
|
||||||
|
EntityBlock* entBlock;
|
||||||
if (!m_freeIdList.empty())
|
if (!m_freeIdList.empty())
|
||||||
{
|
{
|
||||||
// We get an identifier
|
// We get an identifier
|
||||||
id = m_freeIdList.back();
|
id = m_freeIdList.back();
|
||||||
m_freeIdList.pop_back();
|
m_freeIdList.pop_back();
|
||||||
|
|
||||||
|
entBlock = &m_entities[id];
|
||||||
|
entBlock->handle.Reset(&entBlock->entity); //< Reset handle (as it was reset when entity got destroyed)
|
||||||
|
|
||||||
|
m_entityBlocks[id] = entBlock;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We allocate a new entity
|
// We allocate a new entity
|
||||||
id = static_cast<Ndk::EntityId>(m_entities.size());
|
id = static_cast<Ndk::EntityId>(m_entityBlocks.size());
|
||||||
|
|
||||||
// We can't use emplace_back due to the scope
|
if (m_entities.capacity() > m_entities.size())
|
||||||
m_entities.push_back(Entity(this, id));
|
{
|
||||||
|
NazaraAssert(m_waitingEntities.empty(), "There should be no waiting entities if space is available in main container");
|
||||||
|
|
||||||
|
m_entities.push_back(Entity(this, id)); //< We can't use emplace_back due to the scope
|
||||||
|
entBlock = &m_entities.back();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Pushing to entities would reallocate vector and thus, invalidate EntityHandles (which we don't want until world update)
|
||||||
|
// To prevent this, allocate them into a separate vector and move them at update
|
||||||
|
// For now, we are counting on m_entities grow strategy to keep allocation frequency low
|
||||||
|
m_waitingEntities.emplace_back(std::make_unique<EntityBlock>(Entity(this, id)));
|
||||||
|
entBlock = m_waitingEntities.back().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id >= m_entityBlocks.size())
|
||||||
|
m_entityBlocks.resize(id + 1);
|
||||||
|
|
||||||
|
m_entityBlocks[id] = entBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We initialise the entity and we add it to the list of alive entities
|
// We initialize the entity and we add it to the list of alive entities
|
||||||
Entity& entity = m_entities[id].entity;
|
entBlock->entity.Create();
|
||||||
entity.Create();
|
|
||||||
|
|
||||||
m_aliveEntities.emplace_back(&entity);
|
m_aliveEntities.Insert(&entBlock->entity);
|
||||||
m_entities[id].aliveIndex = m_aliveEntities.size() - 1;
|
|
||||||
|
|
||||||
return m_aliveEntities.back();
|
return entBlock->handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -96,8 +118,10 @@ namespace Ndk
|
||||||
// First, destruction of entities, then handles
|
// First, destruction of entities, then handles
|
||||||
// This is made to avoid that handle warn uselessly entities before their destruction
|
// This is made to avoid that handle warn uselessly entities before their destruction
|
||||||
m_entities.clear();
|
m_entities.clear();
|
||||||
|
m_entityBlocks.clear();
|
||||||
|
m_waitingEntities.clear();
|
||||||
|
|
||||||
m_aliveEntities.clear();
|
m_aliveEntities.Clear();
|
||||||
m_dirtyEntities.Clear();
|
m_dirtyEntities.Clear();
|
||||||
m_killedEntities.Clear();
|
m_killedEntities.Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -120,7 +144,7 @@ namespace Ndk
|
||||||
return EntityHandle::InvalidHandle;
|
return EntityHandle::InvalidHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityHandle clone = CreateEntity();
|
const EntityHandle& clone = CreateEntity();
|
||||||
|
|
||||||
const Nz::Bitset<>& componentBits = original->GetComponentBits();
|
const Nz::Bitset<>& componentBits = original->GetComponentBits();
|
||||||
for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i))
|
for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i))
|
||||||
|
|
@ -129,41 +153,7 @@ namespace Ndk
|
||||||
clone->AddComponent(std::move(component));
|
clone->AddComponent(std::move(component));
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetEntity(clone->GetId());
|
return clone;
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Kills an entity
|
|
||||||
*
|
|
||||||
* \param Pointer to the entity
|
|
||||||
*
|
|
||||||
* \remark No change is done if entity is invalid
|
|
||||||
*/
|
|
||||||
|
|
||||||
void World::KillEntity(Entity* entity)
|
|
||||||
{
|
|
||||||
if (IsEntityValid(entity))
|
|
||||||
m_killedEntities.UnboundedSet(entity->GetId(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets an entity
|
|
||||||
* \return A constant reference to the modified entity
|
|
||||||
*
|
|
||||||
* \param id Identifier of the entity
|
|
||||||
*
|
|
||||||
* \remark Produces a NazaraError if entity identifier is not valid
|
|
||||||
*/
|
|
||||||
|
|
||||||
const EntityHandle& World::GetEntity(EntityId id)
|
|
||||||
{
|
|
||||||
if (IsEntityIdValid(id))
|
|
||||||
return m_aliveEntities[m_entities[id].aliveIndex];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NazaraError("Invalid ID");
|
|
||||||
return EntityHandle::InvalidHandle;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -177,45 +167,43 @@ namespace Ndk
|
||||||
if (!m_orderedSystemsUpdated)
|
if (!m_orderedSystemsUpdated)
|
||||||
ReorderSystems();
|
ReorderSystems();
|
||||||
|
|
||||||
|
// Move waiting entities to entity list
|
||||||
|
if (!m_waitingEntities.empty())
|
||||||
|
{
|
||||||
|
constexpr std::size_t MinEntityCapacity = 10; //< We want to be able to grow maximum entity count by at least ten without going to the waiting list
|
||||||
|
|
||||||
|
m_entities.reserve(m_entities.size() + m_waitingEntities.size() + MinEntityCapacity);
|
||||||
|
for (auto& blockPtr : m_waitingEntities)
|
||||||
|
m_entities.push_back(std::move(*blockPtr));
|
||||||
|
|
||||||
|
m_waitingEntities.clear();
|
||||||
|
|
||||||
|
// Update entity blocks pointers
|
||||||
|
for (std::size_t i = 0; i < m_entities.size(); ++i)
|
||||||
|
m_entityBlocks[i] = &m_entities[i];
|
||||||
|
}
|
||||||
|
|
||||||
// Handle killed entities before last call
|
// Handle killed entities before last call
|
||||||
for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i))
|
for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i))
|
||||||
{
|
{
|
||||||
EntityBlock& block = m_entities[i];
|
NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
|
||||||
Entity& entity = block.entity;
|
|
||||||
|
|
||||||
NazaraAssert(entity.IsValid(), "Entity must be valid");
|
Entity* entity = &m_entityBlocks[i]->entity;
|
||||||
|
|
||||||
// Destruction of the entity (invalidation of handle by the same way)
|
// Destruction of the entity (invalidation of handle by the same way)
|
||||||
entity.Destroy();
|
entity->Destroy();
|
||||||
|
|
||||||
// Send back the identifier of the entity to the free queue
|
// Send back the identifier of the entity to the free queue
|
||||||
m_freeIdList.push_back(entity.GetId());
|
m_freeIdList.push_back(entity->GetId());
|
||||||
|
|
||||||
// We take out the handle from the list of alive entities
|
|
||||||
// With the idiom swap and pop
|
|
||||||
|
|
||||||
NazaraAssert(block.aliveIndex < m_aliveEntities.size(), "Alive index out of range");
|
|
||||||
|
|
||||||
if (block.aliveIndex < m_aliveEntities.size() - 1) // If it's not the last handle
|
|
||||||
{
|
|
||||||
EntityHandle& lastHandle = m_aliveEntities.back();
|
|
||||||
EntityHandle& myHandle = m_aliveEntities[block.aliveIndex];
|
|
||||||
|
|
||||||
myHandle = std::move(lastHandle);
|
|
||||||
|
|
||||||
// We don't forget to update the index associated to the entity
|
|
||||||
m_entities[myHandle->GetId()].aliveIndex = block.aliveIndex;
|
|
||||||
}
|
|
||||||
m_aliveEntities.pop_back();
|
|
||||||
}
|
}
|
||||||
m_killedEntities.Reset();
|
m_killedEntities.Reset();
|
||||||
|
|
||||||
// Handle of entities which need an update from the systems
|
// Handle of entities which need an update from the systems
|
||||||
for (std::size_t i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i))
|
for (std::size_t i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i))
|
||||||
{
|
{
|
||||||
NazaraAssert(i < m_entities.size(), "Entity index out of range");
|
NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
|
||||||
|
|
||||||
Entity* entity = &m_entities[i].entity;
|
Entity* entity = &m_entityBlocks[i]->entity;
|
||||||
|
|
||||||
// Check entity validity (as it could have been reported as dirty and killed during the same iteration)
|
// Check entity validity (as it could have been reported as dirty and killed during the same iteration)
|
||||||
if (!entity->IsValid())
|
if (!entity->IsValid())
|
||||||
|
|
@ -242,7 +230,7 @@ namespace Ndk
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No, it shouldn't, remove it if it's part of the system
|
// No it shouldn't, remove it if it's part of the system
|
||||||
if (partOfSystem)
|
if (partOfSystem)
|
||||||
system->RemoveEntity(entity);
|
system->RemoveEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ namespace Nz
|
||||||
virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) = 0;
|
virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) = 0;
|
||||||
virtual void AddPointLight(const PointLight& light);
|
virtual void AddPointLight(const PointLight& light);
|
||||||
virtual void AddSpotLight(const SpotLight& light);
|
virtual void AddSpotLight(const SpotLight& light);
|
||||||
virtual void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) = 0;
|
virtual void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) = 0;
|
||||||
|
|
||||||
virtual void Clear(bool fully = false);
|
virtual void Clear(bool fully = false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ namespace Nz
|
||||||
virtual Vector3f GetForward() const = 0;
|
virtual Vector3f GetForward() const = 0;
|
||||||
virtual const Frustumf& GetFrustum() const = 0;
|
virtual const Frustumf& GetFrustum() const = 0;
|
||||||
virtual const Matrix4f& GetProjectionMatrix() const = 0;
|
virtual const Matrix4f& GetProjectionMatrix() const = 0;
|
||||||
|
virtual Nz::ProjectionType GetProjectionType() const = 0;
|
||||||
virtual const RenderTarget* GetTarget() const = 0;
|
virtual const RenderTarget* GetTarget() const = 0;
|
||||||
virtual const Matrix4f& GetViewMatrix() const = 0;
|
virtual const Matrix4f& GetViewMatrix() const = 0;
|
||||||
virtual const Recti& GetViewport() const = 0;
|
virtual const Recti& GetViewport() const = 0;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Nz
|
||||||
void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override;
|
void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override;
|
||||||
void AddDrawable(int renderOrder, const Drawable* drawable) override;
|
void AddDrawable(int renderOrder, const Drawable* drawable) override;
|
||||||
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
||||||
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override;
|
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override;
|
||||||
|
|
||||||
void Clear(bool fully = false) override;
|
void Clear(bool fully = false) override;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ namespace Nz
|
||||||
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
||||||
void AddPointLight(const PointLight& light) override;
|
void AddPointLight(const PointLight& light) override;
|
||||||
void AddSpotLight(const SpotLight& light) override;
|
void AddSpotLight(const SpotLight& light) override;
|
||||||
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override;
|
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline bool IsMaterialSuitable(const Material* material) const;
|
inline bool IsMaterialSuitable(const Material* material) const;
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <Nazara/Graphics/Material.hpp>
|
#include <Nazara/Graphics/Material.hpp>
|
||||||
#include <Nazara/Math/Box.hpp>
|
#include <Nazara/Math/Box.hpp>
|
||||||
#include <Nazara/Math/Matrix4.hpp>
|
#include <Nazara/Math/Matrix4.hpp>
|
||||||
|
#include <Nazara/Math/Plane.hpp>
|
||||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||||
#include <Nazara/Utility/MeshData.hpp>
|
#include <Nazara/Utility/MeshData.hpp>
|
||||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||||
|
|
@ -41,7 +42,7 @@ namespace Nz
|
||||||
void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override;
|
void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override;
|
||||||
void AddDrawable(int renderOrder, const Drawable* drawable) override;
|
void AddDrawable(int renderOrder, const Drawable* drawable) override;
|
||||||
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
||||||
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override;
|
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override;
|
||||||
|
|
||||||
void Clear(bool fully = false) override;
|
void Clear(bool fully = false) override;
|
||||||
|
|
||||||
|
|
@ -73,7 +74,7 @@ namespace Nz
|
||||||
std::vector<BillboardData> billboards;
|
std::vector<BillboardData> billboards;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const Material*, BatchedBillboardEntry, MaterialComparator> BatchedBillboardContainer;
|
using BatchedBillboardContainer = std::map<const Material*, BatchedBillboardEntry, MaterialComparator>;
|
||||||
|
|
||||||
struct BatchedBillboardPipelineEntry
|
struct BatchedBillboardPipelineEntry
|
||||||
{
|
{
|
||||||
|
|
@ -81,7 +82,7 @@ namespace Nz
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator> BillboardPipelineBatches;
|
using BillboardPipelineBatches = std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator>;
|
||||||
|
|
||||||
/// Sprites
|
/// Sprites
|
||||||
struct SpriteChain_XYZ_Color_UV
|
struct SpriteChain_XYZ_Color_UV
|
||||||
|
|
@ -97,7 +98,7 @@ namespace Nz
|
||||||
std::vector<SpriteChain_XYZ_Color_UV> spriteChains;
|
std::vector<SpriteChain_XYZ_Color_UV> spriteChains;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const Texture*, BatchedSpriteEntry> SpriteOverlayBatches;
|
using SpriteOverlayBatches = std::map<const Texture*, BatchedSpriteEntry>;
|
||||||
|
|
||||||
struct BatchedBasicSpriteEntry
|
struct BatchedBasicSpriteEntry
|
||||||
{
|
{
|
||||||
|
|
@ -107,7 +108,7 @@ namespace Nz
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator> SpriteMaterialBatches;
|
using SpriteMaterialBatches = std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator>;
|
||||||
|
|
||||||
struct BatchedSpritePipelineEntry
|
struct BatchedSpritePipelineEntry
|
||||||
{
|
{
|
||||||
|
|
@ -115,7 +116,7 @@ namespace Nz
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator> SpritePipelineBatches;
|
using SpritePipelineBatches = std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator>;
|
||||||
|
|
||||||
/// Meshes
|
/// Meshes
|
||||||
struct MeshDataComparator
|
struct MeshDataComparator
|
||||||
|
|
@ -132,7 +133,7 @@ namespace Nz
|
||||||
Spheref squaredBoundingSphere;
|
Spheref squaredBoundingSphere;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<MeshData, MeshInstanceEntry, MeshDataComparator> MeshInstanceContainer;
|
using MeshInstanceContainer = std::map<MeshData, MeshInstanceEntry, MeshDataComparator>;
|
||||||
|
|
||||||
struct BatchedModelEntry
|
struct BatchedModelEntry
|
||||||
{
|
{
|
||||||
|
|
@ -142,7 +143,7 @@ namespace Nz
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const Material*, BatchedModelEntry, MaterialComparator> MeshMaterialBatches;
|
using MeshMaterialBatches = std::map<const Material*, BatchedModelEntry, MaterialComparator>;
|
||||||
|
|
||||||
struct BatchedMaterialEntry
|
struct BatchedMaterialEntry
|
||||||
{
|
{
|
||||||
|
|
@ -150,25 +151,33 @@ namespace Nz
|
||||||
MeshMaterialBatches materialMap;
|
MeshMaterialBatches materialMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator> MeshPipelineBatches;
|
using MeshPipelineBatches = std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator>;
|
||||||
|
|
||||||
struct TransparentModelData
|
struct UnbatchedModelData
|
||||||
{
|
{
|
||||||
Matrix4f transformMatrix;
|
Matrix4f transformMatrix;
|
||||||
MeshData meshData;
|
MeshData meshData;
|
||||||
Spheref squaredBoundingSphere;
|
Spheref obbSphere;
|
||||||
const Material* material;
|
const Material* material;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<std::size_t> TransparentModelContainer;
|
struct UnbatchedSpriteData
|
||||||
|
{
|
||||||
|
std::size_t spriteCount;
|
||||||
|
const Material* material;
|
||||||
|
const Texture* overlay;
|
||||||
|
const VertexStruct_XYZ_Color_UV* vertices;
|
||||||
|
};
|
||||||
|
|
||||||
struct Layer
|
struct Layer
|
||||||
{
|
{
|
||||||
BillboardPipelineBatches billboards;
|
BillboardPipelineBatches billboards;
|
||||||
SpritePipelineBatches basicSprites;
|
SpritePipelineBatches opaqueSprites;
|
||||||
MeshPipelineBatches opaqueModels;
|
MeshPipelineBatches opaqueModels;
|
||||||
TransparentModelContainer transparentModels;
|
std::vector<std::size_t> depthSortedMeshes;
|
||||||
std::vector<TransparentModelData> transparentModelData;
|
std::vector<std::size_t> depthSortedSprites;
|
||||||
|
std::vector<UnbatchedModelData> depthSortedMeshData;
|
||||||
|
std::vector<UnbatchedSpriteData> depthSortedSpriteData;
|
||||||
std::vector<const Drawable*> otherDrawables;
|
std::vector<const Drawable*> otherDrawables;
|
||||||
unsigned int clearCount = 0;
|
unsigned int clearCount = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -179,6 +188,10 @@ namespace Nz
|
||||||
BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count);
|
BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count);
|
||||||
Layer& GetLayer(int i); ///TODO: Inline
|
Layer& GetLayer(int i); ///TODO: Inline
|
||||||
|
|
||||||
|
void SortBillboards(Layer& layer, const Planef& nearPlane);
|
||||||
|
void SortForOrthographic(const AbstractViewer* viewer);
|
||||||
|
void SortForPerspective(const AbstractViewer* viewer);
|
||||||
|
|
||||||
void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer);
|
void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer);
|
||||||
void OnMaterialInvalidation(const Material* material);
|
void OnMaterialInvalidation(const Material* material);
|
||||||
void OnTextureInvalidation(const Texture* texture);
|
void OnTextureInvalidation(const Texture* texture);
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ namespace Nz
|
||||||
void DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
void DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||||
void DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
void DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||||
void DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
void DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||||
|
void DrawOrderedSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||||
void DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
void DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||||
const ShaderUniforms* GetShaderUniforms(const Shader* shader) const;
|
const ShaderUniforms* GetShaderUniforms(const Shader* shader) const;
|
||||||
void OnShaderInvalidated(const Shader* shader) const;
|
void OnShaderInvalidated(const Shader* shader) const;
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,13 @@ namespace Nz
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> /*constexpr*/ std::enable_if_t<!std::is_signed<T>::value || !std::is_integral<T>::value, bool> NumberEquals(T a, T b, T maxDifference)
|
template<typename T> /*constexpr*/ std::enable_if_t<std::is_floating_point<T>::value, bool> NumberEquals(T a, T b, T maxDifference)
|
||||||
|
{
|
||||||
|
T diff = std::abs(a - b);
|
||||||
|
return diff <= maxDifference;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T> /*constexpr*/ std::enable_if_t<!std::is_signed<T>::value || (!std::is_integral<T>::value && !std::is_floating_point<T>::value), bool> NumberEquals(T a, T b, T maxDifference)
|
||||||
{
|
{
|
||||||
if (b > a)
|
if (b > a)
|
||||||
std::swap(a, b);
|
std::swap(a, b);
|
||||||
|
|
@ -112,13 +118,8 @@ namespace Nz
|
||||||
if (b > a)
|
if (b > a)
|
||||||
std::swap(a, b);
|
std::swap(a, b);
|
||||||
|
|
||||||
if ((b < 0) && (a > std::numeric_limits<T>::max() + b))
|
using UnsignedT = std::make_unsigned_t<T>;
|
||||||
return false;
|
return static_cast<UnsignedT>(a) - static_cast<UnsignedT>(b) <= static_cast<UnsignedT>(maxDifference);
|
||||||
|
|
||||||
if ((b > 0) && (a < std::numeric_limits<T>::min() + b))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return std::abs(a - b) <= maxDifference;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -487,7 +488,7 @@ namespace Nz
|
||||||
template<typename T, typename T2>
|
template<typename T, typename T2>
|
||||||
constexpr T Lerp(const T& from, const T& to, const T2& interpolation)
|
constexpr T Lerp(const T& from, const T& to, const T2& interpolation)
|
||||||
{
|
{
|
||||||
return from + interpolation * (to - from);
|
return static_cast<T>(from + interpolation * (to - from));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
||||||
|
|
@ -74,8 +74,8 @@ namespace Nz
|
||||||
Box& Transform(const Matrix4<T>& matrix, bool applyTranslation = true);
|
Box& Transform(const Matrix4<T>& matrix, bool applyTranslation = true);
|
||||||
Box& Translate(const Vector3<T>& translation);
|
Box& Translate(const Vector3<T>& translation);
|
||||||
|
|
||||||
T& operator[](unsigned int i);
|
T& operator[](std::size_t i);
|
||||||
T operator[](unsigned int i) const;
|
T operator[](std::size_t i) const;
|
||||||
|
|
||||||
Box operator*(T scalar) const;
|
Box operator*(T scalar) const;
|
||||||
Box operator*(const Vector3<T>& vec) const;
|
Box operator*(const Vector3<T>& vec) const;
|
||||||
|
|
|
||||||
|
|
@ -735,24 +735,15 @@ namespace Nz
|
||||||
* \brief Returns the ith element of the box
|
* \brief Returns the ith element of the box
|
||||||
* \return A reference to the ith element of the box
|
* \return A reference to the ith element of the box
|
||||||
*
|
*
|
||||||
* \remark Access to index greather than 6 is undefined behavior
|
* \remark Access to index greater than 6 is undefined behavior
|
||||||
* \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined
|
* \remark Produce a NazaraError if you try to access to index greater than 6 with NAZARA_MATH_SAFE defined
|
||||||
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6
|
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& Box<T>::operator[](unsigned int i)
|
T& Box<T>::operator[](std::size_t i)
|
||||||
{
|
{
|
||||||
#if NAZARA_MATH_SAFE
|
NazaraAssert(i < 6, "Index out of range");
|
||||||
if (i >= 6)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 6)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return *(&x+i);
|
return *(&x+i);
|
||||||
}
|
}
|
||||||
|
|
@ -761,24 +752,15 @@ namespace Nz
|
||||||
* \brief Returns the ith element of the box
|
* \brief Returns the ith element of the box
|
||||||
* \return A value to the ith element of the box
|
* \return A value to the ith element of the box
|
||||||
*
|
*
|
||||||
* \remark Access to index greather than 6 is undefined behavior
|
* \remark Access to index greater than 6 is undefined behavior
|
||||||
* \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined
|
* \remark Produce a NazaraError if you try to access to index greater than 6 with NAZARA_MATH_SAFE defined
|
||||||
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6
|
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Box<T>::operator[](unsigned int i) const
|
T Box<T>::operator[](std::size_t i) const
|
||||||
{
|
{
|
||||||
#if NAZARA_MATH_SAFE
|
NazaraAssert(i < 6, "Index out of range");
|
||||||
if (i >= 6)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 6)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return *(&x+i);
|
return *(&x+i);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,8 @@ namespace Nz
|
||||||
|
|
||||||
Rect& Translate(const Vector2<T>& translation);
|
Rect& Translate(const Vector2<T>& translation);
|
||||||
|
|
||||||
T& operator[](unsigned int i);
|
T& operator[](std::size_t i);
|
||||||
T operator[](unsigned int i) const;
|
T operator[](std::size_t i) const;
|
||||||
|
|
||||||
Rect operator*(T scalar) const;
|
Rect operator*(T scalar) const;
|
||||||
Rect operator*(const Vector2<T>& vec) const;
|
Rect operator*(const Vector2<T>& vec) const;
|
||||||
|
|
|
||||||
|
|
@ -578,23 +578,14 @@ namespace Nz
|
||||||
* \return A reference to the ith element of the rectangle
|
* \return A reference to the ith element of the rectangle
|
||||||
*
|
*
|
||||||
* \remark Access to index greather than 4 is undefined behavior
|
* \remark Access to index greather than 4 is undefined behavior
|
||||||
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
* \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
|
||||||
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& Rect<T>::operator[](unsigned int i)
|
T& Rect<T>::operator[](std::size_t i)
|
||||||
{
|
{
|
||||||
#if NAZARA_MATH_SAFE
|
NazaraAssert(i < 4, "Index out of range");
|
||||||
if (i >= 4)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 4)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return *(&x+i);
|
return *(&x+i);
|
||||||
}
|
}
|
||||||
|
|
@ -603,24 +594,15 @@ namespace Nz
|
||||||
* \brief Returns the ith element of the rectangle
|
* \brief Returns the ith element of the rectangle
|
||||||
* \return A value to the ith element of the rectangle
|
* \return A value to the ith element of the rectangle
|
||||||
*
|
*
|
||||||
* \remark Access to index greather than 4 is undefined behavior
|
* \remark Access to index greater than 4 is undefined behavior
|
||||||
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
* \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
|
||||||
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Rect<T>::operator[](unsigned int i) const
|
T Rect<T>::operator[](std::size_t i) const
|
||||||
{
|
{
|
||||||
#if NAZARA_MATH_SAFE
|
NazaraAssert(i < 4, "Index out of range");
|
||||||
if (i >= 4)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 4)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return *(&x+i);
|
return *(&x+i);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ namespace Nz
|
||||||
|
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
|
|
||||||
T& operator[](unsigned int i);
|
T& operator[](std::size_t i);
|
||||||
T operator[](unsigned int i) const;
|
T operator[](std::size_t i) const;
|
||||||
|
|
||||||
Sphere operator*(T scalar) const;
|
Sphere operator*(T scalar) const;
|
||||||
Sphere& operator=(const Sphere& other) = default;
|
Sphere& operator=(const Sphere& other) = default;
|
||||||
|
|
|
||||||
|
|
@ -466,24 +466,15 @@ namespace Nz
|
||||||
* \brief Returns the ith element of the sphere
|
* \brief Returns the ith element of the sphere
|
||||||
* \return A reference to the ith element of the sphere
|
* \return A reference to the ith element of the sphere
|
||||||
*
|
*
|
||||||
* \remark Access to index greather than 4 is undefined behavior
|
* \remark Access to index greater than 4 is undefined behavior
|
||||||
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
* \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
|
||||||
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T& Sphere<T>::operator[](unsigned int i)
|
T& Sphere<T>::operator[](std::size_t i)
|
||||||
{
|
{
|
||||||
#if NAZARA_MATH_SAFE
|
NazaraAssert(i < 4, "Index out of range");
|
||||||
if (i >= 4)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 4)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return *(&x+i);
|
return *(&x+i);
|
||||||
}
|
}
|
||||||
|
|
@ -492,24 +483,15 @@ namespace Nz
|
||||||
* \brief Returns the ith element of the sphere
|
* \brief Returns the ith element of the sphere
|
||||||
* \return A value to the ith element of the sphere
|
* \return A value to the ith element of the sphere
|
||||||
*
|
*
|
||||||
* \remark Access to index greather than 4 is undefined behavior
|
* \remark Access to index greater than 4 is undefined behavior
|
||||||
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
* \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
|
||||||
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T Sphere<T>::operator[](unsigned int i) const
|
T Sphere<T>::operator[](std::size_t i) const
|
||||||
{
|
{
|
||||||
#if NAZARA_MATH_SAFE
|
NazaraAssert(i < 4, "Index out of range");
|
||||||
if (i >= 4)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 4)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return *(&x+i);
|
return *(&x+i);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#ifndef NAZARA_ENUMS_NETWORK_HPP
|
#ifndef NAZARA_ENUMS_NETWORK_HPP
|
||||||
#define NAZARA_ENUMS_NETWORK_HPP
|
#define NAZARA_ENUMS_NETWORK_HPP
|
||||||
|
|
||||||
#include <Nazara/Prerequesites.hpp>
|
#include <Nazara/Core/Flags.hpp>
|
||||||
|
|
||||||
namespace Nz
|
namespace Nz
|
||||||
{
|
{
|
||||||
|
|
@ -91,6 +91,23 @@ namespace Nz
|
||||||
SocketError_Max = SocketError_UnreachableHost
|
SocketError_Max = SocketError_UnreachableHost
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SocketPollEvent
|
||||||
|
{
|
||||||
|
SocketPollEvent_Read, //< One or more sockets is ready for a read operation
|
||||||
|
SocketPollEvent_Write, //< One or more sockets is ready for a write operation
|
||||||
|
|
||||||
|
SocketPollEvent_Max = SocketPollEvent_Write
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct EnumAsFlags<SocketPollEvent>
|
||||||
|
{
|
||||||
|
static constexpr bool value = true;
|
||||||
|
static constexpr int max = SocketPollEvent_Max;
|
||||||
|
};
|
||||||
|
|
||||||
|
using SocketPollEventFlags = Flags<SocketPollEvent>;
|
||||||
|
|
||||||
enum SocketState
|
enum SocketState
|
||||||
{
|
{
|
||||||
SocketState_Bound, //< The socket is currently bound
|
SocketState_Bound, //< The socket is currently bound
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,11 @@ namespace Nz
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
bool IsReady(const AbstractSocket& socket) const;
|
bool IsReadyToRead(const AbstractSocket& socket) const;
|
||||||
|
bool IsReadyToWrite(const AbstractSocket& socket) const;
|
||||||
bool IsRegistered(const AbstractSocket& socket) const;
|
bool IsRegistered(const AbstractSocket& socket) const;
|
||||||
|
|
||||||
bool RegisterSocket(AbstractSocket& socket);
|
bool RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags);
|
||||||
void UnregisterSocket(AbstractSocket& socket);
|
void UnregisterSocket(AbstractSocket& socket);
|
||||||
|
|
||||||
bool Wait(UInt64 msTimeout);
|
bool Wait(UInt64 msTimeout);
|
||||||
|
|
@ -41,4 +42,4 @@ namespace Nz
|
||||||
|
|
||||||
#include <Nazara/Network/SocketPoller.inl>
|
#include <Nazara/Network/SocketPoller.inl>
|
||||||
|
|
||||||
#endif // NAZARA_SOCKETPOLLER_HPP
|
#endif // NAZARA_SOCKETPOLLER_HPP
|
||||||
|
|
|
||||||
|
|
@ -64,10 +64,10 @@ namespace Nz
|
||||||
|
|
||||||
struct Callback
|
struct Callback
|
||||||
{
|
{
|
||||||
ContactEndCallback endCallback;
|
ContactEndCallback endCallback = nullptr;
|
||||||
ContactPreSolveCallback preSolveCallback;
|
ContactPreSolveCallback preSolveCallback = nullptr;
|
||||||
ContactPostSolveCallback postSolveCallback;
|
ContactPostSolveCallback postSolveCallback = nullptr;
|
||||||
ContactStartCallback startCallback;
|
ContactStartCallback startCallback = nullptr;
|
||||||
void* userdata;
|
void* userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,15 +26,15 @@ namespace Nz
|
||||||
|
|
||||||
Reference operator*() const;
|
Reference operator*() const;
|
||||||
|
|
||||||
Reference operator[](unsigned int index) const;
|
Reference operator[](std::size_t index) const;
|
||||||
|
|
||||||
IndexIterator& operator=(const IndexIterator& iterator);
|
IndexIterator& operator=(const IndexIterator& iterator);
|
||||||
|
|
||||||
IndexIterator operator+(unsigned int indexCount) const;
|
IndexIterator operator+(std::size_t indexCount) const;
|
||||||
IndexIterator operator-(unsigned int indexCount) const;
|
IndexIterator operator-(std::size_t indexCount) const;
|
||||||
|
|
||||||
IndexIterator& operator+=(unsigned int indexCount);
|
IndexIterator& operator+=(std::size_t indexCount);
|
||||||
IndexIterator& operator-=(unsigned int indexCount);
|
IndexIterator& operator-=(std::size_t indexCount);
|
||||||
|
|
||||||
IndexIterator& operator++();
|
IndexIterator& operator++();
|
||||||
IndexIterator operator++(int);
|
IndexIterator operator++(int);
|
||||||
|
|
@ -50,10 +50,10 @@ namespace Nz
|
||||||
friend bool operator>=(const IndexIterator& lhs, const IndexIterator& rhs);
|
friend bool operator>=(const IndexIterator& lhs, const IndexIterator& rhs);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
IndexIterator(IndexMapper* mapper, unsigned int index);
|
IndexIterator(IndexMapper* mapper, std::size_t index);
|
||||||
|
|
||||||
IndexMapper* m_mapper;
|
IndexMapper* m_mapper;
|
||||||
unsigned int m_index;
|
std::size_t m_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IndexIterator::Reference
|
class IndexIterator::Reference
|
||||||
|
|
@ -70,10 +70,10 @@ namespace Nz
|
||||||
operator UInt32() const;
|
operator UInt32() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Reference(IndexMapper* mapper, unsigned int index);
|
Reference(IndexMapper* mapper, std::size_t index);
|
||||||
|
|
||||||
IndexMapper* m_mapper;
|
IndexMapper* m_mapper;
|
||||||
unsigned int m_index;
|
std::size_t m_index;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexIterator::IndexIterator(IndexMapper* mapper, unsigned int index) :
|
inline IndexIterator::IndexIterator(IndexMapper* mapper, std::size_t index) :
|
||||||
m_mapper(mapper),
|
m_mapper(mapper),
|
||||||
m_index(index)
|
m_index(index)
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +31,7 @@ namespace Nz
|
||||||
return Reference(m_mapper, m_index);
|
return Reference(m_mapper, m_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexIterator::Reference IndexIterator::operator[](unsigned int index) const
|
inline IndexIterator::Reference IndexIterator::operator[](std::size_t index) const
|
||||||
{
|
{
|
||||||
return Reference(m_mapper, m_index+index);
|
return Reference(m_mapper, m_index+index);
|
||||||
}
|
}
|
||||||
|
|
@ -44,24 +44,24 @@ namespace Nz
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexIterator IndexIterator::operator+(unsigned int indexCount) const
|
inline IndexIterator IndexIterator::operator+(std::size_t indexCount) const
|
||||||
{
|
{
|
||||||
return IndexIterator(m_mapper, m_index + indexCount);
|
return IndexIterator(m_mapper, m_index + indexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexIterator IndexIterator::operator-(unsigned int indexCount) const
|
inline IndexIterator IndexIterator::operator-(std::size_t indexCount) const
|
||||||
{
|
{
|
||||||
return IndexIterator(m_mapper, m_index - indexCount);
|
return IndexIterator(m_mapper, m_index - indexCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexIterator& IndexIterator::operator+=(unsigned int indexCount)
|
inline IndexIterator& IndexIterator::operator+=(std::size_t indexCount)
|
||||||
{
|
{
|
||||||
m_index += indexCount;
|
m_index += indexCount;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexIterator& IndexIterator::operator-=(unsigned int indexCount)
|
inline IndexIterator& IndexIterator::operator-=(std::size_t indexCount)
|
||||||
{
|
{
|
||||||
m_index += indexCount;
|
m_index += indexCount;
|
||||||
|
|
||||||
|
|
@ -133,7 +133,7 @@ namespace Nz
|
||||||
|
|
||||||
/**************************IndexIterator::Reference*************************/
|
/**************************IndexIterator::Reference*************************/
|
||||||
|
|
||||||
inline IndexIterator::Reference::Reference(IndexMapper* mapper, unsigned int index) :
|
inline IndexIterator::Reference::Reference(IndexMapper* mapper, std::size_t index) :
|
||||||
m_mapper(mapper),
|
m_mapper(mapper),
|
||||||
m_index(index)
|
m_index(index)
|
||||||
{
|
{
|
||||||
|
|
@ -148,7 +148,7 @@ namespace Nz
|
||||||
|
|
||||||
inline IndexIterator::Reference& IndexIterator::Reference::operator=(const IndexIterator::Reference& reference)
|
inline IndexIterator::Reference& IndexIterator::Reference::operator=(const IndexIterator::Reference& reference)
|
||||||
{
|
{
|
||||||
m_mapper->Set(m_index, reference); // Conversion implicite en UInt32
|
m_mapper->Set(m_index, reference); // Implicit conversion to UInt32
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,6 @@ namespace Nz
|
||||||
class IndexIterator;
|
class IndexIterator;
|
||||||
class SubMesh;
|
class SubMesh;
|
||||||
|
|
||||||
using IndexMapperGetter = UInt32 (*)(const void* buffer, unsigned int i);
|
|
||||||
using IndexMapperSetter = void (*)(void* buffer, unsigned int i, UInt32 value);
|
|
||||||
|
|
||||||
class NAZARA_UTILITY_API IndexMapper
|
class NAZARA_UTILITY_API IndexMapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -29,11 +26,11 @@ namespace Nz
|
||||||
IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly);
|
IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly);
|
||||||
~IndexMapper() = default;
|
~IndexMapper() = default;
|
||||||
|
|
||||||
UInt32 Get(unsigned int i) const;
|
UInt32 Get(std::size_t i) const;
|
||||||
const IndexBuffer* GetBuffer() const;
|
const IndexBuffer* GetBuffer() const;
|
||||||
unsigned int GetIndexCount() const;
|
std::size_t GetIndexCount() const;
|
||||||
|
|
||||||
void Set(unsigned int i, UInt32 value);
|
void Set(std::size_t i, UInt32 value);
|
||||||
|
|
||||||
void Unmap();
|
void Unmap();
|
||||||
|
|
||||||
|
|
@ -45,10 +42,13 @@ namespace Nz
|
||||||
// Méthodes STD
|
// Méthodes STD
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using Getter = UInt32(*)(const void* buffer, std::size_t i);
|
||||||
|
using Setter = void(*)(void* buffer, std::size_t i, UInt32 value);
|
||||||
|
|
||||||
BufferMapper<IndexBuffer> m_mapper;
|
BufferMapper<IndexBuffer> m_mapper;
|
||||||
IndexMapperGetter m_getter;
|
Getter m_getter;
|
||||||
IndexMapperSetter m_setter;
|
Setter m_setter;
|
||||||
unsigned int m_indexCount;
|
std::size_t m_indexCount;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ namespace Nz
|
||||||
|
|
||||||
bool Advance();
|
bool Advance();
|
||||||
|
|
||||||
UInt32 operator[](unsigned int i) const;
|
UInt32 operator[](std::size_t i) const;
|
||||||
|
|
||||||
void Unmap();
|
void Unmap();
|
||||||
|
|
||||||
|
|
@ -32,8 +32,8 @@ namespace Nz
|
||||||
PrimitiveMode m_primitiveMode;
|
PrimitiveMode m_primitiveMode;
|
||||||
UInt32 m_triangleIndices[3];
|
UInt32 m_triangleIndices[3];
|
||||||
IndexMapper m_indexMapper;
|
IndexMapper m_indexMapper;
|
||||||
unsigned int m_currentIndex;
|
std::size_t m_currentIndex;
|
||||||
unsigned int m_indexCount;
|
std::size_t m_indexCount;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
||||||
|
|
||||||
if (animatedMesh)
|
if (animatedMesh)
|
||||||
{
|
{
|
||||||
mesh->CreateSkeletal(joints.size());
|
mesh->CreateSkeletal(UInt32(joints.size()));
|
||||||
|
|
||||||
Skeleton* skeleton = mesh->GetSkeleton();
|
Skeleton* skeleton = mesh->GetSkeleton();
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
||||||
mesh->CreateStatic();
|
mesh->CreateStatic();
|
||||||
|
|
||||||
// aiMaterial index in scene => Material index and data in Mesh
|
// aiMaterial index in scene => Material index and data in Mesh
|
||||||
std::unordered_map<unsigned int, std::pair<std::size_t, ParameterList>> materials;
|
std::unordered_map<unsigned int, std::pair<UInt32, ParameterList>> materials;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
|
||||||
{
|
{
|
||||||
|
|
@ -300,7 +300,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
||||||
if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS)
|
if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS)
|
||||||
matData.SetParameter(MaterialData::FaceCulling, !iValue);
|
matData.SetParameter(MaterialData::FaceCulling, !iValue);
|
||||||
|
|
||||||
matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(materials.size(), std::move(matData)))).first;
|
matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
subMesh->SetMaterialIndex(matIt->first);
|
subMesh->SetMaterialIndex(matIt->first);
|
||||||
|
|
@ -308,7 +308,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
||||||
mesh->AddSubMesh(subMesh);
|
mesh->AddSubMesh(subMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh->SetMaterialCount(std::max<UInt32>(materials.size(), 1));
|
mesh->SetMaterialCount(std::max<UInt32>(UInt32(materials.size()), 1));
|
||||||
for (const auto& pair : materials)
|
for (const auto& pair : materials)
|
||||||
mesh->SetMaterialData(pair.second.first, pair.second.second);
|
mesh->SetMaterialData(pair.second.first, pair.second.second);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ Vous pouvez lire des tutoriaux sur l'installation, la compilation et l'utilisati
|
||||||
[Wiki](https://github.com/DigitalPulseSoftware/NazaraEngine/wiki)
|
[Wiki](https://github.com/DigitalPulseSoftware/NazaraEngine/wiki)
|
||||||
[Forum](https://forum.digitalpulsesoftware.net)
|
[Forum](https://forum.digitalpulsesoftware.net)
|
||||||
|
|
||||||
###Remerciements:
|
### Remerciements:
|
||||||
|
|
||||||
- **RafBill** et **Raakz:** Recherche de bugs et/ou tests
|
- **RafBill** et **Raakz:** Recherche de bugs et/ou tests
|
||||||
- **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur
|
- **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
struct HashMD5_state
|
struct HashMD5_state
|
||||||
{
|
{
|
||||||
UInt32 count[2]; /* message length in bits, lsw first */
|
std::size_t count[2]; /* message length in bits, lsw first */
|
||||||
UInt32 abcd[4]; /* digest buffer */
|
UInt32 abcd[4]; /* digest buffer */
|
||||||
UInt8 buf[64]; /* accumulate block */
|
UInt8 buf[64]; /* accumulate block */
|
||||||
};
|
};
|
||||||
|
|
@ -280,9 +280,9 @@ namespace Nz
|
||||||
void HashMD5::Append(const UInt8* data, std::size_t len)
|
void HashMD5::Append(const UInt8* data, std::size_t len)
|
||||||
{
|
{
|
||||||
const UInt8 *p = data;
|
const UInt8 *p = data;
|
||||||
int left = len;
|
std::size_t left = len;
|
||||||
int offset = (m_state->count[0] >> 3) & 63;
|
int offset = (m_state->count[0] >> 3) & 63;
|
||||||
UInt32 nbits = len << 3;
|
std::size_t nbits = len << 3;
|
||||||
|
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
@ -296,7 +296,7 @@ namespace Nz
|
||||||
/* Process an initial partial block. */
|
/* Process an initial partial block. */
|
||||||
if (offset)
|
if (offset)
|
||||||
{
|
{
|
||||||
int copy = (offset + len > 64 ? 64 - offset : len);
|
std::size_t copy = (offset + len > 64 ? 64 - offset : len);
|
||||||
|
|
||||||
std::memcpy(m_state->buf + offset, p, copy);
|
std::memcpy(m_state->buf + offset, p, copy);
|
||||||
if (offset + copy < 64)
|
if (offset + copy < 64)
|
||||||
|
|
|
||||||
|
|
@ -75,8 +75,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
struct HashWhirlpool_state
|
struct HashWhirlpool_state
|
||||||
{
|
{
|
||||||
int bufferBits; // current number of bits on the buffer */
|
std::size_t bufferBits; // current number of bits on the buffer */
|
||||||
int bufferPos; // current (possibly incomplete) byte slot on the buffer */
|
std::size_t bufferPos; // current (possibly incomplete) byte slot on the buffer */
|
||||||
UInt8 bitLength[32]; // global number of hashed bits (256-bit counter) */
|
UInt8 bitLength[32]; // global number of hashed bits (256-bit counter) */
|
||||||
UInt8 buffer[64]; // buffer of data to hash */
|
UInt8 buffer[64]; // buffer of data to hash */
|
||||||
UInt64 hash[8]; // the hashing state */
|
UInt64 hash[8]; // the hashing state */
|
||||||
|
|
@ -877,8 +877,8 @@ namespace Nz
|
||||||
UInt32 b;
|
UInt32 b;
|
||||||
UInt8* buffer = m_state->buffer;
|
UInt8* buffer = m_state->buffer;
|
||||||
UInt8* bitLength = m_state->bitLength;
|
UInt8* bitLength = m_state->bitLength;
|
||||||
int bufferBits = m_state->bufferBits;
|
std::size_t bufferBits = m_state->bufferBits;
|
||||||
int bufferPos = m_state->bufferPos;
|
std::size_t bufferPos = m_state->bufferPos;
|
||||||
|
|
||||||
// tally the length of the added data
|
// tally the length of the added data
|
||||||
UInt64 value = len;
|
UInt64 value = len;
|
||||||
|
|
@ -968,8 +968,8 @@ namespace Nz
|
||||||
|
|
||||||
UInt8 *buffer = m_state->buffer;
|
UInt8 *buffer = m_state->buffer;
|
||||||
UInt8 *bitLength = m_state->bitLength;
|
UInt8 *bitLength = m_state->bitLength;
|
||||||
int bufferBits = m_state->bufferBits;
|
std::size_t bufferBits = m_state->bufferBits;
|
||||||
int bufferPos = m_state->bufferPos;
|
std::size_t bufferPos = m_state->bufferPos;
|
||||||
UInt8 *digest = result;
|
UInt8 *digest = result;
|
||||||
|
|
||||||
// append a '1'-bit
|
// append a '1'-bit
|
||||||
|
|
|
||||||
|
|
@ -2115,7 +2115,7 @@ namespace Nz
|
||||||
|
|
||||||
return ptr - m_sharedString->string.get();
|
return ptr - m_sharedString->string.get();
|
||||||
}
|
}
|
||||||
catch (utf8::not_enough_room& e)
|
catch (utf8::not_enough_room& /*e*/)
|
||||||
{
|
{
|
||||||
// Returns npos
|
// Returns npos
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,8 +191,8 @@ namespace Nz
|
||||||
|
|
||||||
void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
|
||||||
{
|
{
|
||||||
if (material->IsBlendingEnabled())
|
if (material->IsBlendingEnabled() || material->IsDepthSortingEnabled()) //< Fixme: Deferred Shading should be able to handle depth sorting
|
||||||
// One transparent material ? I don't like it, go see if I'm in the forward queue
|
// Deferred Shading cannot handle blended objects, put them in the forward list
|
||||||
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
|
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -254,7 +254,7 @@ namespace Nz
|
||||||
* \param overlay Texture of the sprites
|
* \param overlay Texture of the sprites
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
|
void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
|
||||||
{
|
{
|
||||||
m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay);
|
m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ namespace Nz
|
||||||
* \remark Produces a NazaraAssert if material is invalid
|
* \remark Produces a NazaraAssert if material is invalid
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
|
void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
|
||||||
{
|
{
|
||||||
NazaraAssert(material, "Invalid material");
|
NazaraAssert(material, "Invalid material");
|
||||||
NazaraUnused(renderOrder);
|
NazaraUnused(renderOrder);
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ namespace Nz
|
||||||
if (!layer.opaqueModels.empty())
|
if (!layer.opaqueModels.empty())
|
||||||
DrawOpaqueModels(sceneData, layer);
|
DrawOpaqueModels(sceneData, layer);
|
||||||
|
|
||||||
if (!layer.basicSprites.empty())
|
if (!layer.opaqueSprites.empty())
|
||||||
DrawBasicSprites(sceneData, layer);
|
DrawBasicSprites(sceneData, layer);
|
||||||
|
|
||||||
if (!layer.billboards.empty())
|
if (!layer.billboards.empty())
|
||||||
|
|
@ -219,7 +219,7 @@ namespace Nz
|
||||||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||||
|
|
||||||
for (auto& pipelinePair : layer.basicSprites)
|
for (auto& pipelinePair : layer.opaqueSprites)
|
||||||
{
|
{
|
||||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||||
auto& pipelineEntry = pipelinePair.second;
|
auto& pipelineEntry = pipelinePair.second;
|
||||||
|
|
|
||||||
|
|
@ -376,23 +376,23 @@ namespace Nz
|
||||||
{
|
{
|
||||||
NazaraAssert(material, "Invalid material");
|
NazaraAssert(material, "Invalid material");
|
||||||
|
|
||||||
if (material->IsBlendingEnabled())
|
if (material->IsDepthSortingEnabled())
|
||||||
{
|
{
|
||||||
Layer& currentLayer = GetLayer(renderOrder);
|
Layer& currentLayer = GetLayer(renderOrder);
|
||||||
auto& transparentModels = currentLayer.transparentModels;
|
auto& transparentMeshes = currentLayer.depthSortedMeshes;
|
||||||
auto& transparentModelData = currentLayer.transparentModelData;
|
auto& transparentData = currentLayer.depthSortedMeshData;
|
||||||
|
|
||||||
// The material is transparent, we must draw this mesh using another way (after the rendering of opages objects while sorting them)
|
// The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them)
|
||||||
std::size_t index = transparentModelData.size();
|
std::size_t index = transparentData.size();
|
||||||
transparentModelData.resize(index+1);
|
transparentData.resize(index+1);
|
||||||
|
|
||||||
TransparentModelData& data = transparentModelData.back();
|
UnbatchedModelData& data = transparentData.back();
|
||||||
data.material = material;
|
data.material = material;
|
||||||
data.meshData = meshData;
|
data.meshData = meshData;
|
||||||
data.squaredBoundingSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
data.obbSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
||||||
data.transformMatrix = transformMatrix;
|
data.transformMatrix = transformMatrix;
|
||||||
|
|
||||||
transparentModels.push_back(index);
|
transparentMeshes.push_back(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -457,53 +457,74 @@ namespace Nz
|
||||||
*
|
*
|
||||||
* \remark Produces a NazaraAssert if material is invalid
|
* \remark Produces a NazaraAssert if material is invalid
|
||||||
*/
|
*/
|
||||||
void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay)
|
void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
|
||||||
{
|
{
|
||||||
NazaraAssert(material, "Invalid material");
|
NazaraAssert(material, "Invalid material");
|
||||||
|
|
||||||
Layer& currentLayer = GetLayer(renderOrder);
|
Layer& currentLayer = GetLayer(renderOrder);
|
||||||
SpritePipelineBatches& basicSprites = currentLayer.basicSprites;
|
|
||||||
|
|
||||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
if (material->IsDepthSortingEnabled())
|
||||||
|
|
||||||
auto pipelineIt = basicSprites.find(materialPipeline);
|
|
||||||
if (pipelineIt == basicSprites.end())
|
|
||||||
{
|
{
|
||||||
BatchedSpritePipelineEntry materialEntry;
|
auto& transparentSprites = currentLayer.depthSortedSprites;
|
||||||
pipelineIt = basicSprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
auto& transparentData = currentLayer.depthSortedSpriteData;
|
||||||
|
|
||||||
|
// The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them)
|
||||||
|
std::size_t index = transparentData.size();
|
||||||
|
transparentData.resize(index + 1);
|
||||||
|
|
||||||
|
UnbatchedSpriteData& data = transparentData.back();
|
||||||
|
data.material = material;
|
||||||
|
data.overlay = overlay;
|
||||||
|
data.spriteCount = spriteCount;
|
||||||
|
data.vertices = vertices;
|
||||||
|
|
||||||
|
transparentSprites.push_back(index);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
|
|
||||||
pipelineEntry.enabled = true;
|
|
||||||
|
|
||||||
SpriteMaterialBatches& materialMap = pipelineEntry.materialMap;
|
|
||||||
|
|
||||||
auto matIt = materialMap.find(material);
|
|
||||||
if (matIt == materialMap.end())
|
|
||||||
{
|
{
|
||||||
BatchedBasicSpriteEntry entry;
|
SpritePipelineBatches& sprites = currentLayer.opaqueSprites;
|
||||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
|
||||||
|
|
||||||
matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first;
|
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||||
|
|
||||||
|
auto pipelineIt = sprites.find(materialPipeline);
|
||||||
|
if (pipelineIt == sprites.end())
|
||||||
|
{
|
||||||
|
BatchedSpritePipelineEntry materialEntry;
|
||||||
|
pipelineIt = sprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
|
||||||
|
pipelineEntry.enabled = true;
|
||||||
|
|
||||||
|
SpriteMaterialBatches& materialMap = pipelineEntry.materialMap;
|
||||||
|
|
||||||
|
auto matIt = materialMap.find(material);
|
||||||
|
if (matIt == materialMap.end())
|
||||||
|
{
|
||||||
|
BatchedBasicSpriteEntry entry;
|
||||||
|
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||||
|
|
||||||
|
matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchedBasicSpriteEntry& entry = matIt->second;
|
||||||
|
entry.enabled = true;
|
||||||
|
|
||||||
|
auto& overlayMap = entry.overlayMap;
|
||||||
|
|
||||||
|
auto overlayIt = overlayMap.find(overlay);
|
||||||
|
if (overlayIt == overlayMap.end())
|
||||||
|
{
|
||||||
|
BatchedSpriteEntry overlayEntry;
|
||||||
|
if (overlay)
|
||||||
|
overlayEntry.textureReleaseSlot.Connect(overlay->OnTextureRelease, this, &ForwardRenderQueue::OnTextureInvalidation);
|
||||||
|
|
||||||
|
overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& spriteVector = overlayIt->second.spriteChains;
|
||||||
|
spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount}));
|
||||||
}
|
}
|
||||||
|
|
||||||
BatchedBasicSpriteEntry& entry = matIt->second;
|
|
||||||
entry.enabled = true;
|
|
||||||
|
|
||||||
auto& overlayMap = entry.overlayMap;
|
|
||||||
|
|
||||||
auto overlayIt = overlayMap.find(overlay);
|
|
||||||
if (overlayIt == overlayMap.end())
|
|
||||||
{
|
|
||||||
BatchedSpriteEntry overlayEntry;
|
|
||||||
if (overlay)
|
|
||||||
overlayEntry.textureReleaseSlot.Connect(overlay->OnTextureRelease, this, &ForwardRenderQueue::OnTextureInvalidation);
|
|
||||||
|
|
||||||
overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& spriteVector = overlayIt->second.spriteChains;
|
|
||||||
spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -545,7 +566,7 @@ namespace Nz
|
||||||
pipelineEntry.enabled = false;
|
pipelineEntry.enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& pipelinePair : layer.basicSprites)
|
for (auto& pipelinePair : layer.opaqueSprites)
|
||||||
{
|
{
|
||||||
auto& pipelineEntry = pipelinePair.second;
|
auto& pipelineEntry = pipelinePair.second;
|
||||||
|
|
||||||
|
|
@ -596,9 +617,11 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
layer.depthSortedMeshes.clear();
|
||||||
|
layer.depthSortedMeshData.clear();
|
||||||
|
layer.depthSortedSpriteData.clear();
|
||||||
|
layer.depthSortedSprites.clear();
|
||||||
layer.otherDrawables.clear();
|
layer.otherDrawables.clear();
|
||||||
layer.transparentModels.clear();
|
|
||||||
layer.transparentModelData.clear();
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -613,44 +636,10 @@ namespace Nz
|
||||||
|
|
||||||
void ForwardRenderQueue::Sort(const AbstractViewer* viewer)
|
void ForwardRenderQueue::Sort(const AbstractViewer* viewer)
|
||||||
{
|
{
|
||||||
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
if (viewer->GetProjectionType() == ProjectionType_Orthogonal)
|
||||||
Vector3f viewerPos = viewer->GetEyePosition();
|
SortForOrthographic(viewer);
|
||||||
Vector3f viewerNormal = viewer->GetForward();
|
else
|
||||||
|
SortForPerspective(viewer);
|
||||||
for (auto& pair : layers)
|
|
||||||
{
|
|
||||||
Layer& layer = pair.second;
|
|
||||||
|
|
||||||
std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (std::size_t index1, std::size_t index2)
|
|
||||||
{
|
|
||||||
const Spheref& sphere1 = layer.transparentModelData[index1].squaredBoundingSphere;
|
|
||||||
const Spheref& sphere2 = layer.transparentModelData[index2].squaredBoundingSphere;
|
|
||||||
|
|
||||||
Vector3f position1 = sphere1.GetNegativeVertex(viewerNormal);
|
|
||||||
Vector3f position2 = sphere2.GetNegativeVertex(viewerNormal);
|
|
||||||
|
|
||||||
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (auto& pipelinePair : layer.billboards)
|
|
||||||
{
|
|
||||||
for (auto& matPair : pipelinePair.second.materialMap)
|
|
||||||
{
|
|
||||||
const Material* mat = matPair.first;
|
|
||||||
|
|
||||||
if (mat->IsDepthSortingEnabled())
|
|
||||||
{
|
|
||||||
BatchedBillboardEntry& entry = matPair.second;
|
|
||||||
auto& billboardVector = entry.billboards;
|
|
||||||
|
|
||||||
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos] (const BillboardData& data1, const BillboardData& data2)
|
|
||||||
{
|
|
||||||
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -715,12 +704,91 @@ namespace Nz
|
||||||
return layer;
|
return layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForwardRenderQueue::SortBillboards(Layer& layer, const Planef& nearPlane)
|
||||||
|
{
|
||||||
|
for (auto& pipelinePair : layer.billboards)
|
||||||
|
{
|
||||||
|
for (auto& matPair : pipelinePair.second.materialMap)
|
||||||
|
{
|
||||||
|
const Material* mat = matPair.first;
|
||||||
|
|
||||||
|
if (mat->IsDepthSortingEnabled())
|
||||||
|
{
|
||||||
|
BatchedBillboardEntry& entry = matPair.second;
|
||||||
|
auto& billboardVector = entry.billboards;
|
||||||
|
|
||||||
|
std::sort(billboardVector.begin(), billboardVector.end(), [&nearPlane] (const BillboardData& data1, const BillboardData& data2)
|
||||||
|
{
|
||||||
|
return nearPlane.Distance(data1.center) > nearPlane.Distance(data2.center);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardRenderQueue::SortForOrthographic(const AbstractViewer * viewer)
|
||||||
|
{
|
||||||
|
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||||
|
Vector3f viewerPos = viewer->GetEyePosition();
|
||||||
|
|
||||||
|
for (auto& pair : layers)
|
||||||
|
{
|
||||||
|
Layer& layer = pair.second;
|
||||||
|
|
||||||
|
std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2)
|
||||||
|
{
|
||||||
|
const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere;
|
||||||
|
const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere;
|
||||||
|
|
||||||
|
return nearPlane.Distance(sphere1.GetPosition()) < nearPlane.Distance(sphere2.GetPosition());
|
||||||
|
});
|
||||||
|
|
||||||
|
std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2)
|
||||||
|
{
|
||||||
|
const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position;
|
||||||
|
const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position;
|
||||||
|
|
||||||
|
return nearPlane.Distance(pos1) < nearPlane.Distance(pos2);
|
||||||
|
});
|
||||||
|
|
||||||
|
SortBillboards(layer, nearPlane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardRenderQueue::SortForPerspective(const AbstractViewer* viewer)
|
||||||
|
{
|
||||||
|
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||||
|
Vector3f viewerPos = viewer->GetEyePosition();
|
||||||
|
|
||||||
|
for (auto& pair : layers)
|
||||||
|
{
|
||||||
|
Layer& layer = pair.second;
|
||||||
|
|
||||||
|
std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2)
|
||||||
|
{
|
||||||
|
const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere;
|
||||||
|
const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere;
|
||||||
|
|
||||||
|
return viewerPos.SquaredDistance(sphere1.GetPosition()) > viewerPos.SquaredDistance(sphere2.GetPosition());
|
||||||
|
});
|
||||||
|
|
||||||
|
std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2)
|
||||||
|
{
|
||||||
|
const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position;
|
||||||
|
const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position;
|
||||||
|
|
||||||
|
return viewerPos.SquaredDistance(pos1) > viewerPos.SquaredDistance(pos2);
|
||||||
|
});
|
||||||
|
|
||||||
|
SortBillboards(layer, nearPlane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Handle the invalidation of an index buffer
|
* \brief Handle the invalidation of an index buffer
|
||||||
*
|
*
|
||||||
* \param indexBuffer Index buffer being invalidated
|
* \param indexBuffer Index buffer being invalidated
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
||||||
{
|
{
|
||||||
for (auto& pair : layers)
|
for (auto& pair : layers)
|
||||||
|
|
@ -757,7 +825,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
Layer& layer = pair.second;
|
Layer& layer = pair.second;
|
||||||
|
|
||||||
for (auto& pipelineEntry : layer.basicSprites)
|
for (auto& pipelineEntry : layer.opaqueSprites)
|
||||||
pipelineEntry.second.materialMap.erase(material);
|
pipelineEntry.second.materialMap.erase(material);
|
||||||
|
|
||||||
for (auto& pipelineEntry : layer.billboards)
|
for (auto& pipelineEntry : layer.billboards)
|
||||||
|
|
@ -779,7 +847,7 @@ namespace Nz
|
||||||
for (auto& pair : layers)
|
for (auto& pair : layers)
|
||||||
{
|
{
|
||||||
Layer& layer = pair.second;
|
Layer& layer = pair.second;
|
||||||
for (auto& pipelineEntry : layer.basicSprites)
|
for (auto& pipelineEntry : layer.opaqueSprites)
|
||||||
{
|
{
|
||||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||||
materialEntry.second.overlayMap.erase(texture);
|
materialEntry.second.overlayMap.erase(texture);
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ namespace Nz
|
||||||
Vector2f uv;
|
Vector2f uv;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::size_t s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
UInt32 s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||||
std::size_t s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -101,12 +101,15 @@ namespace Nz
|
||||||
if (!layer.opaqueModels.empty())
|
if (!layer.opaqueModels.empty())
|
||||||
DrawOpaqueModels(sceneData, layer);
|
DrawOpaqueModels(sceneData, layer);
|
||||||
|
|
||||||
if (!layer.transparentModels.empty())
|
if (!layer.depthSortedMeshes.empty())
|
||||||
DrawTransparentModels(sceneData, layer);
|
DrawTransparentModels(sceneData, layer);
|
||||||
|
|
||||||
if (!layer.basicSprites.empty())
|
if (!layer.opaqueSprites.empty())
|
||||||
DrawBasicSprites(sceneData, layer);
|
DrawBasicSprites(sceneData, layer);
|
||||||
|
|
||||||
|
if (!layer.depthSortedSprites.empty())
|
||||||
|
DrawOrderedSprites(sceneData, layer);
|
||||||
|
|
||||||
if (!layer.billboards.empty())
|
if (!layer.billboards.empty())
|
||||||
DrawBillboards(sceneData, layer);
|
DrawBillboards(sceneData, layer);
|
||||||
|
|
||||||
|
|
@ -301,7 +304,10 @@ namespace Nz
|
||||||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||||
|
|
||||||
for (auto& pipelinePair : layer.basicSprites)
|
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
||||||
|
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||||
|
|
||||||
|
for (auto& pipelinePair : layer.opaqueSprites)
|
||||||
{
|
{
|
||||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||||
auto& pipelineEntry = pipelinePair.second;
|
auto& pipelineEntry = pipelinePair.second;
|
||||||
|
|
@ -323,6 +329,9 @@ namespace Nz
|
||||||
// Position of the camera
|
// Position of the camera
|
||||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||||
|
|
||||||
|
// Overlay texture unit
|
||||||
|
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||||
|
|
||||||
lastShader = shader;
|
lastShader = shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -335,10 +344,6 @@ namespace Nz
|
||||||
{
|
{
|
||||||
material->Apply(pipelineInstance);
|
material->Apply(pipelineInstance);
|
||||||
|
|
||||||
unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
|
||||||
|
|
||||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
|
||||||
|
|
||||||
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
|
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
|
||||||
|
|
||||||
auto& overlayMap = matEntry.overlayMap;
|
auto& overlayMap = matEntry.overlayMap;
|
||||||
|
|
@ -362,7 +367,6 @@ namespace Nz
|
||||||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||||
|
|
||||||
std::size_t spriteCount = 0;
|
std::size_t spriteCount = 0;
|
||||||
std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
@ -777,6 +781,142 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForwardRenderTechnique::DrawOrderedSprites(const SceneData & sceneData, ForwardRenderQueue::Layer & layer) const
|
||||||
|
{
|
||||||
|
NazaraAssert(sceneData.viewer, "Invalid viewer");
|
||||||
|
|
||||||
|
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
|
||||||
|
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||||
|
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||||
|
|
||||||
|
const Material* lastMaterial = nullptr;
|
||||||
|
const MaterialPipeline* lastPipeline = nullptr;
|
||||||
|
const Shader* lastShader = nullptr;
|
||||||
|
const Texture* lastOverlay = nullptr;
|
||||||
|
const MaterialPipeline::Instance* pipelineInstance = nullptr;
|
||||||
|
|
||||||
|
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
||||||
|
|
||||||
|
bool updateVertexBuffer = true;
|
||||||
|
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||||
|
|
||||||
|
std::size_t alreadyDrawnCount = 0;
|
||||||
|
std::size_t spriteIndex = 0;
|
||||||
|
std::size_t spriteChainOffset = 0;
|
||||||
|
auto splitChainIt = layer.depthSortedSprites.end();
|
||||||
|
|
||||||
|
for (auto it = layer.depthSortedSprites.begin(); it != layer.depthSortedSprites.end();)
|
||||||
|
{
|
||||||
|
if (updateVertexBuffer)
|
||||||
|
{
|
||||||
|
// We open the buffer in writing mode
|
||||||
|
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
|
||||||
|
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||||
|
|
||||||
|
std::size_t availableSpriteSpace = maxSpriteCount;
|
||||||
|
bool split = false;
|
||||||
|
for (auto it2 = it; it2 != layer.depthSortedSprites.end(); ++it2)
|
||||||
|
{
|
||||||
|
const ForwardRenderQueue::UnbatchedSpriteData& spriteData = layer.depthSortedSpriteData[*it2];
|
||||||
|
|
||||||
|
std::size_t count = std::min(availableSpriteSpace, spriteData.spriteCount - spriteChainOffset);
|
||||||
|
|
||||||
|
std::memcpy(vertices, spriteData.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
|
||||||
|
vertices += count * 4;
|
||||||
|
|
||||||
|
availableSpriteSpace -= count;
|
||||||
|
|
||||||
|
// Have we treated the entire chain ?
|
||||||
|
if (count != spriteData.spriteCount)
|
||||||
|
{
|
||||||
|
// Oops, not enough space to store current chain
|
||||||
|
spriteChainOffset += count;
|
||||||
|
splitChainIt = it2;
|
||||||
|
split = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch to next sprite chain, if any
|
||||||
|
spriteChainOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
spriteIndex = 0;
|
||||||
|
updateVertexBuffer = false;
|
||||||
|
|
||||||
|
if (!split)
|
||||||
|
splitChainIt = layer.depthSortedSprites.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t index = *it;
|
||||||
|
|
||||||
|
const ForwardRenderQueue::UnbatchedSpriteData& spriteData = layer.depthSortedSpriteData[index];
|
||||||
|
|
||||||
|
const Material* material = spriteData.material;
|
||||||
|
if (material != lastMaterial)
|
||||||
|
{
|
||||||
|
const MaterialPipeline* pipeline = material->GetPipeline();
|
||||||
|
if (pipeline != lastPipeline)
|
||||||
|
{
|
||||||
|
pipelineInstance = &pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
|
||||||
|
|
||||||
|
const Shader* shader = pipelineInstance->uberInstance->GetShader();
|
||||||
|
|
||||||
|
// Uniforms are conserved in our program, there's no point to send them back until they change
|
||||||
|
if (shader != lastShader)
|
||||||
|
{
|
||||||
|
// Index of uniforms in the shader
|
||||||
|
const ShaderUniforms* shaderUniforms = GetShaderUniforms(shader);
|
||||||
|
|
||||||
|
// Ambient color of the scene
|
||||||
|
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
|
||||||
|
// Position of the camera
|
||||||
|
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||||
|
// Overlay texture unit
|
||||||
|
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||||
|
|
||||||
|
lastShader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastPipeline = pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
material->Apply(*pipelineInstance);
|
||||||
|
|
||||||
|
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
|
||||||
|
|
||||||
|
lastMaterial = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Texture* overlay = (spriteData.overlay) ? spriteData.overlay : &m_whiteTexture;
|
||||||
|
if (overlay != lastOverlay)
|
||||||
|
{
|
||||||
|
Renderer::SetTexture(overlayTextureUnit, overlay);
|
||||||
|
lastOverlay = overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t spriteCount;
|
||||||
|
if (it != splitChainIt)
|
||||||
|
{
|
||||||
|
spriteCount = spriteData.spriteCount - alreadyDrawnCount;
|
||||||
|
alreadyDrawnCount = 0;
|
||||||
|
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
spriteCount = spriteChainOffset;
|
||||||
|
|
||||||
|
alreadyDrawnCount = spriteCount;
|
||||||
|
updateVertexBuffer = true;
|
||||||
|
|
||||||
|
// Restart at current iterator next time
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, spriteIndex * 6, spriteCount * 6);
|
||||||
|
spriteIndex += spriteCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Draws transparent models
|
* \brief Draws transparent models
|
||||||
*
|
*
|
||||||
|
|
@ -796,9 +936,9 @@ namespace Nz
|
||||||
const ShaderUniforms* shaderUniforms = nullptr;
|
const ShaderUniforms* shaderUniforms = nullptr;
|
||||||
unsigned int lightCount = 0;
|
unsigned int lightCount = 0;
|
||||||
|
|
||||||
for (unsigned int index : layer.transparentModels)
|
for (std::size_t index : layer.depthSortedMeshes)
|
||||||
{
|
{
|
||||||
const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index];
|
const ForwardRenderQueue::UnbatchedModelData& modelData = layer.depthSortedMeshData[index];
|
||||||
|
|
||||||
// Material
|
// Material
|
||||||
const Material* material = modelData.material;
|
const Material* material = modelData.material;
|
||||||
|
|
@ -865,8 +1005,8 @@ namespace Nz
|
||||||
if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)
|
if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)
|
||||||
{
|
{
|
||||||
// Compute the closest lights
|
// Compute the closest lights
|
||||||
Vector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition();
|
Vector3f position = matrix.GetTranslation() + modelData.obbSphere.GetPosition();
|
||||||
float radius = modelData.squaredBoundingSphere.radius;
|
float radius = modelData.obbSphere.radius;
|
||||||
ChooseLights(Spheref(position, radius), false);
|
ChooseLights(Spheref(position, radius), false);
|
||||||
|
|
||||||
for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||||
|
|
|
||||||
|
|
@ -197,6 +197,7 @@ namespace Nz
|
||||||
pipelineInfo.blending = true;
|
pipelineInfo.blending = true;
|
||||||
pipelineInfo.depthWrite = false;
|
pipelineInfo.depthWrite = false;
|
||||||
pipelineInfo.faceCulling = false;
|
pipelineInfo.faceCulling = false;
|
||||||
|
pipelineInfo.depthSorting = true;
|
||||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||||
|
|
||||||
|
|
@ -207,6 +208,7 @@ namespace Nz
|
||||||
pipelineInfo.depthBuffer = true;
|
pipelineInfo.depthBuffer = true;
|
||||||
pipelineInfo.depthWrite = false;
|
pipelineInfo.depthWrite = false;
|
||||||
pipelineInfo.faceCulling = false;
|
pipelineInfo.faceCulling = false;
|
||||||
|
pipelineInfo.depthSorting = true;
|
||||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ namespace Nz
|
||||||
|
|
||||||
m_serviceTime = GetElapsedMilliseconds();
|
m_serviceTime = GetElapsedMilliseconds();
|
||||||
}
|
}
|
||||||
while (m_poller.IsReady(m_socket));
|
while (m_poller.IsReadyToRead(m_socket));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -327,7 +327,7 @@ namespace Nz
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_poller.RegisterSocket(m_socket);
|
m_poller.RegisterSocket(m_socket, SocketPollEvent_Read);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,19 @@ namespace Nz
|
||||||
|
|
||||||
void SocketPollerImpl::Clear()
|
void SocketPollerImpl::Clear()
|
||||||
{
|
{
|
||||||
m_activeSockets.clear();
|
m_readyToReadSockets.clear();
|
||||||
|
m_readyToWriteSockets.clear();
|
||||||
m_sockets.clear();
|
m_sockets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
|
||||||
{
|
{
|
||||||
return m_activeSockets.count(socket) != 0;
|
return m_readyToReadSockets.count(socket) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
|
||||||
|
{
|
||||||
|
return m_readyToWriteSockets.count(socket) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
||||||
|
|
@ -37,15 +43,21 @@ namespace Nz
|
||||||
return m_sockets.count(socket) != 0;
|
return m_sockets.count(socket) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
|
||||||
{
|
{
|
||||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||||
|
|
||||||
epoll_event event;
|
epoll_event entry;
|
||||||
event.events = EPOLLIN;
|
entry.events = 0;
|
||||||
event.data.fd = socket;
|
entry.data.fd = socket;
|
||||||
|
|
||||||
if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &event) != 0)
|
if (eventFlags & SocketPollEvent_Read)
|
||||||
|
entry.events |= EPOLLIN;
|
||||||
|
|
||||||
|
if (eventFlags & SocketPollEvent_Write)
|
||||||
|
entry.events |= EPOLLOUT;
|
||||||
|
|
||||||
|
if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &entry) != 0)
|
||||||
{
|
{
|
||||||
NazaraError("Failed to add socket to epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')');
|
NazaraError("Failed to add socket to epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')');
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -60,7 +72,8 @@ namespace Nz
|
||||||
{
|
{
|
||||||
NazaraAssert(IsRegistered(socket), "Socket is not registered");
|
NazaraAssert(IsRegistered(socket), "Socket is not registered");
|
||||||
|
|
||||||
m_activeSockets.erase(socket);
|
m_readyToReadSockets.erase(socket);
|
||||||
|
m_readyToWriteSockets.erase(socket);
|
||||||
m_sockets.erase(socket);
|
m_sockets.erase(socket);
|
||||||
|
|
||||||
if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0)
|
if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0)
|
||||||
|
|
@ -84,21 +97,27 @@ namespace Nz
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_activeSockets.clear();
|
m_readyToReadSockets.clear();
|
||||||
|
m_readyToWriteSockets.clear();
|
||||||
if (activeSockets > 0)
|
if (activeSockets > 0)
|
||||||
{
|
{
|
||||||
int socketCount = activeSockets;
|
int socketCount = activeSockets;
|
||||||
for (int i = 0; i < socketCount; ++i)
|
for (int i = 0; i < socketCount; ++i)
|
||||||
{
|
{
|
||||||
if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
|
if (m_events[i].events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR))
|
||||||
{
|
{
|
||||||
m_activeSockets.insert(m_events[i].data.fd);
|
if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
|
||||||
|
m_readyToReadSockets.insert(m_events[i].data.fd);
|
||||||
|
|
||||||
|
if (m_events[i].events & (EPOLLOUT | EPOLLERR))
|
||||||
|
m_readyToWriteSockets.insert(m_events[i].data.fd);
|
||||||
|
|
||||||
if (m_events[i].events & EPOLLERR)
|
if (m_events[i].events & EPOLLERR)
|
||||||
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll with EPOLLERR status");
|
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll with EPOLLERR status");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN (events: 0x" + String::Number(m_events[i].events, 16) + ')');
|
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN nor EPOLLOUT flags (events: 0x" + String::Number(m_events[i].events, 16) + ')');
|
||||||
activeSockets--;
|
activeSockets--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,18 @@ namespace Nz
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
bool IsReady(SocketHandle socket) const;
|
bool IsReadyToRead(SocketHandle socket) const;
|
||||||
|
bool IsReadyToWrite(SocketHandle socket) const;
|
||||||
bool IsRegistered(SocketHandle socket) const;
|
bool IsRegistered(SocketHandle socket) const;
|
||||||
|
|
||||||
bool RegisterSocket(SocketHandle socket);
|
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
|
||||||
void UnregisterSocket(SocketHandle socket);
|
void UnregisterSocket(SocketHandle socket);
|
||||||
|
|
||||||
int Wait(UInt64 msTimeout, SocketError* error);
|
int Wait(UInt64 msTimeout, SocketError* error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_set<SocketHandle> m_activeSockets;
|
std::unordered_set<SocketHandle> m_readyToReadSockets;
|
||||||
|
std::unordered_set<SocketHandle> m_readyToWriteSockets;
|
||||||
std::unordered_set<SocketHandle> m_sockets;
|
std::unordered_set<SocketHandle> m_sockets;
|
||||||
std::vector<epoll_event> m_events;
|
std::vector<epoll_event> m_events;
|
||||||
int m_handle;
|
int m_handle;
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,20 @@ namespace Nz
|
||||||
{
|
{
|
||||||
void SocketPollerImpl::Clear()
|
void SocketPollerImpl::Clear()
|
||||||
{
|
{
|
||||||
m_activeSockets.clear();
|
m_readyToReadSockets.clear();
|
||||||
|
m_readyToWriteSockets.clear();
|
||||||
m_allSockets.clear();
|
m_allSockets.clear();
|
||||||
m_sockets.clear();
|
m_sockets.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
|
||||||
{
|
{
|
||||||
return m_activeSockets.count(socket) != 0;
|
return m_readyToReadSockets.count(socket) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
|
||||||
|
{
|
||||||
|
return m_readyToWriteSockets.count(socket) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
bool SocketPollerImpl::IsRegistered(SocketHandle socket) const
|
||||||
|
|
@ -25,16 +31,22 @@ namespace Nz
|
||||||
return m_allSockets.count(socket) != 0;
|
return m_allSockets.count(socket) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
|
||||||
{
|
{
|
||||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||||
|
|
||||||
PollSocket entry = {
|
PollSocket entry = {
|
||||||
socket,
|
socket,
|
||||||
POLLRDNORM,
|
0,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (eventFlags & SocketPollEvent_Read)
|
||||||
|
entry.events |= POLLRDNORM;
|
||||||
|
|
||||||
|
if (eventFlags & SocketPollEvent_Write)
|
||||||
|
entry.events |= POLLWRNORM;
|
||||||
|
|
||||||
m_allSockets[socket] = m_sockets.size();
|
m_allSockets[socket] = m_sockets.size();
|
||||||
m_sockets.emplace_back(entry);
|
m_sockets.emplace_back(entry);
|
||||||
|
|
||||||
|
|
@ -57,10 +69,11 @@ namespace Nz
|
||||||
// Now move it properly (lastElement is invalid after the following line) and pop it
|
// Now move it properly (lastElement is invalid after the following line) and pop it
|
||||||
m_sockets[entry] = std::move(m_sockets.back());
|
m_sockets[entry] = std::move(m_sockets.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sockets.pop_back();
|
m_sockets.pop_back();
|
||||||
m_activeSockets.erase(socket);
|
|
||||||
m_allSockets.erase(socket);
|
m_allSockets.erase(socket);
|
||||||
|
m_readyToReadSockets.erase(socket);
|
||||||
|
m_readyToWriteSockets.erase(socket);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
|
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
|
||||||
|
|
@ -68,20 +81,25 @@ namespace Nz
|
||||||
int activeSockets;
|
int activeSockets;
|
||||||
|
|
||||||
// Reset status of sockets
|
// Reset status of sockets
|
||||||
for (PollSocket& entry : m_sockets)
|
|
||||||
entry.revents = 0;
|
|
||||||
|
|
||||||
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
|
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
|
||||||
|
|
||||||
m_activeSockets.clear();
|
m_readyToReadSockets.clear();
|
||||||
if (activeSockets > 0)
|
m_readyToWriteSockets.clear();
|
||||||
|
if (activeSockets > 0U)
|
||||||
{
|
{
|
||||||
int socketRemaining = activeSockets;
|
int socketRemaining = activeSockets;
|
||||||
for (PollSocket& entry : m_sockets)
|
for (PollSocket& entry : m_sockets)
|
||||||
{
|
{
|
||||||
if (entry.revents & POLLRDNORM)
|
if (entry.revents != 0)
|
||||||
{
|
{
|
||||||
m_activeSockets.insert(entry.fd);
|
if (entry.revents & POLLRDNORM)
|
||||||
|
m_readyToReadSockets.insert(entry.fd);
|
||||||
|
|
||||||
|
if (entry.revents & POLLWRNORM)
|
||||||
|
m_readyToWriteSockets.insert(entry.fd);
|
||||||
|
|
||||||
|
entry.revents = 0;
|
||||||
|
|
||||||
if (--socketRemaining == 0)
|
if (--socketRemaining == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,13 +27,14 @@ namespace Nz
|
||||||
bool IsReady(SocketHandle socket) const;
|
bool IsReady(SocketHandle socket) const;
|
||||||
bool IsRegistered(SocketHandle socket) const;
|
bool IsRegistered(SocketHandle socket) const;
|
||||||
|
|
||||||
bool RegisterSocket(SocketHandle socket);
|
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
|
||||||
void UnregisterSocket(SocketHandle socket);
|
void UnregisterSocket(SocketHandle socket);
|
||||||
|
|
||||||
int Wait(UInt64 msTimeout, SocketError* error);
|
int Wait(UInt64 msTimeout, SocketError* error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_set<SocketHandle> m_activeSockets;
|
std::unordered_set<SocketHandle> m_readyToReadSockets;
|
||||||
|
std::unordered_set<SocketHandle> m_readyToWriteSockets;
|
||||||
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
|
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
|
||||||
std::vector<PollSocket> m_sockets;
|
std::vector<PollSocket> m_sockets;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -57,12 +57,13 @@ namespace Nz
|
||||||
/*!
|
/*!
|
||||||
* \brief Checks if a specific socket is ready to read data
|
* \brief Checks if a specific socket is ready to read data
|
||||||
*
|
*
|
||||||
* This function allows you to read the results of the last Wait operation and if a specific socket is ready.
|
* This function allows you to read the results of the last Wait operation and if a specific socket is ready to read (has incoming data).
|
||||||
*
|
*
|
||||||
* A socket in the ready state (with the exception of TcpServer) has incoming data and can be read without blocking.
|
* A socket in the ready to read state (with the exception of TcpServer) has incoming data and can be read without blocking.
|
||||||
*
|
*
|
||||||
* \remark When used on a TcpServer socket, this function returns true if the server is ready to accept a new client.
|
* \remark You must call Wait before using this function in order to refresh the read state.
|
||||||
* \remark You must call Wait before using this function in order to refresh the state.
|
* \remark A socket must be registered with SocketPollerEvent_Read event flag for its read state to be watched
|
||||||
|
* \remark A TcpServer socket becomes ready to read when it is ready to accept a new client.
|
||||||
*
|
*
|
||||||
* \param socket Reference to the socket to check
|
* \param socket Reference to the socket to check
|
||||||
*
|
*
|
||||||
|
|
@ -70,11 +71,32 @@ namespace Nz
|
||||||
*
|
*
|
||||||
* \see Wait
|
* \see Wait
|
||||||
*/
|
*/
|
||||||
bool SocketPoller::IsReady(const AbstractSocket& socket) const
|
bool SocketPoller::IsReadyToRead(const AbstractSocket& socket) const
|
||||||
{
|
{
|
||||||
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
|
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
|
||||||
|
|
||||||
return m_impl->IsReady(socket.GetNativeHandle());
|
return m_impl->IsReadyToRead(socket.GetNativeHandle());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Checks if a specific socket is ready to write data
|
||||||
|
*
|
||||||
|
* This function allows you to read the results of the last Wait operation and if a specific socket is ready to write (can be written to without blocking).
|
||||||
|
*
|
||||||
|
* \remark You must call Wait before using this function in order to refresh the read state.
|
||||||
|
* \remark A socket must be registered with SocketPollerEvent_Write event flag for its read state to be watched
|
||||||
|
*
|
||||||
|
* \param socket Reference to the socket to check
|
||||||
|
*
|
||||||
|
* \return True if the socket is available for writing without blocking, false otherwise
|
||||||
|
*
|
||||||
|
* \see Wait
|
||||||
|
*/
|
||||||
|
bool SocketPoller::IsReadyToWrite(const AbstractSocket& socket) const
|
||||||
|
{
|
||||||
|
NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller");
|
||||||
|
|
||||||
|
return m_impl->IsReadyToWrite(socket.GetNativeHandle());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -97,7 +119,7 @@ namespace Nz
|
||||||
/*!
|
/*!
|
||||||
* \brief Register a socket in the SocketPoller
|
* \brief Register a socket in the SocketPoller
|
||||||
*
|
*
|
||||||
* A registered socket is part of the SocketPoller and will be checked by the next Wait operations.
|
* A registered socket is part of the SocketPoller and will be checked by the next Wait operations according to the event flags passed when registered.
|
||||||
*
|
*
|
||||||
* The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler.
|
* The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler.
|
||||||
*
|
*
|
||||||
|
|
@ -107,17 +129,18 @@ namespace Nz
|
||||||
* \remark The socket should not be freed while it is registered in the SocketPooler.
|
* \remark The socket should not be freed while it is registered in the SocketPooler.
|
||||||
*
|
*
|
||||||
* \param socket Reference to the socket to register
|
* \param socket Reference to the socket to register
|
||||||
|
* \param eventFlags Socket events to watch
|
||||||
*
|
*
|
||||||
* \return True if the socket is registered, false otherwise
|
* \return True if the socket is registered, false otherwise
|
||||||
*
|
*
|
||||||
* \see IsRegistered
|
* \see IsRegistered
|
||||||
* \see UnregisterSocket
|
* \see UnregisterSocket
|
||||||
*/
|
*/
|
||||||
bool SocketPoller::RegisterSocket(AbstractSocket& socket)
|
bool SocketPoller::RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags)
|
||||||
{
|
{
|
||||||
NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller");
|
NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller");
|
||||||
|
|
||||||
return m_impl->RegisterSocket(socket.GetNativeHandle());
|
return m_impl->RegisterSocket(socket.GetNativeHandle(), eventFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
@ -145,7 +168,7 @@ namespace Nz
|
||||||
* \brief Wait until any registered socket switches to a ready state.
|
* \brief Wait until any registered socket switches to a ready state.
|
||||||
*
|
*
|
||||||
* Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready.
|
* Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready.
|
||||||
* To query the ready state of the registered socket, use the IsReady function.
|
* To query the ready state of the registered socket, use the IsReadyToRead or IsReadyToWrite functions.
|
||||||
*
|
*
|
||||||
* \param msTimeout Maximum time to wait in milliseconds, 0 for infinity
|
* \param msTimeout Maximum time to wait in milliseconds, 0 for infinity
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -10,29 +10,43 @@ namespace Nz
|
||||||
SocketPollerImpl::SocketPollerImpl()
|
SocketPollerImpl::SocketPollerImpl()
|
||||||
{
|
{
|
||||||
#if !NAZARA_NETWORK_POLL_SUPPORT
|
#if !NAZARA_NETWORK_POLL_SUPPORT
|
||||||
FD_ZERO(&m_activeSockets);
|
FD_ZERO(&m_readSockets);
|
||||||
FD_ZERO(&m_sockets);
|
FD_ZERO(&m_readyToReadSockets);
|
||||||
|
FD_ZERO(&m_readyToWriteSockets);
|
||||||
|
FD_ZERO(&m_writeSockets);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SocketPollerImpl::Clear()
|
void SocketPollerImpl::Clear()
|
||||||
{
|
{
|
||||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
m_activeSockets.clear();
|
|
||||||
m_allSockets.clear();
|
m_allSockets.clear();
|
||||||
|
m_readyToReadSockets.clear();
|
||||||
|
m_readyToWriteSockets.clear();
|
||||||
m_sockets.clear();
|
m_sockets.clear();
|
||||||
#else
|
#else
|
||||||
FD_ZERO(&m_activeSockets);
|
FD_ZERO(&m_readSockets);
|
||||||
FD_ZERO(&m_sockets);
|
FD_ZERO(&m_readyToReadSockets);
|
||||||
|
FD_ZERO(&m_readyToWriteSockets);
|
||||||
|
FD_ZERO(&m_writeSockets);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
|
||||||
{
|
{
|
||||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
return m_activeSockets.count(socket) != 0;
|
return m_readyToReadSockets.count(socket) != 0;
|
||||||
#else
|
#else
|
||||||
return FD_ISSET(socket, &m_activeSockets) != 0;
|
return FD_ISSET(socket, &m_readyToReadSockets) != 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const
|
||||||
|
{
|
||||||
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
|
return m_readyToWriteSockets.count(socket) != 0;
|
||||||
|
#else
|
||||||
|
return FD_ISSET(socket, &m_readyToWriteSockets) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,31 +55,45 @@ namespace Nz
|
||||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
return m_allSockets.count(socket) != 0;
|
return m_allSockets.count(socket) != 0;
|
||||||
#else
|
#else
|
||||||
return FD_ISSET(socket, &m_sockets) != 0;
|
return FD_ISSET(socket, &m_readSockets) != 0 ||
|
||||||
|
FD_ISSET(socket, &m_writeSockets) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
|
||||||
{
|
{
|
||||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||||
|
|
||||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
PollSocket entry = {
|
PollSocket entry = {
|
||||||
socket,
|
socket,
|
||||||
POLLRDNORM,
|
0,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (eventFlags & SocketPollEvent_Read)
|
||||||
|
entry.events |= POLLRDNORM;
|
||||||
|
|
||||||
|
if (eventFlags & SocketPollEvent_Write)
|
||||||
|
entry.events |= POLLWRNORM;
|
||||||
|
|
||||||
m_allSockets[socket] = m_sockets.size();
|
m_allSockets[socket] = m_sockets.size();
|
||||||
m_sockets.emplace_back(entry);
|
m_sockets.emplace_back(entry);
|
||||||
#else
|
#else
|
||||||
if (m_sockets.fd_count > FD_SETSIZE)
|
for (std::size_t i = 0; i < 2; ++i)
|
||||||
{
|
{
|
||||||
NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
|
if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0)
|
||||||
return false;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
FD_SET(socket, &m_sockets);
|
fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets;
|
||||||
|
if (targetSet.fd_count > FD_SETSIZE)
|
||||||
|
{
|
||||||
|
NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_SET(socket, &targetSet);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -88,13 +116,16 @@ namespace Nz
|
||||||
// Now move it properly (lastElement is invalid after the following line) and pop it
|
// Now move it properly (lastElement is invalid after the following line) and pop it
|
||||||
m_sockets[entry] = std::move(m_sockets.back());
|
m_sockets[entry] = std::move(m_sockets.back());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sockets.pop_back();
|
m_sockets.pop_back();
|
||||||
m_activeSockets.erase(socket);
|
|
||||||
m_allSockets.erase(socket);
|
m_allSockets.erase(socket);
|
||||||
|
m_readyToReadSockets.erase(socket);
|
||||||
|
m_readyToWriteSockets.erase(socket);
|
||||||
#else
|
#else
|
||||||
FD_CLR(socket, &m_activeSockets);
|
FD_CLR(socket, &m_readSockets);
|
||||||
FD_CLR(socket, &m_sockets);
|
FD_CLR(socket, &m_readyToReadSockets);
|
||||||
|
FD_CLR(socket, &m_readyToWriteSockets);
|
||||||
|
FD_CLR(socket, &m_writeSockets);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,35 +134,28 @@ namespace Nz
|
||||||
int activeSockets;
|
int activeSockets;
|
||||||
|
|
||||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
// Reset status of sockets
|
|
||||||
for (PollSocket& entry : m_sockets)
|
|
||||||
entry.revents = 0;
|
|
||||||
|
|
||||||
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
|
activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast<int>(msTimeout), error);
|
||||||
|
|
||||||
m_activeSockets.clear();
|
|
||||||
if (activeSockets > 0U)
|
|
||||||
{
|
|
||||||
int socketRemaining = activeSockets;
|
|
||||||
for (PollSocket& entry : m_sockets)
|
|
||||||
{
|
|
||||||
if (entry.revents & POLLRDNORM)
|
|
||||||
{
|
|
||||||
m_activeSockets.insert(entry.fd);
|
|
||||||
if (--socketRemaining == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
|
fd_set* readSet = nullptr;
|
||||||
|
fd_set* writeSet = nullptr;
|
||||||
|
|
||||||
m_activeSockets = m_sockets;
|
if (m_readSockets.fd_count > 0)
|
||||||
|
{
|
||||||
|
m_readyToReadSockets = m_readSockets;
|
||||||
|
readSet = &m_readyToReadSockets;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_writeSockets.fd_count > 0)
|
||||||
|
{
|
||||||
|
m_readyToWriteSockets = m_writeSockets;
|
||||||
|
readSet = &m_readyToWriteSockets;
|
||||||
|
}
|
||||||
|
|
||||||
timeval tv;
|
timeval tv;
|
||||||
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
|
tv.tv_sec = static_cast<long>(msTimeout / 1000ULL);
|
||||||
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
|
tv.tv_usec = static_cast<long>((msTimeout % 1000ULL) * 1000ULL);
|
||||||
|
|
||||||
activeSockets = ::select(0xDEADBEEF, &m_activeSockets, nullptr, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
|
activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
|
||||||
if (activeSockets == SOCKET_ERROR)
|
if (activeSockets == SOCKET_ERROR)
|
||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
|
|
|
||||||
|
|
@ -25,24 +25,28 @@ namespace Nz
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
bool IsReady(SocketHandle socket) const;
|
bool IsReadyToRead(SocketHandle socket) const;
|
||||||
|
bool IsReadyToWrite(SocketHandle socket) const;
|
||||||
bool IsRegistered(SocketHandle socket) const;
|
bool IsRegistered(SocketHandle socket) const;
|
||||||
|
|
||||||
bool RegisterSocket(SocketHandle socket);
|
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
|
||||||
void UnregisterSocket(SocketHandle socket);
|
void UnregisterSocket(SocketHandle socket);
|
||||||
|
|
||||||
int Wait(UInt64 msTimeout, SocketError* error);
|
int Wait(UInt64 msTimeout, SocketError* error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||||
std::unordered_set<SocketHandle> m_activeSockets;
|
std::unordered_set<SocketHandle> m_readyToReadSockets;
|
||||||
|
std::unordered_set<SocketHandle> m_readyToWriteSockets;
|
||||||
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
|
std::unordered_map<SocketHandle, std::size_t> m_allSockets;
|
||||||
std::vector<PollSocket> m_sockets;
|
std::vector<PollSocket> m_sockets;
|
||||||
#else
|
#else
|
||||||
fd_set m_sockets;
|
fd_set m_readSockets;
|
||||||
fd_set m_activeSockets;
|
fd_set m_readyToReadSockets;
|
||||||
|
fd_set m_readyToWriteSockets;
|
||||||
|
fd_set m_writeSockets;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
|
#endif // NAZARA_SOCKETPOLLERIMPL_HPP
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,9 @@ namespace Nz
|
||||||
|
|
||||||
if (cpShape* shape = cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, &queryInfo))
|
if (cpShape* shape = cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, &queryInfo))
|
||||||
{
|
{
|
||||||
result->closestPoint.Set(queryInfo.point.x, queryInfo.point.y);
|
result->closestPoint.Set(Nz::Vector2<cpFloat>(queryInfo.point.x, queryInfo.point.y));
|
||||||
result->distance = queryInfo.distance;
|
result->distance = float(queryInfo.distance);
|
||||||
result->fraction.Set(queryInfo.gradient.x, queryInfo.gradient.y);
|
result->fraction.Set(Nz::Vector2<cpFloat>(queryInfo.gradient.x, queryInfo.gradient.y));
|
||||||
result->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
result->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -90,9 +90,9 @@ namespace Nz
|
||||||
ResultType results = static_cast<ResultType>(data);
|
ResultType results = static_cast<ResultType>(data);
|
||||||
|
|
||||||
RaycastHit hitInfo;
|
RaycastHit hitInfo;
|
||||||
hitInfo.fraction = alpha;
|
hitInfo.fraction = float(alpha);
|
||||||
hitInfo.hitNormal.Set(normal.x, normal.y);
|
hitInfo.hitNormal.Set(Nz::Vector2<cpFloat>(normal.x, normal.y));
|
||||||
hitInfo.hitPos.Set(point.x, point.y);
|
hitInfo.hitPos.Set(Nz::Vector2<cpFloat>(point.x, point.y));
|
||||||
hitInfo.nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
hitInfo.nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||||
|
|
||||||
results->emplace_back(std::move(hitInfo));
|
results->emplace_back(std::move(hitInfo));
|
||||||
|
|
@ -116,9 +116,9 @@ namespace Nz
|
||||||
|
|
||||||
if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo))
|
if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo))
|
||||||
{
|
{
|
||||||
hitInfo->fraction = queryInfo.alpha;
|
hitInfo->fraction = float(queryInfo.alpha);
|
||||||
hitInfo->hitNormal.Set(queryInfo.normal.x, queryInfo.normal.y);
|
hitInfo->hitNormal.Set(Nz::Vector2<cpFloat>(queryInfo.normal.x, queryInfo.normal.y));
|
||||||
hitInfo->hitPos.Set(queryInfo.point.x, queryInfo.point.y);
|
hitInfo->hitPos.Set(Nz::Vector2<cpFloat>(queryInfo.point.x, queryInfo.point.y));
|
||||||
hitInfo->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(queryInfo.shape));
|
hitInfo->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(queryInfo.shape));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ namespace Nz
|
||||||
cpVect vel = cpBodyGetVelocity(m_handle);
|
cpVect vel = cpBodyGetVelocity(m_handle);
|
||||||
|
|
||||||
Destroy();
|
Destroy();
|
||||||
Create(mass, moment);
|
Create(float(mass), float(moment));
|
||||||
|
|
||||||
cpBodySetAngle(m_handle, rot);
|
cpBodySetAngle(m_handle, rot);
|
||||||
cpBodySetPosition(m_handle, pos);
|
cpBodySetPosition(m_handle, pos);
|
||||||
|
|
|
||||||
|
|
@ -121,9 +121,7 @@ namespace Nz
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Peut être rajouté par une extension
|
return; //< Block NVidia buffer usage hint for now
|
||||||
ss << "Unknown";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
ss << '\n';
|
ss << '\n';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,8 @@ namespace Nz
|
||||||
|
|
||||||
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
|
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
|
||||||
|
|
||||||
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0);
|
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, 0);
|
||||||
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.storage, 0);
|
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, 0);
|
||||||
|
|
||||||
// Index buffer
|
// Index buffer
|
||||||
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
||||||
|
|
@ -236,7 +236,7 @@ namespace Nz
|
||||||
// Index buffer
|
// Index buffer
|
||||||
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
|
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
|
||||||
|
|
||||||
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0);
|
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, 0);
|
||||||
|
|
||||||
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
||||||
IndexIterator index = indexMapper.begin();
|
IndexIterator index = indexMapper.begin();
|
||||||
|
|
@ -251,7 +251,7 @@ namespace Nz
|
||||||
indexMapper.Unmap();
|
indexMapper.Unmap();
|
||||||
|
|
||||||
// Vertex buffer
|
// Vertex buffer
|
||||||
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0);
|
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, 0);
|
||||||
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_WriteOnly);
|
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_WriteOnly);
|
||||||
|
|
||||||
MeshVertex* vertices = static_cast<MeshVertex*>(vertexMapper.GetPointer());
|
MeshVertex* vertices = static_cast<MeshVertex*>(vertexMapper.GetPointer());
|
||||||
|
|
|
||||||
|
|
@ -233,8 +233,8 @@ namespace Nz
|
||||||
}
|
}
|
||||||
|
|
||||||
// Création des buffers
|
// Création des buffers
|
||||||
IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indices.size(), parameters.storage, 0);
|
IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), UInt32(indices.size()), parameters.storage, 0);
|
||||||
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0);
|
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, 0);
|
||||||
|
|
||||||
// Remplissage des indices
|
// Remplissage des indices
|
||||||
IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly);
|
IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly);
|
||||||
|
|
|
||||||
|
|
@ -228,7 +228,7 @@ namespace Nz
|
||||||
|
|
||||||
if (p < 0)
|
if (p < 0)
|
||||||
{
|
{
|
||||||
p += m_positions.size() - 1;
|
p += static_cast<int>(m_positions.size() - 1);
|
||||||
if (p < 0)
|
if (p < 0)
|
||||||
{
|
{
|
||||||
Error("Vertex index out of range (" + String::Number(p) + " < 0");
|
Error("Vertex index out of range (" + String::Number(p) + " < 0");
|
||||||
|
|
@ -239,7 +239,7 @@ namespace Nz
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
{
|
{
|
||||||
n += m_normals.size() - 1;
|
n += static_cast<int>(m_normals.size() - 1);
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
{
|
{
|
||||||
Error("Normal index out of range (" + String::Number(n) + " < 0");
|
Error("Normal index out of range (" + String::Number(n) + " < 0");
|
||||||
|
|
@ -250,7 +250,7 @@ namespace Nz
|
||||||
|
|
||||||
if (t < 0)
|
if (t < 0)
|
||||||
{
|
{
|
||||||
t += m_texCoords.size() - 1;
|
t += static_cast<int>(m_texCoords.size() - 1);
|
||||||
if (t < 0)
|
if (t < 0)
|
||||||
{
|
{
|
||||||
Error("Texture coordinates index out of range (" + String::Number(t) + " < 0");
|
Error("Texture coordinates index out of range (" + String::Number(t) + " < 0");
|
||||||
|
|
|
||||||
|
|
@ -12,38 +12,38 @@ namespace Nz
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
UInt32 GetterSequential(const void* buffer, unsigned int i)
|
UInt32 GetterSequential(const void* buffer, std::size_t i)
|
||||||
{
|
{
|
||||||
NazaraUnused(buffer);
|
NazaraUnused(buffer);
|
||||||
|
|
||||||
return i;
|
return static_cast<UInt32>(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 Getter16(const void* buffer, unsigned int i)
|
UInt32 Getter16(const void* buffer, std::size_t i)
|
||||||
{
|
{
|
||||||
const UInt16* ptr = static_cast<const UInt16*>(buffer);
|
const UInt16* ptr = static_cast<const UInt16*>(buffer);
|
||||||
return ptr[i];
|
return ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 Getter32(const void* buffer, unsigned int i)
|
UInt32 Getter32(const void* buffer, std::size_t i)
|
||||||
{
|
{
|
||||||
const UInt32* ptr = static_cast<const UInt32*>(buffer);
|
const UInt32* ptr = static_cast<const UInt32*>(buffer);
|
||||||
return ptr[i];
|
return ptr[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Setter16(void* buffer, unsigned int i, UInt32 value)
|
void Setter16(void* buffer, std::size_t i, UInt32 value)
|
||||||
{
|
{
|
||||||
UInt16* ptr = static_cast<UInt16*>(buffer);
|
UInt16* ptr = static_cast<UInt16*>(buffer);
|
||||||
ptr[i] = static_cast<UInt16>(value);
|
ptr[i] = static_cast<UInt16>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Setter32(void* buffer, unsigned int i, UInt32 value)
|
void Setter32(void* buffer, std::size_t i, UInt32 value)
|
||||||
{
|
{
|
||||||
UInt32* ptr = static_cast<UInt32*>(buffer);
|
UInt32* ptr = static_cast<UInt32*>(buffer);
|
||||||
ptr[i] = value;
|
ptr[i] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetterError(void*, unsigned int, UInt32)
|
void SetterError(void*, std::size_t, UInt32)
|
||||||
{
|
{
|
||||||
NazaraError("Index buffer opened with read-only access");
|
NazaraError("Index buffer opened with read-only access");
|
||||||
}
|
}
|
||||||
|
|
@ -113,15 +113,9 @@ namespace Nz
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 IndexMapper::Get(unsigned int i) const
|
UInt32 IndexMapper::Get(std::size_t i) const
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
NazaraAssert(i < m_indexCount, "Index out of range");
|
||||||
if (i >= m_indexCount)
|
|
||||||
{
|
|
||||||
NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')');
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_getter(m_mapper.GetPointer(), i);
|
return m_getter(m_mapper.GetPointer(), i);
|
||||||
}
|
}
|
||||||
|
|
@ -131,20 +125,14 @@ namespace Nz
|
||||||
return m_mapper.GetBuffer();
|
return m_mapper.GetBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int IndexMapper::GetIndexCount() const
|
std::size_t IndexMapper::GetIndexCount() const
|
||||||
{
|
{
|
||||||
return m_indexCount;
|
return m_indexCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexMapper::Set(unsigned int i, UInt32 value)
|
void IndexMapper::Set(std::size_t i, UInt32 value)
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
NazaraAssert(i < m_indexCount, "Index out of range");
|
||||||
if (i >= m_indexCount)
|
|
||||||
{
|
|
||||||
NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_setter(m_mapper.GetPointer(), i, value);
|
m_setter(m_mapper.GetPointer(), i, value);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ namespace Nz
|
||||||
NazaraAssert(subMesh, "Invalid submesh");
|
NazaraAssert(subMesh, "Invalid submesh");
|
||||||
NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type");
|
NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type");
|
||||||
|
|
||||||
m_impl->subMeshes.push_back(subMesh);
|
m_impl->subMeshes.emplace_back(subMesh);
|
||||||
|
|
||||||
InvalidateAABB();
|
InvalidateAABB();
|
||||||
}
|
}
|
||||||
|
|
@ -92,10 +92,10 @@ namespace Nz
|
||||||
NazaraAssert(subMesh, "Invalid submesh");
|
NazaraAssert(subMesh, "Invalid submesh");
|
||||||
NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type");
|
NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type");
|
||||||
|
|
||||||
UInt32 index = m_impl->subMeshes.size();
|
std::size_t index = m_impl->subMeshes.size();
|
||||||
|
|
||||||
m_impl->subMeshes.push_back(subMesh);
|
m_impl->subMeshes.emplace_back(subMesh);
|
||||||
m_impl->subMeshMap[identifier] = index;
|
m_impl->subMeshMap[identifier] = static_cast<UInt32>(index);
|
||||||
|
|
||||||
InvalidateAABB();
|
InvalidateAABB();
|
||||||
}
|
}
|
||||||
|
|
@ -349,11 +349,11 @@ namespace Nz
|
||||||
|
|
||||||
if (!m_impl->aabbUpdated)
|
if (!m_impl->aabbUpdated)
|
||||||
{
|
{
|
||||||
UInt32 subMeshCount = m_impl->subMeshes.size();
|
std::size_t subMeshCount = m_impl->subMeshes.size();
|
||||||
if (subMeshCount > 0)
|
if (subMeshCount > 0)
|
||||||
{
|
{
|
||||||
m_impl->aabb.Set(m_impl->subMeshes[0]->GetAABB());
|
m_impl->aabb.Set(m_impl->subMeshes[0]->GetAABB());
|
||||||
for (UInt32 i = 1; i < subMeshCount; ++i)
|
for (std::size_t i = 1; i < subMeshCount; ++i)
|
||||||
m_impl->aabb.ExtendTo(m_impl->subMeshes[i]->GetAABB());
|
m_impl->aabb.ExtendTo(m_impl->subMeshes[i]->GetAABB());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -407,7 +407,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
NazaraAssert(m_impl, "Mesh should be created first");
|
NazaraAssert(m_impl, "Mesh should be created first");
|
||||||
|
|
||||||
return m_impl->materialData.size();
|
return static_cast<UInt32>(m_impl->materialData.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
Skeleton* Mesh::GetSkeleton()
|
Skeleton* Mesh::GetSkeleton()
|
||||||
|
|
@ -466,7 +466,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
NazaraAssert(m_impl, "Mesh should be created first");
|
NazaraAssert(m_impl, "Mesh should be created first");
|
||||||
|
|
||||||
return m_impl->subMeshes.size();
|
return static_cast<UInt32>(m_impl->subMeshes.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 Mesh::GetSubMeshIndex(const String& identifier) const
|
UInt32 Mesh::GetSubMeshIndex(const String& identifier) const
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ namespace Nz
|
||||||
m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly)
|
m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly)
|
||||||
|
|
||||||
if (m_font)
|
if (m_font)
|
||||||
m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, m_font->GetSizeInfo(m_characterSize).lineHeight), 0});
|
m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, float(m_font->GetSizeInfo(m_characterSize).lineHeight)), 0});
|
||||||
else
|
else
|
||||||
m_lines.emplace_back(Line{Rectf::Zero(), 0});
|
m_lines.emplace_back(Line{Rectf::Zero(), 0});
|
||||||
}
|
}
|
||||||
|
|
@ -354,7 +354,7 @@ namespace Nz
|
||||||
{
|
{
|
||||||
glyph.atlas = nullptr;
|
glyph.atlas = nullptr;
|
||||||
|
|
||||||
glyph.bounds.Set(m_drawPos.x, m_drawPos.y, float(advance), sizeInfo.lineHeight);
|
glyph.bounds.Set(float(m_drawPos.x), float(m_drawPos.y), float(advance), float(sizeInfo.lineHeight));
|
||||||
|
|
||||||
glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
|
glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
|
||||||
glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
|
glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
|
||||||
|
|
@ -377,7 +377,7 @@ namespace Nz
|
||||||
m_drawPos.x = 0;
|
m_drawPos.x = 0;
|
||||||
m_drawPos.y += sizeInfo.lineHeight;
|
m_drawPos.y += sizeInfo.lineHeight;
|
||||||
|
|
||||||
m_lines.emplace_back(Line{Rectf(0.f, sizeInfo.lineHeight * m_lines.size(), 0.f, sizeInfo.lineHeight), m_glyphs.size() + 1});
|
m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,12 +72,12 @@ namespace Nz
|
||||||
|
|
||||||
if (!m_impl->aabbUpdated)
|
if (!m_impl->aabbUpdated)
|
||||||
{
|
{
|
||||||
UInt32 jointCount = m_impl->joints.size();
|
std::size_t jointCount = m_impl->joints.size();
|
||||||
if (jointCount > 0)
|
if (jointCount > 0)
|
||||||
{
|
{
|
||||||
Vector3f pos = m_impl->joints[0].GetPosition();
|
Vector3f pos = m_impl->joints[0].GetPosition();
|
||||||
m_impl->aabb.Set(pos.x, pos.y, pos.z, 0.f, 0.f, 0.f);
|
m_impl->aabb.Set(pos.x, pos.y, pos.z, 0.f, 0.f, 0.f);
|
||||||
for (UInt32 i = 1; i < jointCount; ++i)
|
for (std::size_t i = 1; i < jointCount; ++i)
|
||||||
m_impl->aabb.ExtendTo(m_impl->joints[i].GetPosition());
|
m_impl->aabb.ExtendTo(m_impl->joints[i].GetPosition());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -219,7 +219,7 @@ namespace Nz
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return m_impl->joints.size();
|
return static_cast<UInt32>(m_impl->joints.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int Skeleton::GetJointIndex(const String& jointName) const
|
int Skeleton::GetJointIndex(const String& jointName) const
|
||||||
|
|
@ -411,16 +411,9 @@ namespace Nz
|
||||||
String name = m_impl->joints[i].GetName();
|
String name = m_impl->joints[i].GetName();
|
||||||
if (!name.IsEmpty())
|
if (!name.IsEmpty())
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
NazaraAssert(m_impl->jointMap.find(name) == m_impl->jointMap.end(), "Joint name \"" + name + "\" is already present in joint map");
|
||||||
auto it = m_impl->jointMap.find(name);
|
|
||||||
if (it != m_impl->jointMap.end())
|
|
||||||
{
|
|
||||||
NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + String::Number(it->second));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_impl->jointMap[name] = i;
|
m_impl->jointMap[name] = static_cast<UInt32>(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,18 +66,9 @@ namespace Nz
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt32 TriangleIterator::operator[](unsigned int i) const
|
UInt32 TriangleIterator::operator[](std::size_t i) const
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
NazaraAssert(i < 3, "Index out of range");
|
||||||
if (i >= 3)
|
|
||||||
{
|
|
||||||
StringStream ss;
|
|
||||||
ss << "Index out of range: (" << i << " >= 3)";
|
|
||||||
|
|
||||||
NazaraError(ss);
|
|
||||||
throw std::domain_error(ss.ToString());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_triangleIndices[i];
|
return m_triangleIndices[i];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include <Nazara/Math/Algorithm.hpp>
|
#include <Nazara/Math/Algorithm.hpp>
|
||||||
#include <Catch/catch.hpp>
|
#include <Catch/catch.hpp>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
TEST_CASE("Approach", "[MATH][ALGORITHM]")
|
TEST_CASE("Approach", "[MATH][ALGORITHM]")
|
||||||
{
|
{
|
||||||
|
|
@ -48,6 +49,11 @@ TEST_CASE("CountBits", "[MATH][ALGORITHM]")
|
||||||
{
|
{
|
||||||
REQUIRE(Nz::CountBits(0) == 0);
|
REQUIRE(Nz::CountBits(0) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("Number 0xFFFFFFFF has 32 bit set to 1")
|
||||||
|
{
|
||||||
|
REQUIRE(Nz::CountBits(0xFFFFFFFF) == 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]")
|
TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]")
|
||||||
|
|
@ -205,9 +211,19 @@ TEST_CASE("NumberEquals", "[MATH][ALGORITHM]")
|
||||||
CHECK(Nz::NumberEquals(2.35, 2.35, 0.01));
|
CHECK(Nz::NumberEquals(2.35, 2.35, 0.01));
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("3 and 4 unsigned should be the same at 1")
|
SECTION("0 and 4 unsigned should be the same at 1")
|
||||||
{
|
{
|
||||||
CHECK(Nz::NumberEquals(3U, 4U, 1U));
|
CHECK(Nz::NumberEquals(0U, 4U, 4U));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Maximum integer and -1 should not be equal")
|
||||||
|
{
|
||||||
|
CHECK_FALSE(Nz::NumberEquals(std::numeric_limits<int>::max(), -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Maximum integer and minimum integer should not be equal")
|
||||||
|
{
|
||||||
|
CHECK_FALSE(Nz::NumberEquals(std::numeric_limits<int>::max(), std::numeric_limits<int>::min()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]")
|
||||||
|
|
||||||
WHEN("We register the server socket to the poller")
|
WHEN("We register the server socket to the poller")
|
||||||
{
|
{
|
||||||
REQUIRE(serverPoller.RegisterSocket(server));
|
REQUIRE(serverPoller.RegisterSocket(server, Nz::SocketPollEvent_Read));
|
||||||
|
|
||||||
THEN("The poller should have registered our socket")
|
THEN("The poller should have registered our socket")
|
||||||
{
|
{
|
||||||
|
|
@ -48,7 +48,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]")
|
||||||
|
|
||||||
WHEN("We register the client socket to the poller")
|
WHEN("We register the client socket to the poller")
|
||||||
{
|
{
|
||||||
REQUIRE(serverPoller.RegisterSocket(serverToClient));
|
REQUIRE(serverPoller.RegisterSocket(serverToClient, Nz::SocketPollEvent_Read));
|
||||||
|
|
||||||
THEN("The poller should have registered our socket")
|
THEN("The poller should have registered our socket")
|
||||||
{
|
{
|
||||||
|
|
@ -65,7 +65,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]")
|
||||||
|
|
||||||
REQUIRE(serverPoller.Wait(1000));
|
REQUIRE(serverPoller.Wait(1000));
|
||||||
|
|
||||||
CHECK(serverPoller.IsReady(serverToClient));
|
CHECK(serverPoller.IsReadyToRead(serverToClient));
|
||||||
|
|
||||||
CHECK(serverToClient.Read(buffer.data(), buffer.size()) == sent);
|
CHECK(serverToClient.Read(buffer.data(), buffer.size()) == sent);
|
||||||
|
|
||||||
|
|
@ -73,7 +73,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]")
|
||||||
{
|
{
|
||||||
REQUIRE_FALSE(serverPoller.Wait(100));
|
REQUIRE_FALSE(serverPoller.Wait(100));
|
||||||
|
|
||||||
REQUIRE_FALSE(serverPoller.IsReady(serverToClient));
|
REQUIRE_FALSE(serverPoller.IsReadyToRead(serverToClient));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
|
||||||
|
|
||||||
WHEN("We add an entity")
|
WHEN("We add an entity")
|
||||||
{
|
{
|
||||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
Ndk::EntityHandle entity = world.CreateEntity();
|
||||||
entity->AddComponent<Ndk::VelocityComponent>();
|
entity->AddComponent<Ndk::VelocityComponent>();
|
||||||
|
|
||||||
THEN("System should have it")
|
THEN("System should have it")
|
||||||
|
|
@ -50,7 +50,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
|
||||||
|
|
||||||
WHEN("We add an entity with excluded component")
|
WHEN("We add an entity with excluded component")
|
||||||
{
|
{
|
||||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
Ndk::EntityHandle entity = world.CreateEntity();
|
||||||
entity->AddComponent<Ndk::VelocityComponent>();
|
entity->AddComponent<Ndk::VelocityComponent>();
|
||||||
entity->AddComponent<Ndk::NodeComponent>();
|
entity->AddComponent<Ndk::NodeComponent>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,18 +57,18 @@ SCENARIO("Entity", "[NDK][ENTITY]")
|
||||||
{
|
{
|
||||||
Ndk::World world;
|
Ndk::World world;
|
||||||
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
|
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
|
||||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
Ndk::EntityHandle entity = world.CreateEntity();
|
||||||
|
|
||||||
WHEN("We add our UpdateComponent")
|
WHEN("We add our UpdateComponent")
|
||||||
{
|
{
|
||||||
UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>();
|
UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>();
|
||||||
REQUIRE(!updatableComponent.IsUpdated());
|
CHECK(!updatableComponent.IsUpdated());
|
||||||
|
|
||||||
THEN("Update the world should update the entity's component")
|
THEN("Update the world should update the entity's component")
|
||||||
{
|
{
|
||||||
world.Update(1.f);
|
world.Update(1.f);
|
||||||
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
||||||
REQUIRE(updatableComponentGet.IsUpdated());
|
CHECK(updatableComponentGet.IsUpdated());
|
||||||
}
|
}
|
||||||
|
|
||||||
THEN("Update the world should not update the entity's component if it's disabled")
|
THEN("Update the world should not update the entity's component if it's disabled")
|
||||||
|
|
@ -76,14 +76,14 @@ SCENARIO("Entity", "[NDK][ENTITY]")
|
||||||
entity->Enable(false);
|
entity->Enable(false);
|
||||||
world.Update(1.f);
|
world.Update(1.f);
|
||||||
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
||||||
REQUIRE(!updatableComponentGet.IsUpdated());
|
CHECK(!updatableComponentGet.IsUpdated());
|
||||||
}
|
}
|
||||||
|
|
||||||
THEN("We can remove its component")
|
THEN("We can remove its component")
|
||||||
{
|
{
|
||||||
entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>());
|
entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>());
|
||||||
world.Update(1.f);
|
world.Update(1.f);
|
||||||
REQUIRE(!entity->HasComponent<UpdatableComponent>());
|
CHECK(!entity->HasComponent<UpdatableComponent>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ SCENARIO("Entity", "[NDK][ENTITY]")
|
||||||
|
|
||||||
THEN("It's no more valid")
|
THEN("It's no more valid")
|
||||||
{
|
{
|
||||||
REQUIRE(!world.IsEntityValid(entity));
|
CHECK(!world.IsEntityValid(entity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
|
||||||
GIVEN("A world & an entity")
|
GIVEN("A world & an entity")
|
||||||
{
|
{
|
||||||
Ndk::World world;
|
Ndk::World world;
|
||||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
Ndk::EntityHandle entity = world.CreateEntity();
|
||||||
|
|
||||||
WHEN("We set the ownership of the entity to our owner")
|
WHEN("We set the ownership of the entity to our owner")
|
||||||
{
|
{
|
||||||
|
|
@ -15,13 +15,21 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
|
||||||
|
|
||||||
THEN("Entity is still valid")
|
THEN("Entity is still valid")
|
||||||
{
|
{
|
||||||
REQUIRE(entity.IsValid());
|
CHECK(entity.IsValid());
|
||||||
}
|
}
|
||||||
|
|
||||||
THEN("Resetting or getting out of scope is no more valid")
|
THEN("Resetting or getting out of scope is no more valid")
|
||||||
{
|
{
|
||||||
entityOwner.Reset();
|
entityOwner.Reset();
|
||||||
world.Update(1.f);
|
world.Update(1.f);
|
||||||
|
CHECK(!entity.IsValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN("Moving an entity owner works")
|
||||||
|
{
|
||||||
|
Ndk::EntityOwner entityOwner2(std::move(entityOwner));
|
||||||
|
entityOwner2.Reset();
|
||||||
|
world.Update(1.f);
|
||||||
REQUIRE(!entity.IsValid());
|
REQUIRE(!entity.IsValid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,21 +28,79 @@ class TestState : public Ndk::State
|
||||||
bool m_isUpdated;
|
bool m_isUpdated;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SecondTestState : public Ndk::State
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Enter(Ndk::StateMachine& /*fsm*/) override
|
||||||
|
{
|
||||||
|
m_isUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsUpdated() const
|
||||||
|
{
|
||||||
|
return m_isUpdated;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Leave(Ndk::StateMachine& /*fsm*/) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Update(Ndk::StateMachine& fsm, float /*elapsedTime*/) override
|
||||||
|
{
|
||||||
|
if (fsm.IsTopState(this))
|
||||||
|
m_isUpdated = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_isUpdated;
|
||||||
|
};
|
||||||
|
|
||||||
SCENARIO("State & StateMachine", "[NDK][STATE]")
|
SCENARIO("State & StateMachine", "[NDK][STATE]")
|
||||||
{
|
{
|
||||||
GIVEN("A statemachine with our TestState")
|
GIVEN("A statemachine with our test states")
|
||||||
{
|
{
|
||||||
std::shared_ptr<TestState> testState = std::make_shared<TestState>();
|
std::shared_ptr<TestState> testState = std::make_shared<TestState>();
|
||||||
Ndk::StateMachine stateMachine(testState);
|
std::shared_ptr<SecondTestState> secondTestState = std::make_shared<SecondTestState>();
|
||||||
|
Ndk::StateMachine stateMachine(secondTestState);
|
||||||
|
stateMachine.PushState(testState);
|
||||||
REQUIRE(!testState->IsUpdated());
|
REQUIRE(!testState->IsUpdated());
|
||||||
|
REQUIRE(!secondTestState->IsUpdated());
|
||||||
|
|
||||||
WHEN("We update our machine")
|
WHEN("We update our machine")
|
||||||
{
|
{
|
||||||
stateMachine.Update(1.f);
|
stateMachine.Update(1.f);
|
||||||
|
|
||||||
THEN("Our state has been updated")
|
THEN("Our state on the top has been updated but not the bottom one")
|
||||||
{
|
{
|
||||||
|
REQUIRE(stateMachine.IsTopState(testState.get()));
|
||||||
|
REQUIRE(!stateMachine.IsTopState(secondTestState.get()));
|
||||||
|
|
||||||
REQUIRE(testState->IsUpdated());
|
REQUIRE(testState->IsUpdated());
|
||||||
|
REQUIRE(!secondTestState->IsUpdated());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("We exchange the states' positions while emptying the stack")
|
||||||
|
{
|
||||||
|
REQUIRE(stateMachine.PopStatesUntil(secondTestState));
|
||||||
|
REQUIRE(stateMachine.IsTopState(secondTestState.get()));
|
||||||
|
|
||||||
|
std::shared_ptr<Ndk::State> oldState = stateMachine.PopState();
|
||||||
|
REQUIRE(stateMachine.PopState() == nullptr);
|
||||||
|
|
||||||
|
stateMachine.SetState(testState);
|
||||||
|
stateMachine.PushState(oldState);
|
||||||
|
|
||||||
|
stateMachine.Update(1.f);
|
||||||
|
|
||||||
|
THEN("Both states should be updated")
|
||||||
|
{
|
||||||
|
REQUIRE(!stateMachine.IsTopState(testState.get()));
|
||||||
|
REQUIRE(stateMachine.IsTopState(secondTestState.get()));
|
||||||
|
|
||||||
|
REQUIRE(testState->IsUpdated());
|
||||||
|
REQUIRE(secondTestState->IsUpdated());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ SCENARIO("ListenerSystem", "[NDK][LISTENERSYSTEM]")
|
||||||
GIVEN("A world and an entity with listener & node components")
|
GIVEN("A world and an entity with listener & node components")
|
||||||
{
|
{
|
||||||
Ndk::World world;
|
Ndk::World world;
|
||||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
Ndk::EntityHandle entity = world.CreateEntity();
|
||||||
Ndk::ListenerComponent& listenerComponent = entity->AddComponent<Ndk::ListenerComponent>();
|
Ndk::ListenerComponent& listenerComponent = entity->AddComponent<Ndk::ListenerComponent>();
|
||||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ SCENARIO("World", "[NDK][WORLD]")
|
||||||
AND_WHEN("We update our world with our entity")
|
AND_WHEN("We update our world with our entity")
|
||||||
{
|
{
|
||||||
REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>());
|
REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>());
|
||||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
Ndk::EntityHandle entity = world.CreateEntity();
|
||||||
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
|
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
|
||||||
|
|
||||||
THEN("Our entity component must be updated")
|
THEN("Our entity component must be updated")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue