Merge remote-tracking branch 'refs/remotes/origin/master' into enet_wip_nothing_to_see_here
This commit is contained in:
commit
9a30a7ee04
|
|
@ -23,7 +23,6 @@ namespace Ndk
|
|||
using Factory = std::function<BaseComponent*()>;
|
||||
|
||||
BaseComponent(ComponentIndex componentIndex);
|
||||
BaseComponent(const BaseComponent&) = default;
|
||||
BaseComponent(BaseComponent&&) = default;
|
||||
virtual ~BaseComponent();
|
||||
|
||||
|
|
@ -34,10 +33,12 @@ namespace Ndk
|
|||
|
||||
inline static ComponentIndex GetMaxComponentIndex();
|
||||
|
||||
BaseComponent& operator=(const BaseComponent&) = default;
|
||||
BaseComponent& operator=(const BaseComponent&) = delete;
|
||||
BaseComponent& operator=(BaseComponent&&) = default;
|
||||
|
||||
protected:
|
||||
BaseComponent(const BaseComponent&) = default;
|
||||
|
||||
ComponentIndex m_componentIndex;
|
||||
EntityHandle m_entity;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <NDK/Entity.hpp>
|
||||
#include <NDK/EntityList.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
|
|
@ -33,7 +34,7 @@ namespace Ndk
|
|||
|
||||
bool Filters(const Entity* entity) const;
|
||||
|
||||
inline const std::vector<EntityHandle>& GetEntities() const;
|
||||
inline const EntityList& GetEntities() const;
|
||||
inline SystemIndex GetIndex() const;
|
||||
inline int GetUpdateOrder() const;
|
||||
inline float GetUpdateRate() const;
|
||||
|
|
@ -84,12 +85,11 @@ namespace Ndk
|
|||
static inline bool Initialize();
|
||||
static inline void Uninitialize();
|
||||
|
||||
std::vector<EntityHandle> m_entities;
|
||||
Nz::Bitset<Nz::UInt64> m_entityBits;
|
||||
Nz::Bitset<> m_excludedComponents;
|
||||
mutable Nz::Bitset<> m_filterResult;
|
||||
Nz::Bitset<> m_requiredAnyComponents;
|
||||
Nz::Bitset<> m_requiredComponents;
|
||||
EntityList m_entities;
|
||||
SystemIndex m_systemIndex;
|
||||
World* m_world;
|
||||
bool m_updateEnabled;
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ namespace Ndk
|
|||
* \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;
|
||||
}
|
||||
|
|
@ -121,10 +121,7 @@ namespace Ndk
|
|||
|
||||
inline bool BaseSystem::HasEntity(const Entity* entity) const
|
||||
{
|
||||
if (!entity)
|
||||
return false;
|
||||
|
||||
return m_entityBits.UnboundedTest(entity->GetId());
|
||||
return m_entities.Has(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -288,9 +285,7 @@ namespace Ndk
|
|||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
|
||||
m_entities.emplace_back(entity);
|
||||
m_entityBits.UnboundedSet(entity->GetId(), true);
|
||||
|
||||
m_entities.Insert(entity);
|
||||
entity->RegisterSystem(m_systemIndex);
|
||||
|
||||
OnEntityAdded(entity);
|
||||
|
|
@ -308,14 +303,7 @@ namespace Ndk
|
|||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
|
||||
auto it = std::find(m_entities.begin(), m_entities.end(), *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());
|
||||
m_entities.Remove(entity);
|
||||
entity->UnregisterSystem(m_systemIndex);
|
||||
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ namespace Ndk
|
|||
const Nz::Frustumf& GetFrustum() const override;
|
||||
inline unsigned int GetLayer() const;
|
||||
const Nz::Matrix4f& GetProjectionMatrix() const override;
|
||||
inline Nz::ProjectionType GetProjectionType() const;
|
||||
Nz::ProjectionType GetProjectionType() const override;
|
||||
inline const Nz::Vector2f& GetSize() const;
|
||||
const Nz::RenderTarget* GetTarget() const override;
|
||||
inline const Nz::Rectf& GetTargetRegion() const;
|
||||
|
|
|
|||
|
|
@ -117,16 +117,6 @@ namespace Ndk
|
|||
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
|
||||
* \return Size of the camera
|
||||
|
|
|
|||
|
|
@ -51,6 +51,9 @@ namespace Ndk
|
|||
|
||||
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;
|
||||
|
||||
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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -17,14 +17,17 @@
|
|||
namespace Ndk
|
||||
{
|
||||
class BaseComponent;
|
||||
class BaseSystem;
|
||||
class Entity;
|
||||
class EntityList;
|
||||
class World;
|
||||
|
||||
using EntityHandle = Nz::ObjectHandle<Entity>;
|
||||
|
||||
class NDK_API Entity : public Nz::HandledObject<Entity>
|
||||
{
|
||||
friend class BaseSystem;
|
||||
friend BaseSystem;
|
||||
friend EntityList;
|
||||
friend World;
|
||||
|
||||
public:
|
||||
|
|
@ -78,13 +81,16 @@ namespace Ndk
|
|||
|
||||
inline Nz::Bitset<>& GetRemovedComponentBits();
|
||||
|
||||
inline void RegisterEntityList(EntityList* list);
|
||||
inline void RegisterSystem(SystemIndex index);
|
||||
|
||||
inline void SetWorld(World* world) noexcept;
|
||||
|
||||
inline void UnregisterEntityList(EntityList* list);
|
||||
inline void UnregisterSystem(SystemIndex index);
|
||||
|
||||
std::vector<std::unique_ptr<BaseComponent>> m_components;
|
||||
std::vector<EntityList*> m_containedInLists;
|
||||
Nz::Bitset<> m_componentBits;
|
||||
Nz::Bitset<> m_removedComponentBits;
|
||||
Nz::Bitset<> m_systemBits;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <Nazara/Core/Error.hpp>
|
||||
#include <Nazara/Core/StringStream.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -257,11 +258,10 @@ namespace Ndk
|
|||
return m_removedComponentBits;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Registers a system for the entity
|
||||
*
|
||||
* \param index Index of the system
|
||||
*/
|
||||
inline void Entity::RegisterEntityList(EntityList* list)
|
||||
{
|
||||
m_containedInLists.push_back(list);
|
||||
}
|
||||
|
||||
inline void Entity::RegisterSystem(SystemIndex index)
|
||||
{
|
||||
|
|
@ -289,6 +289,16 @@ namespace Ndk
|
|||
* \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)
|
||||
{
|
||||
m_systemBits.UnboundedReset(index);
|
||||
|
|
|
|||
|
|
@ -15,46 +15,68 @@ namespace Ndk
|
|||
{
|
||||
class NDK_API EntityList
|
||||
{
|
||||
public:
|
||||
using Container = std::vector<EntityHandle>;
|
||||
friend Entity;
|
||||
|
||||
EntityList() = default;
|
||||
~EntityList() = default;
|
||||
public:
|
||||
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 bool Has(const Entity* entity);
|
||||
inline bool Has(EntityId entity);
|
||||
inline bool Has(const Entity* entity) const;
|
||||
inline bool Has(EntityId entity) const;
|
||||
|
||||
inline void Insert(Entity* entity);
|
||||
|
||||
inline void Remove(Entity* entity);
|
||||
|
||||
// STL API
|
||||
inline Container::iterator begin();
|
||||
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 iterator begin() const;
|
||||
inline bool empty() const;
|
||||
inline iterator end() const;
|
||||
inline size_type size() const;
|
||||
|
||||
inline Container::iterator end();
|
||||
inline Container::const_iterator end() const;
|
||||
|
||||
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;
|
||||
inline EntityList& operator=(const EntityList& entityList);
|
||||
inline EntityList& operator=(EntityList&& entityList) noexcept;
|
||||
|
||||
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;
|
||||
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"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||
|
||||
#include <NDK/EntityList.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
|
|
@ -14,24 +15,71 @@ namespace Ndk
|
|||
*/
|
||||
|
||||
/*!
|
||||
* \brief Clears the set from every entities
|
||||
* \brief Construct a new entity list
|
||||
*/
|
||||
|
||||
inline void EntityList::Clear()
|
||||
inline EntityList::EntityList() :
|
||||
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
|
||||
*
|
||||
* \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)
|
||||
inline bool EntityList::Has(const Entity* entity) const
|
||||
{
|
||||
NazaraAssert(!m_world || !entity || entity->GetWorld() == m_world, "Incompatible world");
|
||||
|
||||
return entity && entity->IsValid() && Has(entity->GetId());
|
||||
}
|
||||
|
||||
|
|
@ -41,8 +89,7 @@ namespace Ndk
|
|||
*
|
||||
* \param id Identifier of the entity
|
||||
*/
|
||||
|
||||
inline bool EntityList::Has(EntityId entity)
|
||||
inline bool EntityList::Has(EntityId entity) const
|
||||
{
|
||||
return m_entityBits.UnboundedTest(entity);
|
||||
}
|
||||
|
|
@ -50,17 +97,23 @@ namespace Ndk
|
|||
/*!
|
||||
* \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 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)
|
||||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
|
||||
if (!Has(entity))
|
||||
{
|
||||
m_entities.emplace_back(entity);
|
||||
entity->RegisterEntityList(this);
|
||||
|
||||
m_entityBits.UnboundedSet(entity->GetId(), true);
|
||||
m_world = entity->GetWorld();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,89 +123,138 @@ namespace Ndk
|
|||
* \param entity Pointer to the entity
|
||||
*
|
||||
* \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)
|
||||
{
|
||||
if (Has(entity))
|
||||
{
|
||||
auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
|
||||
NazaraAssert(it != m_entities.end(), "Entity should be part of the vector");
|
||||
m_entityBits.Reset(entity->GetId());
|
||||
|
||||
std::swap(*it, m_entities.back());
|
||||
m_entities.pop_back(); // We get it out of the vector
|
||||
m_entityBits.UnboundedSet(entity->GetId(), false);
|
||||
entity->UnregisterEntityList(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Nz::Interface STD
|
||||
inline EntityList::Container::iterator EntityList::begin()
|
||||
// STL Interface
|
||||
inline EntityList::iterator EntityList::begin() const
|
||||
{
|
||||
return m_entities.begin();
|
||||
}
|
||||
|
||||
inline EntityList::Container::const_iterator EntityList::begin() const
|
||||
{
|
||||
return m_entities.begin();
|
||||
}
|
||||
|
||||
inline EntityList::Container::const_iterator EntityList::cbegin() const
|
||||
{
|
||||
return m_entities.cbegin();
|
||||
}
|
||||
|
||||
inline EntityList::Container::const_iterator EntityList::cend() const
|
||||
{
|
||||
return m_entities.cend();
|
||||
}
|
||||
|
||||
inline EntityList::Container::const_reverse_iterator EntityList::crbegin() const
|
||||
{
|
||||
return m_entities.crbegin();
|
||||
}
|
||||
|
||||
inline EntityList::Container::const_reverse_iterator EntityList::crend() const
|
||||
{
|
||||
return m_entities.crend();
|
||||
return EntityList::iterator(this, m_entityBits.FindFirst());
|
||||
}
|
||||
|
||||
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"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include <NDK/Prerequesites.hpp>
|
||||
#include <NDK/State.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
|
|
@ -25,14 +26,21 @@ namespace Ndk
|
|||
|
||||
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 StateMachine& operator=(StateMachine&& fsm) = default;
|
||||
StateMachine& operator=(const StateMachine&) = delete;
|
||||
|
||||
private:
|
||||
std::shared_ptr<State> m_currentState;
|
||||
std::shared_ptr<State> m_nextState;
|
||||
std::vector<std::shared_ptr<State>> m_states;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <NDK/StateMachine.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace Ndk
|
||||
|
|
@ -11,7 +10,7 @@ namespace Ndk
|
|||
/*!
|
||||
* \ingroup NDK
|
||||
* \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
|
||||
*/
|
||||
|
||||
inline StateMachine::StateMachine(std::shared_ptr<State> originalState) :
|
||||
m_currentState(std::move(originalState))
|
||||
inline StateMachine::StateMachine(std::shared_ptr<State> originalState)
|
||||
{
|
||||
NazaraAssert(m_currentState, "StateMachine must have a state to begin with");
|
||||
m_currentState->Enter(*this);
|
||||
NazaraAssert(originalState, "StateMachine must have a state to begin with");
|
||||
PushState(std::move(originalState));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object
|
||||
*
|
||||
* \remark Calls "Leave" on the state
|
||||
* \remark Calls "Leave" on all the states
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
*
|
||||
* \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
|
||||
{
|
||||
return m_currentState;
|
||||
return m_states.back();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the state
|
||||
* \return True if update is successful
|
||||
* \brief Checks whether the state is on the top of the machine
|
||||
* \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
|
||||
*/
|
||||
|
||||
inline bool StateMachine::Update(float elapsedTime)
|
||||
{
|
||||
if (m_nextState)
|
||||
{
|
||||
m_currentState->Leave(*this);
|
||||
m_currentState = std::move(m_nextState);
|
||||
m_currentState->Enter(*this);
|
||||
}
|
||||
|
||||
return m_currentState->Update(*this, elapsedTime);
|
||||
return std::all_of(m_states.begin(), m_states.end(), [=](std::shared_ptr<State>& state) {
|
||||
return state->Update(*this, elapsedTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ namespace Ndk
|
|||
|
||||
std::unique_ptr<Nz::AbstractRenderTechnique> m_renderTechnique;
|
||||
std::vector<GraphicsComponentCullingList::VolumeEntry> m_volumeEntries;
|
||||
EntityList m_cameras;
|
||||
std::vector<EntityHandle> m_cameras;
|
||||
EntityList m_drawables;
|
||||
EntityList m_directionalLights;
|
||||
EntityList m_lights;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <NDK/Entity.hpp>
|
||||
#include <NDK/EntityList.hpp>
|
||||
#include <NDK/System.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
|
@ -28,7 +29,7 @@ namespace Ndk
|
|||
friend Entity;
|
||||
|
||||
public:
|
||||
using EntityList = std::vector<EntityHandle>;
|
||||
using EntityVector = std::vector<EntityHandle>;
|
||||
|
||||
inline World(bool addDefaultSystems = true);
|
||||
World(const World&) = delete;
|
||||
|
|
@ -41,21 +42,21 @@ namespace Ndk
|
|||
template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args);
|
||||
|
||||
const EntityHandle& CreateEntity();
|
||||
inline EntityList CreateEntities(unsigned int count);
|
||||
inline EntityVector CreateEntities(unsigned int count);
|
||||
|
||||
void Clear() noexcept;
|
||||
const EntityHandle& CloneEntity(EntityId id);
|
||||
|
||||
const EntityHandle& GetEntity(EntityId id);
|
||||
inline const EntityList& GetEntities();
|
||||
inline const EntityHandle& GetEntity(EntityId id);
|
||||
inline const EntityList& GetEntities() const;
|
||||
inline BaseSystem& GetSystem(SystemIndex index);
|
||||
template<typename SystemType> SystemType& GetSystem();
|
||||
|
||||
inline bool HasSystem(SystemIndex index) const;
|
||||
template<typename SystemType> bool HasSystem() const;
|
||||
|
||||
void KillEntity(Entity* entity);
|
||||
inline void KillEntities(const EntityList& list);
|
||||
inline void KillEntity(Entity* entity);
|
||||
inline void KillEntities(const EntityVector& list);
|
||||
|
||||
inline bool IsEntityValid(const Entity* entity) const;
|
||||
inline bool IsEntityIdValid(EntityId id) const;
|
||||
|
|
@ -79,19 +80,22 @@ namespace Ndk
|
|||
struct EntityBlock
|
||||
{
|
||||
EntityBlock(Entity&& e) :
|
||||
entity(std::move(e))
|
||||
entity(std::move(e)),
|
||||
handle(&entity)
|
||||
{
|
||||
}
|
||||
|
||||
EntityBlock(EntityBlock&& block) = default;
|
||||
|
||||
Entity entity;
|
||||
std::size_t aliveIndex;
|
||||
EntityHandle handle;
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<BaseSystem>> m_systems;
|
||||
std::vector<BaseSystem*> m_orderedSystems;
|
||||
std::vector<EntityBlock> m_entities;
|
||||
std::vector<EntityBlock*> m_entityBlocks;
|
||||
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
|
||||
std::vector<EntityId> m_freeIdList;
|
||||
EntityList m_aliveEntities;
|
||||
Nz::Bitset<Nz::UInt64> m_dirtyEntities;
|
||||
|
|
|
|||
|
|
@ -82,9 +82,9 @@ namespace Ndk
|
|||
* \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);
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
|
|
@ -98,7 +98,7 @@ namespace Ndk
|
|||
* \return A constant reference to the entities
|
||||
*/
|
||||
|
||||
inline const World::EntityList& World::GetEntities()
|
||||
inline const EntityList& World::GetEntities() const
|
||||
{
|
||||
return m_aliveEntities;
|
||||
}
|
||||
|
|
@ -164,18 +164,53 @@ namespace Ndk
|
|||
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
|
||||
*
|
||||
* This function has the same effect as calling KillEntity for every entity contained in the vector
|
||||
*
|
||||
* \param list Set of entities to kill
|
||||
*/
|
||||
|
||||
inline void World::KillEntities(const EntityList& list)
|
||||
inline void World::KillEntities(const EntityVector& list)
|
||||
{
|
||||
for (const EntityHandle& entity : list)
|
||||
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
|
||||
* \return true If it is the case
|
||||
|
|
@ -197,7 +232,7 @@ namespace Ndk
|
|||
|
||||
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_dirtyEntities = std::move(world.m_dirtyEntities);
|
||||
m_entityBlocks = std::move(world.m_entityBlocks);
|
||||
m_freeIdList = std::move(world.m_freeIdList);
|
||||
m_killedEntities = std::move(world.m_killedEntities);
|
||||
m_orderedSystems = std::move(world.m_orderedSystems);
|
||||
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
||||
m_waitingEntities = std::move(world.m_waitingEntities);
|
||||
|
||||
m_entities = std::move(world.m_entities);
|
||||
for (EntityBlock& block : m_entities)
|
||||
|
|
@ -284,7 +321,7 @@ namespace Ndk
|
|||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,17 @@ namespace Ndk
|
|||
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
|
||||
* \return A constant reference to the render target of the camera
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@ namespace Ndk
|
|||
Entity::Entity(Entity&& entity) :
|
||||
HandledObject(std::move(entity)),
|
||||
m_components(std::move(entity.m_components)),
|
||||
m_containedInLists(std::move(entity.m_containedInLists)),
|
||||
m_componentBits(std::move(entity.m_componentBits)),
|
||||
m_removedComponentBits(std::move(entity.m_removedComponentBits)),
|
||||
m_systemBits(std::move(entity.m_systemBits)),
|
||||
m_id(entity.m_id),
|
||||
m_world(entity.m_world),
|
||||
|
|
@ -175,9 +177,15 @@ namespace Ndk
|
|||
m_components.clear();
|
||||
m_componentBits.Reset();
|
||||
|
||||
// And then free every handle
|
||||
// Free every handle
|
||||
UnregisterAllHandles();
|
||||
|
||||
// Remove from every list
|
||||
for (EntityList* list : m_containedInLists)
|
||||
list->NotifyEntityDestruction(this);
|
||||
|
||||
m_containedInLists.clear();
|
||||
|
||||
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_cameras.Remove(entity);
|
||||
m_directionalLights.Remove(entity);
|
||||
m_drawables.Remove(entity);
|
||||
m_lights.Remove(entity);
|
||||
m_particleGroups.Remove(entity);
|
||||
m_pointSpotLights.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>())
|
||||
{
|
||||
|
|
@ -74,14 +76,23 @@ namespace Ndk
|
|||
|
||||
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)
|
||||
{
|
||||
return handle1->GetComponent<CameraComponent>().GetLayer() < handle2->GetComponent<CameraComponent>().GetLayer();
|
||||
});
|
||||
}
|
||||
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>())
|
||||
{
|
||||
|
|
@ -181,7 +192,7 @@ namespace Ndk
|
|||
GraphicsComponent& graphicsComponent = drawable->GetComponent<GraphicsComponent>();
|
||||
graphicsComponent.EnsureBoundingVolumeUpdate();
|
||||
}
|
||||
|
||||
|
||||
bool forceInvalidation = false;
|
||||
|
||||
std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation);
|
||||
|
|
|
|||
|
|
@ -60,29 +60,51 @@ namespace Ndk
|
|||
const EntityHandle& World::CreateEntity()
|
||||
{
|
||||
EntityId id;
|
||||
EntityBlock* entBlock;
|
||||
if (!m_freeIdList.empty())
|
||||
{
|
||||
// We get an identifier
|
||||
id = m_freeIdList.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
|
||||
{
|
||||
// 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
|
||||
m_entities.push_back(Entity(this, id));
|
||||
if (m_entities.capacity() > m_entities.size())
|
||||
{
|
||||
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
|
||||
Entity& entity = m_entities[id].entity;
|
||||
entity.Create();
|
||||
// We initialize the entity and we add it to the list of alive entities
|
||||
entBlock->entity.Create();
|
||||
|
||||
m_aliveEntities.emplace_back(&entity);
|
||||
m_entities[id].aliveIndex = m_aliveEntities.size() - 1;
|
||||
m_aliveEntities.Insert(&entBlock->entity);
|
||||
|
||||
return m_aliveEntities.back();
|
||||
return entBlock->handle;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -96,8 +118,10 @@ namespace Ndk
|
|||
// First, destruction of entities, then handles
|
||||
// This is made to avoid that handle warn uselessly entities before their destruction
|
||||
m_entities.clear();
|
||||
m_entityBlocks.clear();
|
||||
m_waitingEntities.clear();
|
||||
|
||||
m_aliveEntities.clear();
|
||||
m_aliveEntities.Clear();
|
||||
m_dirtyEntities.Clear();
|
||||
m_killedEntities.Clear();
|
||||
}
|
||||
|
|
@ -120,7 +144,7 @@ namespace Ndk
|
|||
return EntityHandle::InvalidHandle;
|
||||
}
|
||||
|
||||
EntityHandle clone = CreateEntity();
|
||||
const EntityHandle& clone = CreateEntity();
|
||||
|
||||
const Nz::Bitset<>& componentBits = original->GetComponentBits();
|
||||
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));
|
||||
}
|
||||
|
||||
return GetEntity(clone->GetId());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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;
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -177,45 +167,43 @@ namespace Ndk
|
|||
if (!m_orderedSystemsUpdated)
|
||||
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
|
||||
for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i))
|
||||
{
|
||||
EntityBlock& block = m_entities[i];
|
||||
Entity& entity = block.entity;
|
||||
NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
|
||||
|
||||
NazaraAssert(entity.IsValid(), "Entity must be valid");
|
||||
Entity* entity = &m_entityBlocks[i]->entity;
|
||||
|
||||
// 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
|
||||
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_freeIdList.push_back(entity->GetId());
|
||||
}
|
||||
m_killedEntities.Reset();
|
||||
|
||||
// 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))
|
||||
{
|
||||
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)
|
||||
if (!entity->IsValid())
|
||||
|
|
@ -242,7 +230,7 @@ namespace Ndk
|
|||
}
|
||||
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)
|
||||
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 AddPointLight(const PointLight& 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Nz
|
|||
virtual Vector3f GetForward() const = 0;
|
||||
virtual const Frustumf& GetFrustum() const = 0;
|
||||
virtual const Matrix4f& GetProjectionMatrix() const = 0;
|
||||
virtual Nz::ProjectionType GetProjectionType() const = 0;
|
||||
virtual const RenderTarget* GetTarget() const = 0;
|
||||
virtual const Matrix4f& GetViewMatrix() 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 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 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace Nz
|
|||
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
|
||||
void AddPointLight(const PointLight& 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:
|
||||
inline bool IsMaterialSuitable(const Material* material) const;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <Nazara/Graphics/Material.hpp>
|
||||
#include <Nazara/Math/Box.hpp>
|
||||
#include <Nazara/Math/Matrix4.hpp>
|
||||
#include <Nazara/Math/Plane.hpp>
|
||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||
#include <Nazara/Utility/MeshData.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 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 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;
|
||||
|
||||
|
|
@ -73,7 +74,7 @@ namespace Nz
|
|||
std::vector<BillboardData> billboards;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedBillboardEntry, MaterialComparator> BatchedBillboardContainer;
|
||||
using BatchedBillboardContainer = std::map<const Material*, BatchedBillboardEntry, MaterialComparator>;
|
||||
|
||||
struct BatchedBillboardPipelineEntry
|
||||
{
|
||||
|
|
@ -81,7 +82,7 @@ namespace Nz
|
|||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator> BillboardPipelineBatches;
|
||||
using BillboardPipelineBatches = std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator>;
|
||||
|
||||
/// Sprites
|
||||
struct SpriteChain_XYZ_Color_UV
|
||||
|
|
@ -97,7 +98,7 @@ namespace Nz
|
|||
std::vector<SpriteChain_XYZ_Color_UV> spriteChains;
|
||||
};
|
||||
|
||||
typedef std::map<const Texture*, BatchedSpriteEntry> SpriteOverlayBatches;
|
||||
using SpriteOverlayBatches = std::map<const Texture*, BatchedSpriteEntry>;
|
||||
|
||||
struct BatchedBasicSpriteEntry
|
||||
{
|
||||
|
|
@ -107,7 +108,7 @@ namespace Nz
|
|||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator> SpriteMaterialBatches;
|
||||
using SpriteMaterialBatches = std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator>;
|
||||
|
||||
struct BatchedSpritePipelineEntry
|
||||
{
|
||||
|
|
@ -115,7 +116,7 @@ namespace Nz
|
|||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator> SpritePipelineBatches;
|
||||
using SpritePipelineBatches = std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator>;
|
||||
|
||||
/// Meshes
|
||||
struct MeshDataComparator
|
||||
|
|
@ -132,7 +133,7 @@ namespace Nz
|
|||
Spheref squaredBoundingSphere;
|
||||
};
|
||||
|
||||
typedef std::map<MeshData, MeshInstanceEntry, MeshDataComparator> MeshInstanceContainer;
|
||||
using MeshInstanceContainer = std::map<MeshData, MeshInstanceEntry, MeshDataComparator>;
|
||||
|
||||
struct BatchedModelEntry
|
||||
{
|
||||
|
|
@ -142,7 +143,7 @@ namespace Nz
|
|||
bool enabled = false;
|
||||
};
|
||||
|
||||
typedef std::map<const Material*, BatchedModelEntry, MaterialComparator> MeshMaterialBatches;
|
||||
using MeshMaterialBatches = std::map<const Material*, BatchedModelEntry, MaterialComparator>;
|
||||
|
||||
struct BatchedMaterialEntry
|
||||
{
|
||||
|
|
@ -150,25 +151,33 @@ namespace Nz
|
|||
MeshMaterialBatches materialMap;
|
||||
};
|
||||
|
||||
typedef std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator> MeshPipelineBatches;
|
||||
using MeshPipelineBatches = std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator>;
|
||||
|
||||
struct TransparentModelData
|
||||
struct UnbatchedModelData
|
||||
{
|
||||
Matrix4f transformMatrix;
|
||||
MeshData meshData;
|
||||
Spheref squaredBoundingSphere;
|
||||
Spheref obbSphere;
|
||||
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
|
||||
{
|
||||
BillboardPipelineBatches billboards;
|
||||
SpritePipelineBatches basicSprites;
|
||||
SpritePipelineBatches opaqueSprites;
|
||||
MeshPipelineBatches opaqueModels;
|
||||
TransparentModelContainer transparentModels;
|
||||
std::vector<TransparentModelData> transparentModelData;
|
||||
std::vector<std::size_t> depthSortedMeshes;
|
||||
std::vector<std::size_t> depthSortedSprites;
|
||||
std::vector<UnbatchedModelData> depthSortedMeshData;
|
||||
std::vector<UnbatchedSpriteData> depthSortedSpriteData;
|
||||
std::vector<const Drawable*> otherDrawables;
|
||||
unsigned int clearCount = 0;
|
||||
};
|
||||
|
|
@ -179,6 +188,10 @@ namespace Nz
|
|||
BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count);
|
||||
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 OnMaterialInvalidation(const Material* material);
|
||||
void OnTextureInvalidation(const Texture* texture);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ namespace Nz
|
|||
void DrawBasicSprites(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 DrawOrderedSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||
void DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
|
||||
const ShaderUniforms* GetShaderUniforms(const Shader* shader) const;
|
||||
void OnShaderInvalidated(const Shader* shader) const;
|
||||
|
|
|
|||
|
|
@ -98,7 +98,13 @@ namespace Nz
|
|||
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)
|
||||
std::swap(a, b);
|
||||
|
|
@ -112,13 +118,8 @@ namespace Nz
|
|||
if (b > a)
|
||||
std::swap(a, b);
|
||||
|
||||
if ((b < 0) && (a > std::numeric_limits<T>::max() + b))
|
||||
return false;
|
||||
|
||||
if ((b > 0) && (a < std::numeric_limits<T>::min() + b))
|
||||
return false;
|
||||
|
||||
return std::abs(a - b) <= maxDifference;
|
||||
using UnsignedT = std::make_unsigned_t<T>;
|
||||
return static_cast<UnsignedT>(a) - static_cast<UnsignedT>(b) <= static_cast<UnsignedT>(maxDifference);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +488,7 @@ namespace Nz
|
|||
template<typename T, typename T2>
|
||||
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& Translate(const Vector3<T>& translation);
|
||||
|
||||
T& operator[](unsigned int i);
|
||||
T operator[](unsigned int i) const;
|
||||
T& operator[](std::size_t i);
|
||||
T operator[](std::size_t i) const;
|
||||
|
||||
Box operator*(T scalar) const;
|
||||
Box operator*(const Vector3<T>& vec) const;
|
||||
|
|
|
|||
|
|
@ -735,24 +735,15 @@ namespace Nz
|
|||
* \brief Returns 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 Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined
|
||||
* \remark Access to index greater than 6 is undefined behavior
|
||||
* \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
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T& Box<T>::operator[](unsigned int i)
|
||||
T& Box<T>::operator[](std::size_t i)
|
||||
{
|
||||
#if NAZARA_MATH_SAFE
|
||||
if (i >= 6)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 6)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 6, "Index out of range");
|
||||
|
||||
return *(&x+i);
|
||||
}
|
||||
|
|
@ -761,24 +752,15 @@ namespace Nz
|
|||
* \brief Returns 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 Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined
|
||||
* \remark Access to index greater than 6 is undefined behavior
|
||||
* \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
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T Box<T>::operator[](unsigned int i) const
|
||||
T Box<T>::operator[](std::size_t i) const
|
||||
{
|
||||
#if NAZARA_MATH_SAFE
|
||||
if (i >= 6)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 6)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 6, "Index out of range");
|
||||
|
||||
return *(&x+i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ namespace Nz
|
|||
|
||||
Rect& Translate(const Vector2<T>& translation);
|
||||
|
||||
T& operator[](unsigned int i);
|
||||
T operator[](unsigned int i) const;
|
||||
T& operator[](std::size_t i);
|
||||
T operator[](std::size_t i) const;
|
||||
|
||||
Rect operator*(T scalar) const;
|
||||
Rect operator*(const Vector2<T>& vec) const;
|
||||
|
|
|
|||
|
|
@ -578,23 +578,14 @@ namespace Nz
|
|||
* \return A reference to the ith element of the rectangle
|
||||
*
|
||||
* \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
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T& Rect<T>::operator[](unsigned int i)
|
||||
T& Rect<T>::operator[](std::size_t i)
|
||||
{
|
||||
#if NAZARA_MATH_SAFE
|
||||
if (i >= 4)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 4)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 4, "Index out of range");
|
||||
|
||||
return *(&x+i);
|
||||
}
|
||||
|
|
@ -603,24 +594,15 @@ namespace Nz
|
|||
* \brief Returns 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 Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
||||
* \remark Access to index greater than 4 is undefined behavior
|
||||
* \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
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T Rect<T>::operator[](unsigned int i) const
|
||||
T Rect<T>::operator[](std::size_t i) const
|
||||
{
|
||||
#if NAZARA_MATH_SAFE
|
||||
if (i >= 4)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 4)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 4, "Index out of range");
|
||||
|
||||
return *(&x+i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ namespace Nz
|
|||
|
||||
String ToString() const;
|
||||
|
||||
T& operator[](unsigned int i);
|
||||
T operator[](unsigned int i) const;
|
||||
T& operator[](std::size_t i);
|
||||
T operator[](std::size_t i) const;
|
||||
|
||||
Sphere operator*(T scalar) const;
|
||||
Sphere& operator=(const Sphere& other) = default;
|
||||
|
|
|
|||
|
|
@ -466,24 +466,15 @@ namespace Nz
|
|||
* \brief Returns 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 Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
||||
* \remark Access to index greater than 4 is undefined behavior
|
||||
* \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
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T& Sphere<T>::operator[](unsigned int i)
|
||||
T& Sphere<T>::operator[](std::size_t i)
|
||||
{
|
||||
#if NAZARA_MATH_SAFE
|
||||
if (i >= 4)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 4)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 4, "Index out of range");
|
||||
|
||||
return *(&x+i);
|
||||
}
|
||||
|
|
@ -492,24 +483,15 @@ namespace Nz
|
|||
* \brief Returns 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 Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined
|
||||
* \remark Access to index greater than 4 is undefined behavior
|
||||
* \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
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T Sphere<T>::operator[](unsigned int i) const
|
||||
T Sphere<T>::operator[](std::size_t i) const
|
||||
{
|
||||
#if NAZARA_MATH_SAFE
|
||||
if (i >= 4)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 4)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 4, "Index out of range");
|
||||
|
||||
return *(&x+i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef NAZARA_ENUMS_NETWORK_HPP
|
||||
#define NAZARA_ENUMS_NETWORK_HPP
|
||||
|
||||
#include <Nazara/Prerequesites.hpp>
|
||||
#include <Nazara/Core/Flags.hpp>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -91,6 +91,23 @@ namespace Nz
|
|||
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
|
||||
{
|
||||
SocketState_Bound, //< The socket is currently bound
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ namespace Nz
|
|||
|
||||
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 RegisterSocket(AbstractSocket& socket);
|
||||
bool RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags);
|
||||
void UnregisterSocket(AbstractSocket& socket);
|
||||
|
||||
bool Wait(UInt64 msTimeout);
|
||||
|
|
@ -41,4 +42,4 @@ namespace Nz
|
|||
|
||||
#include <Nazara/Network/SocketPoller.inl>
|
||||
|
||||
#endif // NAZARA_SOCKETPOLLER_HPP
|
||||
#endif // NAZARA_SOCKETPOLLER_HPP
|
||||
|
|
|
|||
|
|
@ -64,10 +64,10 @@ namespace Nz
|
|||
|
||||
struct Callback
|
||||
{
|
||||
ContactEndCallback endCallback;
|
||||
ContactPreSolveCallback preSolveCallback;
|
||||
ContactPostSolveCallback postSolveCallback;
|
||||
ContactStartCallback startCallback;
|
||||
ContactEndCallback endCallback = nullptr;
|
||||
ContactPreSolveCallback preSolveCallback = nullptr;
|
||||
ContactPostSolveCallback postSolveCallback = nullptr;
|
||||
ContactStartCallback startCallback = nullptr;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,15 +26,15 @@ namespace Nz
|
|||
|
||||
Reference operator*() const;
|
||||
|
||||
Reference operator[](unsigned int index) const;
|
||||
Reference operator[](std::size_t index) const;
|
||||
|
||||
IndexIterator& operator=(const IndexIterator& iterator);
|
||||
|
||||
IndexIterator operator+(unsigned int indexCount) const;
|
||||
IndexIterator operator-(unsigned int indexCount) const;
|
||||
IndexIterator operator+(std::size_t indexCount) const;
|
||||
IndexIterator operator-(std::size_t indexCount) const;
|
||||
|
||||
IndexIterator& operator+=(unsigned int indexCount);
|
||||
IndexIterator& operator-=(unsigned int indexCount);
|
||||
IndexIterator& operator+=(std::size_t indexCount);
|
||||
IndexIterator& operator-=(std::size_t indexCount);
|
||||
|
||||
IndexIterator& operator++();
|
||||
IndexIterator operator++(int);
|
||||
|
|
@ -50,10 +50,10 @@ namespace Nz
|
|||
friend bool operator>=(const IndexIterator& lhs, const IndexIterator& rhs);
|
||||
|
||||
private:
|
||||
IndexIterator(IndexMapper* mapper, unsigned int index);
|
||||
IndexIterator(IndexMapper* mapper, std::size_t index);
|
||||
|
||||
IndexMapper* m_mapper;
|
||||
unsigned int m_index;
|
||||
std::size_t m_index;
|
||||
};
|
||||
|
||||
class IndexIterator::Reference
|
||||
|
|
@ -70,10 +70,10 @@ namespace Nz
|
|||
operator UInt32() const;
|
||||
|
||||
private:
|
||||
Reference(IndexMapper* mapper, unsigned int index);
|
||||
Reference(IndexMapper* mapper, std::size_t index);
|
||||
|
||||
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_index(index)
|
||||
{
|
||||
|
|
@ -31,7 +31,7 @@ namespace Nz
|
|||
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);
|
||||
}
|
||||
|
|
@ -44,24 +44,24 @@ namespace Nz
|
|||
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);
|
||||
}
|
||||
|
||||
inline IndexIterator IndexIterator::operator-(unsigned int indexCount) const
|
||||
inline IndexIterator IndexIterator::operator-(std::size_t indexCount) const
|
||||
{
|
||||
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;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline IndexIterator& IndexIterator::operator-=(unsigned int indexCount)
|
||||
inline IndexIterator& IndexIterator::operator-=(std::size_t indexCount)
|
||||
{
|
||||
m_index += indexCount;
|
||||
|
||||
|
|
@ -133,7 +133,7 @@ namespace Nz
|
|||
|
||||
/**************************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_index(index)
|
||||
{
|
||||
|
|
@ -148,7 +148,7 @@ namespace Nz
|
|||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ namespace Nz
|
|||
class IndexIterator;
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
|
@ -29,11 +26,11 @@ namespace Nz
|
|||
IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly);
|
||||
~IndexMapper() = default;
|
||||
|
||||
UInt32 Get(unsigned int i) const;
|
||||
UInt32 Get(std::size_t i) 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();
|
||||
|
||||
|
|
@ -45,10 +42,13 @@ namespace Nz
|
|||
// Méthodes STD
|
||||
|
||||
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;
|
||||
IndexMapperGetter m_getter;
|
||||
IndexMapperSetter m_setter;
|
||||
unsigned int m_indexCount;
|
||||
Getter m_getter;
|
||||
Setter m_setter;
|
||||
std::size_t m_indexCount;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace Nz
|
|||
|
||||
bool Advance();
|
||||
|
||||
UInt32 operator[](unsigned int i) const;
|
||||
UInt32 operator[](std::size_t i) const;
|
||||
|
||||
void Unmap();
|
||||
|
||||
|
|
@ -32,8 +32,8 @@ namespace Nz
|
|||
PrimitiveMode m_primitiveMode;
|
||||
UInt32 m_triangleIndices[3];
|
||||
IndexMapper m_indexMapper;
|
||||
unsigned int m_currentIndex;
|
||||
unsigned int m_indexCount;
|
||||
std::size_t m_currentIndex;
|
||||
std::size_t m_indexCount;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
|||
|
||||
if (animatedMesh)
|
||||
{
|
||||
mesh->CreateSkeletal(joints.size());
|
||||
mesh->CreateSkeletal(UInt32(joints.size()));
|
||||
|
||||
Skeleton* skeleton = mesh->GetSkeleton();
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
|||
mesh->CreateStatic();
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -300,7 +300,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
|||
if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS)
|
||||
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);
|
||||
|
|
@ -308,7 +308,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
|
|||
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)
|
||||
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)
|
||||
[Forum](https://forum.digitalpulsesoftware.net)
|
||||
|
||||
###Remerciements:
|
||||
### Remerciements:
|
||||
|
||||
- **RafBill** et **Raakz:** Recherche de bugs et/ou tests
|
||||
- **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ namespace Nz
|
|||
{
|
||||
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 */
|
||||
UInt8 buf[64]; /* accumulate block */
|
||||
};
|
||||
|
|
@ -280,9 +280,9 @@ namespace Nz
|
|||
void HashMD5::Append(const UInt8* data, std::size_t len)
|
||||
{
|
||||
const UInt8 *p = data;
|
||||
int left = len;
|
||||
std::size_t left = len;
|
||||
int offset = (m_state->count[0] >> 3) & 63;
|
||||
UInt32 nbits = len << 3;
|
||||
std::size_t nbits = len << 3;
|
||||
|
||||
if (len <= 0)
|
||||
return;
|
||||
|
|
@ -296,7 +296,7 @@ namespace Nz
|
|||
/* Process an initial partial block. */
|
||||
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);
|
||||
if (offset + copy < 64)
|
||||
|
|
|
|||
|
|
@ -75,8 +75,8 @@ namespace Nz
|
|||
{
|
||||
struct HashWhirlpool_state
|
||||
{
|
||||
int bufferBits; // current number of bits on the buffer */
|
||||
int bufferPos; // current (possibly incomplete) byte slot on the buffer */
|
||||
std::size_t bufferBits; // current number of bits 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 buffer[64]; // buffer of data to hash */
|
||||
UInt64 hash[8]; // the hashing state */
|
||||
|
|
@ -877,8 +877,8 @@ namespace Nz
|
|||
UInt32 b;
|
||||
UInt8* buffer = m_state->buffer;
|
||||
UInt8* bitLength = m_state->bitLength;
|
||||
int bufferBits = m_state->bufferBits;
|
||||
int bufferPos = m_state->bufferPos;
|
||||
std::size_t bufferBits = m_state->bufferBits;
|
||||
std::size_t bufferPos = m_state->bufferPos;
|
||||
|
||||
// tally the length of the added data
|
||||
UInt64 value = len;
|
||||
|
|
@ -968,8 +968,8 @@ namespace Nz
|
|||
|
||||
UInt8 *buffer = m_state->buffer;
|
||||
UInt8 *bitLength = m_state->bitLength;
|
||||
int bufferBits = m_state->bufferBits;
|
||||
int bufferPos = m_state->bufferPos;
|
||||
std::size_t bufferBits = m_state->bufferBits;
|
||||
std::size_t bufferPos = m_state->bufferPos;
|
||||
UInt8 *digest = result;
|
||||
|
||||
// append a '1'-bit
|
||||
|
|
|
|||
|
|
@ -2115,7 +2115,7 @@ namespace Nz
|
|||
|
||||
return ptr - m_sharedString->string.get();
|
||||
}
|
||||
catch (utf8::not_enough_room& e)
|
||||
catch (utf8::not_enough_room& /*e*/)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
if (material->IsBlendingEnabled())
|
||||
// One transparent material ? I don't like it, go see if I'm in the forward queue
|
||||
if (material->IsBlendingEnabled() || material->IsDepthSortingEnabled()) //< Fixme: Deferred Shading should be able to handle depth sorting
|
||||
// Deferred Shading cannot handle blended objects, put them in the forward list
|
||||
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
|
||||
else
|
||||
{
|
||||
|
|
@ -254,7 +254,7 @@ namespace Nz
|
|||
* \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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ namespace Nz
|
|||
* \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");
|
||||
NazaraUnused(renderOrder);
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ namespace Nz
|
|||
if (!layer.opaqueModels.empty())
|
||||
DrawOpaqueModels(sceneData, layer);
|
||||
|
||||
if (!layer.basicSprites.empty())
|
||||
if (!layer.opaqueSprites.empty())
|
||||
DrawBasicSprites(sceneData, layer);
|
||||
|
||||
if (!layer.billboards.empty())
|
||||
|
|
@ -219,7 +219,7 @@ namespace Nz
|
|||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
Renderer::SetVertexBuffer(&m_spriteBuffer);
|
||||
|
||||
for (auto& pipelinePair : layer.basicSprites)
|
||||
for (auto& pipelinePair : layer.opaqueSprites)
|
||||
{
|
||||
const MaterialPipeline* pipeline = pipelinePair.first;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
|
|
|||
|
|
@ -376,23 +376,23 @@ namespace Nz
|
|||
{
|
||||
NazaraAssert(material, "Invalid material");
|
||||
|
||||
if (material->IsBlendingEnabled())
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
auto& transparentModels = currentLayer.transparentModels;
|
||||
auto& transparentModelData = currentLayer.transparentModelData;
|
||||
auto& transparentMeshes = currentLayer.depthSortedMeshes;
|
||||
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)
|
||||
std::size_t index = transparentModelData.size();
|
||||
transparentModelData.resize(index+1);
|
||||
// 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);
|
||||
|
||||
TransparentModelData& data = transparentModelData.back();
|
||||
UnbatchedModelData& data = transparentData.back();
|
||||
data.material = material;
|
||||
data.meshData = meshData;
|
||||
data.squaredBoundingSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
||||
data.obbSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
|
||||
data.transformMatrix = transformMatrix;
|
||||
|
||||
transparentModels.push_back(index);
|
||||
transparentMeshes.push_back(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -457,53 +457,74 @@ namespace Nz
|
|||
*
|
||||
* \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");
|
||||
|
||||
Layer& currentLayer = GetLayer(renderOrder);
|
||||
SpritePipelineBatches& basicSprites = currentLayer.basicSprites;
|
||||
|
||||
const MaterialPipeline* materialPipeline = material->GetPipeline();
|
||||
|
||||
auto pipelineIt = basicSprites.find(materialPipeline);
|
||||
if (pipelineIt == basicSprites.end())
|
||||
if (material->IsDepthSortingEnabled())
|
||||
{
|
||||
BatchedSpritePipelineEntry materialEntry;
|
||||
pipelineIt = basicSprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
|
||||
auto& transparentSprites = currentLayer.depthSortedSprites;
|
||||
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);
|
||||
}
|
||||
|
||||
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
|
||||
pipelineEntry.enabled = true;
|
||||
|
||||
SpriteMaterialBatches& materialMap = pipelineEntry.materialMap;
|
||||
|
||||
auto matIt = materialMap.find(material);
|
||||
if (matIt == materialMap.end())
|
||||
else
|
||||
{
|
||||
BatchedBasicSpriteEntry entry;
|
||||
entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation);
|
||||
SpritePipelineBatches& sprites = currentLayer.opaqueSprites;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (auto& pipelinePair : layer.basicSprites)
|
||||
for (auto& pipelinePair : layer.opaqueSprites)
|
||||
{
|
||||
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.transparentModels.clear();
|
||||
layer.transparentModelData.clear();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
|
@ -613,44 +636,10 @@ namespace Nz
|
|||
|
||||
void ForwardRenderQueue::Sort(const AbstractViewer* viewer)
|
||||
{
|
||||
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
|
||||
Vector3f viewerPos = viewer->GetEyePosition();
|
||||
Vector3f viewerNormal = viewer->GetForward();
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (viewer->GetProjectionType() == ProjectionType_Orthogonal)
|
||||
SortForOrthographic(viewer);
|
||||
else
|
||||
SortForPerspective(viewer);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -715,12 +704,91 @@ namespace Nz
|
|||
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
|
||||
*
|
||||
* \param indexBuffer Index buffer being invalidated
|
||||
*/
|
||||
|
||||
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
|
||||
{
|
||||
for (auto& pair : layers)
|
||||
|
|
@ -757,7 +825,7 @@ namespace Nz
|
|||
{
|
||||
Layer& layer = pair.second;
|
||||
|
||||
for (auto& pipelineEntry : layer.basicSprites)
|
||||
for (auto& pipelineEntry : layer.opaqueSprites)
|
||||
pipelineEntry.second.materialMap.erase(material);
|
||||
|
||||
for (auto& pipelineEntry : layer.billboards)
|
||||
|
|
@ -779,7 +847,7 @@ namespace Nz
|
|||
for (auto& pair : layers)
|
||||
{
|
||||
Layer& layer = pair.second;
|
||||
for (auto& pipelineEntry : layer.basicSprites)
|
||||
for (auto& pipelineEntry : layer.opaqueSprites)
|
||||
{
|
||||
for (auto& materialEntry : pipelineEntry.second.materialMap)
|
||||
materialEntry.second.overlayMap.erase(texture);
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ namespace Nz
|
|||
Vector2f uv;
|
||||
};
|
||||
|
||||
std::size_t s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||
std::size_t s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
||||
UInt32 s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
|
||||
UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -101,12 +101,15 @@ namespace Nz
|
|||
if (!layer.opaqueModels.empty())
|
||||
DrawOpaqueModels(sceneData, layer);
|
||||
|
||||
if (!layer.transparentModels.empty())
|
||||
if (!layer.depthSortedMeshes.empty())
|
||||
DrawTransparentModels(sceneData, layer);
|
||||
|
||||
if (!layer.basicSprites.empty())
|
||||
if (!layer.opaqueSprites.empty())
|
||||
DrawBasicSprites(sceneData, layer);
|
||||
|
||||
if (!layer.depthSortedSprites.empty())
|
||||
DrawOrderedSprites(sceneData, layer);
|
||||
|
||||
if (!layer.billboards.empty())
|
||||
DrawBillboards(sceneData, layer);
|
||||
|
||||
|
|
@ -301,7 +304,10 @@ namespace Nz
|
|||
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
|
||||
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;
|
||||
auto& pipelineEntry = pipelinePair.second;
|
||||
|
|
@ -323,6 +329,9 @@ namespace Nz
|
|||
// Position of the camera
|
||||
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
|
||||
|
||||
// Overlay texture unit
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||
|
||||
lastShader = shader;
|
||||
}
|
||||
|
||||
|
|
@ -335,10 +344,6 @@ namespace Nz
|
|||
{
|
||||
material->Apply(pipelineInstance);
|
||||
|
||||
unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
|
||||
|
||||
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
|
||||
|
||||
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
|
||||
|
||||
auto& overlayMap = matEntry.overlayMap;
|
||||
|
|
@ -362,7 +367,6 @@ namespace Nz
|
|||
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
|
||||
|
||||
std::size_t spriteCount = 0;
|
||||
std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
|
||||
|
||||
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
|
||||
*
|
||||
|
|
@ -796,9 +936,9 @@ namespace Nz
|
|||
const ShaderUniforms* shaderUniforms = nullptr;
|
||||
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
|
||||
const Material* material = modelData.material;
|
||||
|
|
@ -865,8 +1005,8 @@ namespace Nz
|
|||
if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)
|
||||
{
|
||||
// Compute the closest lights
|
||||
Vector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition();
|
||||
float radius = modelData.squaredBoundingSphere.radius;
|
||||
Vector3f position = matrix.GetTranslation() + modelData.obbSphere.GetPosition();
|
||||
float radius = modelData.obbSphere.radius;
|
||||
ChooseLights(Spheref(position, radius), false);
|
||||
|
||||
for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ namespace Nz
|
|||
pipelineInfo.blending = true;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.depthSorting = true;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
|
|
@ -207,6 +208,7 @@ namespace Nz
|
|||
pipelineInfo.depthBuffer = true;
|
||||
pipelineInfo.depthWrite = false;
|
||||
pipelineInfo.faceCulling = false;
|
||||
pipelineInfo.depthSorting = true;
|
||||
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
|
||||
pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,13 +23,19 @@ namespace Nz
|
|||
|
||||
void SocketPollerImpl::Clear()
|
||||
{
|
||||
m_activeSockets.clear();
|
||||
m_readyToReadSockets.clear();
|
||||
m_readyToWriteSockets.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
|
||||
|
|
@ -37,15 +43,21 @@ namespace Nz
|
|||
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");
|
||||
|
||||
epoll_event event;
|
||||
event.events = EPOLLIN;
|
||||
event.data.fd = socket;
|
||||
epoll_event entry;
|
||||
entry.events = 0;
|
||||
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() + ')');
|
||||
return false;
|
||||
|
|
@ -60,7 +72,8 @@ namespace Nz
|
|||
{
|
||||
NazaraAssert(IsRegistered(socket), "Socket is not registered");
|
||||
|
||||
m_activeSockets.erase(socket);
|
||||
m_readyToReadSockets.erase(socket);
|
||||
m_readyToWriteSockets.erase(socket);
|
||||
m_sockets.erase(socket);
|
||||
|
||||
if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0)
|
||||
|
|
@ -84,21 +97,27 @@ namespace Nz
|
|||
return 0;
|
||||
}
|
||||
|
||||
m_activeSockets.clear();
|
||||
m_readyToReadSockets.clear();
|
||||
m_readyToWriteSockets.clear();
|
||||
if (activeSockets > 0)
|
||||
{
|
||||
int socketCount = activeSockets;
|
||||
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)
|
||||
NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll with EPOLLERR status");
|
||||
}
|
||||
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--;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,18 @@ namespace Nz
|
|||
|
||||
void Clear();
|
||||
|
||||
bool IsReady(SocketHandle socket) const;
|
||||
bool IsReadyToRead(SocketHandle socket) const;
|
||||
bool IsReadyToWrite(SocketHandle socket) const;
|
||||
bool IsRegistered(SocketHandle socket) const;
|
||||
|
||||
bool RegisterSocket(SocketHandle socket);
|
||||
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
|
||||
void UnregisterSocket(SocketHandle socket);
|
||||
|
||||
int Wait(UInt64 msTimeout, SocketError* error);
|
||||
|
||||
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::vector<epoll_event> m_events;
|
||||
int m_handle;
|
||||
|
|
|
|||
|
|
@ -10,14 +10,20 @@ namespace Nz
|
|||
{
|
||||
void SocketPollerImpl::Clear()
|
||||
{
|
||||
m_activeSockets.clear();
|
||||
m_readyToReadSockets.clear();
|
||||
m_readyToWriteSockets.clear();
|
||||
m_allSockets.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
|
||||
|
|
@ -25,16 +31,22 @@ namespace Nz
|
|||
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");
|
||||
|
||||
PollSocket entry = {
|
||||
socket,
|
||||
POLLRDNORM,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
if (eventFlags & SocketPollEvent_Read)
|
||||
entry.events |= POLLRDNORM;
|
||||
|
||||
if (eventFlags & SocketPollEvent_Write)
|
||||
entry.events |= POLLWRNORM;
|
||||
|
||||
m_allSockets[socket] = m_sockets.size();
|
||||
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
|
||||
m_sockets[entry] = std::move(m_sockets.back());
|
||||
}
|
||||
|
||||
m_sockets.pop_back();
|
||||
m_activeSockets.erase(socket);
|
||||
|
||||
m_allSockets.erase(socket);
|
||||
m_readyToReadSockets.erase(socket);
|
||||
m_readyToWriteSockets.erase(socket);
|
||||
}
|
||||
|
||||
int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error)
|
||||
|
|
@ -68,20 +81,25 @@ namespace Nz
|
|||
int activeSockets;
|
||||
|
||||
// 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);
|
||||
|
||||
m_activeSockets.clear();
|
||||
if (activeSockets > 0)
|
||||
m_readyToReadSockets.clear();
|
||||
m_readyToWriteSockets.clear();
|
||||
if (activeSockets > 0U)
|
||||
{
|
||||
int socketRemaining = activeSockets;
|
||||
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)
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,13 +27,14 @@ namespace Nz
|
|||
bool IsReady(SocketHandle socket) const;
|
||||
bool IsRegistered(SocketHandle socket) const;
|
||||
|
||||
bool RegisterSocket(SocketHandle socket);
|
||||
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
|
||||
void UnregisterSocket(SocketHandle socket);
|
||||
|
||||
int Wait(UInt64 msTimeout, SocketError* error);
|
||||
|
||||
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::vector<PollSocket> m_sockets;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -57,12 +57,13 @@ namespace Nz
|
|||
/*!
|
||||
* \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 state.
|
||||
* \remark You must call Wait before using this function in order to refresh the read 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
|
||||
*
|
||||
|
|
@ -70,11 +71,32 @@ namespace Nz
|
|||
*
|
||||
* \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");
|
||||
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
|
@ -107,17 +129,18 @@ namespace Nz
|
|||
* \remark The socket should not be freed while it is registered in the SocketPooler.
|
||||
*
|
||||
* \param socket Reference to the socket to register
|
||||
* \param eventFlags Socket events to watch
|
||||
*
|
||||
* \return True if the socket is registered, false otherwise
|
||||
*
|
||||
* \see IsRegistered
|
||||
* \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");
|
||||
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -10,29 +10,43 @@ namespace Nz
|
|||
SocketPollerImpl::SocketPollerImpl()
|
||||
{
|
||||
#if !NAZARA_NETWORK_POLL_SUPPORT
|
||||
FD_ZERO(&m_activeSockets);
|
||||
FD_ZERO(&m_sockets);
|
||||
FD_ZERO(&m_readSockets);
|
||||
FD_ZERO(&m_readyToReadSockets);
|
||||
FD_ZERO(&m_readyToWriteSockets);
|
||||
FD_ZERO(&m_writeSockets);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SocketPollerImpl::Clear()
|
||||
{
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
m_activeSockets.clear();
|
||||
m_allSockets.clear();
|
||||
m_readyToReadSockets.clear();
|
||||
m_readyToWriteSockets.clear();
|
||||
m_sockets.clear();
|
||||
#else
|
||||
FD_ZERO(&m_activeSockets);
|
||||
FD_ZERO(&m_sockets);
|
||||
FD_ZERO(&m_readSockets);
|
||||
FD_ZERO(&m_readyToReadSockets);
|
||||
FD_ZERO(&m_readyToWriteSockets);
|
||||
FD_ZERO(&m_writeSockets);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::IsReady(SocketHandle socket) const
|
||||
bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const
|
||||
{
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
return m_activeSockets.count(socket) != 0;
|
||||
return m_readyToReadSockets.count(socket) != 0;
|
||||
#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
|
||||
}
|
||||
|
||||
|
|
@ -41,31 +55,45 @@ namespace Nz
|
|||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
return m_allSockets.count(socket) != 0;
|
||||
#else
|
||||
return FD_ISSET(socket, &m_sockets) != 0;
|
||||
return FD_ISSET(socket, &m_readSockets) != 0 ||
|
||||
FD_ISSET(socket, &m_writeSockets) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket)
|
||||
bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags)
|
||||
{
|
||||
NazaraAssert(!IsRegistered(socket), "Socket is already registered");
|
||||
|
||||
#if NAZARA_NETWORK_POLL_SUPPORT
|
||||
PollSocket entry = {
|
||||
socket,
|
||||
POLLRDNORM,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
if (eventFlags & SocketPollEvent_Read)
|
||||
entry.events |= POLLRDNORM;
|
||||
|
||||
if (eventFlags & SocketPollEvent_Write)
|
||||
entry.events |= POLLWRNORM;
|
||||
|
||||
m_allSockets[socket] = m_sockets.size();
|
||||
m_sockets.emplace_back(entry);
|
||||
#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) + ")");
|
||||
return false;
|
||||
}
|
||||
if (eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write) == 0)
|
||||
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
|
||||
|
||||
return true;
|
||||
|
|
@ -88,13 +116,16 @@ namespace Nz
|
|||
// Now move it properly (lastElement is invalid after the following line) and pop it
|
||||
m_sockets[entry] = std::move(m_sockets.back());
|
||||
}
|
||||
|
||||
m_sockets.pop_back();
|
||||
m_activeSockets.erase(socket);
|
||||
|
||||
m_allSockets.erase(socket);
|
||||
m_readyToReadSockets.erase(socket);
|
||||
m_readyToWriteSockets.erase(socket);
|
||||
#else
|
||||
FD_CLR(socket, &m_activeSockets);
|
||||
FD_CLR(socket, &m_sockets);
|
||||
FD_CLR(socket, &m_readSockets);
|
||||
FD_CLR(socket, &m_readyToReadSockets);
|
||||
FD_CLR(socket, &m_readyToWriteSockets);
|
||||
FD_CLR(socket, &m_writeSockets);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -103,35 +134,18 @@ namespace Nz
|
|||
int activeSockets;
|
||||
|
||||
#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);
|
||||
x
|
||||
|
||||
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
|
||||
|
||||
m_activeSockets = m_sockets;
|
||||
m_readyToReadSockets = m_readSockets;
|
||||
m_readyToWriteSockets = m_writeSockets;
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = static_cast<long>(msTimeout / 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, &m_readyToReadSockets, &m_readyToWriteSockets, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows
|
||||
if (activeSockets == SOCKET_ERROR)
|
||||
{
|
||||
if (error)
|
||||
|
|
|
|||
|
|
@ -25,24 +25,28 @@ namespace Nz
|
|||
|
||||
void Clear();
|
||||
|
||||
bool IsReady(SocketHandle socket) const;
|
||||
bool IsReadyToRead(SocketHandle socket) const;
|
||||
bool IsReadyToWrite(SocketHandle socket) const;
|
||||
bool IsRegistered(SocketHandle socket) const;
|
||||
|
||||
bool RegisterSocket(SocketHandle socket);
|
||||
bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags);
|
||||
void UnregisterSocket(SocketHandle socket);
|
||||
|
||||
int Wait(UInt64 msTimeout, SocketError* error);
|
||||
|
||||
private:
|
||||
#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::vector<PollSocket> m_sockets;
|
||||
#else
|
||||
fd_set m_sockets;
|
||||
fd_set m_activeSockets;
|
||||
fd_set m_readSockets;
|
||||
fd_set m_readyToReadSockets;
|
||||
fd_set m_readyToWriteSockets;
|
||||
fd_set m_writeSockets;
|
||||
#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))
|
||||
{
|
||||
result->closestPoint.Set(queryInfo.point.x, queryInfo.point.y);
|
||||
result->distance = queryInfo.distance;
|
||||
result->fraction.Set(queryInfo.gradient.x, queryInfo.gradient.y);
|
||||
result->closestPoint.Set(Nz::Vector2<cpFloat>(queryInfo.point.x, queryInfo.point.y));
|
||||
result->distance = float(queryInfo.distance);
|
||||
result->fraction.Set(Nz::Vector2<cpFloat>(queryInfo.gradient.x, queryInfo.gradient.y));
|
||||
result->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||
|
||||
return true;
|
||||
|
|
@ -90,9 +90,9 @@ namespace Nz
|
|||
ResultType results = static_cast<ResultType>(data);
|
||||
|
||||
RaycastHit hitInfo;
|
||||
hitInfo.fraction = alpha;
|
||||
hitInfo.hitNormal.Set(normal.x, normal.y);
|
||||
hitInfo.hitPos.Set(point.x, point.y);
|
||||
hitInfo.fraction = float(alpha);
|
||||
hitInfo.hitNormal.Set(Nz::Vector2<cpFloat>(normal.x, normal.y));
|
||||
hitInfo.hitPos.Set(Nz::Vector2<cpFloat>(point.x, point.y));
|
||||
hitInfo.nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
|
||||
|
||||
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))
|
||||
{
|
||||
hitInfo->fraction = queryInfo.alpha;
|
||||
hitInfo->hitNormal.Set(queryInfo.normal.x, queryInfo.normal.y);
|
||||
hitInfo->hitPos.Set(queryInfo.point.x, queryInfo.point.y);
|
||||
hitInfo->fraction = float(queryInfo.alpha);
|
||||
hitInfo->hitNormal.Set(Nz::Vector2<cpFloat>(queryInfo.normal.x, queryInfo.normal.y));
|
||||
hitInfo->hitPos.Set(Nz::Vector2<cpFloat>(queryInfo.point.x, queryInfo.point.y));
|
||||
hitInfo->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(queryInfo.shape));
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ namespace Nz
|
|||
cpVect vel = cpBodyGetVelocity(m_handle);
|
||||
|
||||
Destroy();
|
||||
Create(mass, moment);
|
||||
Create(float(mass), float(moment));
|
||||
|
||||
cpBodySetAngle(m_handle, rot);
|
||||
cpBodySetPosition(m_handle, pos);
|
||||
|
|
|
|||
|
|
@ -121,9 +121,7 @@ namespace Nz
|
|||
break;
|
||||
|
||||
default:
|
||||
// Peut être rajouté par une extension
|
||||
ss << "Unknown";
|
||||
break;
|
||||
return; //< Block NVidia buffer usage hint for now
|
||||
}
|
||||
ss << '\n';
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ namespace Nz
|
|||
|
||||
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
|
||||
|
||||
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0);
|
||||
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, 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), UInt32(vertexCount), parameters.storage, 0);
|
||||
|
||||
// Index buffer
|
||||
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
|
||||
|
|
@ -236,7 +236,7 @@ namespace Nz
|
|||
// Index buffer
|
||||
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);
|
||||
IndexIterator index = indexMapper.begin();
|
||||
|
|
@ -251,7 +251,7 @@ namespace Nz
|
|||
indexMapper.Unmap();
|
||||
|
||||
// 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);
|
||||
|
||||
MeshVertex* vertices = static_cast<MeshVertex*>(vertexMapper.GetPointer());
|
||||
|
|
|
|||
|
|
@ -233,8 +233,8 @@ namespace Nz
|
|||
}
|
||||
|
||||
// Création des buffers
|
||||
IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indices.size(), parameters.storage, 0);
|
||||
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, 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), UInt32(vertexCount), parameters.storage, 0);
|
||||
|
||||
// Remplissage des indices
|
||||
IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly);
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ namespace Nz
|
|||
|
||||
if (p < 0)
|
||||
{
|
||||
p += m_positions.size() - 1;
|
||||
p += static_cast<int>(m_positions.size() - 1);
|
||||
if (p < 0)
|
||||
{
|
||||
Error("Vertex index out of range (" + String::Number(p) + " < 0");
|
||||
|
|
@ -239,7 +239,7 @@ namespace Nz
|
|||
|
||||
if (n < 0)
|
||||
{
|
||||
n += m_normals.size() - 1;
|
||||
n += static_cast<int>(m_normals.size() - 1);
|
||||
if (n < 0)
|
||||
{
|
||||
Error("Normal index out of range (" + String::Number(n) + " < 0");
|
||||
|
|
@ -250,7 +250,7 @@ namespace Nz
|
|||
|
||||
if (t < 0)
|
||||
{
|
||||
t += m_texCoords.size() - 1;
|
||||
t += static_cast<int>(m_texCoords.size() - 1);
|
||||
if (t < 0)
|
||||
{
|
||||
Error("Texture coordinates index out of range (" + String::Number(t) + " < 0");
|
||||
|
|
|
|||
|
|
@ -12,38 +12,38 @@ namespace Nz
|
|||
{
|
||||
namespace
|
||||
{
|
||||
UInt32 GetterSequential(const void* buffer, unsigned int i)
|
||||
UInt32 GetterSequential(const void* buffer, std::size_t i)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
ptr[i] = value;
|
||||
}
|
||||
|
||||
void SetterError(void*, unsigned int, UInt32)
|
||||
void SetterError(void*, std::size_t, UInt32)
|
||||
{
|
||||
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
|
||||
if (i >= m_indexCount)
|
||||
{
|
||||
NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')');
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < m_indexCount, "Index out of range");
|
||||
|
||||
return m_getter(m_mapper.GetPointer(), i);
|
||||
}
|
||||
|
|
@ -131,20 +125,14 @@ namespace Nz
|
|||
return m_mapper.GetBuffer();
|
||||
}
|
||||
|
||||
unsigned int IndexMapper::GetIndexCount() const
|
||||
std::size_t IndexMapper::GetIndexCount() const
|
||||
{
|
||||
return m_indexCount;
|
||||
}
|
||||
|
||||
void IndexMapper::Set(unsigned int i, UInt32 value)
|
||||
void IndexMapper::Set(std::size_t i, UInt32 value)
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (i >= m_indexCount)
|
||||
{
|
||||
NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')');
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < m_indexCount, "Index out of range");
|
||||
|
||||
m_setter(m_mapper.GetPointer(), i, value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ namespace Nz
|
|||
NazaraAssert(subMesh, "Invalid submesh");
|
||||
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();
|
||||
}
|
||||
|
|
@ -92,10 +92,10 @@ namespace Nz
|
|||
NazaraAssert(subMesh, "Invalid submesh");
|
||||
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->subMeshMap[identifier] = index;
|
||||
m_impl->subMeshes.emplace_back(subMesh);
|
||||
m_impl->subMeshMap[identifier] = static_cast<UInt32>(index);
|
||||
|
||||
InvalidateAABB();
|
||||
}
|
||||
|
|
@ -349,11 +349,11 @@ namespace Nz
|
|||
|
||||
if (!m_impl->aabbUpdated)
|
||||
{
|
||||
UInt32 subMeshCount = m_impl->subMeshes.size();
|
||||
std::size_t subMeshCount = m_impl->subMeshes.size();
|
||||
if (subMeshCount > 0)
|
||||
{
|
||||
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());
|
||||
}
|
||||
else
|
||||
|
|
@ -407,7 +407,7 @@ namespace Nz
|
|||
{
|
||||
NazaraAssert(m_impl, "Mesh should be created first");
|
||||
|
||||
return m_impl->materialData.size();
|
||||
return static_cast<UInt32>(m_impl->materialData.size());
|
||||
}
|
||||
|
||||
Skeleton* Mesh::GetSkeleton()
|
||||
|
|
@ -466,7 +466,7 @@ namespace Nz
|
|||
{
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
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
|
||||
m_lines.emplace_back(Line{Rectf::Zero(), 0});
|
||||
}
|
||||
|
|
@ -354,7 +354,7 @@ namespace Nz
|
|||
{
|
||||
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[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
|
||||
|
|
@ -377,7 +377,7 @@ namespace Nz
|
|||
m_drawPos.x = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,12 +72,12 @@ namespace Nz
|
|||
|
||||
if (!m_impl->aabbUpdated)
|
||||
{
|
||||
UInt32 jointCount = m_impl->joints.size();
|
||||
std::size_t jointCount = m_impl->joints.size();
|
||||
if (jointCount > 0)
|
||||
{
|
||||
Vector3f pos = m_impl->joints[0].GetPosition();
|
||||
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());
|
||||
}
|
||||
else
|
||||
|
|
@ -219,7 +219,7 @@ namespace Nz
|
|||
}
|
||||
#endif
|
||||
|
||||
return m_impl->joints.size();
|
||||
return static_cast<UInt32>(m_impl->joints.size());
|
||||
}
|
||||
|
||||
int Skeleton::GetJointIndex(const String& jointName) const
|
||||
|
|
@ -411,16 +411,9 @@ namespace Nz
|
|||
String name = m_impl->joints[i].GetName();
|
||||
if (!name.IsEmpty())
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
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
|
||||
NazaraAssert(m_impl->jointMap.find(name) == m_impl->jointMap.end(), "Joint name \"" + name + "\" is already present in joint map");
|
||||
|
||||
m_impl->jointMap[name] = i;
|
||||
m_impl->jointMap[name] = static_cast<UInt32>(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,18 +66,9 @@ namespace Nz
|
|||
return true;
|
||||
}
|
||||
|
||||
UInt32 TriangleIterator::operator[](unsigned int i) const
|
||||
UInt32 TriangleIterator::operator[](std::size_t i) const
|
||||
{
|
||||
#if NAZARA_UTILITY_SAFE
|
||||
if (i >= 3)
|
||||
{
|
||||
StringStream ss;
|
||||
ss << "Index out of range: (" << i << " >= 3)";
|
||||
|
||||
NazaraError(ss);
|
||||
throw std::domain_error(ss.ToString());
|
||||
}
|
||||
#endif
|
||||
NazaraAssert(i < 3, "Index out of range");
|
||||
|
||||
return m_triangleIndices[i];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include <Nazara/Math/Algorithm.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
TEST_CASE("Approach", "[MATH][ALGORITHM]")
|
||||
{
|
||||
|
|
@ -48,6 +49,11 @@ TEST_CASE("CountBits", "[MATH][ALGORITHM]")
|
|||
{
|
||||
REQUIRE(Nz::CountBits(0) == 0);
|
||||
}
|
||||
|
||||
SECTION("Number 0xFFFFFFFF has 32 bit set to 1")
|
||||
{
|
||||
REQUIRE(Nz::CountBits(0xFFFFFFFF) == 32);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]")
|
||||
|
|
@ -205,9 +211,19 @@ TEST_CASE("NumberEquals", "[MATH][ALGORITHM]")
|
|||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
|
|||
|
||||
WHEN("We add an entity")
|
||||
{
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
entity->AddComponent<Ndk::VelocityComponent>();
|
||||
|
||||
THEN("System should have it")
|
||||
|
|
@ -50,7 +50,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
|
|||
|
||||
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::NodeComponent>();
|
||||
|
||||
|
|
|
|||
|
|
@ -57,18 +57,18 @@ SCENARIO("Entity", "[NDK][ENTITY]")
|
|||
{
|
||||
Ndk::World world;
|
||||
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
|
||||
WHEN("We add our UpdateComponent")
|
||||
{
|
||||
UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>();
|
||||
REQUIRE(!updatableComponent.IsUpdated());
|
||||
CHECK(!updatableComponent.IsUpdated());
|
||||
|
||||
THEN("Update the world should update the entity's component")
|
||||
{
|
||||
world.Update(1.f);
|
||||
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")
|
||||
|
|
@ -76,14 +76,14 @@ SCENARIO("Entity", "[NDK][ENTITY]")
|
|||
entity->Enable(false);
|
||||
world.Update(1.f);
|
||||
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
||||
REQUIRE(!updatableComponentGet.IsUpdated());
|
||||
CHECK(!updatableComponentGet.IsUpdated());
|
||||
}
|
||||
|
||||
THEN("We can remove its component")
|
||||
{
|
||||
entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>());
|
||||
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")
|
||||
{
|
||||
REQUIRE(!world.IsEntityValid(entity));
|
||||
CHECK(!world.IsEntityValid(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
|
|||
GIVEN("A world & an entity")
|
||||
{
|
||||
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")
|
||||
{
|
||||
|
|
@ -15,13 +15,21 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
|
|||
|
||||
THEN("Entity is still valid")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
CHECK(entity.IsValid());
|
||||
}
|
||||
|
||||
THEN("Resetting or getting out of scope is no more valid")
|
||||
{
|
||||
entityOwner.Reset();
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,21 +28,79 @@ class TestState : public Ndk::State
|
|||
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]")
|
||||
{
|
||||
GIVEN("A statemachine with our TestState")
|
||||
GIVEN("A statemachine with our test states")
|
||||
{
|
||||
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(!secondTestState->IsUpdated());
|
||||
|
||||
WHEN("We update our machine")
|
||||
{
|
||||
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(!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")
|
||||
{
|
||||
Ndk::World world;
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
Ndk::ListenerComponent& listenerComponent = entity->AddComponent<Ndk::ListenerComponent>();
|
||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ SCENARIO("World", "[NDK][WORLD]")
|
|||
AND_WHEN("We update our world with our entity")
|
||||
{
|
||||
REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>());
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
|
||||
|
||||
THEN("Our entity component must be updated")
|
||||
|
|
|
|||
Loading…
Reference in New Issue