Merge remote-tracking branch 'refs/remotes/origin/master' into entitylist-refactor

This commit is contained in:
Lynix 2017-04-21 22:08:13 +02:00
commit c1e9fe7b04
5 changed files with 199 additions and 42 deletions

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

@ -73,7 +73,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 +81,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 +97,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 +107,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 +115,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 +132,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 +142,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,7 +150,7 @@ 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 TransparentModelData
{ {
@ -160,7 +160,7 @@ namespace Nz
const Material* material; const Material* material;
}; };
typedef std::vector<std::size_t> TransparentModelContainer; using TransparentModelContainer = std::vector<std::size_t>;
struct Layer struct Layer
{ {

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

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