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

This commit is contained in:
Lynix 2017-05-11 20:52:04 +02:00
commit 75d57b3c29
64 changed files with 1087 additions and 604 deletions

View File

@ -9,6 +9,7 @@
#include <Nazara/Core/Bitset.hpp> #include <Nazara/Core/Bitset.hpp>
#include <NDK/Entity.hpp> #include <NDK/Entity.hpp>
#include <NDK/EntityList.hpp>
#include <vector> #include <vector>
namespace Ndk namespace Ndk
@ -33,7 +34,7 @@ namespace Ndk
bool Filters(const Entity* entity) const; bool Filters(const Entity* entity) const;
inline const std::vector<EntityHandle>& GetEntities() const; inline const EntityList& GetEntities() const;
inline SystemIndex GetIndex() const; inline SystemIndex GetIndex() const;
inline int GetUpdateOrder() const; inline int GetUpdateOrder() const;
inline float GetUpdateRate() const; inline float GetUpdateRate() const;
@ -84,12 +85,11 @@ namespace Ndk
static inline bool Initialize(); static inline bool Initialize();
static inline void Uninitialize(); static inline void Uninitialize();
std::vector<EntityHandle> m_entities;
Nz::Bitset<Nz::UInt64> m_entityBits;
Nz::Bitset<> m_excludedComponents; Nz::Bitset<> m_excludedComponents;
mutable Nz::Bitset<> m_filterResult; mutable Nz::Bitset<> m_filterResult;
Nz::Bitset<> m_requiredAnyComponents; Nz::Bitset<> m_requiredAnyComponents;
Nz::Bitset<> m_requiredComponents; Nz::Bitset<> m_requiredComponents;
EntityList m_entities;
SystemIndex m_systemIndex; SystemIndex m_systemIndex;
World* m_world; World* m_world;
bool m_updateEnabled; bool m_updateEnabled;

View File

@ -56,7 +56,7 @@ namespace Ndk
* \return A constant reference to the list of entities * \return A constant reference to the list of entities
*/ */
inline const std::vector<EntityHandle>& BaseSystem::GetEntities() const inline const EntityList& BaseSystem::GetEntities() const
{ {
return m_entities; return m_entities;
} }
@ -121,10 +121,7 @@ namespace Ndk
inline bool BaseSystem::HasEntity(const Entity* entity) const inline bool BaseSystem::HasEntity(const Entity* entity) const
{ {
if (!entity) return m_entities.Has(entity);
return false;
return m_entityBits.UnboundedTest(entity->GetId());
} }
/*! /*!
@ -288,9 +285,7 @@ namespace Ndk
{ {
NazaraAssert(entity, "Invalid entity"); NazaraAssert(entity, "Invalid entity");
m_entities.emplace_back(entity); m_entities.Insert(entity);
m_entityBits.UnboundedSet(entity->GetId(), true);
entity->RegisterSystem(m_systemIndex); entity->RegisterSystem(m_systemIndex);
OnEntityAdded(entity); OnEntityAdded(entity);
@ -308,14 +303,7 @@ namespace Ndk
{ {
NazaraAssert(entity, "Invalid entity"); NazaraAssert(entity, "Invalid entity");
auto it = std::find(m_entities.begin(), m_entities.end(), *entity); m_entities.Remove(entity);
NazaraAssert(it != m_entities.end(), "Entity is not part of this system");
// To avoid moving a lot of handles, we swap and pop
std::swap(*it, m_entities.back());
m_entities.pop_back(); // We get it out of the vector
m_entityBits.Reset(entity->GetId());
entity->UnregisterSystem(m_systemIndex); entity->UnregisterSystem(m_systemIndex);
OnEntityRemoved(entity); // And we alert our callback OnEntityRemoved(entity); // And we alert our callback
@ -360,7 +348,7 @@ namespace Ndk
} }
/*! /*!
* \brief Uninitializes the BaseSystem * \brief Uninitialize the BaseSystem
*/ */
inline void BaseSystem::Uninitialize() inline void BaseSystem::Uninitialize()

View File

@ -44,7 +44,7 @@ namespace Ndk
const Nz::Frustumf& GetFrustum() const override; const Nz::Frustumf& GetFrustum() const override;
inline unsigned int GetLayer() const; inline unsigned int GetLayer() const;
const Nz::Matrix4f& GetProjectionMatrix() const override; const Nz::Matrix4f& GetProjectionMatrix() const override;
inline Nz::ProjectionType GetProjectionType() const; Nz::ProjectionType GetProjectionType() const override;
inline const Nz::Vector2f& GetSize() const; inline const Nz::Vector2f& GetSize() const;
const Nz::RenderTarget* GetTarget() const override; const Nz::RenderTarget* GetTarget() const override;
inline const Nz::Rectf& GetTargetRegion() const; inline const Nz::Rectf& GetTargetRegion() const;

View File

@ -117,16 +117,6 @@ namespace Ndk
return m_layer; return m_layer;
} }
/*!
* \brief Gets the projection type of the camera
* \return Projection type of the camera
*/
inline Nz::ProjectionType CameraComponent::GetProjectionType() const
{
return m_projectionType;
}
/*! /*!
* \brief Gets the size of the camera * \brief Gets the size of the camera
* \return Size of the camera * \return Size of the camera

View File

@ -54,6 +54,9 @@ namespace Ndk
inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const; inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const;
inline void UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix);
inline void UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder);
static ComponentIndex componentIndex; static ComponentIndex componentIndex;
private: private:

View File

@ -170,6 +170,32 @@ namespace Ndk
} }
} }
inline void GraphicsComponent::UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix)
{
for (auto& renderable : m_renderables)
{
if (renderable.renderable == instancedRenderable)
{
renderable.data.localMatrix = localMatrix;
InvalidateBoundingVolume();
break;
}
}
}
inline void GraphicsComponent::UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder)
{
for (auto& renderable : m_renderables)
{
if (renderable.renderable == instancedRenderable)
{
renderable.data.renderOrder = renderOrder;
break;
}
}
}
/*! /*!
* \brief Invalidates the bounding volume * \brief Invalidates the bounding volume
*/ */

View File

@ -16,45 +16,64 @@ namespace Ndk
class NDK_API EntityList class NDK_API EntityList
{ {
public: public:
using Container = std::vector<EntityHandle>; class iterator;
friend iterator;
using size_type = std::size_t;
EntityList() = default; inline EntityList();
inline EntityList(const EntityList& entityList);
inline EntityList(EntityList&& entityList) noexcept;
~EntityList() = default; ~EntityList() = default;
inline void Clear(); inline void Clear();
inline bool Has(const Entity* entity); inline bool Has(const Entity* entity) const;
inline bool Has(EntityId entity); inline bool Has(EntityId entity) const;
inline void Insert(Entity* entity); inline void Insert(Entity* entity);
inline void Remove(Entity* entity); inline void Remove(Entity* entity);
// STL API // STL API
inline Container::iterator begin(); inline iterator begin() const;
inline Container::const_iterator begin() const;
inline Container::const_iterator cbegin() const;
inline Container::const_iterator cend() const;
inline Container::const_reverse_iterator crbegin() const;
inline Container::const_reverse_iterator crend() const;
inline bool empty() const; inline bool empty() const;
inline iterator end() const;
inline size_type size() const;
inline Container::iterator end(); inline EntityList& operator=(const EntityList& entityList);
inline Container::const_iterator end() const; inline EntityList& operator=(EntityList&& entityList) noexcept;
inline Container::reverse_iterator rbegin();
inline Container::const_reverse_iterator rbegin() const;
inline Container::reverse_iterator rend();
inline Container::const_reverse_iterator rend() const;
inline Container::size_type size() const;
private: private:
std::vector<EntityHandle> m_entities; inline std::size_t FindNext(std::size_t currentId) const;
inline World* GetWorld() const;
Nz::Bitset<Nz::UInt64> m_entityBits; Nz::Bitset<Nz::UInt64> m_entityBits;
World* m_world;
};
class NDK_API EntityList::iterator : public std::iterator<std::forward_iterator_tag, const EntityHandle>
{
friend EntityList;
public:
inline iterator(const iterator& iterator);
const EntityHandle& operator*() const;
inline iterator& operator=(const iterator& iterator);
inline iterator& operator++();
inline iterator operator++(int);
friend inline bool operator==(const iterator& lhs, const iterator& rhs);
friend inline bool operator!=(const iterator& lhs, const iterator& rhs);
friend inline void swap(iterator& lhs, iterator& rhs);
private:
inline iterator(const EntityList* world, std::size_t nextId);
std::size_t m_nextEntityId;
const EntityList* m_list;
}; };
} }

View File

@ -2,8 +2,10 @@
// This file is part of the "Nazara Development Kit" // This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp // For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <NDK/EntityList.hpp>
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <algorithm> #include <algorithm>
#include "EntityList.hpp"
namespace Ndk namespace Ndk
{ {
@ -14,24 +16,55 @@ namespace Ndk
*/ */
/*! /*!
* \brief Clears the set from every entities * \brief Construct a new entity list
*/ */
inline EntityList::EntityList() :
inline void EntityList::Clear() m_world(nullptr)
{ {
m_entities.clear();
m_entityBits.Clear();
} }
/*! /*!
* \brief Checks whether or not the set contains the entity * \brief Construct a new entity list by copying another one
*/
inline EntityList::EntityList(const EntityList& entityList) :
m_entityBits(entityList.m_entityBits),
m_world(entityList.m_world)
{
}
/*!
* \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)
{
}
/*!
* \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()
{
m_entityBits.Clear();
m_world = nullptr;
}
/*!
* \brief Checks whether or not the EntityList contains the entity
* \return true If it is the case * \return true If it is the case
* *
* \param entity Pointer to the entity * \param entity Pointer to the entity
*
* \remark If the Insert function was called since the EntityList construction (or last call to Clear), the entity passed by parameter must belong to the same world as the previously inserted entities.
*/ */
inline bool EntityList::Has(const Entity* entity) const
inline bool EntityList::Has(const Entity* entity)
{ {
NazaraAssert(!m_world || !entity || entity->GetWorld() == m_world, "Incompatible world");
return entity && entity->IsValid() && Has(entity->GetId()); return entity && entity->IsValid() && Has(entity->GetId());
} }
@ -41,8 +74,7 @@ namespace Ndk
* *
* \param id Identifier of the entity * \param id Identifier of the entity
*/ */
inline bool EntityList::Has(EntityId entity) const
inline bool EntityList::Has(EntityId entity)
{ {
return m_entityBits.UnboundedTest(entity); return m_entityBits.UnboundedTest(entity);
} }
@ -50,18 +82,21 @@ namespace Ndk
/*! /*!
* \brief Inserts the entity into the set * \brief Inserts the entity into the set
* *
* \param entity Pointer to the entity * Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list.
*
* \param entity Valid pointer to an entity
* *
* \remark If entity is already contained, no action is performed * \remark If entity is already contained, no action is performed
* \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities
* \remark It's up to the programmer to remove an entity from this list before its deletion
*/ */
inline void EntityList::Insert(Entity* entity) inline void EntityList::Insert(Entity* entity)
{ {
if (!Has(entity)) NazaraAssert(entity, "Invalid entity");
{ NazaraAssert(!m_world || entity->GetWorld() == m_world, "Incompatible world");
m_entities.emplace_back(entity);
m_entityBits.UnboundedSet(entity->GetId(), true); m_entityBits.UnboundedSet(entity->GetId(), true);
} m_world = entity->GetWorld();
} }
/*! /*!
@ -70,89 +105,117 @@ namespace Ndk
* \param entity Pointer to the entity * \param entity Pointer to the entity
* *
* \remark If entity is not contained, no action is performed * \remark If entity is not contained, no action is performed
* \remark This function never resets the implicit world member, even if it empties the list. Use the Clear method if you want to reset it.
*
* \see Clear
*/ */
inline void EntityList::Remove(Entity* entity) inline void EntityList::Remove(Entity* entity)
{ {
if (Has(entity))
{
auto it = std::find(m_entities.begin(), m_entities.end(), *entity);
NazaraAssert(it != m_entities.end(), "Entity should be part of the vector");
std::swap(*it, m_entities.back());
m_entities.pop_back(); // We get it out of the vector
m_entityBits.UnboundedSet(entity->GetId(), false); m_entityBits.UnboundedSet(entity->GetId(), false);
} }
}
// Nz::Interface STD // STL Interface
inline EntityList::Container::iterator EntityList::begin() inline EntityList::iterator EntityList::begin() const
{ {
return m_entities.begin(); return EntityList::iterator(this, m_entityBits.FindFirst());
}
inline EntityList::Container::const_iterator EntityList::begin() const
{
return m_entities.begin();
}
inline EntityList::Container::const_iterator EntityList::cbegin() const
{
return m_entities.cbegin();
}
inline EntityList::Container::const_iterator EntityList::cend() const
{
return m_entities.cend();
}
inline EntityList::Container::const_reverse_iterator EntityList::crbegin() const
{
return m_entities.crbegin();
}
inline EntityList::Container::const_reverse_iterator EntityList::crend() const
{
return m_entities.crend();
} }
inline bool EntityList::empty() const inline bool EntityList::empty() const
{ {
return m_entities.empty(); return !m_entityBits.TestAny();
} }
inline EntityList::Container::iterator EntityList::end() inline EntityList::iterator EntityList::end() const
{ {
return m_entities.end(); return EntityList::iterator(this, m_entityBits.npos);
} }
inline EntityList::Container::const_iterator EntityList::end() const inline EntityList::size_type EntityList::size() const
{ {
return m_entities.end(); return m_entityBits.Count();
} }
inline EntityList::Container::reverse_iterator EntityList::rbegin() inline EntityList& EntityList::operator=(const EntityList& entityList)
{ {
return m_entities.rbegin(); m_entityBits = entityList.m_entityBits;
m_world = entityList.m_world;
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;
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 EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) :
m_nextEntityId(nextId),
m_list(list)
{ {
return m_entities.size(); }
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;
std::swap(lhs.m_nextEntityId, rhs.m_nextEntityId);
} }
} }

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Jérôme Leclercq // Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Development Kit" // This file is part of the "Nazara Development Kit"
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp // For conditions of distribution and use, see copyright notice in Prerequesites.hpp
@ -10,6 +10,7 @@
#include <NDK/Prerequesites.hpp> #include <NDK/Prerequesites.hpp>
#include <NDK/State.hpp> #include <NDK/State.hpp>
#include <memory> #include <memory>
#include <vector>
namespace Ndk namespace Ndk
{ {
@ -25,14 +26,21 @@ namespace Ndk
inline const std::shared_ptr<State>& GetCurrentState() const; inline const std::shared_ptr<State>& GetCurrentState() const;
inline bool IsTopState(const State* state) const;
inline std::shared_ptr<State> PopState();
inline bool PopStatesUntil(std::shared_ptr<State> state);
inline void PushState(std::shared_ptr<State> state);
inline void SetState(std::shared_ptr<State> state);
inline bool Update(float elapsedTime); inline bool Update(float elapsedTime);
inline StateMachine& operator=(StateMachine&& fsm) = default; inline StateMachine& operator=(StateMachine&& fsm) = default;
StateMachine& operator=(const StateMachine&) = delete; StateMachine& operator=(const StateMachine&) = delete;
private: private:
std::shared_ptr<State> m_currentState; std::vector<std::shared_ptr<State>> m_states;
std::shared_ptr<State> m_nextState;
}; };
} }

View File

@ -3,7 +3,6 @@
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp // For conditions of distribution and use, see copyright notice in Prerequesites.hpp
#include <Nazara/Core/Error.hpp> #include <Nazara/Core/Error.hpp>
#include <NDK/StateMachine.hpp>
#include <utility> #include <utility>
namespace Ndk namespace Ndk
@ -11,7 +10,7 @@ namespace Ndk
/*! /*!
* \ingroup NDK * \ingroup NDK
* \class Ndk::StateMachine * \class Ndk::StateMachine
* \brief NDK class that represents a state machine, to represent the multiple states of your program * \brief NDK class that represents a state machine, to represent the multiple states of your program as a stack
*/ */
/*! /*!
@ -23,61 +22,153 @@ namespace Ndk
* \remark Produces a NazaraAssert if nullptr is given * \remark Produces a NazaraAssert if nullptr is given
*/ */
inline StateMachine::StateMachine(std::shared_ptr<State> originalState) : inline StateMachine::StateMachine(std::shared_ptr<State> originalState)
m_currentState(std::move(originalState))
{ {
NazaraAssert(m_currentState, "StateMachine must have a state to begin with"); NazaraAssert(originalState, "StateMachine must have a state to begin with");
m_currentState->Enter(*this); PushState(std::move(originalState));
} }
/*! /*!
* \brief Destructs the object * \brief Destructs the object
* *
* \remark Calls "Leave" on the state * \remark Calls "Leave" on all the states
*/ */
inline StateMachine::~StateMachine() inline StateMachine::~StateMachine()
{ {
m_currentState->Leave(*this); for (std::shared_ptr<State>& state : m_states)
state->Leave(*this);
} }
/*! /*!
* \brief Changes the current state of the machine * \brief Replaces the current state on the top of the machine
* *
* \param state Next state to represent * \param state State to replace the top one if it is nullptr, no action is performed
*/ */
inline void StateMachine::ChangeState(std::shared_ptr<State> state) inline void StateMachine::ChangeState(std::shared_ptr<State> state)
{ {
m_nextState = std::move(state); if (state)
{
PopState();
PushState(std::move(state));
}
} }
/*! /*!
* \brief Gets the current state of the machine * \brief Gets the current state on the top of the machine
* \return A constant reference to the state * \return A constant reference to the state
*
* \remark The stack is supposed to be non empty, otherwise it is undefined behaviour
*
* \see PopStatesUntil
*/ */
inline const std::shared_ptr<State>& StateMachine::GetCurrentState() const inline const std::shared_ptr<State>& StateMachine::GetCurrentState() const
{ {
return m_currentState; return m_states.back();
} }
/*! /*!
* \brief Updates the state * \brief Checks whether the state is on the top of the machine
* \return True if update is successful * \return true If it is the case
*
* \param state State to compare the top with
*/
inline bool StateMachine::IsTopState(const State* state) const
{
if (m_states.empty())
return false;
return m_states.back().get() == state;
}
/*!
* \brief Pops the state on the top of the machine
* \return Old state on the top, nullptr if stack was empty
*
* \remark This method can completely empty the stack
*/
inline std::shared_ptr<State> StateMachine::PopState()
{
if (m_states.empty())
return nullptr;
m_states.back()->Leave(*this);
std::shared_ptr<State> oldTopState = std::move(m_states.back());
m_states.pop_back();
return oldTopState;
}
/*!
* \brief Pops all the states of the machine until a specific one is reached
* \return true If that specific state is on top, false if stack is empty
*
* \param state State to find on the stack if it is nullptr, no action is performed
*
* \remark This method can completely empty the stack
*/
inline bool StateMachine::PopStatesUntil(std::shared_ptr<State> state)
{
if (!state)
return false;
while (!m_states.empty() && !IsTopState(state.get()))
PopState();
return !m_states.empty();
}
/*!
* \brief Pushes a new state on the top of the machine
*
* \param state Next state to represent if it is nullptr, it performs no action
*
* \remark Produces a NazaraAssert if the same state is pushed two times on the stack
*/
inline void StateMachine::PushState(std::shared_ptr<State> state)
{
if (state)
{
NazaraAssert(std::find(m_states.begin(), m_states.end(), state) == m_states.end(), "The same state was pushed two times");
m_states.push_back(std::move(state));
m_states.back()->Enter(*this);
}
}
/*!
* \brief Pops every states of the machine to put a new one
*
* \param state State to reset the stack with if it is nullptr, no action is performed
*/
inline void StateMachine::SetState(std::shared_ptr<State> state)
{
if (state)
{
while (!m_states.empty())
PopState();
PushState(std::move(state));
}
}
/*!
* \brief Updates all the states
* \return true If update is successful for everyone of them
* *
* \param elapsedTime Delta time used for the update * \param elapsedTime Delta time used for the update
*/ */
inline bool StateMachine::Update(float elapsedTime) inline bool StateMachine::Update(float elapsedTime)
{ {
if (m_nextState) return std::all_of(m_states.begin(), m_states.end(), [=](std::shared_ptr<State>& state) {
{ return state->Update(*this, elapsedTime);
m_currentState->Leave(*this); });
m_currentState = std::move(m_nextState);
m_currentState->Enter(*this);
}
return m_currentState->Update(*this, elapsedTime);
} }
} }

View File

@ -57,7 +57,7 @@ namespace Ndk
std::unique_ptr<Nz::AbstractRenderTechnique> m_renderTechnique; std::unique_ptr<Nz::AbstractRenderTechnique> m_renderTechnique;
std::vector<GraphicsComponentCullingList::VolumeEntry> m_volumeEntries; std::vector<GraphicsComponentCullingList::VolumeEntry> m_volumeEntries;
EntityList m_cameras; std::vector<EntityHandle> m_cameras;
EntityList m_drawables; EntityList m_drawables;
EntityList m_directionalLights; EntityList m_directionalLights;
EntityList m_lights; EntityList m_lights;

View File

@ -10,6 +10,7 @@
#include <Nazara/Core/Bitset.hpp> #include <Nazara/Core/Bitset.hpp>
#include <Nazara/Core/HandledObject.hpp> #include <Nazara/Core/HandledObject.hpp>
#include <NDK/Entity.hpp> #include <NDK/Entity.hpp>
#include <NDK/EntityList.hpp>
#include <NDK/System.hpp> #include <NDK/System.hpp>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
@ -28,7 +29,7 @@ namespace Ndk
friend Entity; friend Entity;
public: public:
using EntityList = std::vector<EntityHandle>; using EntityVector = std::vector<EntityHandle>;
inline World(bool addDefaultSystems = true); inline World(bool addDefaultSystems = true);
World(const World&) = delete; World(const World&) = delete;
@ -41,21 +42,21 @@ namespace Ndk
template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args); template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args);
const EntityHandle& CreateEntity(); const EntityHandle& CreateEntity();
inline EntityList CreateEntities(unsigned int count); inline EntityVector CreateEntities(unsigned int count);
void Clear() noexcept; void Clear() noexcept;
const EntityHandle& CloneEntity(EntityId id); const EntityHandle& CloneEntity(EntityId id);
const EntityHandle& GetEntity(EntityId id); inline const EntityHandle& GetEntity(EntityId id);
inline const EntityList& GetEntities(); inline const EntityList& GetEntities() const;
inline BaseSystem& GetSystem(SystemIndex index); inline BaseSystem& GetSystem(SystemIndex index);
template<typename SystemType> SystemType& GetSystem(); template<typename SystemType> SystemType& GetSystem();
inline bool HasSystem(SystemIndex index) const; inline bool HasSystem(SystemIndex index) const;
template<typename SystemType> bool HasSystem() const; template<typename SystemType> bool HasSystem() const;
void KillEntity(Entity* entity); inline void KillEntity(Entity* entity);
inline void KillEntities(const EntityList& list); inline void KillEntities(const EntityVector& list);
inline bool IsEntityValid(const Entity* entity) const; inline bool IsEntityValid(const Entity* entity) const;
inline bool IsEntityIdValid(EntityId id) const; inline bool IsEntityIdValid(EntityId id) const;
@ -79,19 +80,22 @@ namespace Ndk
struct EntityBlock struct EntityBlock
{ {
EntityBlock(Entity&& e) : EntityBlock(Entity&& e) :
entity(std::move(e)) entity(std::move(e)),
handle(&entity)
{ {
} }
EntityBlock(EntityBlock&& block) = default; EntityBlock(EntityBlock&& block) = default;
Entity entity; Entity entity;
std::size_t aliveIndex; EntityHandle handle;
}; };
std::vector<std::unique_ptr<BaseSystem>> m_systems; std::vector<std::unique_ptr<BaseSystem>> m_systems;
std::vector<BaseSystem*> m_orderedSystems; std::vector<BaseSystem*> m_orderedSystems;
std::vector<EntityBlock> m_entities; std::vector<EntityBlock> m_entities;
std::vector<EntityBlock*> m_entityBlocks;
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
std::vector<EntityId> m_freeIdList; std::vector<EntityId> m_freeIdList;
EntityList m_aliveEntities; EntityList m_aliveEntities;
Nz::Bitset<Nz::UInt64> m_dirtyEntities; Nz::Bitset<Nz::UInt64> m_dirtyEntities;

View File

@ -82,9 +82,9 @@ namespace Ndk
* \param count Number of entities to create * \param count Number of entities to create
*/ */
inline World::EntityList World::CreateEntities(unsigned int count) inline World::EntityVector World::CreateEntities(unsigned int count)
{ {
EntityList list; EntityVector list;
list.reserve(count); list.reserve(count);
for (unsigned int i = 0; i < count; ++i) for (unsigned int i = 0; i < count; ++i)
@ -98,7 +98,7 @@ namespace Ndk
* \return A constant reference to the entities * \return A constant reference to the entities
*/ */
inline const World::EntityList& World::GetEntities() inline const EntityList& World::GetEntities() const
{ {
return m_aliveEntities; return m_aliveEntities;
} }
@ -164,18 +164,53 @@ namespace Ndk
return HasSystem(index); return HasSystem(index);
} }
/*!
* \brief Marks an entity for deletion
*
* \param Pointer to the entity
*
* \remark If the entity pointer is invalid, nothing is done
* \remark For safety, entities are not killed until the next world update
*/
inline void World::KillEntity(Entity* entity)
{
if (IsEntityValid(entity))
m_killedEntities.UnboundedSet(entity->GetId(), true);
}
/*! /*!
* \brief Kills a set of entities * \brief Kills a set of entities
* *
* This function has the same effect as calling KillEntity for every entity contained in the vector
*
* \param list Set of entities to kill * \param list Set of entities to kill
*/ */
inline void World::KillEntities(const EntityVector& list)
inline void World::KillEntities(const EntityList& list)
{ {
for (const EntityHandle& entity : list) for (const EntityHandle& entity : list)
KillEntity(entity); KillEntity(entity);
} }
/*!
* \brief Gets an entity
* \return A constant reference to a handle of the entity
*
* \param id Identifier of the entity
*
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a reference to a handle from a world update to another
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
*/
inline const EntityHandle& World::GetEntity(EntityId id)
{
if (IsEntityIdValid(id))
return m_entityBlocks[id]->handle;
else
{
NazaraError("Invalid ID");
return EntityHandle::InvalidHandle;
}
}
/*! /*!
* \brief Checks whether or not an entity is valid * \brief Checks whether or not an entity is valid
* \return true If it is the case * \return true If it is the case
@ -197,7 +232,7 @@ namespace Ndk
inline bool World::IsEntityIdValid(EntityId id) const inline bool World::IsEntityIdValid(EntityId id) const
{ {
return id < m_entities.size() && m_entities[id].entity.IsValid(); return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid();
} }
/*! /*!
@ -266,10 +301,12 @@ namespace Ndk
{ {
m_aliveEntities = std::move(world.m_aliveEntities); m_aliveEntities = std::move(world.m_aliveEntities);
m_dirtyEntities = std::move(world.m_dirtyEntities); m_dirtyEntities = std::move(world.m_dirtyEntities);
m_entityBlocks = std::move(world.m_entityBlocks);
m_freeIdList = std::move(world.m_freeIdList); m_freeIdList = std::move(world.m_freeIdList);
m_killedEntities = std::move(world.m_killedEntities); m_killedEntities = std::move(world.m_killedEntities);
m_orderedSystems = std::move(world.m_orderedSystems); m_orderedSystems = std::move(world.m_orderedSystems);
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated; m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
m_waitingEntities = std::move(world.m_waitingEntities);
m_entities = std::move(world.m_entities); m_entities = std::move(world.m_entities);
for (EntityBlock& block : m_entities) for (EntityBlock& block : m_entities)
@ -284,7 +321,7 @@ namespace Ndk
inline void World::Invalidate() inline void World::Invalidate()
{ {
m_dirtyEntities.Resize(m_entities.size(), false); m_dirtyEntities.Resize(m_entityBlocks.size(), false);
m_dirtyEntities.Set(true); // Activation of all bits m_dirtyEntities.Set(true); // Activation of all bits
} }

View File

@ -93,6 +93,17 @@ namespace Ndk
return m_projectionMatrix; return m_projectionMatrix;
} }
/*!
* \brief Gets the projection type of the camera
* \return Projection type of the camera
*/
Nz::ProjectionType CameraComponent::GetProjectionType() const
{
return m_projectionType;
}
/*! /*!
* \brief Gets the target of the camera * \brief Gets the target of the camera
* \return A constant reference to the render target of the camera * \return A constant reference to the render target of the camera

View File

@ -24,6 +24,7 @@ namespace Ndk
HandledObject(std::move(entity)), HandledObject(std::move(entity)),
m_components(std::move(entity.m_components)), m_components(std::move(entity.m_components)),
m_componentBits(std::move(entity.m_componentBits)), m_componentBits(std::move(entity.m_componentBits)),
m_removedComponentBits(std::move(entity.m_removedComponentBits)),
m_systemBits(std::move(entity.m_systemBits)), m_systemBits(std::move(entity.m_systemBits)),
m_id(entity.m_id), m_id(entity.m_id),
m_world(entity.m_world), m_world(entity.m_world),

View File

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

View File

@ -49,7 +49,15 @@ namespace Ndk
{ {
m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list
m_cameras.Remove(entity); for (auto it = m_cameras.begin(); it != m_cameras.end(); ++it)
{
if (it->GetObject() == entity)
{
m_cameras.erase(it);
break;
}
}
m_directionalLights.Remove(entity); m_directionalLights.Remove(entity);
m_drawables.Remove(entity); m_drawables.Remove(entity);
m_lights.Remove(entity); m_lights.Remove(entity);
@ -75,14 +83,23 @@ namespace Ndk
if (entity->HasComponent<CameraComponent>() && entity->HasComponent<NodeComponent>()) if (entity->HasComponent<CameraComponent>() && entity->HasComponent<NodeComponent>())
{ {
m_cameras.Insert(entity); m_cameras.emplace_back(entity);
std::sort(m_cameras.begin(), m_cameras.end(), [](const EntityHandle& handle1, const EntityHandle& handle2) std::sort(m_cameras.begin(), m_cameras.end(), [](const EntityHandle& handle1, const EntityHandle& handle2)
{ {
return handle1->GetComponent<CameraComponent>().GetLayer() < handle2->GetComponent<CameraComponent>().GetLayer(); return handle1->GetComponent<CameraComponent>().GetLayer() < handle2->GetComponent<CameraComponent>().GetLayer();
}); });
} }
else else
m_cameras.Remove(entity); {
for (auto it = m_cameras.begin(); it != m_cameras.end(); ++it)
{
if (it->GetObject() == entity)
{
m_cameras.erase(it);
break;
}
}
}
if (entity->HasComponent<GraphicsComponent>() && entity->HasComponent<NodeComponent>()) if (entity->HasComponent<GraphicsComponent>() && entity->HasComponent<NodeComponent>())
{ {

View File

@ -60,29 +60,51 @@ namespace Ndk
const EntityHandle& World::CreateEntity() const EntityHandle& World::CreateEntity()
{ {
EntityId id; EntityId id;
EntityBlock* entBlock;
if (!m_freeIdList.empty()) if (!m_freeIdList.empty())
{ {
// We get an identifier // We get an identifier
id = m_freeIdList.back(); id = m_freeIdList.back();
m_freeIdList.pop_back(); m_freeIdList.pop_back();
entBlock = &m_entities[id];
entBlock->handle.Reset(&entBlock->entity); //< Reset handle (as it was reset when entity got destroyed)
m_entityBlocks[id] = entBlock;
} }
else else
{ {
// We allocate a new entity // We allocate a new entity
id = static_cast<Ndk::EntityId>(m_entities.size()); id = static_cast<Ndk::EntityId>(m_entityBlocks.size());
// We can't use emplace_back due to the scope if (m_entities.capacity() > m_entities.size())
m_entities.push_back(Entity(this, id)); {
NazaraAssert(m_waitingEntities.empty(), "There should be no waiting entities if space is available in main container");
m_entities.push_back(Entity(this, id)); //< We can't use emplace_back due to the scope
entBlock = &m_entities.back();
}
else
{
// Pushing to entities would reallocate vector and thus, invalidate EntityHandles (which we don't want until world update)
// To prevent this, allocate them into a separate vector and move them at update
// For now, we are counting on m_entities grow strategy to keep allocation frequency low
m_waitingEntities.emplace_back(std::make_unique<EntityBlock>(Entity(this, id)));
entBlock = m_waitingEntities.back().get();
} }
// We initialise the entity and we add it to the list of alive entities if (id >= m_entityBlocks.size())
Entity& entity = m_entities[id].entity; m_entityBlocks.resize(id + 1);
entity.Create();
m_aliveEntities.emplace_back(&entity); m_entityBlocks[id] = entBlock;
m_entities[id].aliveIndex = m_aliveEntities.size() - 1; }
return m_aliveEntities.back(); // We initialize the entity and we add it to the list of alive entities
entBlock->entity.Create();
m_aliveEntities.Insert(&entBlock->entity);
return entBlock->handle;
} }
/*! /*!
@ -96,8 +118,9 @@ namespace Ndk
// First, destruction of entities, then handles // First, destruction of entities, then handles
// This is made to avoid that handle warn uselessly entities before their destruction // This is made to avoid that handle warn uselessly entities before their destruction
m_entities.clear(); m_entities.clear();
m_entityBlocks.clear();
m_aliveEntities.clear(); m_aliveEntities.Clear();
m_dirtyEntities.Clear(); m_dirtyEntities.Clear();
m_killedEntities.Clear(); m_killedEntities.Clear();
} }
@ -120,7 +143,7 @@ namespace Ndk
return EntityHandle::InvalidHandle; return EntityHandle::InvalidHandle;
} }
EntityHandle clone = CreateEntity(); const EntityHandle& clone = CreateEntity();
const Nz::Bitset<>& componentBits = original->GetComponentBits(); const Nz::Bitset<>& componentBits = original->GetComponentBits();
for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i)) for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i))
@ -132,40 +155,6 @@ namespace Ndk
return GetEntity(clone->GetId()); 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;
}
}
/*! /*!
* \brief Updates the world * \brief Updates the world
* *
@ -177,45 +166,43 @@ namespace Ndk
if (!m_orderedSystemsUpdated) if (!m_orderedSystemsUpdated)
ReorderSystems(); ReorderSystems();
// Move waiting entities to entity list
if (!m_waitingEntities.empty())
{
constexpr std::size_t MinEntityCapacity = 10; //< We want to be able to grow maximum entity count by at least ten without going to the waiting list
m_entities.reserve(m_entities.size() + m_waitingEntities.size() + MinEntityCapacity);
for (auto& blockPtr : m_waitingEntities)
m_entities.push_back(std::move(*blockPtr));
m_waitingEntities.clear();
// Update entity blocks pointers
for (std::size_t i = 0; i < m_entities.size(); ++i)
m_entityBlocks[i] = &m_entities[i];
}
// Handle killed entities before last call // Handle killed entities before last call
for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i)) for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i))
{ {
EntityBlock& block = m_entities[i]; NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
Entity& entity = block.entity;
NazaraAssert(entity.IsValid(), "Entity must be valid"); Entity* entity = &m_entityBlocks[i]->entity;
// Destruction of the entity (invalidation of handle by the same way) // Destruction of the entity (invalidation of handle by the same way)
entity.Destroy(); entity->Destroy();
// Send back the identifier of the entity to the free queue // Send back the identifier of the entity to the free queue
m_freeIdList.push_back(entity.GetId()); m_freeIdList.push_back(entity->GetId());
// We take out the handle from the list of alive entities
// With the idiom swap and pop
NazaraAssert(block.aliveIndex < m_aliveEntities.size(), "Alive index out of range");
if (block.aliveIndex < m_aliveEntities.size() - 1) // If it's not the last handle
{
EntityHandle& lastHandle = m_aliveEntities.back();
EntityHandle& myHandle = m_aliveEntities[block.aliveIndex];
myHandle = std::move(lastHandle);
// We don't forget to update the index associated to the entity
m_entities[myHandle->GetId()].aliveIndex = block.aliveIndex;
}
m_aliveEntities.pop_back();
} }
m_killedEntities.Reset(); m_killedEntities.Reset();
// Handle of entities which need an update from the systems // Handle of entities which need an update from the systems
for (std::size_t i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i)) for (std::size_t i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i))
{ {
NazaraAssert(i < m_entities.size(), "Entity index out of range"); NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
Entity* entity = &m_entities[i].entity; Entity* entity = &m_entityBlocks[i]->entity;
// Check entity validity (as it could have been reported as dirty and killed during the same iteration) // Check entity validity (as it could have been reported as dirty and killed during the same iteration)
if (!entity->IsValid()) if (!entity->IsValid())
@ -242,7 +229,7 @@ namespace Ndk
} }
else else
{ {
// No, it shouldn't, remove it if it's part of the system // No it shouldn't, remove it if it's part of the system
if (partOfSystem) if (partOfSystem)
system->RemoveEntity(entity); system->RemoveEntity(entity);
} }

View File

@ -51,7 +51,7 @@ namespace Nz
virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) = 0; virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) = 0;
virtual void AddPointLight(const PointLight& light); virtual void AddPointLight(const PointLight& light);
virtual void AddSpotLight(const SpotLight& light); virtual void AddSpotLight(const SpotLight& light);
virtual void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) = 0; virtual void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) = 0;
virtual void Clear(bool fully = false); virtual void Clear(bool fully = false);

View File

@ -33,6 +33,7 @@ namespace Nz
virtual Vector3f GetForward() const = 0; virtual Vector3f GetForward() const = 0;
virtual const Frustumf& GetFrustum() const = 0; virtual const Frustumf& GetFrustum() const = 0;
virtual const Matrix4f& GetProjectionMatrix() const = 0; virtual const Matrix4f& GetProjectionMatrix() const = 0;
virtual Nz::ProjectionType GetProjectionType() const = 0;
virtual const RenderTarget* GetTarget() const = 0; virtual const RenderTarget* GetTarget() const = 0;
virtual const Matrix4f& GetViewMatrix() const = 0; virtual const Matrix4f& GetViewMatrix() const = 0;
virtual const Recti& GetViewport() const = 0; virtual const Recti& GetViewport() const = 0;

View File

@ -37,7 +37,7 @@ namespace Nz
void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override; void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override;
void AddDrawable(int renderOrder, const Drawable* drawable) override; void AddDrawable(int renderOrder, const Drawable* drawable) override;
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override;
void Clear(bool fully = false) override; void Clear(bool fully = false) override;

View File

@ -38,7 +38,7 @@ namespace Nz
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
void AddPointLight(const PointLight& light) override; void AddPointLight(const PointLight& light) override;
void AddSpotLight(const SpotLight& light) override; void AddSpotLight(const SpotLight& light) override;
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override;
private: private:
inline bool IsMaterialSuitable(const Material* material) const; inline bool IsMaterialSuitable(const Material* material) const;

View File

@ -13,6 +13,7 @@
#include <Nazara/Graphics/Material.hpp> #include <Nazara/Graphics/Material.hpp>
#include <Nazara/Math/Box.hpp> #include <Nazara/Math/Box.hpp>
#include <Nazara/Math/Matrix4.hpp> #include <Nazara/Math/Matrix4.hpp>
#include <Nazara/Math/Plane.hpp>
#include <Nazara/Utility/IndexBuffer.hpp> #include <Nazara/Utility/IndexBuffer.hpp>
#include <Nazara/Utility/MeshData.hpp> #include <Nazara/Utility/MeshData.hpp>
#include <Nazara/Utility/VertexBuffer.hpp> #include <Nazara/Utility/VertexBuffer.hpp>
@ -41,7 +42,7 @@ namespace Nz
void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override; void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr<const Vector3f> positionPtr, SparsePtr<const float> sizePtr, SparsePtr<const float> anglePtr, SparsePtr<const float> alphaPtr) override;
void AddDrawable(int renderOrder, const Drawable* drawable) override; void AddDrawable(int renderOrder, const Drawable* drawable) override;
void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override;
void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override;
void Clear(bool fully = false) override; void Clear(bool fully = false) override;
@ -73,7 +74,7 @@ namespace Nz
std::vector<BillboardData> billboards; std::vector<BillboardData> billboards;
}; };
typedef std::map<const Material*, BatchedBillboardEntry, MaterialComparator> BatchedBillboardContainer; using BatchedBillboardContainer = std::map<const Material*, BatchedBillboardEntry, MaterialComparator>;
struct BatchedBillboardPipelineEntry struct BatchedBillboardPipelineEntry
{ {
@ -81,7 +82,7 @@ namespace Nz
bool enabled = false; bool enabled = false;
}; };
typedef std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator> BillboardPipelineBatches; using BillboardPipelineBatches = std::map<const MaterialPipeline*, BatchedBillboardPipelineEntry, MaterialPipelineComparator>;
/// Sprites /// Sprites
struct SpriteChain_XYZ_Color_UV struct SpriteChain_XYZ_Color_UV
@ -97,7 +98,7 @@ namespace Nz
std::vector<SpriteChain_XYZ_Color_UV> spriteChains; std::vector<SpriteChain_XYZ_Color_UV> spriteChains;
}; };
typedef std::map<const Texture*, BatchedSpriteEntry> SpriteOverlayBatches; using SpriteOverlayBatches = std::map<const Texture*, BatchedSpriteEntry>;
struct BatchedBasicSpriteEntry struct BatchedBasicSpriteEntry
{ {
@ -107,7 +108,7 @@ namespace Nz
bool enabled = false; bool enabled = false;
}; };
typedef std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator> SpriteMaterialBatches; using SpriteMaterialBatches = std::map<const Material*, BatchedBasicSpriteEntry, MaterialComparator>;
struct BatchedSpritePipelineEntry struct BatchedSpritePipelineEntry
{ {
@ -115,7 +116,7 @@ namespace Nz
bool enabled = false; bool enabled = false;
}; };
typedef std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator> SpritePipelineBatches; using SpritePipelineBatches = std::map<const MaterialPipeline*, BatchedSpritePipelineEntry, MaterialPipelineComparator>;
/// Meshes /// Meshes
struct MeshDataComparator struct MeshDataComparator
@ -132,7 +133,7 @@ namespace Nz
Spheref squaredBoundingSphere; Spheref squaredBoundingSphere;
}; };
typedef std::map<MeshData, MeshInstanceEntry, MeshDataComparator> MeshInstanceContainer; using MeshInstanceContainer = std::map<MeshData, MeshInstanceEntry, MeshDataComparator>;
struct BatchedModelEntry struct BatchedModelEntry
{ {
@ -142,7 +143,7 @@ namespace Nz
bool enabled = false; bool enabled = false;
}; };
typedef std::map<const Material*, BatchedModelEntry, MaterialComparator> MeshMaterialBatches; using MeshMaterialBatches = std::map<const Material*, BatchedModelEntry, MaterialComparator>;
struct BatchedMaterialEntry struct BatchedMaterialEntry
{ {
@ -150,25 +151,33 @@ namespace Nz
MeshMaterialBatches materialMap; MeshMaterialBatches materialMap;
}; };
typedef std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator> MeshPipelineBatches; using MeshPipelineBatches = std::map<const MaterialPipeline*, BatchedMaterialEntry, MaterialPipelineComparator>;
struct TransparentModelData struct UnbatchedModelData
{ {
Matrix4f transformMatrix; Matrix4f transformMatrix;
MeshData meshData; MeshData meshData;
Spheref squaredBoundingSphere; Spheref obbSphere;
const Material* material; const Material* material;
}; };
typedef std::vector<std::size_t> TransparentModelContainer; struct UnbatchedSpriteData
{
std::size_t spriteCount;
const Material* material;
const Texture* overlay;
const VertexStruct_XYZ_Color_UV* vertices;
};
struct Layer struct Layer
{ {
BillboardPipelineBatches billboards; BillboardPipelineBatches billboards;
SpritePipelineBatches basicSprites; SpritePipelineBatches opaqueSprites;
MeshPipelineBatches opaqueModels; MeshPipelineBatches opaqueModels;
TransparentModelContainer transparentModels; std::vector<std::size_t> depthSortedMeshes;
std::vector<TransparentModelData> transparentModelData; std::vector<std::size_t> depthSortedSprites;
std::vector<UnbatchedModelData> depthSortedMeshData;
std::vector<UnbatchedSpriteData> depthSortedSpriteData;
std::vector<const Drawable*> otherDrawables; std::vector<const Drawable*> otherDrawables;
unsigned int clearCount = 0; unsigned int clearCount = 0;
}; };
@ -179,6 +188,10 @@ namespace Nz
BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count); BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count);
Layer& GetLayer(int i); ///TODO: Inline Layer& GetLayer(int i); ///TODO: Inline
void SortBillboards(Layer& layer, const Planef& nearPlane);
void SortForOrthographic(const AbstractViewer* viewer);
void SortForPerspective(const AbstractViewer* viewer);
void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer); void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer);
void OnMaterialInvalidation(const Material* material); void OnMaterialInvalidation(const Material* material);
void OnTextureInvalidation(const Texture* texture); void OnTextureInvalidation(const Texture* texture);

View File

@ -43,6 +43,7 @@ namespace Nz
void DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
void DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
void DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
void DrawOrderedSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
void DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const;
const ShaderUniforms* GetShaderUniforms(const Shader* shader) const; const ShaderUniforms* GetShaderUniforms(const Shader* shader) const;
void OnShaderInvalidated(const Shader* shader) const; void OnShaderInvalidated(const Shader* shader) const;

View File

@ -98,7 +98,13 @@ namespace Nz
return 0; return 0;
} }
template<typename T> /*constexpr*/ std::enable_if_t<!std::is_signed<T>::value || !std::is_integral<T>::value, bool> NumberEquals(T a, T b, T maxDifference) template<typename T> /*constexpr*/ std::enable_if_t<std::is_floating_point<T>::value, bool> NumberEquals(T a, T b, T maxDifference)
{
T diff = std::abs(a - b);
return diff <= maxDifference;
}
template<typename T> /*constexpr*/ std::enable_if_t<!std::is_signed<T>::value || (!std::is_integral<T>::value && !std::is_floating_point<T>::value), bool> NumberEquals(T a, T b, T maxDifference)
{ {
if (b > a) if (b > a)
std::swap(a, b); std::swap(a, b);
@ -112,13 +118,8 @@ namespace Nz
if (b > a) if (b > a)
std::swap(a, b); std::swap(a, b);
if ((b < 0) && (a > std::numeric_limits<T>::max() + b)) using UnsignedT = std::make_unsigned_t<T>;
return false; return static_cast<UnsignedT>(a) - static_cast<UnsignedT>(b) <= static_cast<UnsignedT>(maxDifference);
if ((b > 0) && (a < std::numeric_limits<T>::min() + b))
return false;
return std::abs(a - b) <= maxDifference;
} }
} }
@ -487,7 +488,7 @@ namespace Nz
template<typename T, typename T2> template<typename T, typename T2>
constexpr T Lerp(const T& from, const T& to, const T2& interpolation) constexpr T Lerp(const T& from, const T& to, const T2& interpolation)
{ {
return from + interpolation * (to - from); return static_cast<T>(from + interpolation * (to - from));
} }
/*! /*!

View File

@ -74,8 +74,8 @@ namespace Nz
Box& Transform(const Matrix4<T>& matrix, bool applyTranslation = true); Box& Transform(const Matrix4<T>& matrix, bool applyTranslation = true);
Box& Translate(const Vector3<T>& translation); Box& Translate(const Vector3<T>& translation);
T& operator[](unsigned int i); T& operator[](std::size_t i);
T operator[](unsigned int i) const; T operator[](std::size_t i) const;
Box operator*(T scalar) const; Box operator*(T scalar) const;
Box operator*(const Vector3<T>& vec) const; Box operator*(const Vector3<T>& vec) const;

View File

@ -735,24 +735,15 @@ namespace Nz
* \brief Returns the ith element of the box * \brief Returns the ith element of the box
* \return A reference to the ith element of the box * \return A reference to the ith element of the box
* *
* \remark Access to index greather than 6 is undefined behavior * \remark Access to index greater than 6 is undefined behavior
* \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined * \remark Produce a NazaraError if you try to access to index greater than 6 with NAZARA_MATH_SAFE defined
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6 * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6
*/ */
template<typename T> template<typename T>
T& Box<T>::operator[](unsigned int i) T& Box<T>::operator[](std::size_t i)
{ {
#if NAZARA_MATH_SAFE NazaraAssert(i < 6, "Index out of range");
if (i >= 6)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 6)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return *(&x+i); return *(&x+i);
} }
@ -761,24 +752,15 @@ namespace Nz
* \brief Returns the ith element of the box * \brief Returns the ith element of the box
* \return A value to the ith element of the box * \return A value to the ith element of the box
* *
* \remark Access to index greather than 6 is undefined behavior * \remark Access to index greater than 6 is undefined behavior
* \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined * \remark Produce a NazaraError if you try to access to index greater than 6 with NAZARA_MATH_SAFE defined
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6 * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6
*/ */
template<typename T> template<typename T>
T Box<T>::operator[](unsigned int i) const T Box<T>::operator[](std::size_t i) const
{ {
#if NAZARA_MATH_SAFE NazaraAssert(i < 6, "Index out of range");
if (i >= 6)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 6)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return *(&x+i); return *(&x+i);
} }

View File

@ -64,8 +64,8 @@ namespace Nz
Rect& Translate(const Vector2<T>& translation); Rect& Translate(const Vector2<T>& translation);
T& operator[](unsigned int i); T& operator[](std::size_t i);
T operator[](unsigned int i) const; T operator[](std::size_t i) const;
Rect operator*(T scalar) const; Rect operator*(T scalar) const;
Rect operator*(const Vector2<T>& vec) const; Rect operator*(const Vector2<T>& vec) const;

View File

@ -578,23 +578,14 @@ namespace Nz
* \return A reference to the ith element of the rectangle * \return A reference to the ith element of the rectangle
* *
* \remark Access to index greather than 4 is undefined behavior * \remark Access to index greather than 4 is undefined behavior
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
*/ */
template<typename T> template<typename T>
T& Rect<T>::operator[](unsigned int i) T& Rect<T>::operator[](std::size_t i)
{ {
#if NAZARA_MATH_SAFE NazaraAssert(i < 4, "Index out of range");
if (i >= 4)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 4)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return *(&x+i); return *(&x+i);
} }
@ -603,24 +594,15 @@ namespace Nz
* \brief Returns the ith element of the rectangle * \brief Returns the ith element of the rectangle
* \return A value to the ith element of the rectangle * \return A value to the ith element of the rectangle
* *
* \remark Access to index greather than 4 is undefined behavior * \remark Access to index greater than 4 is undefined behavior
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
*/ */
template<typename T> template<typename T>
T Rect<T>::operator[](unsigned int i) const T Rect<T>::operator[](std::size_t i) const
{ {
#if NAZARA_MATH_SAFE NazaraAssert(i < 4, "Index out of range");
if (i >= 4)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 4)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return *(&x+i); return *(&x+i);
} }

View File

@ -60,8 +60,8 @@ namespace Nz
String ToString() const; String ToString() const;
T& operator[](unsigned int i); T& operator[](std::size_t i);
T operator[](unsigned int i) const; T operator[](std::size_t i) const;
Sphere operator*(T scalar) const; Sphere operator*(T scalar) const;
Sphere& operator=(const Sphere& other) = default; Sphere& operator=(const Sphere& other) = default;

View File

@ -466,24 +466,15 @@ namespace Nz
* \brief Returns the ith element of the sphere * \brief Returns the ith element of the sphere
* \return A reference to the ith element of the sphere * \return A reference to the ith element of the sphere
* *
* \remark Access to index greather than 4 is undefined behavior * \remark Access to index greater than 4 is undefined behavior
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
*/ */
template<typename T> template<typename T>
T& Sphere<T>::operator[](unsigned int i) T& Sphere<T>::operator[](std::size_t i)
{ {
#if NAZARA_MATH_SAFE NazaraAssert(i < 4, "Index out of range");
if (i >= 4)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 4)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return *(&x+i); return *(&x+i);
} }
@ -492,24 +483,15 @@ namespace Nz
* \brief Returns the ith element of the sphere * \brief Returns the ith element of the sphere
* \return A value to the ith element of the sphere * \return A value to the ith element of the sphere
* *
* \remark Access to index greather than 4 is undefined behavior * \remark Access to index greater than 4 is undefined behavior
* \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined
* \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4
*/ */
template<typename T> template<typename T>
T Sphere<T>::operator[](unsigned int i) const T Sphere<T>::operator[](std::size_t i) const
{ {
#if NAZARA_MATH_SAFE NazaraAssert(i < 4, "Index out of range");
if (i >= 4)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 4)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return *(&x+i); return *(&x+i);
} }

View File

@ -64,10 +64,10 @@ namespace Nz
struct Callback struct Callback
{ {
ContactEndCallback endCallback; ContactEndCallback endCallback = nullptr;
ContactPreSolveCallback preSolveCallback; ContactPreSolveCallback preSolveCallback = nullptr;
ContactPostSolveCallback postSolveCallback; ContactPostSolveCallback postSolveCallback = nullptr;
ContactStartCallback startCallback; ContactStartCallback startCallback = nullptr;
void* userdata; void* userdata;
}; };

View File

@ -26,15 +26,15 @@ namespace Nz
Reference operator*() const; Reference operator*() const;
Reference operator[](unsigned int index) const; Reference operator[](std::size_t index) const;
IndexIterator& operator=(const IndexIterator& iterator); IndexIterator& operator=(const IndexIterator& iterator);
IndexIterator operator+(unsigned int indexCount) const; IndexIterator operator+(std::size_t indexCount) const;
IndexIterator operator-(unsigned int indexCount) const; IndexIterator operator-(std::size_t indexCount) const;
IndexIterator& operator+=(unsigned int indexCount); IndexIterator& operator+=(std::size_t indexCount);
IndexIterator& operator-=(unsigned int indexCount); IndexIterator& operator-=(std::size_t indexCount);
IndexIterator& operator++(); IndexIterator& operator++();
IndexIterator operator++(int); IndexIterator operator++(int);
@ -50,10 +50,10 @@ namespace Nz
friend bool operator>=(const IndexIterator& lhs, const IndexIterator& rhs); friend bool operator>=(const IndexIterator& lhs, const IndexIterator& rhs);
private: private:
IndexIterator(IndexMapper* mapper, unsigned int index); IndexIterator(IndexMapper* mapper, std::size_t index);
IndexMapper* m_mapper; IndexMapper* m_mapper;
unsigned int m_index; std::size_t m_index;
}; };
class IndexIterator::Reference class IndexIterator::Reference
@ -70,10 +70,10 @@ namespace Nz
operator UInt32() const; operator UInt32() const;
private: private:
Reference(IndexMapper* mapper, unsigned int index); Reference(IndexMapper* mapper, std::size_t index);
IndexMapper* m_mapper; IndexMapper* m_mapper;
unsigned int m_index; std::size_t m_index;
}; };
} }

View File

@ -20,7 +20,7 @@ namespace Nz
{ {
} }
inline IndexIterator::IndexIterator(IndexMapper* mapper, unsigned int index) : inline IndexIterator::IndexIterator(IndexMapper* mapper, std::size_t index) :
m_mapper(mapper), m_mapper(mapper),
m_index(index) m_index(index)
{ {
@ -31,7 +31,7 @@ namespace Nz
return Reference(m_mapper, m_index); return Reference(m_mapper, m_index);
} }
inline IndexIterator::Reference IndexIterator::operator[](unsigned int index) const inline IndexIterator::Reference IndexIterator::operator[](std::size_t index) const
{ {
return Reference(m_mapper, m_index+index); return Reference(m_mapper, m_index+index);
} }
@ -44,24 +44,24 @@ namespace Nz
return *this; return *this;
} }
inline IndexIterator IndexIterator::operator+(unsigned int indexCount) const inline IndexIterator IndexIterator::operator+(std::size_t indexCount) const
{ {
return IndexIterator(m_mapper, m_index + indexCount); return IndexIterator(m_mapper, m_index + indexCount);
} }
inline IndexIterator IndexIterator::operator-(unsigned int indexCount) const inline IndexIterator IndexIterator::operator-(std::size_t indexCount) const
{ {
return IndexIterator(m_mapper, m_index - indexCount); return IndexIterator(m_mapper, m_index - indexCount);
} }
inline IndexIterator& IndexIterator::operator+=(unsigned int indexCount) inline IndexIterator& IndexIterator::operator+=(std::size_t indexCount)
{ {
m_index += indexCount; m_index += indexCount;
return *this; return *this;
} }
inline IndexIterator& IndexIterator::operator-=(unsigned int indexCount) inline IndexIterator& IndexIterator::operator-=(std::size_t indexCount)
{ {
m_index += indexCount; m_index += indexCount;
@ -133,7 +133,7 @@ namespace Nz
/**************************IndexIterator::Reference*************************/ /**************************IndexIterator::Reference*************************/
inline IndexIterator::Reference::Reference(IndexMapper* mapper, unsigned int index) : inline IndexIterator::Reference::Reference(IndexMapper* mapper, std::size_t index) :
m_mapper(mapper), m_mapper(mapper),
m_index(index) m_index(index)
{ {
@ -148,7 +148,7 @@ namespace Nz
inline IndexIterator::Reference& IndexIterator::Reference::operator=(const IndexIterator::Reference& reference) inline IndexIterator::Reference& IndexIterator::Reference::operator=(const IndexIterator::Reference& reference)
{ {
m_mapper->Set(m_index, reference); // Conversion implicite en UInt32 m_mapper->Set(m_index, reference); // Implicit conversion to UInt32
return *this; return *this;
} }

View File

@ -17,9 +17,6 @@ namespace Nz
class IndexIterator; class IndexIterator;
class SubMesh; class SubMesh;
using IndexMapperGetter = UInt32 (*)(const void* buffer, unsigned int i);
using IndexMapperSetter = void (*)(void* buffer, unsigned int i, UInt32 value);
class NAZARA_UTILITY_API IndexMapper class NAZARA_UTILITY_API IndexMapper
{ {
public: public:
@ -29,11 +26,11 @@ namespace Nz
IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly); IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly);
~IndexMapper() = default; ~IndexMapper() = default;
UInt32 Get(unsigned int i) const; UInt32 Get(std::size_t i) const;
const IndexBuffer* GetBuffer() const; const IndexBuffer* GetBuffer() const;
unsigned int GetIndexCount() const; std::size_t GetIndexCount() const;
void Set(unsigned int i, UInt32 value); void Set(std::size_t i, UInt32 value);
void Unmap(); void Unmap();
@ -45,10 +42,13 @@ namespace Nz
// Méthodes STD // Méthodes STD
private: private:
using Getter = UInt32(*)(const void* buffer, std::size_t i);
using Setter = void(*)(void* buffer, std::size_t i, UInt32 value);
BufferMapper<IndexBuffer> m_mapper; BufferMapper<IndexBuffer> m_mapper;
IndexMapperGetter m_getter; Getter m_getter;
IndexMapperSetter m_setter; Setter m_setter;
unsigned int m_indexCount; std::size_t m_indexCount;
}; };
} }

View File

@ -24,7 +24,7 @@ namespace Nz
bool Advance(); bool Advance();
UInt32 operator[](unsigned int i) const; UInt32 operator[](std::size_t i) const;
void Unmap(); void Unmap();
@ -32,8 +32,8 @@ namespace Nz
PrimitiveMode m_primitiveMode; PrimitiveMode m_primitiveMode;
UInt32 m_triangleIndices[3]; UInt32 m_triangleIndices[3];
IndexMapper m_indexMapper; IndexMapper m_indexMapper;
unsigned int m_currentIndex; std::size_t m_currentIndex;
unsigned int m_indexCount; std::size_t m_indexCount;
}; };
} }

View File

@ -153,7 +153,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
if (animatedMesh) if (animatedMesh)
{ {
mesh->CreateSkeletal(joints.size()); mesh->CreateSkeletal(UInt32(joints.size()));
Skeleton* skeleton = mesh->GetSkeleton(); Skeleton* skeleton = mesh->GetSkeleton();
@ -171,7 +171,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
mesh->CreateStatic(); mesh->CreateStatic();
// aiMaterial index in scene => Material index and data in Mesh // aiMaterial index in scene => Material index and data in Mesh
std::unordered_map<unsigned int, std::pair<std::size_t, ParameterList>> materials; std::unordered_map<unsigned int, std::pair<UInt32, ParameterList>> materials;
for (unsigned int i = 0; i < scene->mNumMeshes; ++i) for (unsigned int i = 0; i < scene->mNumMeshes; ++i)
{ {
@ -300,7 +300,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS)
matData.SetParameter(MaterialData::FaceCulling, !iValue); matData.SetParameter(MaterialData::FaceCulling, !iValue);
matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(materials.size(), std::move(matData)))).first; matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first;
} }
subMesh->SetMaterialIndex(matIt->first); subMesh->SetMaterialIndex(matIt->first);
@ -308,7 +308,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters)
mesh->AddSubMesh(subMesh); mesh->AddSubMesh(subMesh);
} }
mesh->SetMaterialCount(std::max<UInt32>(materials.size(), 1)); mesh->SetMaterialCount(std::max<UInt32>(UInt32(materials.size()), 1));
for (const auto& pair : materials) for (const auto& pair : materials)
mesh->SetMaterialData(pair.second.first, pair.second.second); mesh->SetMaterialData(pair.second.first, pair.second.second);
} }

View File

@ -101,7 +101,7 @@ namespace Nz
{ {
struct HashMD5_state struct HashMD5_state
{ {
UInt32 count[2]; /* message length in bits, lsw first */ std::size_t count[2]; /* message length in bits, lsw first */
UInt32 abcd[4]; /* digest buffer */ UInt32 abcd[4]; /* digest buffer */
UInt8 buf[64]; /* accumulate block */ UInt8 buf[64]; /* accumulate block */
}; };
@ -280,9 +280,9 @@ namespace Nz
void HashMD5::Append(const UInt8* data, std::size_t len) void HashMD5::Append(const UInt8* data, std::size_t len)
{ {
const UInt8 *p = data; const UInt8 *p = data;
int left = len; std::size_t left = len;
int offset = (m_state->count[0] >> 3) & 63; int offset = (m_state->count[0] >> 3) & 63;
UInt32 nbits = len << 3; std::size_t nbits = len << 3;
if (len <= 0) if (len <= 0)
return; return;
@ -296,7 +296,7 @@ namespace Nz
/* Process an initial partial block. */ /* Process an initial partial block. */
if (offset) if (offset)
{ {
int copy = (offset + len > 64 ? 64 - offset : len); std::size_t copy = (offset + len > 64 ? 64 - offset : len);
std::memcpy(m_state->buf + offset, p, copy); std::memcpy(m_state->buf + offset, p, copy);
if (offset + copy < 64) if (offset + copy < 64)

View File

@ -75,8 +75,8 @@ namespace Nz
{ {
struct HashWhirlpool_state struct HashWhirlpool_state
{ {
int bufferBits; // current number of bits on the buffer */ std::size_t bufferBits; // current number of bits on the buffer */
int bufferPos; // current (possibly incomplete) byte slot on the buffer */ std::size_t bufferPos; // current (possibly incomplete) byte slot on the buffer */
UInt8 bitLength[32]; // global number of hashed bits (256-bit counter) */ UInt8 bitLength[32]; // global number of hashed bits (256-bit counter) */
UInt8 buffer[64]; // buffer of data to hash */ UInt8 buffer[64]; // buffer of data to hash */
UInt64 hash[8]; // the hashing state */ UInt64 hash[8]; // the hashing state */
@ -877,8 +877,8 @@ namespace Nz
UInt32 b; UInt32 b;
UInt8* buffer = m_state->buffer; UInt8* buffer = m_state->buffer;
UInt8* bitLength = m_state->bitLength; UInt8* bitLength = m_state->bitLength;
int bufferBits = m_state->bufferBits; std::size_t bufferBits = m_state->bufferBits;
int bufferPos = m_state->bufferPos; std::size_t bufferPos = m_state->bufferPos;
// tally the length of the added data // tally the length of the added data
UInt64 value = len; UInt64 value = len;
@ -968,8 +968,8 @@ namespace Nz
UInt8 *buffer = m_state->buffer; UInt8 *buffer = m_state->buffer;
UInt8 *bitLength = m_state->bitLength; UInt8 *bitLength = m_state->bitLength;
int bufferBits = m_state->bufferBits; std::size_t bufferBits = m_state->bufferBits;
int bufferPos = m_state->bufferPos; std::size_t bufferPos = m_state->bufferPos;
UInt8 *digest = result; UInt8 *digest = result;
// append a '1'-bit // append a '1'-bit

View File

@ -2115,7 +2115,7 @@ namespace Nz
return ptr - m_sharedString->string.get(); return ptr - m_sharedString->string.get();
} }
catch (utf8::not_enough_room& e) catch (utf8::not_enough_room& /*e*/)
{ {
// Returns npos // Returns npos
} }

View File

@ -191,8 +191,8 @@ namespace Nz
void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix)
{ {
if (material->IsBlendingEnabled()) if (material->IsBlendingEnabled() || material->IsDepthSortingEnabled()) //< Fixme: Deferred Shading should be able to handle depth sorting
// One transparent material ? I don't like it, go see if I'm in the forward queue // Deferred Shading cannot handle blended objects, put them in the forward list
m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix); m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix);
else else
{ {
@ -254,7 +254,7 @@ namespace Nz
* \param overlay Texture of the sprites * \param overlay Texture of the sprites
*/ */
void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
{ {
m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay); m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay);
} }

View File

@ -351,7 +351,7 @@ namespace Nz
* \remark Produces a NazaraAssert if material is invalid * \remark Produces a NazaraAssert if material is invalid
*/ */
void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
NazaraUnused(renderOrder); NazaraUnused(renderOrder);

View File

@ -95,7 +95,7 @@ namespace Nz
if (!layer.opaqueModels.empty()) if (!layer.opaqueModels.empty())
DrawOpaqueModels(sceneData, layer); DrawOpaqueModels(sceneData, layer);
if (!layer.basicSprites.empty()) if (!layer.opaqueSprites.empty())
DrawBasicSprites(sceneData, layer); DrawBasicSprites(sceneData, layer);
if (!layer.billboards.empty()) if (!layer.billboards.empty())
@ -219,7 +219,7 @@ namespace Nz
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
Renderer::SetVertexBuffer(&m_spriteBuffer); Renderer::SetVertexBuffer(&m_spriteBuffer);
for (auto& pipelinePair : layer.basicSprites) for (auto& pipelinePair : layer.opaqueSprites)
{ {
const MaterialPipeline* pipeline = pipelinePair.first; const MaterialPipeline* pipeline = pipelinePair.first;
auto& pipelineEntry = pipelinePair.second; auto& pipelineEntry = pipelinePair.second;

View File

@ -376,23 +376,23 @@ namespace Nz
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
if (material->IsBlendingEnabled()) if (material->IsDepthSortingEnabled())
{ {
Layer& currentLayer = GetLayer(renderOrder); Layer& currentLayer = GetLayer(renderOrder);
auto& transparentModels = currentLayer.transparentModels; auto& transparentMeshes = currentLayer.depthSortedMeshes;
auto& transparentModelData = currentLayer.transparentModelData; auto& transparentData = currentLayer.depthSortedMeshData;
// The material is transparent, we must draw this mesh using another way (after the rendering of opages objects while sorting them) // The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them)
std::size_t index = transparentModelData.size(); std::size_t index = transparentData.size();
transparentModelData.resize(index+1); transparentData.resize(index+1);
TransparentModelData& data = transparentModelData.back(); UnbatchedModelData& data = transparentData.back();
data.material = material; data.material = material;
data.meshData = meshData; data.meshData = meshData;
data.squaredBoundingSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius()); data.obbSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius());
data.transformMatrix = transformMatrix; data.transformMatrix = transformMatrix;
transparentModels.push_back(index); transparentMeshes.push_back(index);
} }
else else
{ {
@ -457,20 +457,40 @@ namespace Nz
* *
* \remark Produces a NazaraAssert if material is invalid * \remark Produces a NazaraAssert if material is invalid
*/ */
void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay)
{ {
NazaraAssert(material, "Invalid material"); NazaraAssert(material, "Invalid material");
Layer& currentLayer = GetLayer(renderOrder); Layer& currentLayer = GetLayer(renderOrder);
SpritePipelineBatches& basicSprites = currentLayer.basicSprites;
if (material->IsDepthSortingEnabled())
{
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);
}
else
{
SpritePipelineBatches& sprites = currentLayer.opaqueSprites;
const MaterialPipeline* materialPipeline = material->GetPipeline(); const MaterialPipeline* materialPipeline = material->GetPipeline();
auto pipelineIt = basicSprites.find(materialPipeline); auto pipelineIt = sprites.find(materialPipeline);
if (pipelineIt == basicSprites.end()) if (pipelineIt == sprites.end())
{ {
BatchedSpritePipelineEntry materialEntry; BatchedSpritePipelineEntry materialEntry;
pipelineIt = basicSprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first; pipelineIt = sprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first;
} }
BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second; BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second;
@ -505,6 +525,7 @@ namespace Nz
auto& spriteVector = overlayIt->second.spriteChains; auto& spriteVector = overlayIt->second.spriteChains;
spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount})); spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount}));
} }
}
/*! /*!
* \brief Clears the queue * \brief Clears the queue
@ -545,7 +566,7 @@ namespace Nz
pipelineEntry.enabled = false; pipelineEntry.enabled = false;
} }
for (auto& pipelinePair : layer.basicSprites) for (auto& pipelinePair : layer.opaqueSprites)
{ {
auto& pipelineEntry = pipelinePair.second; auto& pipelineEntry = pipelinePair.second;
@ -596,9 +617,11 @@ namespace Nz
} }
} }
layer.depthSortedMeshes.clear();
layer.depthSortedMeshData.clear();
layer.depthSortedSpriteData.clear();
layer.depthSortedSprites.clear();
layer.otherDrawables.clear(); layer.otherDrawables.clear();
layer.transparentModels.clear();
layer.transparentModelData.clear();
++it; ++it;
} }
} }
@ -613,44 +636,10 @@ namespace Nz
void ForwardRenderQueue::Sort(const AbstractViewer* viewer) void ForwardRenderQueue::Sort(const AbstractViewer* viewer)
{ {
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near); if (viewer->GetProjectionType() == ProjectionType_Orthogonal)
Vector3f viewerPos = viewer->GetEyePosition(); SortForOrthographic(viewer);
Vector3f viewerNormal = viewer->GetForward(); else
SortForPerspective(viewer);
for (auto& pair : layers)
{
Layer& layer = pair.second;
std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (std::size_t index1, std::size_t index2)
{
const Spheref& sphere1 = layer.transparentModelData[index1].squaredBoundingSphere;
const Spheref& sphere2 = layer.transparentModelData[index2].squaredBoundingSphere;
Vector3f position1 = sphere1.GetNegativeVertex(viewerNormal);
Vector3f position2 = sphere2.GetNegativeVertex(viewerNormal);
return nearPlane.Distance(position1) > nearPlane.Distance(position2);
});
for (auto& pipelinePair : layer.billboards)
{
for (auto& matPair : pipelinePair.second.materialMap)
{
const Material* mat = matPair.first;
if (mat->IsDepthSortingEnabled())
{
BatchedBillboardEntry& entry = matPair.second;
auto& billboardVector = entry.billboards;
std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos] (const BillboardData& data1, const BillboardData& data2)
{
return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center);
});
}
}
}
}
} }
/*! /*!
@ -715,12 +704,91 @@ namespace Nz
return layer; return layer;
} }
void ForwardRenderQueue::SortBillboards(Layer& layer, const Planef& nearPlane)
{
for (auto& pipelinePair : layer.billboards)
{
for (auto& matPair : pipelinePair.second.materialMap)
{
const Material* mat = matPair.first;
if (mat->IsDepthSortingEnabled())
{
BatchedBillboardEntry& entry = matPair.second;
auto& billboardVector = entry.billboards;
std::sort(billboardVector.begin(), billboardVector.end(), [&nearPlane] (const BillboardData& data1, const BillboardData& data2)
{
return nearPlane.Distance(data1.center) > nearPlane.Distance(data2.center);
});
}
}
}
}
void ForwardRenderQueue::SortForOrthographic(const AbstractViewer * viewer)
{
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
Vector3f viewerPos = viewer->GetEyePosition();
for (auto& pair : layers)
{
Layer& layer = pair.second;
std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2)
{
const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere;
const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere;
return nearPlane.Distance(sphere1.GetPosition()) < nearPlane.Distance(sphere2.GetPosition());
});
std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2)
{
const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position;
const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position;
return nearPlane.Distance(pos1) < nearPlane.Distance(pos2);
});
SortBillboards(layer, nearPlane);
}
}
void ForwardRenderQueue::SortForPerspective(const AbstractViewer* viewer)
{
Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near);
Vector3f viewerPos = viewer->GetEyePosition();
for (auto& pair : layers)
{
Layer& layer = pair.second;
std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2)
{
const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere;
const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere;
return viewerPos.SquaredDistance(sphere1.GetPosition()) > viewerPos.SquaredDistance(sphere2.GetPosition());
});
std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2)
{
const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position;
const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position;
return viewerPos.SquaredDistance(pos1) > viewerPos.SquaredDistance(pos2);
});
SortBillboards(layer, nearPlane);
}
}
/*! /*!
* \brief Handle the invalidation of an index buffer * \brief Handle the invalidation of an index buffer
* *
* \param indexBuffer Index buffer being invalidated * \param indexBuffer Index buffer being invalidated
*/ */
void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer)
{ {
for (auto& pair : layers) for (auto& pair : layers)
@ -757,7 +825,7 @@ namespace Nz
{ {
Layer& layer = pair.second; Layer& layer = pair.second;
for (auto& pipelineEntry : layer.basicSprites) for (auto& pipelineEntry : layer.opaqueSprites)
pipelineEntry.second.materialMap.erase(material); pipelineEntry.second.materialMap.erase(material);
for (auto& pipelineEntry : layer.billboards) for (auto& pipelineEntry : layer.billboards)
@ -779,7 +847,7 @@ namespace Nz
for (auto& pair : layers) for (auto& pair : layers)
{ {
Layer& layer = pair.second; Layer& layer = pair.second;
for (auto& pipelineEntry : layer.basicSprites) for (auto& pipelineEntry : layer.opaqueSprites)
{ {
for (auto& materialEntry : pipelineEntry.second.materialMap) for (auto& materialEntry : pipelineEntry.second.materialMap)
materialEntry.second.overlayMap.erase(texture); materialEntry.second.overlayMap.erase(texture);

View File

@ -33,8 +33,8 @@ namespace Nz
Vector2f uv; Vector2f uv;
}; };
std::size_t s_maxQuads = std::numeric_limits<UInt16>::max() / 6; UInt32 s_maxQuads = std::numeric_limits<UInt16>::max() / 6;
std::size_t s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB
} }
/*! /*!
@ -101,12 +101,15 @@ namespace Nz
if (!layer.opaqueModels.empty()) if (!layer.opaqueModels.empty())
DrawOpaqueModels(sceneData, layer); DrawOpaqueModels(sceneData, layer);
if (!layer.transparentModels.empty()) if (!layer.depthSortedMeshes.empty())
DrawTransparentModels(sceneData, layer); DrawTransparentModels(sceneData, layer);
if (!layer.basicSprites.empty()) if (!layer.opaqueSprites.empty())
DrawBasicSprites(sceneData, layer); DrawBasicSprites(sceneData, layer);
if (!layer.depthSortedSprites.empty())
DrawOrderedSprites(sceneData, layer);
if (!layer.billboards.empty()) if (!layer.billboards.empty())
DrawBillboards(sceneData, layer); DrawBillboards(sceneData, layer);
@ -309,7 +312,10 @@ namespace Nz
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
Renderer::SetVertexBuffer(&m_spriteBuffer); Renderer::SetVertexBuffer(&m_spriteBuffer);
for (auto& pipelinePair : layer.basicSprites) const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
for (auto& pipelinePair : layer.opaqueSprites)
{ {
const MaterialPipeline* pipeline = pipelinePair.first; const MaterialPipeline* pipeline = pipelinePair.first;
auto& pipelineEntry = pipelinePair.second; auto& pipelineEntry = pipelinePair.second;
@ -331,6 +337,9 @@ namespace Nz
// Position of the camera // Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
// Overlay texture unit
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
lastShader = shader; lastShader = shader;
} }
@ -343,10 +352,6 @@ namespace Nz
{ {
material->Apply(pipelineInstance); material->Apply(pipelineInstance);
unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler()); Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
auto& overlayMap = matEntry.overlayMap; auto& overlayMap = matEntry.overlayMap;
@ -370,7 +375,6 @@ namespace Nz
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer()); VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
std::size_t spriteCount = 0; std::size_t spriteCount = 0;
std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
do do
{ {
@ -797,6 +801,142 @@ namespace Nz
} }
} }
void ForwardRenderTechnique::DrawOrderedSprites(const SceneData & sceneData, ForwardRenderQueue::Layer & layer) const
{
NazaraAssert(sceneData.viewer, "Invalid viewer");
Renderer::SetIndexBuffer(&s_quadIndexBuffer);
Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity());
Renderer::SetVertexBuffer(&m_spriteBuffer);
const Material* lastMaterial = nullptr;
const MaterialPipeline* lastPipeline = nullptr;
const Shader* lastShader = nullptr;
const Texture* lastOverlay = nullptr;
const MaterialPipeline::Instance* pipelineInstance = nullptr;
const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay);
bool updateVertexBuffer = true;
const std::size_t maxSpriteCount = std::min<std::size_t>(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4);
std::size_t alreadyDrawnCount = 0;
std::size_t spriteIndex = 0;
std::size_t spriteChainOffset = 0;
auto splitChainIt = layer.depthSortedSprites.end();
for (auto it = layer.depthSortedSprites.begin(); it != layer.depthSortedSprites.end();)
{
if (updateVertexBuffer)
{
// We open the buffer in writing mode
BufferMapper<VertexBuffer> vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite);
VertexStruct_XYZ_Color_UV* vertices = static_cast<VertexStruct_XYZ_Color_UV*>(vertexMapper.GetPointer());
std::size_t availableSpriteSpace = maxSpriteCount;
bool split = false;
for (auto it2 = it; it2 != layer.depthSortedSprites.end(); ++it2)
{
const ForwardRenderQueue::UnbatchedSpriteData& spriteData = layer.depthSortedSpriteData[*it2];
std::size_t count = std::min(availableSpriteSpace, spriteData.spriteCount - spriteChainOffset);
std::memcpy(vertices, spriteData.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV));
vertices += count * 4;
availableSpriteSpace -= count;
// Have we treated the entire chain ?
if (count != spriteData.spriteCount)
{
// Oops, not enough space to store current chain
spriteChainOffset += count;
splitChainIt = it2;
split = true;
break;
}
// Switch to next sprite chain, if any
spriteChainOffset = 0;
}
spriteIndex = 0;
updateVertexBuffer = false;
if (!split)
splitChainIt = layer.depthSortedSprites.end();
}
std::size_t index = *it;
const ForwardRenderQueue::UnbatchedSpriteData& spriteData = layer.depthSortedSpriteData[index];
const Material* material = spriteData.material;
if (material != lastMaterial)
{
const MaterialPipeline* pipeline = material->GetPipeline();
if (pipeline != lastPipeline)
{
pipelineInstance = &pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor);
const Shader* shader = pipelineInstance->uberInstance->GetShader();
// Uniforms are conserved in our program, there's no point to send them back until they change
if (shader != lastShader)
{
// Index of uniforms in the shader
const ShaderUniforms* shaderUniforms = GetShaderUniforms(shader);
// Ambient color of the scene
shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor);
// Position of the camera
shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition());
// Overlay texture unit
shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit);
lastShader = shader;
}
lastPipeline = pipeline;
}
material->Apply(*pipelineInstance);
Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler());
lastMaterial = material;
}
const Texture* overlay = (spriteData.overlay) ? spriteData.overlay : &m_whiteTexture;
if (overlay != lastOverlay)
{
Renderer::SetTexture(overlayTextureUnit, overlay);
lastOverlay = overlay;
}
std::size_t spriteCount;
if (it != splitChainIt)
{
spriteCount = spriteData.spriteCount - alreadyDrawnCount;
alreadyDrawnCount = 0;
++it;
}
else
{
spriteCount = spriteChainOffset;
alreadyDrawnCount = spriteCount;
updateVertexBuffer = true;
// Restart at current iterator next time
}
Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, spriteIndex * 6, spriteCount * 6);
spriteIndex += spriteCount;
}
}
/*! /*!
* \brief Draws transparent models * \brief Draws transparent models
* *
@ -816,9 +956,9 @@ namespace Nz
const ShaderUniforms* shaderUniforms = nullptr; const ShaderUniforms* shaderUniforms = nullptr;
unsigned int lightCount = 0; unsigned int lightCount = 0;
for (unsigned int index : layer.transparentModels) for (std::size_t index : layer.depthSortedMeshes)
{ {
const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index]; const ForwardRenderQueue::UnbatchedModelData& modelData = layer.depthSortedMeshData[index];
// Material // Material
const Material* material = modelData.material; const Material* material = modelData.material;
@ -885,8 +1025,8 @@ namespace Nz
if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS) if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)
{ {
// Compute the closest lights // Compute the closest lights
Vector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition(); Vector3f position = matrix.GetTranslation() + modelData.obbSphere.GetPosition();
float radius = modelData.squaredBoundingSphere.radius; float radius = modelData.obbSphere.radius;
ChooseLights(Spheref(position, radius), false); ChooseLights(Spheref(position, radius), false);
for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i)

View File

@ -198,6 +198,7 @@ namespace Nz
pipelineInfo.blending = true; pipelineInfo.blending = true;
pipelineInfo.depthWrite = false; pipelineInfo.depthWrite = false;
pipelineInfo.faceCulling = false; pipelineInfo.faceCulling = false;
pipelineInfo.depthSorting = true;
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha; pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
pipelineInfo.srcBlend = BlendFunc_SrcAlpha; pipelineInfo.srcBlend = BlendFunc_SrcAlpha;
@ -208,6 +209,7 @@ namespace Nz
pipelineInfo.depthBuffer = true; pipelineInfo.depthBuffer = true;
pipelineInfo.depthWrite = false; pipelineInfo.depthWrite = false;
pipelineInfo.faceCulling = false; pipelineInfo.faceCulling = false;
pipelineInfo.depthSorting = true;
pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha; pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha;
pipelineInfo.srcBlend = BlendFunc_SrcAlpha; pipelineInfo.srcBlend = BlendFunc_SrcAlpha;

View File

@ -62,9 +62,9 @@ namespace Nz
if (cpShape* shape = cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, &queryInfo)) if (cpShape* shape = cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, &queryInfo))
{ {
result->closestPoint.Set(queryInfo.point.x, queryInfo.point.y); result->closestPoint.Set(Nz::Vector2<cpFloat>(queryInfo.point.x, queryInfo.point.y));
result->distance = queryInfo.distance; result->distance = float(queryInfo.distance);
result->fraction.Set(queryInfo.gradient.x, queryInfo.gradient.y); result->fraction.Set(Nz::Vector2<cpFloat>(queryInfo.gradient.x, queryInfo.gradient.y));
result->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape)); result->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
return true; return true;
@ -90,9 +90,9 @@ namespace Nz
ResultType results = static_cast<ResultType>(data); ResultType results = static_cast<ResultType>(data);
RaycastHit hitInfo; RaycastHit hitInfo;
hitInfo.fraction = alpha; hitInfo.fraction = float(alpha);
hitInfo.hitNormal.Set(normal.x, normal.y); hitInfo.hitNormal.Set(Nz::Vector2<cpFloat>(normal.x, normal.y));
hitInfo.hitPos.Set(point.x, point.y); hitInfo.hitPos.Set(Nz::Vector2<cpFloat>(point.x, point.y));
hitInfo.nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape)); hitInfo.nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(shape));
results->emplace_back(std::move(hitInfo)); results->emplace_back(std::move(hitInfo));
@ -116,9 +116,9 @@ namespace Nz
if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo)) if (cpShape* shape = cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo))
{ {
hitInfo->fraction = queryInfo.alpha; hitInfo->fraction = float(queryInfo.alpha);
hitInfo->hitNormal.Set(queryInfo.normal.x, queryInfo.normal.y); hitInfo->hitNormal.Set(Nz::Vector2<cpFloat>(queryInfo.normal.x, queryInfo.normal.y));
hitInfo->hitPos.Set(queryInfo.point.x, queryInfo.point.y); hitInfo->hitPos.Set(Nz::Vector2<cpFloat>(queryInfo.point.x, queryInfo.point.y));
hitInfo->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(queryInfo.shape)); hitInfo->nearestBody = static_cast<Nz::RigidBody2D*>(cpShapeGetUserData(queryInfo.shape));
return true; return true;

View File

@ -215,7 +215,7 @@ namespace Nz
cpVect vel = cpBodyGetVelocity(m_handle); cpVect vel = cpBodyGetVelocity(m_handle);
Destroy(); Destroy();
Create(mass, moment); Create(float(mass), float(moment));
cpBodySetAngle(m_handle, rot); cpBodySetAngle(m_handle, rot);
cpBodySetPosition(m_handle, pos); cpBodySetPosition(m_handle, pos);

View File

@ -121,9 +121,7 @@ namespace Nz
break; break;
default: default:
// Peut être rajouté par une extension return; //< Block NVidia buffer usage hint for now
ss << "Unknown";
break;
} }
ss << '\n'; ss << '\n';

View File

@ -91,8 +91,8 @@ namespace Nz
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max()); bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0); IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, 0);
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.storage, 0); VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, 0);
// Index buffer // Index buffer
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
@ -236,7 +236,7 @@ namespace Nz
// Index buffer // Index buffer
bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max()); bool largeIndices = (vertexCount > std::numeric_limits<UInt16>::max());
IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0); IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, 0);
IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite);
IndexIterator index = indexMapper.begin(); IndexIterator index = indexMapper.begin();
@ -251,7 +251,7 @@ namespace Nz
indexMapper.Unmap(); indexMapper.Unmap();
// Vertex buffer // Vertex buffer
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0); VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, 0);
BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_WriteOnly); BufferMapper<VertexBuffer> vertexMapper(vertexBuffer, BufferAccess_WriteOnly);
MeshVertex* vertices = static_cast<MeshVertex*>(vertexMapper.GetPointer()); MeshVertex* vertices = static_cast<MeshVertex*>(vertexMapper.GetPointer());

View File

@ -233,8 +233,8 @@ namespace Nz
} }
// Création des buffers // Création des buffers
IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), indices.size(), parameters.storage, 0); IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits<UInt16>::max(), UInt32(indices.size()), parameters.storage, 0);
VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0); VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, 0);
// Remplissage des indices // Remplissage des indices
IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly);

View File

@ -228,7 +228,7 @@ namespace Nz
if (p < 0) if (p < 0)
{ {
p += m_positions.size() - 1; p += static_cast<int>(m_positions.size() - 1);
if (p < 0) if (p < 0)
{ {
Error("Vertex index out of range (" + String::Number(p) + " < 0"); Error("Vertex index out of range (" + String::Number(p) + " < 0");
@ -239,7 +239,7 @@ namespace Nz
if (n < 0) if (n < 0)
{ {
n += m_normals.size() - 1; n += static_cast<int>(m_normals.size() - 1);
if (n < 0) if (n < 0)
{ {
Error("Normal index out of range (" + String::Number(n) + " < 0"); Error("Normal index out of range (" + String::Number(n) + " < 0");
@ -250,7 +250,7 @@ namespace Nz
if (t < 0) if (t < 0)
{ {
t += m_texCoords.size() - 1; t += static_cast<int>(m_texCoords.size() - 1);
if (t < 0) if (t < 0)
{ {
Error("Texture coordinates index out of range (" + String::Number(t) + " < 0"); Error("Texture coordinates index out of range (" + String::Number(t) + " < 0");

View File

@ -12,38 +12,38 @@ namespace Nz
{ {
namespace namespace
{ {
UInt32 GetterSequential(const void* buffer, unsigned int i) UInt32 GetterSequential(const void* buffer, std::size_t i)
{ {
NazaraUnused(buffer); NazaraUnused(buffer);
return i; return static_cast<UInt32>(i);
} }
UInt32 Getter16(const void* buffer, unsigned int i) UInt32 Getter16(const void* buffer, std::size_t i)
{ {
const UInt16* ptr = static_cast<const UInt16*>(buffer); const UInt16* ptr = static_cast<const UInt16*>(buffer);
return ptr[i]; return ptr[i];
} }
UInt32 Getter32(const void* buffer, unsigned int i) UInt32 Getter32(const void* buffer, std::size_t i)
{ {
const UInt32* ptr = static_cast<const UInt32*>(buffer); const UInt32* ptr = static_cast<const UInt32*>(buffer);
return ptr[i]; return ptr[i];
} }
void Setter16(void* buffer, unsigned int i, UInt32 value) void Setter16(void* buffer, std::size_t i, UInt32 value)
{ {
UInt16* ptr = static_cast<UInt16*>(buffer); UInt16* ptr = static_cast<UInt16*>(buffer);
ptr[i] = static_cast<UInt16>(value); ptr[i] = static_cast<UInt16>(value);
} }
void Setter32(void* buffer, unsigned int i, UInt32 value) void Setter32(void* buffer, std::size_t i, UInt32 value)
{ {
UInt32* ptr = static_cast<UInt32*>(buffer); UInt32* ptr = static_cast<UInt32*>(buffer);
ptr[i] = value; ptr[i] = value;
} }
void SetterError(void*, unsigned int, UInt32) void SetterError(void*, std::size_t, UInt32)
{ {
NazaraError("Index buffer opened with read-only access"); NazaraError("Index buffer opened with read-only access");
} }
@ -113,15 +113,9 @@ namespace Nz
{ {
} }
UInt32 IndexMapper::Get(unsigned int i) const UInt32 IndexMapper::Get(std::size_t i) const
{ {
#if NAZARA_UTILITY_SAFE NazaraAssert(i < m_indexCount, "Index out of range");
if (i >= m_indexCount)
{
NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')');
return 0;
}
#endif
return m_getter(m_mapper.GetPointer(), i); return m_getter(m_mapper.GetPointer(), i);
} }
@ -131,20 +125,14 @@ namespace Nz
return m_mapper.GetBuffer(); return m_mapper.GetBuffer();
} }
unsigned int IndexMapper::GetIndexCount() const std::size_t IndexMapper::GetIndexCount() const
{ {
return m_indexCount; return m_indexCount;
} }
void IndexMapper::Set(unsigned int i, UInt32 value) void IndexMapper::Set(std::size_t i, UInt32 value)
{ {
#if NAZARA_UTILITY_SAFE NazaraAssert(i < m_indexCount, "Index out of range");
if (i >= m_indexCount)
{
NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')');
return;
}
#endif
m_setter(m_mapper.GetPointer(), i, value); m_setter(m_mapper.GetPointer(), i, value);
} }

View File

@ -79,7 +79,7 @@ namespace Nz
NazaraAssert(subMesh, "Invalid submesh"); NazaraAssert(subMesh, "Invalid submesh");
NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type"); NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type");
m_impl->subMeshes.push_back(subMesh); m_impl->subMeshes.emplace_back(subMesh);
InvalidateAABB(); InvalidateAABB();
} }
@ -92,10 +92,10 @@ namespace Nz
NazaraAssert(subMesh, "Invalid submesh"); NazaraAssert(subMesh, "Invalid submesh");
NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type"); NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type");
UInt32 index = m_impl->subMeshes.size(); std::size_t index = m_impl->subMeshes.size();
m_impl->subMeshes.push_back(subMesh); m_impl->subMeshes.emplace_back(subMesh);
m_impl->subMeshMap[identifier] = index; m_impl->subMeshMap[identifier] = static_cast<UInt32>(index);
InvalidateAABB(); InvalidateAABB();
} }
@ -349,11 +349,11 @@ namespace Nz
if (!m_impl->aabbUpdated) if (!m_impl->aabbUpdated)
{ {
UInt32 subMeshCount = m_impl->subMeshes.size(); std::size_t subMeshCount = m_impl->subMeshes.size();
if (subMeshCount > 0) if (subMeshCount > 0)
{ {
m_impl->aabb.Set(m_impl->subMeshes[0]->GetAABB()); m_impl->aabb.Set(m_impl->subMeshes[0]->GetAABB());
for (UInt32 i = 1; i < subMeshCount; ++i) for (std::size_t i = 1; i < subMeshCount; ++i)
m_impl->aabb.ExtendTo(m_impl->subMeshes[i]->GetAABB()); m_impl->aabb.ExtendTo(m_impl->subMeshes[i]->GetAABB());
} }
else else
@ -407,7 +407,7 @@ namespace Nz
{ {
NazaraAssert(m_impl, "Mesh should be created first"); NazaraAssert(m_impl, "Mesh should be created first");
return m_impl->materialData.size(); return static_cast<UInt32>(m_impl->materialData.size());
} }
Skeleton* Mesh::GetSkeleton() Skeleton* Mesh::GetSkeleton()
@ -466,7 +466,7 @@ namespace Nz
{ {
NazaraAssert(m_impl, "Mesh should be created first"); NazaraAssert(m_impl, "Mesh should be created first");
return m_impl->subMeshes.size(); return static_cast<UInt32>(m_impl->subMeshes.size());
} }
UInt32 Mesh::GetSubMeshIndex(const String& identifier) const UInt32 Mesh::GetSubMeshIndex(const String& identifier) const

View File

@ -243,7 +243,7 @@ namespace Nz
m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly) m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly)
if (m_font) if (m_font)
m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, m_font->GetSizeInfo(m_characterSize).lineHeight), 0}); m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, float(m_font->GetSizeInfo(m_characterSize).lineHeight)), 0});
else else
m_lines.emplace_back(Line{Rectf::Zero(), 0}); m_lines.emplace_back(Line{Rectf::Zero(), 0});
} }
@ -354,7 +354,7 @@ namespace Nz
{ {
glyph.atlas = nullptr; glyph.atlas = nullptr;
glyph.bounds.Set(m_drawPos.x, m_drawPos.y, float(advance), sizeInfo.lineHeight); glyph.bounds.Set(float(m_drawPos.x), float(m_drawPos.y), float(advance), float(sizeInfo.lineHeight));
glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop)); glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop));
glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop)); glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop));
@ -377,7 +377,7 @@ namespace Nz
m_drawPos.x = 0; m_drawPos.x = 0;
m_drawPos.y += sizeInfo.lineHeight; m_drawPos.y += sizeInfo.lineHeight;
m_lines.emplace_back(Line{Rectf(0.f, sizeInfo.lineHeight * m_lines.size(), 0.f, sizeInfo.lineHeight), m_glyphs.size() + 1}); m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1});
break; break;
} }
} }

View File

@ -72,12 +72,12 @@ namespace Nz
if (!m_impl->aabbUpdated) if (!m_impl->aabbUpdated)
{ {
UInt32 jointCount = m_impl->joints.size(); std::size_t jointCount = m_impl->joints.size();
if (jointCount > 0) if (jointCount > 0)
{ {
Vector3f pos = m_impl->joints[0].GetPosition(); Vector3f pos = m_impl->joints[0].GetPosition();
m_impl->aabb.Set(pos.x, pos.y, pos.z, 0.f, 0.f, 0.f); m_impl->aabb.Set(pos.x, pos.y, pos.z, 0.f, 0.f, 0.f);
for (UInt32 i = 1; i < jointCount; ++i) for (std::size_t i = 1; i < jointCount; ++i)
m_impl->aabb.ExtendTo(m_impl->joints[i].GetPosition()); m_impl->aabb.ExtendTo(m_impl->joints[i].GetPosition());
} }
else else
@ -219,7 +219,7 @@ namespace Nz
} }
#endif #endif
return m_impl->joints.size(); return static_cast<UInt32>(m_impl->joints.size());
} }
int Skeleton::GetJointIndex(const String& jointName) const int Skeleton::GetJointIndex(const String& jointName) const
@ -411,16 +411,9 @@ namespace Nz
String name = m_impl->joints[i].GetName(); String name = m_impl->joints[i].GetName();
if (!name.IsEmpty()) if (!name.IsEmpty())
{ {
#if NAZARA_UTILITY_SAFE NazaraAssert(m_impl->jointMap.find(name) == m_impl->jointMap.end(), "Joint name \"" + name + "\" is already present in joint map");
auto it = m_impl->jointMap.find(name);
if (it != m_impl->jointMap.end())
{
NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + String::Number(it->second));
continue;
}
#endif
m_impl->jointMap[name] = i; m_impl->jointMap[name] = static_cast<UInt32>(i);
} }
} }

View File

@ -66,18 +66,9 @@ namespace Nz
return true; return true;
} }
UInt32 TriangleIterator::operator[](unsigned int i) const UInt32 TriangleIterator::operator[](std::size_t i) const
{ {
#if NAZARA_UTILITY_SAFE NazaraAssert(i < 3, "Index out of range");
if (i >= 3)
{
StringStream ss;
ss << "Index out of range: (" << i << " >= 3)";
NazaraError(ss);
throw std::domain_error(ss.ToString());
}
#endif
return m_triangleIndices[i]; return m_triangleIndices[i];
} }

View File

@ -1,5 +1,6 @@
#include <Nazara/Math/Algorithm.hpp> #include <Nazara/Math/Algorithm.hpp>
#include <Catch/catch.hpp> #include <Catch/catch.hpp>
#include <limits>
TEST_CASE("Approach", "[MATH][ALGORITHM]") TEST_CASE("Approach", "[MATH][ALGORITHM]")
{ {
@ -48,6 +49,11 @@ TEST_CASE("CountBits", "[MATH][ALGORITHM]")
{ {
REQUIRE(Nz::CountBits(0) == 0); REQUIRE(Nz::CountBits(0) == 0);
} }
SECTION("Number 0xFFFFFFFF has 32 bit set to 1")
{
REQUIRE(Nz::CountBits(0xFFFFFFFF) == 32);
}
} }
TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]") TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]")
@ -205,9 +211,19 @@ TEST_CASE("NumberEquals", "[MATH][ALGORITHM]")
CHECK(Nz::NumberEquals(2.35, 2.35, 0.01)); CHECK(Nz::NumberEquals(2.35, 2.35, 0.01));
} }
SECTION("3 and 4 unsigned should be the same at 1") SECTION("0 and 4 unsigned should be the same at 1")
{ {
CHECK(Nz::NumberEquals(3U, 4U, 1U)); CHECK(Nz::NumberEquals(0U, 4U, 4U));
}
SECTION("Maximum integer and -1 should not be equal")
{
CHECK_FALSE(Nz::NumberEquals(std::numeric_limits<int>::max(), -1));
}
SECTION("Maximum integer and minimum integer should not be equal")
{
CHECK_FALSE(Nz::NumberEquals(std::numeric_limits<int>::max(), std::numeric_limits<int>::min()));
} }
} }

View File

@ -38,7 +38,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
WHEN("We add an entity") WHEN("We add an entity")
{ {
const Ndk::EntityHandle& entity = world.CreateEntity(); Ndk::EntityHandle entity = world.CreateEntity();
entity->AddComponent<Ndk::VelocityComponent>(); entity->AddComponent<Ndk::VelocityComponent>();
THEN("System should have it") THEN("System should have it")
@ -50,7 +50,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
WHEN("We add an entity with excluded component") WHEN("We add an entity with excluded component")
{ {
const Ndk::EntityHandle& entity = world.CreateEntity(); Ndk::EntityHandle entity = world.CreateEntity();
entity->AddComponent<Ndk::VelocityComponent>(); entity->AddComponent<Ndk::VelocityComponent>();
entity->AddComponent<Ndk::NodeComponent>(); entity->AddComponent<Ndk::NodeComponent>();

View File

@ -57,18 +57,18 @@ SCENARIO("Entity", "[NDK][ENTITY]")
{ {
Ndk::World world; Ndk::World world;
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>(); Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
const Ndk::EntityHandle& entity = world.CreateEntity(); Ndk::EntityHandle entity = world.CreateEntity();
WHEN("We add our UpdateComponent") WHEN("We add our UpdateComponent")
{ {
UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>(); UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>();
REQUIRE(!updatableComponent.IsUpdated()); CHECK(!updatableComponent.IsUpdated());
THEN("Update the world should update the entity's component") THEN("Update the world should update the entity's component")
{ {
world.Update(1.f); world.Update(1.f);
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>(); UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
REQUIRE(updatableComponentGet.IsUpdated()); CHECK(updatableComponentGet.IsUpdated());
} }
THEN("Update the world should not update the entity's component if it's disabled") THEN("Update the world should not update the entity's component if it's disabled")
@ -76,14 +76,14 @@ SCENARIO("Entity", "[NDK][ENTITY]")
entity->Enable(false); entity->Enable(false);
world.Update(1.f); world.Update(1.f);
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>(); UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
REQUIRE(!updatableComponentGet.IsUpdated()); CHECK(!updatableComponentGet.IsUpdated());
} }
THEN("We can remove its component") THEN("We can remove its component")
{ {
entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>()); entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>());
world.Update(1.f); world.Update(1.f);
REQUIRE(!entity->HasComponent<UpdatableComponent>()); CHECK(!entity->HasComponent<UpdatableComponent>());
} }
} }
@ -94,7 +94,7 @@ SCENARIO("Entity", "[NDK][ENTITY]")
THEN("It's no more valid") THEN("It's no more valid")
{ {
REQUIRE(!world.IsEntityValid(entity)); CHECK(!world.IsEntityValid(entity));
} }
} }
} }

View File

@ -7,7 +7,7 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
GIVEN("A world & an entity") GIVEN("A world & an entity")
{ {
Ndk::World world; Ndk::World world;
const Ndk::EntityHandle& entity = world.CreateEntity(); Ndk::EntityHandle entity = world.CreateEntity();
WHEN("We set the ownership of the entity to our owner") WHEN("We set the ownership of the entity to our owner")
{ {
@ -15,13 +15,21 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
THEN("Entity is still valid") THEN("Entity is still valid")
{ {
REQUIRE(entity.IsValid()); CHECK(entity.IsValid());
} }
THEN("Resetting or getting out of scope is no more valid") THEN("Resetting or getting out of scope is no more valid")
{ {
entityOwner.Reset(); entityOwner.Reset();
world.Update(1.f); world.Update(1.f);
CHECK(!entity.IsValid());
}
THEN("Moving an entity owner works")
{
Ndk::EntityOwner entityOwner2(std::move(entityOwner));
entityOwner2.Reset();
world.Update(1.f);
REQUIRE(!entity.IsValid()); REQUIRE(!entity.IsValid());
} }
} }

View File

@ -28,21 +28,79 @@ class TestState : public Ndk::State
bool m_isUpdated; bool m_isUpdated;
}; };
class SecondTestState : public Ndk::State
{
public:
void Enter(Ndk::StateMachine& /*fsm*/) override
{
m_isUpdated = false;
}
bool IsUpdated() const
{
return m_isUpdated;
}
void Leave(Ndk::StateMachine& /*fsm*/) override
{
}
bool Update(Ndk::StateMachine& fsm, float /*elapsedTime*/) override
{
if (fsm.IsTopState(this))
m_isUpdated = true;
return true;
}
private:
bool m_isUpdated;
};
SCENARIO("State & StateMachine", "[NDK][STATE]") SCENARIO("State & StateMachine", "[NDK][STATE]")
{ {
GIVEN("A statemachine with our TestState") GIVEN("A statemachine with our test states")
{ {
std::shared_ptr<TestState> testState = std::make_shared<TestState>(); std::shared_ptr<TestState> testState = std::make_shared<TestState>();
Ndk::StateMachine stateMachine(testState); std::shared_ptr<SecondTestState> secondTestState = std::make_shared<SecondTestState>();
Ndk::StateMachine stateMachine(secondTestState);
stateMachine.PushState(testState);
REQUIRE(!testState->IsUpdated()); REQUIRE(!testState->IsUpdated());
REQUIRE(!secondTestState->IsUpdated());
WHEN("We update our machine") WHEN("We update our machine")
{ {
stateMachine.Update(1.f); stateMachine.Update(1.f);
THEN("Our state has been updated") THEN("Our state on the top has been updated but not the bottom one")
{ {
REQUIRE(stateMachine.IsTopState(testState.get()));
REQUIRE(!stateMachine.IsTopState(secondTestState.get()));
REQUIRE(testState->IsUpdated()); REQUIRE(testState->IsUpdated());
REQUIRE(!secondTestState->IsUpdated());
}
}
WHEN("We exchange the states' positions while emptying the stack")
{
REQUIRE(stateMachine.PopStatesUntil(secondTestState));
REQUIRE(stateMachine.IsTopState(secondTestState.get()));
std::shared_ptr<Ndk::State> oldState = stateMachine.PopState();
REQUIRE(stateMachine.PopState() == nullptr);
stateMachine.SetState(testState);
stateMachine.PushState(oldState);
stateMachine.Update(1.f);
THEN("Both states should be updated")
{
REQUIRE(!stateMachine.IsTopState(testState.get()));
REQUIRE(stateMachine.IsTopState(secondTestState.get()));
REQUIRE(testState->IsUpdated());
REQUIRE(secondTestState->IsUpdated());
} }
} }
} }

View File

@ -79,7 +79,7 @@ SCENARIO("World", "[NDK][WORLD]")
AND_WHEN("We update our world with our entity") AND_WHEN("We update our world with our entity")
{ {
REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>()); REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>());
const Ndk::EntityHandle& entity = world.CreateEntity(); Ndk::EntityHandle entity = world.CreateEntity();
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>(); UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
THEN("Our entity component must be updated") THEN("Our entity component must be updated")