diff --git a/NazaraModuleTemplate/include/Nazara/ModuleName/Config.hpp b/NazaraModuleTemplate/include/Nazara/ModuleName/Config.hpp index 7f620bb59..d311f8991 100644 --- a/NazaraModuleTemplate/include/Nazara/ModuleName/Config.hpp +++ b/NazaraModuleTemplate/include/Nazara/ModuleName/Config.hpp @@ -27,17 +27,17 @@ #ifndef NAZARA_CONFIG_MODULENAME_HPP #define NAZARA_CONFIG_MODULENAME_HPP -/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci +/// Each modification of a parameter needs a recompilation of the module -// Utilise le MemoryManager pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) #define NAZARA_MODULENAME_MANAGE_MEMORY 0 -// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +// Activate the security tests based on the code (Advised for development) #define NAZARA_MODULENAME_SAFE 1 -/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code +/// Each modification of a parameter following implies a modification (often minor) of the code -/// Vérification des valeurs et types de certaines constantes +/// Checking the values and types of certain constants #include #if !defined(NAZARA_STATIC) diff --git a/NazaraModuleTemplate/include/Nazara/ModuleName/ConfigCheck.hpp b/NazaraModuleTemplate/include/Nazara/ModuleName/ConfigCheck.hpp index 8decf9091..723b9ac02 100644 --- a/NazaraModuleTemplate/include/Nazara/ModuleName/ConfigCheck.hpp +++ b/NazaraModuleTemplate/include/Nazara/ModuleName/ConfigCheck.hpp @@ -7,13 +7,13 @@ #ifndef NAZARA_CONFIG_CHECK_MODULENAME_HPP #define NAZARA_CONFIG_CHECK_MODULENAME_HPP -/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp +/// This file is used to check the constant values defined in Config.hpp #include #define CheckType(name, type, err) static_assert(std::is_ ##type ::value, #type err) #define CheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) -// On force la valeur de MANAGE_MEMORY en mode debug +// We force the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_MODULENAME_MANAGE_MEMORY #undef NAZARA_MODULENAME_MANAGE_MEMORY #define NAZARA_MODULENAME_MANAGE_MEMORY 0 diff --git a/NazaraModuleTemplate/include/Nazara/ModuleName/DebugOff.hpp b/NazaraModuleTemplate/include/Nazara/ModuleName/DebugOff.hpp index 3e9cda8eb..29147254e 100644 --- a/NazaraModuleTemplate/include/Nazara/ModuleName/DebugOff.hpp +++ b/NazaraModuleTemplate/include/Nazara/ModuleName/DebugOff.hpp @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Module name" // For conditions of distribution and use, see copyright notice in Config.hpp -// On suppose que Debug.hpp a déjà été inclus, tout comme Config.hpp +// We suppose that Debug.hpp is already included, same goes for Config.hpp #if NAZARA_MODULENAME_MANAGE_MEMORY #undef delete #undef new diff --git a/SDK/include/NDK/Application.hpp b/SDK/include/NDK/Application.hpp index 2ada48555..06e13cd47 100644 --- a/SDK/include/NDK/Application.hpp +++ b/SDK/include/NDK/Application.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #endif namespace Ndk diff --git a/SDK/include/NDK/BaseComponent.hpp b/SDK/include/NDK/BaseComponent.hpp index 8a4d51bfe..427fb017e 100644 --- a/SDK/include/NDK/BaseComponent.hpp +++ b/SDK/include/NDK/BaseComponent.hpp @@ -23,20 +23,22 @@ namespace Ndk using Factory = std::function; BaseComponent(ComponentIndex componentIndex); - BaseComponent(const BaseComponent&) = default; BaseComponent(BaseComponent&&) = default; virtual ~BaseComponent(); virtual std::unique_ptr Clone() const = 0; + inline const EntityHandle& GetEntity() const; ComponentIndex GetIndex() const; inline static ComponentIndex GetMaxComponentIndex(); - BaseComponent& operator=(const BaseComponent&) = default; + BaseComponent& operator=(const BaseComponent&) = delete; BaseComponent& operator=(BaseComponent&&) = default; protected: + BaseComponent(const BaseComponent&) = default; + ComponentIndex m_componentIndex; EntityHandle m_entity; @@ -47,6 +49,7 @@ namespace Ndk virtual void OnComponentAttached(BaseComponent& component); virtual void OnComponentDetached(BaseComponent& component); virtual void OnDetached(); + virtual void OnEntityDestruction(); void SetEntity(Entity* entity); diff --git a/SDK/include/NDK/BaseComponent.inl b/SDK/include/NDK/BaseComponent.inl index 7abade990..0596eb589 100644 --- a/SDK/include/NDK/BaseComponent.inl +++ b/SDK/include/NDK/BaseComponent.inl @@ -19,11 +19,19 @@ namespace Ndk { } + /*! + * \brief Gets the entity owning this component + * \return A handle to the entity owning this component, may be invalid if no entity owns it. + */ + inline const EntityHandle& BaseComponent::GetEntity() const + { + return m_entity; + } + /*! * \brief Gets the index of the component * \return Index of the component */ - inline ComponentIndex BaseComponent::GetIndex() const { return m_componentIndex; diff --git a/SDK/include/NDK/BaseSystem.hpp b/SDK/include/NDK/BaseSystem.hpp index a323f2952..99dcbf768 100644 --- a/SDK/include/NDK/BaseSystem.hpp +++ b/SDK/include/NDK/BaseSystem.hpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace Ndk @@ -33,7 +34,7 @@ namespace Ndk bool Filters(const Entity* entity) const; - inline const std::vector& GetEntities() const; + inline const EntityList& GetEntities() const; inline SystemIndex GetIndex() const; inline int GetUpdateOrder() const; inline float GetUpdateRate() const; @@ -84,12 +85,11 @@ namespace Ndk static inline bool Initialize(); static inline void Uninitialize(); - std::vector m_entities; - Nz::Bitset m_entityBits; Nz::Bitset<> m_excludedComponents; mutable Nz::Bitset<> m_filterResult; Nz::Bitset<> m_requiredAnyComponents; Nz::Bitset<> m_requiredComponents; + EntityList m_entities; SystemIndex m_systemIndex; World* m_world; bool m_updateEnabled; diff --git a/SDK/include/NDK/BaseSystem.inl b/SDK/include/NDK/BaseSystem.inl index e949d254b..5969dd8e3 100644 --- a/SDK/include/NDK/BaseSystem.inl +++ b/SDK/include/NDK/BaseSystem.inl @@ -56,7 +56,7 @@ namespace Ndk * \return A constant reference to the list of entities */ - inline const std::vector& BaseSystem::GetEntities() const + inline const EntityList& BaseSystem::GetEntities() const { return m_entities; } @@ -121,10 +121,7 @@ namespace Ndk inline bool BaseSystem::HasEntity(const Entity* entity) const { - if (!entity) - return false; - - return m_entityBits.UnboundedTest(entity->GetId()); + return m_entities.Has(entity); } /*! @@ -288,9 +285,7 @@ namespace Ndk { NazaraAssert(entity, "Invalid entity"); - m_entities.emplace_back(entity); - m_entityBits.UnboundedSet(entity->GetId(), true); - + m_entities.Insert(entity); entity->RegisterSystem(m_systemIndex); OnEntityAdded(entity); @@ -308,14 +303,7 @@ namespace Ndk { NazaraAssert(entity, "Invalid entity"); - auto it = std::find(m_entities.begin(), m_entities.end(), *entity); - NazaraAssert(it != m_entities.end(), "Entity is not part of this system"); - - // To avoid moving a lot of handles, we swap and pop - std::swap(*it, m_entities.back()); - m_entities.pop_back(); // We get it out of the vector - - m_entityBits.Reset(entity->GetId()); + m_entities.Remove(entity); entity->UnregisterSystem(m_systemIndex); OnEntityRemoved(entity); // And we alert our callback @@ -360,7 +348,7 @@ namespace Ndk } /*! - * \brief Uninitializes the BaseSystem + * \brief Uninitialize the BaseSystem */ inline void BaseSystem::Uninitialize() diff --git a/SDK/include/NDK/BaseWidget.hpp b/SDK/include/NDK/BaseWidget.hpp index 723e93e80..b4ea5b9d2 100644 --- a/SDK/include/NDK/BaseWidget.hpp +++ b/SDK/include/NDK/BaseWidget.hpp @@ -12,9 +12,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include diff --git a/SDK/include/NDK/BaseWidget.inl b/SDK/include/NDK/BaseWidget.inl index 63b71a942..e84a67a49 100644 --- a/SDK/include/NDK/BaseWidget.inl +++ b/SDK/include/NDK/BaseWidget.inl @@ -10,8 +10,8 @@ namespace Ndk { inline BaseWidget::BaseWidget() : m_canvasIndex(InvalidCanvasIndex), - m_backgroundColor(Nz::Color(230, 230, 230, 255)), m_canvas(nullptr), + m_backgroundColor(Nz::Color(230, 230, 230, 255)), m_cursor(Nz::SystemCursor_Default), m_contentSize(50.f, 50.f), m_widgetParent(nullptr), @@ -33,6 +33,7 @@ namespace Ndk inline void BaseWidget::AddChild(std::unique_ptr&& widget) { widget->Show(m_visible); + widget->SetParent(this); m_children.emplace_back(std::move(widget)); } diff --git a/SDK/include/NDK/Canvas.hpp b/SDK/include/NDK/Canvas.hpp index 0cc314b73..f37ad3cda 100644 --- a/SDK/include/NDK/Canvas.hpp +++ b/SDK/include/NDK/Canvas.hpp @@ -9,8 +9,8 @@ #include #include -#include -#include +#include +#include namespace Ndk { @@ -44,13 +44,13 @@ namespace Ndk void UnregisterWidget(std::size_t index); private: - void OnMouseButtonPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event); - void OnMouseButtonRelease(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event); - void OnMouseMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseMoveEvent& event); - void OnMouseLeft(const Nz::EventHandler* eventHandler); - void OnKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event); - void OnKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event); - void OnTextEntered(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::TextEvent& event); + void OnEventMouseButtonPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event); + void OnEventMouseButtonRelease(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseButtonEvent& event); + void OnEventMouseMoved(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::MouseMoveEvent& event); + void OnEventMouseLeft(const Nz::EventHandler* eventHandler); + void OnEventKeyPressed(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event); + void OnEventKeyReleased(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::KeyEvent& event); + void OnEventTextEntered(const Nz::EventHandler* eventHandler, const Nz::WindowEvent::TextEvent& event); struct WidgetBox { diff --git a/SDK/include/NDK/Canvas.inl b/SDK/include/NDK/Canvas.inl index 3dd5de87f..f3a8dea88 100644 --- a/SDK/include/NDK/Canvas.inl +++ b/SDK/include/NDK/Canvas.inl @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in Prerequesites.hpp #include -#include +#include namespace Ndk { @@ -20,13 +20,13 @@ namespace Ndk RegisterToCanvas(); // Connect to every meaningful event - m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, this, &Canvas::OnKeyPressed); - m_keyReleasedSlot.Connect(eventHandler.OnKeyReleased, this, &Canvas::OnKeyReleased); - m_mouseButtonPressedSlot.Connect(eventHandler.OnMouseButtonPressed, this, &Canvas::OnMouseButtonPressed); - m_mouseButtonReleasedSlot.Connect(eventHandler.OnMouseButtonReleased, this, &Canvas::OnMouseButtonRelease); - m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnMouseMoved); - m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnMouseLeft); - m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnTextEntered); + m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, this, &Canvas::OnEventKeyPressed); + m_keyReleasedSlot.Connect(eventHandler.OnKeyReleased, this, &Canvas::OnEventKeyReleased); + m_mouseButtonPressedSlot.Connect(eventHandler.OnMouseButtonPressed, this, &Canvas::OnEventMouseButtonPressed); + m_mouseButtonReleasedSlot.Connect(eventHandler.OnMouseButtonReleased, this, &Canvas::OnEventMouseButtonRelease); + m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved); + m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnEventMouseLeft); + m_textEnteredSlot.Connect(eventHandler.OnTextEntered, this, &Canvas::OnEventTextEntered); // Disable padding by default SetPadding(0.f, 0.f, 0.f, 0.f); diff --git a/SDK/include/NDK/Components/CameraComponent.hpp b/SDK/include/NDK/Components/CameraComponent.hpp index 04859b1de..f4a29f2e4 100644 --- a/SDK/include/NDK/Components/CameraComponent.hpp +++ b/SDK/include/NDK/Components/CameraComponent.hpp @@ -44,7 +44,7 @@ namespace Ndk const Nz::Frustumf& GetFrustum() const override; inline unsigned int GetLayer() const; const Nz::Matrix4f& GetProjectionMatrix() const override; - inline Nz::ProjectionType GetProjectionType() const; + Nz::ProjectionType GetProjectionType() const override; inline const Nz::Vector2f& GetSize() const; const Nz::RenderTarget* GetTarget() const override; inline const Nz::Rectf& GetTargetRegion() const; diff --git a/SDK/include/NDK/Components/CameraComponent.inl b/SDK/include/NDK/Components/CameraComponent.inl index 0b445f1f3..1018f9f3d 100644 --- a/SDK/include/NDK/Components/CameraComponent.inl +++ b/SDK/include/NDK/Components/CameraComponent.inl @@ -39,6 +39,7 @@ namespace Ndk inline CameraComponent::CameraComponent(const CameraComponent& camera) : Component(camera), AbstractViewer(camera), + HandledObject(camera), m_visibilityHash(camera.m_visibilityHash), m_projectionType(camera.m_projectionType), m_targetRegion(camera.m_targetRegion), @@ -116,16 +117,6 @@ namespace Ndk return m_layer; } - /*! - * \brief Gets the projection type of the camera - * \return Projection type of the camera - */ - - inline Nz::ProjectionType CameraComponent::GetProjectionType() const - { - return m_projectionType; - } - /*! * \brief Gets the size of the camera * \return Size of the camera diff --git a/SDK/include/NDK/Components/CollisionComponent2D.hpp b/SDK/include/NDK/Components/CollisionComponent2D.hpp index 28c3637a2..d793df741 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.hpp +++ b/SDK/include/NDK/Components/CollisionComponent2D.hpp @@ -29,6 +29,7 @@ namespace Ndk CollisionComponent2D(const CollisionComponent2D& collision); ~CollisionComponent2D() = default; + Nz::Rectf GetAABB() const; const Nz::Collider2DRef& GetGeom() const; void SetGeom(Nz::Collider2DRef geom); diff --git a/SDK/include/NDK/Components/CollisionComponent2D.inl b/SDK/include/NDK/Components/CollisionComponent2D.inl index 147e8ec32..6a14fd85e 100644 --- a/SDK/include/NDK/Components/CollisionComponent2D.inl +++ b/SDK/include/NDK/Components/CollisionComponent2D.inl @@ -34,6 +34,16 @@ namespace Ndk { } + /*! + * \brief Gets the collision box representing the entity + * \return The physics collision box + */ + + inline Nz::Rectf CollisionComponent2D::GetAABB() const + { + return m_staticBody->GetAABB(); + } + /*! * \brief Gets the geometry representing the entity * \return A constant reference to the physics geometry diff --git a/SDK/include/NDK/Components/GraphicsComponent.hpp b/SDK/include/NDK/Components/GraphicsComponent.hpp index cd62f9b2f..68961b99a 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.hpp +++ b/SDK/include/NDK/Components/GraphicsComponent.hpp @@ -51,6 +51,9 @@ namespace Ndk inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const; + inline void UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix); + inline void UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder); + static ComponentIndex componentIndex; private: diff --git a/SDK/include/NDK/Components/GraphicsComponent.inl b/SDK/include/NDK/Components/GraphicsComponent.inl index e67b6f323..34bd57dd9 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.inl +++ b/SDK/include/NDK/Components/GraphicsComponent.inl @@ -142,6 +142,32 @@ namespace Ndk } } + inline void GraphicsComponent::UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix) + { + for (auto& renderable : m_renderables) + { + if (renderable.renderable == instancedRenderable) + { + renderable.data.localMatrix = localMatrix; + + InvalidateBoundingVolume(); + break; + } + } + } + + inline void GraphicsComponent::UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder) + { + for (auto& renderable : m_renderables) + { + if (renderable.renderable == instancedRenderable) + { + renderable.data.renderOrder = renderOrder; + break; + } + } + } + /*! * \brief Invalidates the bounding volume */ diff --git a/SDK/include/NDK/Components/ParticleEmitterComponent.hpp b/SDK/include/NDK/Components/ParticleEmitterComponent.hpp index dd40f7aaa..3e2c5f8af 100644 --- a/SDK/include/NDK/Components/ParticleEmitterComponent.hpp +++ b/SDK/include/NDK/Components/ParticleEmitterComponent.hpp @@ -24,7 +24,7 @@ namespace Ndk ParticleEmitterComponent(ParticleEmitterComponent&& emitter) = default; ~ParticleEmitterComponent() = default; - void Enable(bool active = true); + inline void Enable(bool active = true); inline bool IsActive() const; diff --git a/SDK/include/NDK/Components/PhysicsComponent2D.hpp b/SDK/include/NDK/Components/PhysicsComponent2D.hpp index 1f4cc63c9..2bbe693a1 100644 --- a/SDK/include/NDK/Components/PhysicsComponent2D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent2D.hpp @@ -55,6 +55,7 @@ namespace Ndk void OnComponentAttached(BaseComponent& component) override; void OnComponentDetached(BaseComponent& component) override; void OnDetached() override; + void OnEntityDestruction() override; std::unique_ptr m_object; }; diff --git a/SDK/include/NDK/Components/PhysicsComponent3D.hpp b/SDK/include/NDK/Components/PhysicsComponent3D.hpp index f6f13ec09..8be86537e 100644 --- a/SDK/include/NDK/Components/PhysicsComponent3D.hpp +++ b/SDK/include/NDK/Components/PhysicsComponent3D.hpp @@ -62,6 +62,7 @@ namespace Ndk void OnComponentAttached(BaseComponent& component) override; void OnComponentDetached(BaseComponent& component) override; void OnDetached() override; + void OnEntityDestruction() override; std::unique_ptr m_object; }; diff --git a/SDK/include/NDK/Console.hpp b/SDK/include/NDK/Console.hpp index 5c7935a7c..1d49a6cd9 100644 --- a/SDK/include/NDK/Console.hpp +++ b/SDK/include/NDK/Console.hpp @@ -12,14 +12,14 @@ #include #include #include -#include +#include #include #include #include namespace Nz { - class LuaInstance; + class LuaState; } namespace Ndk @@ -32,7 +32,7 @@ namespace Ndk class NDK_API Console : public Nz::Node, public Nz::HandledObject { public: - Console(World& world, const Nz::Vector2f& size, Nz::LuaInstance& instance); + Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state); Console(const Console& console) = delete; Console(Console&& console) = default; ~Console() = default; @@ -83,7 +83,7 @@ namespace Ndk EntityOwner m_input; EntityOwner m_inputBackground; Nz::FontRef m_defaultFont; - Nz::LuaInstance& m_instance; + Nz::LuaState& m_state; Nz::SpriteRef m_historyBackgroundSprite; Nz::SpriteRef m_inputBackgroundSprite; Nz::SimpleTextDrawer m_historyDrawer; diff --git a/SDK/include/NDK/Entity.hpp b/SDK/include/NDK/Entity.hpp index ecf9fcc62..5419da0d2 100644 --- a/SDK/include/NDK/Entity.hpp +++ b/SDK/include/NDK/Entity.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -16,14 +17,17 @@ namespace Ndk { class BaseComponent; + class BaseSystem; class Entity; + class EntityList; class World; using EntityHandle = Nz::ObjectHandle; class NDK_API Entity : public Nz::HandledObject { - friend class BaseSystem; + friend BaseSystem; + friend EntityList; friend World; public: @@ -65,6 +69,8 @@ namespace Ndk Entity& operator=(const Entity&) = delete; Entity& operator=(Entity&&) = delete; + NazaraSignal(OnEntityDestruction, Entity* /*entity*/); + private: Entity(World* world, EntityId id); @@ -75,13 +81,16 @@ namespace Ndk inline Nz::Bitset<>& GetRemovedComponentBits(); + inline void RegisterEntityList(EntityList* list); inline void RegisterSystem(SystemIndex index); inline void SetWorld(World* world) noexcept; + inline void UnregisterEntityList(EntityList* list); inline void UnregisterSystem(SystemIndex index); std::vector> m_components; + std::vector m_containedInLists; Nz::Bitset<> m_componentBits; Nz::Bitset<> m_removedComponentBits; Nz::Bitset<> m_systemBits; diff --git a/SDK/include/NDK/Entity.inl b/SDK/include/NDK/Entity.inl index e6f997226..adb2153d8 100644 --- a/SDK/include/NDK/Entity.inl +++ b/SDK/include/NDK/Entity.inl @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -257,11 +258,10 @@ namespace Ndk return m_removedComponentBits; } - /*! - * \brief Registers a system for the entity - * - * \param index Index of the system - */ + inline void Entity::RegisterEntityList(EntityList* list) + { + m_containedInLists.push_back(list); + } inline void Entity::RegisterSystem(SystemIndex index) { @@ -289,6 +289,16 @@ namespace Ndk * \param index Index of the system */ + inline void Entity::UnregisterEntityList(EntityList* list) + { + auto it = std::find(m_containedInLists.begin(), m_containedInLists.end(), list); + assert(it != m_containedInLists.end()); + + // Swap and pop idiom + *it = m_containedInLists.back(); + m_containedInLists.pop_back(); + } + inline void Entity::UnregisterSystem(SystemIndex index) { m_systemBits.UnboundedReset(index); diff --git a/SDK/include/NDK/EntityList.hpp b/SDK/include/NDK/EntityList.hpp index 4047388cc..8303f7fa4 100644 --- a/SDK/include/NDK/EntityList.hpp +++ b/SDK/include/NDK/EntityList.hpp @@ -15,46 +15,68 @@ namespace Ndk { class NDK_API EntityList { - public: - using Container = std::vector; + friend Entity; - EntityList() = default; - ~EntityList() = default; + public: + class iterator; + friend iterator; + using size_type = std::size_t; + + inline EntityList(); + inline EntityList(const EntityList& entityList); + inline EntityList(EntityList&& entityList) noexcept; + inline ~EntityList(); inline void Clear(); - inline bool Has(const Entity* entity); - inline bool Has(EntityId entity); + inline bool Has(const Entity* entity) const; + inline bool Has(EntityId entity) const; inline void Insert(Entity* entity); inline void Remove(Entity* entity); // STL API - inline Container::iterator begin(); - inline Container::const_iterator begin() const; - - inline Container::const_iterator cbegin() const; - inline Container::const_iterator cend() const; - inline Container::const_reverse_iterator crbegin() const; - inline Container::const_reverse_iterator crend() const; - + inline iterator begin() const; inline bool empty() const; + inline iterator end() const; + inline size_type size() const; - inline Container::iterator end(); - inline Container::const_iterator end() const; - - inline Container::reverse_iterator rbegin(); - inline Container::const_reverse_iterator rbegin() const; - - inline Container::reverse_iterator rend(); - inline Container::const_reverse_iterator rend() const; - - inline Container::size_type size() const; + inline EntityList& operator=(const EntityList& entityList); + inline EntityList& operator=(EntityList&& entityList) noexcept; private: - std::vector m_entities; + inline std::size_t FindNext(std::size_t currentId) const; + inline World* GetWorld() const; + inline void NotifyEntityDestruction(const Entity* entity); + Nz::Bitset m_entityBits; + World* m_world; + }; + + class NDK_API EntityList::iterator : public std::iterator + { + friend EntityList; + + public: + inline iterator(const iterator& it); + + const EntityHandle& operator*() const; + + inline iterator& operator=(const iterator& it); + 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; }; } diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl index 126af0a7e..8d871e2c6 100644 --- a/SDK/include/NDK/EntityList.inl +++ b/SDK/include/NDK/EntityList.inl @@ -2,6 +2,7 @@ // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequesites.hpp +#include #include #include @@ -14,24 +15,71 @@ namespace Ndk */ /*! - * \brief Clears the set from every entities + * \brief Construct a new entity list */ - - inline void EntityList::Clear() + inline EntityList::EntityList() : + m_world(nullptr) { - m_entities.clear(); - m_entityBits.Clear(); } /*! - * \brief Checks whether or not the set contains the entity + * \brief Construct a new entity list by copying another one + */ + inline EntityList::EntityList(const EntityList& entityList) : + m_entityBits(entityList.m_entityBits), + m_world(entityList.m_world) + { + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + } + + /*! + * \brief Construct a new entity list by moving a list into this one + */ + inline EntityList::EntityList(EntityList&& entityList) noexcept : + m_entityBits(std::move(entityList.m_entityBits)), + m_world(entityList.m_world) + { + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + } + + inline EntityList::~EntityList() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + } + + + /*! + * \brief Clears the set from every entities + * + * \remark This resets the implicit world member, allowing you to insert entities from a different world than previously + */ + inline void EntityList::Clear() + { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + + m_entityBits.Clear(); + m_world = nullptr; + } + + /*! + * \brief Checks whether or not the EntityList contains the entity * \return true If it is the case * * \param entity Pointer to the entity + * + * \remark If the Insert function was called since the EntityList construction (or last call to Clear), the entity passed by parameter must belong to the same world as the previously inserted entities. */ - - inline bool EntityList::Has(const Entity* entity) + inline bool EntityList::Has(const Entity* entity) const { + NazaraAssert(!m_world || !entity || entity->GetWorld() == m_world, "Incompatible world"); + return entity && entity->IsValid() && Has(entity->GetId()); } @@ -41,8 +89,7 @@ namespace Ndk * * \param id Identifier of the entity */ - - inline bool EntityList::Has(EntityId entity) + inline bool EntityList::Has(EntityId entity) const { return m_entityBits.UnboundedTest(entity); } @@ -50,17 +97,23 @@ namespace Ndk /*! * \brief Inserts the entity into the set * - * \param entity Pointer to the entity + * Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list. + * + * \param entity Valid pointer to an entity * * \remark If entity is already contained, no action is performed + * \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities */ - inline void EntityList::Insert(Entity* entity) { + NazaraAssert(entity, "Invalid entity"); + if (!Has(entity)) { - m_entities.emplace_back(entity); + entity->RegisterEntityList(this); + m_entityBits.UnboundedSet(entity->GetId(), true); + m_world = entity->GetWorld(); } } @@ -70,89 +123,138 @@ namespace Ndk * \param entity Pointer to the entity * * \remark If entity is not contained, no action is performed + * \remark This function never resets the implicit world member, even if it empties the list. Use the Clear method if you want to reset it. + * + * \see Clear */ - inline void EntityList::Remove(Entity* entity) { if (Has(entity)) { - auto it = std::find(m_entities.begin(), m_entities.end(), *entity); - NazaraAssert(it != m_entities.end(), "Entity should be part of the vector"); + m_entityBits.Reset(entity->GetId()); - std::swap(*it, m_entities.back()); - m_entities.pop_back(); // We get it out of the vector - m_entityBits.UnboundedSet(entity->GetId(), false); + entity->UnregisterEntityList(this); } } - // Nz::Interface STD - inline EntityList::Container::iterator EntityList::begin() + // STL Interface + inline EntityList::iterator EntityList::begin() const { - return m_entities.begin(); - } - - inline EntityList::Container::const_iterator EntityList::begin() const - { - return m_entities.begin(); - } - - inline EntityList::Container::const_iterator EntityList::cbegin() const - { - return m_entities.cbegin(); - } - - inline EntityList::Container::const_iterator EntityList::cend() const - { - return m_entities.cend(); - } - - inline EntityList::Container::const_reverse_iterator EntityList::crbegin() const - { - return m_entities.crbegin(); - } - - inline EntityList::Container::const_reverse_iterator EntityList::crend() const - { - return m_entities.crend(); + return EntityList::iterator(this, m_entityBits.FindFirst()); } inline bool EntityList::empty() const { - return m_entities.empty(); + return !m_entityBits.TestAny(); } - inline EntityList::Container::iterator EntityList::end() + inline EntityList::iterator EntityList::end() const { - return m_entities.end(); + return EntityList::iterator(this, m_entityBits.npos); } - inline EntityList::Container::const_iterator EntityList::end() const + inline EntityList::size_type EntityList::size() const { - return m_entities.end(); + return m_entityBits.Count(); } - inline EntityList::Container::reverse_iterator EntityList::rbegin() + inline EntityList& EntityList::operator=(const EntityList& entityList) { - return m_entities.rbegin(); + m_entityBits = entityList.m_entityBits; + m_world = entityList.m_world; + + for (const Ndk::EntityHandle& entity : *this) + entity->RegisterEntityList(this); + + return *this; } - inline EntityList::Container::const_reverse_iterator EntityList::rbegin() const + inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept { - return m_entities.rbegin(); + m_entityBits = std::move(entityList.m_entityBits); + m_world = entityList.m_world; + + for (const Ndk::EntityHandle& entity : *this) + { + entity->UnregisterEntityList(&entityList); + entity->RegisterEntityList(this); + } + + return *this; } - inline EntityList::Container::reverse_iterator EntityList::rend() + inline std::size_t EntityList::FindNext(std::size_t currentId) const { - return m_entities.rend(); + return m_entityBits.FindNext(currentId); } - inline EntityList::Container::const_reverse_iterator EntityList::rend() const + inline World* EntityList::GetWorld() const { - return m_entities.rend(); + return m_world; } - inline EntityList::Container::size_type EntityList::size() const + inline void EntityList::NotifyEntityDestruction(const Entity* entity) { - return m_entities.size(); + assert(Has(entity)); + + m_entityBits.Reset(entity->GetId()); + } + + + inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) : + m_nextEntityId(nextId), + m_list(list) + { + } + + inline EntityList::iterator::iterator(const iterator& it) : + m_nextEntityId(it.m_nextEntityId), + m_list(it.m_list) + { + } + + inline EntityList::iterator& EntityList::iterator::operator=(const iterator& it) + { + m_nextEntityId = it.m_nextEntityId; + m_list = it.m_list; + + return *this; + } + + inline EntityList::iterator& EntityList::iterator::operator++() + { + m_nextEntityId = m_list->FindNext(m_nextEntityId); + + return *this; + } + + inline EntityList::iterator EntityList::iterator::operator++(int) + { + std::size_t previousId = m_nextEntityId; + + m_nextEntityId = m_list->FindNext(m_nextEntityId); + + return iterator(m_list, previousId); + } + + inline bool operator==(const EntityList::iterator& lhs, const EntityList::iterator& rhs) + { + NazaraAssert(lhs.m_list == rhs.m_list, "Cannot compare iterator coming from different lists"); + + return lhs.m_nextEntityId == rhs.m_nextEntityId; + } + + inline bool operator!=(const EntityList::iterator& lhs, const EntityList::iterator& rhs) + { + return !operator==(lhs, rhs); + } + + inline void swap(EntityList::iterator& lhs, EntityList::iterator& rhs) + { + NazaraAssert(lhs.m_list == rhs.m_list, "Cannot compare iterator coming from different lists"); + + using std::swap; + + swap(lhs.m_nextEntityId, rhs.m_nextEntityId); } } diff --git a/SDK/include/NDK/Lua/LuaBinding.hpp b/SDK/include/NDK/Lua/LuaBinding.hpp index 88b6a88ef..3c994b3b1 100644 --- a/SDK/include/NDK/Lua/LuaBinding.hpp +++ b/SDK/include/NDK/Lua/LuaBinding.hpp @@ -24,7 +24,7 @@ namespace Ndk template void BindComponent(const Nz::String& name); - void RegisterClasses(Nz::LuaInstance& instance); + void RegisterClasses(Nz::LuaState& state); std::unique_ptr core; std::unique_ptr math; @@ -36,17 +36,18 @@ namespace Ndk std::unique_ptr audio; std::unique_ptr graphics; std::unique_ptr renderer; + std::unique_ptr platform; #endif private: template - static int AddComponentOfType(Nz::LuaInstance& lua, EntityHandle& handle); + static int AddComponentOfType(Nz::LuaState& lua, EntityHandle& handle); template - static int PushComponentOfType(Nz::LuaInstance& lua, BaseComponent& component); + static int PushComponentOfType(Nz::LuaState& lua, BaseComponent& component); - using AddComponentFunc = int(*)(Nz::LuaInstance&, EntityHandle&); - using GetComponentFunc = int(*)(Nz::LuaInstance&, BaseComponent&); + using AddComponentFunc = int(*)(Nz::LuaState&, EntityHandle&); + using GetComponentFunc = int(*)(Nz::LuaState&, BaseComponent&); struct ComponentBinding { @@ -56,7 +57,7 @@ namespace Ndk Nz::String name; }; - ComponentBinding* QueryComponentIndex(Nz::LuaInstance& lua, int argIndex = 2); + ComponentBinding* QueryComponentIndex(Nz::LuaState& lua, int argIndex = 2); std::vector m_componentBinding; std::unordered_map m_componentBindingByName; diff --git a/SDK/include/NDK/Lua/LuaBinding.inl b/SDK/include/NDK/Lua/LuaBinding.inl index c9f3f86bb..d95314099 100644 --- a/SDK/include/NDK/Lua/LuaBinding.inl +++ b/SDK/include/NDK/Lua/LuaBinding.inl @@ -6,6 +6,35 @@ namespace Ndk { + namespace Detail + { + template + struct AddComponentIf; + + template<> + struct AddComponentIf + { + template + static int AddComponent(Nz::LuaState& lua, EntityHandle& handle) + { + T& component = handle->AddComponent(); + lua.Push(component.CreateHandle()); + return 1; + } + }; + + template<> + struct AddComponentIf + { + template + static int AddComponent(Nz::LuaState& lua, EntityHandle& /*handle*/) + { + lua.Error("Component has no default constructor and cannot be created from Lua yet"); + return 0; + } + }; + } + /*! * \brief Binds a component to a name * @@ -13,14 +42,15 @@ namespace Ndk * * \remark Produces a NazaraAssert if name is empty */ - template void LuaBinding::BindComponent(const Nz::String& name) { NazaraAssert(!name.IsEmpty(), "Component name cannot be empty"); + static_assert(std::is_base_of::value, "ComponentType must inherit BaseComponent"); + ComponentBinding binding; - binding.adder = &AddComponentOfType; + binding.adder = &Detail::AddComponentIf::value>::template AddComponent; binding.getter = &PushComponentOfType; binding.index = T::componentIndex; binding.name = name; @@ -33,20 +63,8 @@ namespace Ndk } template - int LuaBinding::AddComponentOfType(Nz::LuaInstance& lua, EntityHandle& handle) + int LuaBinding::PushComponentOfType(Nz::LuaState& lua, BaseComponent& component) { - static_assert(std::is_base_of::value, "ComponentType must inherit BaseComponent"); - - T& component = handle->AddComponent(); - lua.Push(component.CreateHandle()); - return 1; - } - - template - int LuaBinding::PushComponentOfType(Nz::LuaInstance& lua, BaseComponent& component) - { - static_assert(std::is_base_of::value, "ComponentType must inherit BaseComponent"); - T& rightComponent = static_cast(component); lua.Push(rightComponent.CreateHandle()); return 1; diff --git a/SDK/include/NDK/Lua/LuaBinding_Audio.hpp b/SDK/include/NDK/Lua/LuaBinding_Audio.hpp index 1764fb729..d842ecc9b 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Audio.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Audio.hpp @@ -21,7 +21,7 @@ namespace Ndk LuaBinding_Audio(LuaBinding& binding); ~LuaBinding_Audio() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass music; Nz::LuaClass sound; diff --git a/SDK/include/NDK/Lua/LuaBinding_Base.hpp b/SDK/include/NDK/Lua/LuaBinding_Base.hpp index 36c41af8c..21d86f191 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Base.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Base.hpp @@ -23,6 +23,7 @@ namespace Ndk class LuaBinding_Renderer; class LuaBinding_SDK; class LuaBinding_Utility; + class LuaBinding_Platform; class NDK_API LuaBinding_Base { @@ -30,7 +31,7 @@ namespace Ndk LuaBinding_Base(LuaBinding& binding); virtual ~LuaBinding_Base(); - virtual void Register(Nz::LuaInstance& instance) = 0; + virtual void Register(Nz::LuaState& state) = 0; // Implementation lies in the respective .cpp files (still searching for a cleaner way..) static std::unique_ptr BindCore(LuaBinding& binding); @@ -43,6 +44,7 @@ namespace Ndk static std::unique_ptr BindAudio(LuaBinding& binding); static std::unique_ptr BindGraphics(LuaBinding& binding); static std::unique_ptr BindRenderer(LuaBinding& binding); + static std::unique_ptr BindPlatform(LuaBinding& binding); #endif protected: diff --git a/SDK/include/NDK/Lua/LuaBinding_Core.hpp b/SDK/include/NDK/Lua/LuaBinding_Core.hpp index 97d31cde4..decca39fc 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Core.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Core.hpp @@ -21,7 +21,7 @@ namespace Ndk LuaBinding_Core(LuaBinding& binding); ~LuaBinding_Core() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass clock; Nz::LuaClass directory; diff --git a/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp b/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp index 0bfece994..cd71f0fc5 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Graphics.hpp @@ -22,7 +22,7 @@ namespace Ndk LuaBinding_Graphics(LuaBinding& binding); ~LuaBinding_Graphics() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass abstractViewer; Nz::LuaClass instancedRenderable; diff --git a/SDK/include/NDK/Lua/LuaBinding_Math.hpp b/SDK/include/NDK/Lua/LuaBinding_Math.hpp index d94f357c3..386912bab 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Math.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Math.hpp @@ -23,7 +23,7 @@ namespace Ndk LuaBinding_Math(LuaBinding& binding); ~LuaBinding_Math() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass eulerAngles; Nz::LuaClass matrix4d; diff --git a/SDK/include/NDK/Lua/LuaBinding_Network.hpp b/SDK/include/NDK/Lua/LuaBinding_Network.hpp index a9a5b31e0..daee2b224 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Network.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Network.hpp @@ -9,6 +9,7 @@ #include #include +#include #include namespace Ndk @@ -19,10 +20,11 @@ namespace Ndk LuaBinding_Network(LuaBinding& binding); ~LuaBinding_Network() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass abstractSocket; Nz::LuaClass ipAddress; + Nz::LuaClass udpSocket; }; } diff --git a/SDK/include/NDK/Lua/LuaBinding_Platform.hpp b/SDK/include/NDK/Lua/LuaBinding_Platform.hpp new file mode 100644 index 000000000..502a443a5 --- /dev/null +++ b/SDK/include/NDK/Lua/LuaBinding_Platform.hpp @@ -0,0 +1,28 @@ +// 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 + +#pragma once + +#ifndef NDK_LUABINDING_SYSTEM_HPP +#define NDK_LUABINDING_SYSTEM_HPP + +#include +#include + +namespace Ndk +{ + class NDK_API LuaBinding_Platform : public LuaBinding_Base + { + public: + LuaBinding_Platform(LuaBinding& binding); + ~LuaBinding_Platform() = default; + + void Register(Nz::LuaState& state) override; + + // Platform + Nz::LuaClass keyboard; + }; +} + +#endif // NDK_LUABINDING_SYSTEM_HPP diff --git a/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp b/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp index a2db03f8d..af1ffeaa5 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Renderer.hpp @@ -18,7 +18,7 @@ namespace Ndk LuaBinding_Renderer(LuaBinding& binding); ~LuaBinding_Renderer() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass texture; Nz::LuaClass textureLibrary; diff --git a/SDK/include/NDK/Lua/LuaBinding_SDK.hpp b/SDK/include/NDK/Lua/LuaBinding_SDK.hpp index b6b7079eb..8a6a0915e 100644 --- a/SDK/include/NDK/Lua/LuaBinding_SDK.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_SDK.hpp @@ -22,7 +22,7 @@ namespace Ndk LuaBinding_SDK(LuaBinding& binding); ~LuaBinding_SDK() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; Nz::LuaClass application; Nz::LuaClass entity; diff --git a/SDK/include/NDK/Lua/LuaBinding_Utility.hpp b/SDK/include/NDK/Lua/LuaBinding_Utility.hpp index b10492efc..33f19184d 100644 --- a/SDK/include/NDK/Lua/LuaBinding_Utility.hpp +++ b/SDK/include/NDK/Lua/LuaBinding_Utility.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -21,12 +20,11 @@ namespace Ndk LuaBinding_Utility(LuaBinding& binding); ~LuaBinding_Utility() = default; - void Register(Nz::LuaInstance& instance) override; + void Register(Nz::LuaState& state) override; // Utility Nz::LuaClass abstractImage; Nz::LuaClass font; - Nz::LuaClass keyboard; Nz::LuaClass node; }; } diff --git a/SDK/include/NDK/LuaAPI.hpp b/SDK/include/NDK/LuaAPI.hpp index 3ed73d9d2..d3e755fc6 100644 --- a/SDK/include/NDK/LuaAPI.hpp +++ b/SDK/include/NDK/LuaAPI.hpp @@ -11,7 +11,7 @@ namespace Nz { - class LuaInstance; + class LuaState; } namespace Ndk @@ -28,7 +28,7 @@ namespace Ndk static bool Initialize(); - static void RegisterClasses(Nz::LuaInstance& instance); + static void RegisterClasses(Nz::LuaState& state); static void Uninitialize(); diff --git a/SDK/include/NDK/LuaAPI.inl b/SDK/include/NDK/LuaAPI.inl index 4cc0e4342..84e3fb34e 100644 --- a/SDK/include/NDK/LuaAPI.inl +++ b/SDK/include/NDK/LuaAPI.inl @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include @@ -28,103 +28,103 @@ namespace Nz { - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Color* color, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Color* color, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - color->r = instance.CheckField("r", index); - color->g = instance.CheckField("g", index); - color->b = instance.CheckField("b", index); - color->a = instance.CheckField("a", 255, index); + color->r = state.CheckField("r", index); + color->g = state.CheckField("g", index); + color->b = state.CheckField("b", index); + color->a = state.CheckField("a", 255, index); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, EulerAnglesd* angles, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, EulerAnglesd* angles, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Table: - angles->Set(instance.CheckField("pitch", index), instance.CheckField("yaw", index), instance.CheckField("roll", index)); + angles->Set(state.CheckField("pitch", index), state.CheckField("yaw", index), state.CheckField("roll", index)); return 1; default: { - if (instance.IsOfType(index, "EulerAngles")) - angles->Set(*static_cast(instance.ToUserdata(index))); + if (state.IsOfType(index, "EulerAngles")) + angles->Set(*static_cast(state.ToUserdata(index))); else - angles->Set(*static_cast(instance.CheckUserdata(index, "Quaternion"))); + angles->Set(*static_cast(state.CheckUserdata(index, "Quaternion"))); return 1; } } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, EulerAnglesf* angles, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, EulerAnglesf* angles, TypeTag) { EulerAnglesd anglesDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &anglesDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &anglesDouble, TypeTag()); angles->Set(anglesDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, FontRef* fontRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, FontRef* fontRef, TypeTag) { - *fontRef = *static_cast(instance.CheckUserdata(index, "Font")); + *fontRef = *static_cast(state.CheckUserdata(index, "Font")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, FontParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, FontParams* params, TypeTag) { NazaraUnused(params); - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); // Structure is empty for now return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, ImageParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, ImageParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->levelCount = instance.CheckField("LevelCount"); - params->loadFormat = instance.CheckField("LoadFormat"); + params->levelCount = state.CheckField("LevelCount"); + params->loadFormat = state.CheckField("LoadFormat"); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, IpAddress* address, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, IpAddress* address, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_String: - address->BuildFromAddress(instance.CheckString(index)); + address->BuildFromAddress(state.CheckString(index)); return 1; default: - *address = *static_cast(instance.CheckUserdata(index, "IpAddress")); + *address = *static_cast(state.CheckUserdata(index, "IpAddress")); return 1; } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Matrix4d* mat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Matrix4d* mat, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Table: { double values[16]; for (std::size_t i = 0; i < 16; ++i) { - instance.PushInteger(i + 1); - instance.GetTable(); + state.PushInteger(i + 1); + state.GetTable(); - values[i] = instance.CheckNumber(-1); - instance.Pop(); + values[i] = state.CheckNumber(-1); + state.Pop(); } mat->Set(values); @@ -133,500 +133,500 @@ namespace Nz default: { - if (instance.IsOfType(index, "Matrix4")) - mat->Set(*static_cast(instance.ToUserdata(index))); + if (state.IsOfType(index, "Matrix4")) + mat->Set(*static_cast(state.ToUserdata(index))); return 1; } } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Matrix4f* mat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Matrix4f* mat, TypeTag) { Matrix4d matDouble = Matrix4d::Identity(); - unsigned int ret = LuaImplQueryArg(instance, index, &matDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &matDouble, TypeTag()); mat->Set(matDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MeshParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MeshParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->animated = instance.CheckField("Animated", params->animated); - params->center = instance.CheckField("Center", params->center); - params->matrix = instance.CheckField("Matrix", params->matrix); - params->optimizeIndexBuffers = instance.CheckField("OptimizeIndexBuffers", params->optimizeIndexBuffers); - params->texCoordOffset = instance.CheckField("TexCoordOffset", params->texCoordOffset); - params->texCoordScale = instance.CheckField("TexCoordScale", params->texCoordScale); + params->animated = state.CheckField("Animated", params->animated); + params->center = state.CheckField("Center", params->center); + params->matrix = state.CheckField("Matrix", params->matrix); + params->optimizeIndexBuffers = state.CheckField("OptimizeIndexBuffers", params->optimizeIndexBuffers); + params->texCoordOffset = state.CheckField("TexCoordOffset", params->texCoordOffset); + params->texCoordScale = state.CheckField("TexCoordScale", params->texCoordScale); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Quaterniond* quat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Quaterniond* quat, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Table: - quat->Set(instance.CheckField("w", index), instance.CheckField("x", index), instance.CheckField("y", index), instance.CheckField("z", index)); + quat->Set(state.CheckField("w", index), state.CheckField("x", index), state.CheckField("y", index), state.CheckField("z", index)); return 1; default: { - if (instance.IsOfType(index, "EulerAngles")) - quat->Set(*static_cast(instance.ToUserdata(index))); + if (state.IsOfType(index, "EulerAngles")) + quat->Set(*static_cast(state.ToUserdata(index))); else - quat->Set(*static_cast(instance.CheckUserdata(index, "Quaternion"))); + quat->Set(*static_cast(state.CheckUserdata(index, "Quaternion"))); return 1; } } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Quaternionf* quat, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Quaternionf* quat, TypeTag) { Quaterniond quatDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &quatDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &quatDouble, TypeTag()); quat->Set(quatDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Rectd* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Rectd* rect, TypeTag) { - instance.CheckType(index, LuaType_Table); + state.CheckType(index, LuaType_Table); - rect->x = instance.CheckField("x", index); - rect->y = instance.CheckField("y", index); - rect->width = instance.CheckField("width", index); - rect->height = instance.CheckField("height", index); + rect->x = state.CheckField("x", index); + rect->y = state.CheckField("y", index); + rect->width = state.CheckField("width", index); + rect->height = state.CheckField("height", index); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Rectf* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Rectf* rect, TypeTag) { Rectd rectDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &rectDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &rectDouble, TypeTag()); rect->Set(rectDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Recti* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Recti* rect, TypeTag) { Rectd rectDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &rectDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &rectDouble, TypeTag()); rect->Set(rectDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Rectui* rect, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Rectui* rect, TypeTag) { Rectd rectDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &rectDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &rectDouble, TypeTag()); rect->Set(rectDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector2d* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2d* vec, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Number: if (index < 0 && index > -2) - instance.Error("Vector2 expected, two numbers are required to convert it"); + state.Error("Vector2 expected, two numbers are required to convert it"); - vec->Set(instance.CheckNumber(index), instance.CheckNumber(index + 1)); + vec->Set(state.CheckNumber(index), state.CheckNumber(index + 1)); return 2; case Nz::LuaType_Table: - vec->Set(instance.CheckField("x", index), instance.CheckField("y", index)); + vec->Set(state.CheckField("x", index), state.CheckField("y", index)); return 1; default: - vec->Set(*static_cast(instance.CheckUserdata(index, "Vector2"))); + vec->Set(*static_cast(state.CheckUserdata(index, "Vector2"))); return 1; } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector2f* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2f* vec, TypeTag) { Vector2d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector2ui* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector2ui* vec, TypeTag) { Vector2d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector3d* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3d* vec, TypeTag) { - switch (instance.GetType(index)) + switch (state.GetType(index)) { case Nz::LuaType_Number: if (index < 0 && index > -3) - instance.Error("Vector3 expected, three numbers are required to convert it"); + state.Error("Vector3 expected, three numbers are required to convert it"); - vec->Set(instance.CheckNumber(index), instance.CheckNumber(index + 1), instance.CheckNumber(index + 2, 0.0)); + vec->Set(state.CheckNumber(index), state.CheckNumber(index + 1), state.CheckNumber(index + 2, 0.0)); return 3; case Nz::LuaType_Table: - vec->Set(instance.CheckField("x", index), instance.CheckField("y", index), instance.CheckField("z", 0.0, index)); + vec->Set(state.CheckField("x", index), state.CheckField("y", index), state.CheckField("z", 0.0, index)); return 1; default: - vec->Set(*static_cast(instance.CheckUserdata(index, "Vector3"))); + vec->Set(*static_cast(state.CheckUserdata(index, "Vector3"))); return 1; } } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector3f* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3f* vec, TypeTag) { Vector3d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Vector3ui* vec, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Vector3ui* vec, TypeTag) { Vector3d vecDouble; - unsigned int ret = LuaImplQueryArg(instance, index, &vecDouble, TypeTag()); + unsigned int ret = LuaImplQueryArg(state, index, &vecDouble, TypeTag()); vec->Set(vecDouble); return ret; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Ndk::EntityHandle* handle, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Ndk::EntityHandle* handle, TypeTag) { - *handle = *static_cast(instance.CheckUserdata(index, "Entity")); + *handle = *static_cast(state.CheckUserdata(index, "Entity")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Ndk::WorldHandle* handle, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, Ndk::WorldHandle* handle, TypeTag) { - *handle = *static_cast(instance.CheckUserdata(index, "World")); + *handle = *static_cast(state.CheckUserdata(index, "World")); return 1; } #ifndef NDK_SERVER - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, InstancedRenderableRef* renderable, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, InstancedRenderableRef* renderable, TypeTag) { - if (instance.IsOfType(index, "InstancedRenderable") || - instance.IsOfType(index, "Model") || - instance.IsOfType(index, "Sprite")) + if (state.IsOfType(index, "InstancedRenderable") || + state.IsOfType(index, "Model") || + state.IsOfType(index, "Sprite")) { - *renderable = *static_cast(instance.ToUserdata(index)); + *renderable = *static_cast(state.ToUserdata(index)); } else - instance.ArgError(index, "is not a InstancedRenderable instance"); + state.ArgError(index, "is not a InstancedRenderable instance"); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MaterialRef* materialRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MaterialRef* materialRef, TypeTag) { - *materialRef = *static_cast(instance.CheckUserdata(index, "Material")); + *materialRef = *static_cast(state.CheckUserdata(index, "Material")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MaterialParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MaterialParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->loadAlphaMap = instance.CheckField("LoadAlphaMap", params->loadAlphaMap); - params->loadDiffuseMap = instance.CheckField("LoadDiffuseMap", params->loadDiffuseMap); - params->loadEmissiveMap = instance.CheckField("LoadEmissiveMap", params->loadEmissiveMap); - params->loadHeightMap = instance.CheckField("LoadHeightMap", params->loadHeightMap); - params->loadNormalMap = instance.CheckField("LoadNormalMap", params->loadNormalMap); - params->loadSpecularMap = instance.CheckField("LoadSpecularMap", params->loadSpecularMap); - params->shaderName = instance.CheckField("ShaderName", params->shaderName); + params->loadAlphaMap = state.CheckField("LoadAlphaMap", params->loadAlphaMap); + params->loadDiffuseMap = state.CheckField("LoadDiffuseMap", params->loadDiffuseMap); + params->loadEmissiveMap = state.CheckField("LoadEmissiveMap", params->loadEmissiveMap); + params->loadHeightMap = state.CheckField("LoadHeightMap", params->loadHeightMap); + params->loadNormalMap = state.CheckField("LoadNormalMap", params->loadNormalMap); + params->loadSpecularMap = state.CheckField("LoadSpecularMap", params->loadSpecularMap); + params->shaderName = state.CheckField("ShaderName", params->shaderName); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, ModelParameters* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, ModelParameters* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->loadMaterials = instance.CheckField("LoadMaterials", params->loadMaterials); + params->loadMaterials = state.CheckField("LoadMaterials", params->loadMaterials); - LuaImplQueryArg(instance, -1, ¶ms->material, TypeTag()); - LuaImplQueryArg(instance, -1, ¶ms->mesh, TypeTag()); + LuaImplQueryArg(state, -1, ¶ms->material, TypeTag()); + LuaImplQueryArg(state, -1, ¶ms->mesh, TypeTag()); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, MusicParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, MusicParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->forceMono = instance.CheckField("ForceMono", params->forceMono); + params->forceMono = state.CheckField("ForceMono", params->forceMono); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, SoundBufferParams* params, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SoundBufferParams* params, TypeTag) { - instance.CheckType(index, Nz::LuaType_Table); + state.CheckType(index, Nz::LuaType_Table); - params->forceMono = instance.CheckField("ForceMono", params->forceMono); + params->forceMono = state.CheckField("ForceMono", params->forceMono); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, SpriteRef* spriteRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, SpriteRef* spriteRef, TypeTag) { - *spriteRef = *static_cast(instance.CheckUserdata(index, "Sprite")); + *spriteRef = *static_cast(state.CheckUserdata(index, "Sprite")); return 1; } - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, TextureRef* textureRef, TypeTag) + inline unsigned int LuaImplQueryArg(const LuaState& state, int index, TextureRef* textureRef, TypeTag) { - *textureRef = *static_cast(instance.CheckUserdata(index, "Texture")); + *textureRef = *static_cast(state.CheckUserdata(index, "Texture")); return 1; } #endif - inline int LuaImplReplyVal(const LuaInstance& instance, Color&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Color&& val, TypeTag) { - instance.PushTable(); - instance.PushField("r", val.r); - instance.PushField("g", val.g); - instance.PushField("b", val.b); - instance.PushField("a", val.a); + state.PushTable(); + state.PushField("r", val.r); + state.PushField("g", val.g); + state.PushField("b", val.b); + state.PushField("a", val.a); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, EulerAnglesd&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, EulerAnglesd&& val, TypeTag) { - instance.PushInstance("EulerAngles", val); + state.PushInstance("EulerAngles", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, EulerAnglesf&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, EulerAnglesf&& val, TypeTag) { - instance.PushInstance("EulerAngles", val); + state.PushInstance("EulerAngles", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, FontRef&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, FontRef&& val, TypeTag) { - instance.PushInstance("Font", val); + state.PushInstance("Font", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Font::SizeInfo&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Font::SizeInfo&& val, TypeTag) { - instance.PushTable(); - instance.PushField("LineHeight", val.lineHeight); - instance.PushField("SpaceAdvance", val.spaceAdvance); - instance.PushField("UnderlinePosition", val.underlinePosition); - instance.PushField("UnderlineThickness", val.underlineThickness); + state.PushTable(); + state.PushField("LineHeight", val.lineHeight); + state.PushField("SpaceAdvance", val.spaceAdvance); + state.PushField("UnderlinePosition", val.underlinePosition); + state.PushField("UnderlineThickness", val.underlineThickness); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, ImageParams&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, ImageParams&& val, TypeTag) { - instance.PushTable(0, 2); - instance.PushField("LevelCount", val.levelCount); - instance.PushField("LoadFormat", val.loadFormat); + state.PushTable(0, 2); + state.PushField("LevelCount", val.levelCount); + state.PushField("LoadFormat", val.loadFormat); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, IpAddress&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, IpAddress&& val, TypeTag) { - instance.PushInstance("IpAddress", val); + state.PushInstance("IpAddress", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Matrix4d&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Matrix4d&& val, TypeTag) { - instance.PushInstance("Matrix4", val); + state.PushInstance("Matrix4", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Matrix4f&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Matrix4f&& val, TypeTag) { - instance.PushInstance("Matrix4", val); + state.PushInstance("Matrix4", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Quaterniond&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Quaterniond&& val, TypeTag) { - instance.PushInstance("Quaternion", val); + state.PushInstance("Quaternion", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Quaternionf&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Quaternionf&& val, TypeTag) { - instance.PushInstance("Quaternion", val); + state.PushInstance("Quaternion", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Rectd&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Rectd&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Rectf&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Rectf&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Recti&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Recti&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Rectui&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Rectui&& val, TypeTag) { - instance.PushInstance("Rect", val); + state.PushInstance("Rect", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector2d&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector2d&& val, TypeTag) { - instance.PushInstance("Vector2", val); + state.PushInstance("Vector2", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector2f&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector2f&& val, TypeTag) { - instance.PushInstance("Vector2", val); + state.PushInstance("Vector2", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector2ui&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector2ui&& val, TypeTag) { - instance.PushInstance("Vector2", val); + state.PushInstance("Vector2", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector3d&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector3d&& val, TypeTag) { - instance.PushInstance("Vector3", val); + state.PushInstance("Vector3", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector3f&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector3f&& val, TypeTag) { - instance.PushInstance("Vector3", val); + state.PushInstance("Vector3", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Vector3ui&& val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Vector3ui&& val, TypeTag) { - instance.PushInstance("Vector3", val); + state.PushInstance("Vector3", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::Entity* ptr, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::Entity* ptr, TypeTag) { - instance.PushInstance("Entity", ptr); + state.PushInstance("Entity", ptr); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::Application* ptr, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::Application* ptr, TypeTag) { - instance.PushInstance("Application", ptr); + state.PushInstance("Application", ptr); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::EntityHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::EntityHandle&& handle, TypeTag) { - instance.PushInstance("Entity", handle); + state.PushInstance("Entity", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::NodeComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::NodeComponentHandle&& handle, TypeTag) { - instance.PushInstance("NodeComponent", handle); + state.PushInstance("NodeComponent", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::VelocityComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::VelocityComponentHandle&& handle, TypeTag) { - instance.PushInstance("VelocityComponent", handle); + state.PushInstance("VelocityComponent", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::World* ptr, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::World* ptr, TypeTag) { - instance.PushInstance("World", ptr); + state.PushInstance("World", ptr); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::WorldHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::WorldHandle&& handle, TypeTag) { - instance.PushInstance("World", handle); + state.PushInstance("World", handle); return 1; } #ifndef NDK_SERVER - inline int LuaImplReplyVal(const LuaInstance& instance, MaterialRef&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, MaterialRef&& handle, TypeTag) { - instance.PushInstance("Material", handle); + state.PushInstance("Material", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, const SoundBuffer* val, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, const SoundBuffer* val, TypeTag) { - instance.PushInstance("SoundBuffer", val); + state.PushInstance("SoundBuffer", val); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, SpriteRef&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, SpriteRef&& handle, TypeTag) { - instance.PushInstance("Sprite", handle); + state.PushInstance("Sprite", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, TextureRef&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, TextureRef&& handle, TypeTag) { - instance.PushInstance("Texture", handle); + state.PushInstance("Texture", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::CameraComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::CameraComponentHandle&& handle, TypeTag) { - instance.PushInstance("CameraComponent", handle); + state.PushInstance("CameraComponent", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::ConsoleHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::ConsoleHandle&& handle, TypeTag) { - instance.PushInstance("Console", handle); + state.PushInstance("Console", handle); return 1; } - inline int LuaImplReplyVal(const LuaInstance& instance, Ndk::GraphicsComponentHandle&& handle, TypeTag) + inline int LuaImplReplyVal(const LuaState& state, Ndk::GraphicsComponentHandle&& handle, TypeTag) { - instance.PushInstance("GraphicsComponent", handle); + state.PushInstance("GraphicsComponent", handle); return 1; } #endif diff --git a/SDK/include/NDK/StateMachine.hpp b/SDK/include/NDK/StateMachine.hpp index dae81ecd0..e9e665c44 100644 --- a/SDK/include/NDK/StateMachine.hpp +++ b/SDK/include/NDK/StateMachine.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2017 Jérôme Leclercq // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequesites.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace Ndk { @@ -25,14 +26,21 @@ namespace Ndk inline const std::shared_ptr& GetCurrentState() const; + inline bool IsTopState(const State* state) const; + + inline std::shared_ptr PopState(); + inline bool PopStatesUntil(std::shared_ptr state); + inline void PushState(std::shared_ptr state); + + inline void SetState(std::shared_ptr state); + inline bool Update(float elapsedTime); inline StateMachine& operator=(StateMachine&& fsm) = default; StateMachine& operator=(const StateMachine&) = delete; private: - std::shared_ptr m_currentState; - std::shared_ptr m_nextState; + std::vector> m_states; }; } diff --git a/SDK/include/NDK/StateMachine.inl b/SDK/include/NDK/StateMachine.inl index d30146a97..1086df54d 100644 --- a/SDK/include/NDK/StateMachine.inl +++ b/SDK/include/NDK/StateMachine.inl @@ -3,7 +3,6 @@ // For conditions of distribution and use, see copyright notice in Prerequesites.hpp #include -#include #include namespace Ndk @@ -11,7 +10,7 @@ namespace Ndk /*! * \ingroup NDK * \class Ndk::StateMachine - * \brief NDK class that represents a state machine, to represent the multiple states of your program + * \brief NDK class that represents a state machine, to represent the multiple states of your program as a stack */ /*! @@ -23,61 +22,153 @@ namespace Ndk * \remark Produces a NazaraAssert if nullptr is given */ - inline StateMachine::StateMachine(std::shared_ptr originalState) : - m_currentState(std::move(originalState)) + inline StateMachine::StateMachine(std::shared_ptr originalState) { - NazaraAssert(m_currentState, "StateMachine must have a state to begin with"); - m_currentState->Enter(*this); + NazaraAssert(originalState, "StateMachine must have a state to begin with"); + PushState(std::move(originalState)); } /*! * \brief Destructs the object * - * \remark Calls "Leave" on the state + * \remark Calls "Leave" on all the states */ inline StateMachine::~StateMachine() { - m_currentState->Leave(*this); + for (std::shared_ptr& state : 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) { - m_nextState = std::move(state); + if (state) + { + PopState(); + PushState(std::move(state)); + } } /*! - * \brief Gets the current state of the machine + * \brief Gets the current state on the top of the machine * \return A constant reference to the state + * + * \remark The stack is supposed to be non empty, otherwise it is undefined behaviour + * + * \see PopStatesUntil */ inline const std::shared_ptr& StateMachine::GetCurrentState() const { - return m_currentState; + return m_states.back(); } /*! - * \brief Updates the state - * \return True if update is successful + * \brief Checks whether the state is on the top of the machine + * \return true If it is the case + * + * \param state State to compare the top with + */ + + inline bool StateMachine::IsTopState(const State* state) const + { + if (m_states.empty()) + return false; + + return m_states.back().get() == state; + } + + /*! + * \brief Pops the state on the top of the machine + * \return Old state on the top, nullptr if stack was empty + * + * \remark This method can completely empty the stack + */ + + inline std::shared_ptr StateMachine::PopState() + { + if (m_states.empty()) + return nullptr; + + m_states.back()->Leave(*this); + std::shared_ptr 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) + { + 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) + { + 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) + { + if (state) + { + while (!m_states.empty()) + PopState(); + + PushState(std::move(state)); + } + } + + /*! + * \brief Updates all the states + * \return true If update is successful for everyone of them * * \param elapsedTime Delta time used for the update */ inline bool StateMachine::Update(float elapsedTime) { - if (m_nextState) - { - m_currentState->Leave(*this); - m_currentState = std::move(m_nextState); - m_currentState->Enter(*this); - } - - return m_currentState->Update(*this, elapsedTime); + return std::all_of(m_states.begin(), m_states.end(), [=](std::shared_ptr& state) { + return state->Update(*this, elapsedTime); + }); } } diff --git a/SDK/include/NDK/Systems/RenderSystem.hpp b/SDK/include/NDK/Systems/RenderSystem.hpp index 61f7bd0a0..a74cb9d0e 100644 --- a/SDK/include/NDK/Systems/RenderSystem.hpp +++ b/SDK/include/NDK/Systems/RenderSystem.hpp @@ -57,7 +57,7 @@ namespace Ndk std::unique_ptr m_renderTechnique; std::vector m_volumeEntries; - EntityList m_cameras; + std::vector m_cameras; EntityList m_drawables; EntityList m_directionalLights; EntityList m_lights; diff --git a/SDK/include/NDK/Widgets.hpp b/SDK/include/NDK/Widgets.hpp index a019c007b..2c3ba7dad 100644 --- a/SDK/include/NDK/Widgets.hpp +++ b/SDK/include/NDK/Widgets.hpp @@ -6,7 +6,9 @@ #define NDK_WIDGETS_GLOBAL_HPP #include +#include #include +#include #include #endif // NDK_WIDGETS_GLOBAL_HPP diff --git a/SDK/include/NDK/Widgets/ButtonWidget.hpp b/SDK/include/NDK/Widgets/ButtonWidget.hpp index d1f940e3f..8f2231501 100644 --- a/SDK/include/NDK/Widgets/ButtonWidget.hpp +++ b/SDK/include/NDK/Widgets/ButtonWidget.hpp @@ -27,7 +27,7 @@ namespace Ndk //virtual ButtonWidget* Clone() const = 0; - void ResizeToContent(); + void ResizeToContent() override; inline void UpdateText(const Nz::AbstractTextDrawer& drawer); @@ -40,7 +40,6 @@ namespace Ndk void Layout() override; void OnMouseEnter() override; - void OnMouseMoved(int x, int y, int deltaX, int deltaY) override; void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override; void OnMouseExit() override; diff --git a/SDK/include/NDK/Widgets/ButtonWidget.inl b/SDK/include/NDK/Widgets/ButtonWidget.inl index fedc7614a..4013d290d 100644 --- a/SDK/include/NDK/Widgets/ButtonWidget.inl +++ b/SDK/include/NDK/Widgets/ButtonWidget.inl @@ -9,5 +9,7 @@ namespace Ndk inline void ButtonWidget::UpdateText(const Nz::AbstractTextDrawer& drawer) { m_textSprite->Update(drawer); + + Layout(); } } diff --git a/SDK/include/NDK/Widgets/CheckboxWidget.hpp b/SDK/include/NDK/Widgets/CheckboxWidget.hpp new file mode 100644 index 000000000..ed31427af --- /dev/null +++ b/SDK/include/NDK/Widgets/CheckboxWidget.hpp @@ -0,0 +1,104 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +#pragma once + +#ifndef NDK_WIDGETS_CHECKBOXWIDGET_HPP +#define NDK_WIDGETS_CHECKBOXWIDGET_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + class World; + + class NDK_API CheckboxWidget : public BaseWidget + { + friend class Sdk; + + public: + CheckboxWidget(BaseWidget* parent = nullptr); + CheckboxWidget(const CheckboxWidget&) = delete; + CheckboxWidget(CheckboxWidget&&) = default; + ~CheckboxWidget() = default; + + //virtual CheckboxWidget* Clone() const = 0; + + inline void EnableAdaptativeMargin(bool enable = true); + inline void EnableCheckbox(bool enable = true); + inline void EnableTristate(bool enable = true); + + inline bool IsCheckboxEnabled() const; + inline bool IsMarginAdaptative() const; + inline bool IsTristateEnabled() const; + + inline const Nz::Vector2f& GetCheckboxSize() const; + inline Nz::Vector2f GetCheckboxBorderSize() const; + inline CheckboxState GetState() const; + inline float GetTextMargin() const; + + inline void SetCheckboxSize(const Nz::Vector2f& size); + CheckboxState SwitchToNextState(); + void SetState(CheckboxState state); + inline void SetTextMargin(float margin); + + void ResizeToContent() override; + inline void UpdateText(const Nz::AbstractTextDrawer& drawer); + + + CheckboxWidget& operator=(const CheckboxWidget&) = delete; + CheckboxWidget& operator=(CheckboxWidget&&) = default; + + NazaraSignal(OnStateChanged, const CheckboxWidget* /*checkbox*/); + + private: + static bool Initialize(); + static void Uninitialize(); + + void Layout() override; + void UpdateCheckbox(); + + void OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) override; + inline bool ContainsCheckbox(int x, int y) const; + + + EntityHandle m_checkboxBorderEntity; + EntityHandle m_checkboxBackgroundEntity; + EntityHandle m_checkboxContentEntity; + EntityHandle m_textEntity; + + Nz::TextureRef m_checkMark; + + Nz::SpriteRef m_checkboxContentSprite; + Nz::SpriteRef m_checkboxBorderSprite; + Nz::SpriteRef m_checkboxBackgroundSprite; + Nz::TextSpriteRef m_textSprite; + + static Nz::Color s_backgroundColor; + static Nz::Color s_disabledBackgroundColor; + static Nz::Color s_disabledBorderColor; + static Nz::Color s_borderColor; + + bool m_adaptativeMargin; + bool m_checkboxEnabled; + bool m_tristateEnabled; + + static float s_borderScale; + float m_textMargin; + CheckboxState m_state; + }; +} + +#include + +#endif // NDK_WIDGETS_CHECKBOXWIDGET_HPP diff --git a/SDK/include/NDK/Widgets/CheckboxWidget.inl b/SDK/include/NDK/Widgets/CheckboxWidget.inl new file mode 100644 index 000000000..cb20a1c0c --- /dev/null +++ b/SDK/include/NDK/Widgets/CheckboxWidget.inl @@ -0,0 +1,91 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +namespace Ndk +{ + inline void CheckboxWidget::EnableAdaptativeMargin(bool enable) + { + m_adaptativeMargin = enable; + Layout(); + } + + inline void CheckboxWidget::EnableCheckbox(bool enable) + { + m_checkboxEnabled = enable; + UpdateCheckbox(); + } + + inline void CheckboxWidget::EnableTristate(bool enable) + { + m_tristateEnabled = enable; + + if (m_tristateEnabled && GetState() == CheckboxState_Tristate) + SetState(CheckboxState_Unchecked); + } + + inline bool CheckboxWidget::IsCheckboxEnabled() const + { + return m_checkboxEnabled; + } + + inline bool CheckboxWidget::IsMarginAdaptative() const + { + return m_adaptativeMargin; + } + + inline bool CheckboxWidget::IsTristateEnabled() const + { + return m_tristateEnabled; + } + + inline const Nz::Vector2f& CheckboxWidget::GetCheckboxSize() const + { + return m_checkboxBorderSprite->GetSize(); + } + + inline Nz::Vector2f CheckboxWidget::GetCheckboxBorderSize() const + { + return GetCheckboxSize() / s_borderScale; + } + + inline CheckboxState CheckboxWidget::GetState() const + { + return m_state; + } + + inline float CheckboxWidget::GetTextMargin() const + { + return m_textMargin; + } + + inline void CheckboxWidget::SetCheckboxSize(const Nz::Vector2f& size) + { + m_checkboxBorderSprite->SetSize(size); + m_checkboxBackgroundSprite->SetSize(size - GetCheckboxBorderSize() * 2.f); + m_checkboxContentSprite->SetSize(GetCheckboxSize() - GetCheckboxBorderSize() * 2.f - Nz::Vector2f { 4.f, 4.f }); + + Layout(); + } + + inline void CheckboxWidget::SetTextMargin(float margin) + { + m_textMargin = margin; + Layout(); + } + + inline void CheckboxWidget::UpdateText(const Nz::AbstractTextDrawer& drawer) + { + m_textSprite->Update(drawer); + Layout(); + } + + inline bool CheckboxWidget::ContainsCheckbox(int x, int y) const + { + Nz::Vector2f checkboxSize = GetCheckboxSize(); + Nz::Vector3f pos = m_checkboxBorderEntity->GetComponent().GetPosition(Nz::CoordSys_Local); + + return x > pos.x && x < pos.x + checkboxSize.x && + y > pos.y && y < pos.y + checkboxSize.y; + } +} diff --git a/SDK/include/NDK/Widgets/Enums.hpp b/SDK/include/NDK/Widgets/Enums.hpp new file mode 100644 index 000000000..38891e3d5 --- /dev/null +++ b/SDK/include/NDK/Widgets/Enums.hpp @@ -0,0 +1,22 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +#pragma once + +#ifndef NAZARA_ENUMS_SDK_HPP +#define NAZARA_ENUMS_SDK_HPP + +namespace Ndk +{ + enum CheckboxState + { + CheckboxState_Checked, + CheckboxState_Tristate, + CheckboxState_Unchecked, + + CheckboxState_Max = CheckboxState_Unchecked + }; +} + +#endif // NAZARA_ENUMS_SDK_HPP diff --git a/SDK/include/NDK/Widgets/ProgressBarWidget.hpp b/SDK/include/NDK/Widgets/ProgressBarWidget.hpp new file mode 100644 index 000000000..354e0b35f --- /dev/null +++ b/SDK/include/NDK/Widgets/ProgressBarWidget.hpp @@ -0,0 +1,106 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +#pragma once + +#ifndef NDK_WIDGETS_PROGRESSBARWIDGET_HPP +#define NDK_WIDGETS_PROGRESSBARWIDGET_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + class World; + + class NDK_API ProgressBarWidget : public BaseWidget + { + friend class Sdk; + + public: + ProgressBarWidget(BaseWidget* parent = nullptr); + ProgressBarWidget(const ProgressBarWidget&) = delete; + ProgressBarWidget(ProgressBarWidget&&) = default; + ~ProgressBarWidget() = default; + + //virtual ProgressBarWidget* Clone() const = 0; + + inline void EnableText(bool enable = true); + inline void EnableBorder(bool enable = true); + + inline bool IsTextEnabled() const; + inline bool IsBorderEnabled() const; + + + inline unsigned GetPercentageValue() const; + inline Nz::Vector2f GetProgressBarSize() const; + inline Nz::Vector2f GetProgressBarBorderSize() const; + inline float GetTextMargin() const; + + + inline const Nz::Color& GetBarBackgroundColor() const; + inline const Nz::Color& GetBarBackgroundCornerColor() const; + inline const Nz::Color& GetBarColor() const; + inline const Nz::Color& GetBarCornerColor() const; + + inline const Nz::TextureRef& GetBarBackgroundTexture() const; + inline const Nz::TextureRef& GetBarTexture() const; + + static const Nz::Color& GetDefaultBarColor(); + static const Nz::Color& GetDefaultBarCornerColor(); + static const Nz::Color& GetDefaultBarBackgroundColor(); + static const Nz::Color& GetDefaultBarBackgroundCornerColor(); + + + inline void SetBarBackgroundColor(const Nz::Color& globalColor, const Nz::Color& cornerColor); + inline void SetBarBackgroundTexture(Nz::TextureRef texture, bool resetColors = true); + inline void SetBarColor(const Nz::Color& globalColor, const Nz::Color& cornerColor); + inline void SetBarTexture(Nz::TextureRef texture, bool resetColors = true); + + + inline void SetPercentageValue(unsigned percentage); + inline void SetTextMargin(float margin); + inline void SetTextColor(const Nz::Color& color); + + inline void ResizeToContent() override {} + + NazaraSignal(OnValueChanged, const ProgressBarWidget* /*progressBar*/); + + private: + void Layout() override; + inline void UpdateText(); + + + EntityHandle m_borderEntity; + EntityHandle m_barEntity; + EntityHandle m_textEntity; + + static Nz::Color s_borderColor; + static Nz::Color s_barBackgroundColor; + static Nz::Color s_barBackgroundCornerColor; + static Nz::Color s_barColor; + static Nz::Color s_barCornerColor; + Nz::Color m_textColor; + + Nz::SpriteRef m_borderSprite; + Nz::SpriteRef m_barBackgroundSprite; + Nz::SpriteRef m_barSprite; + Nz::TextSpriteRef m_textSprite; + + static float s_borderScale; + float m_textMargin; + unsigned m_value; + }; +} + +#include + +#endif // NDK_WIDGETS_PROGRESSBARWIDGET_HPP diff --git a/SDK/include/NDK/Widgets/ProgressBarWidget.inl b/SDK/include/NDK/Widgets/ProgressBarWidget.inl new file mode 100644 index 000000000..325149af9 --- /dev/null +++ b/SDK/include/NDK/Widgets/ProgressBarWidget.inl @@ -0,0 +1,156 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +namespace Ndk +{ + inline void ProgressBarWidget::EnableText(bool enable) + { + m_textEntity->Enable(enable); + Layout(); + } + + inline void ProgressBarWidget::EnableBorder(bool enable) + { + m_borderEntity->Enable(enable); + } + + inline bool ProgressBarWidget::IsTextEnabled() const + { + return m_textEntity->IsEnabled(); + } + + inline bool ProgressBarWidget::IsBorderEnabled() const + { + return m_borderEntity->IsEnabled(); + } + + + inline unsigned ProgressBarWidget::GetPercentageValue() const + { + return m_value; + } + + inline Nz::Vector2f ProgressBarWidget::GetProgressBarSize() const + { + Nz::Vector3f progressBarSize = m_borderSprite->GetBoundingVolume().obb.localBox.GetLengths(); + + if (IsTextEnabled()) + { + Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); + progressBarSize -= { textSize.x + m_textMargin, 0.f, 0.f }; + } + + return { progressBarSize.x, progressBarSize.y }; + } + + inline Nz::Vector2f ProgressBarWidget::GetProgressBarBorderSize() const + { + Nz::Vector2f barSize = GetProgressBarSize(); + return { barSize.y / s_borderScale, barSize.y / s_borderScale }; + } + + inline float ProgressBarWidget::GetTextMargin() const + { + return m_textMargin; + } + + + inline const Nz::Color& ProgressBarWidget::GetBarBackgroundColor() const + { + return m_barBackgroundSprite->GetColor(); + } + + inline const Nz::Color& ProgressBarWidget::GetBarBackgroundCornerColor() const + { + return m_barBackgroundSprite->GetCornerColor(Nz::RectCorner_LeftTop); + } + + inline const Nz::Color& ProgressBarWidget::GetBarColor() const + { + return m_barSprite->GetColor(); + } + + inline const Nz::Color& ProgressBarWidget::GetBarCornerColor() const + { + return m_barSprite->GetCornerColor(Nz::RectCorner_LeftTop); + } + + + inline const Nz::TextureRef& ProgressBarWidget::GetBarBackgroundTexture() const + { + return m_barBackgroundSprite->GetMaterial()->GetDiffuseMap(); + } + + inline const Nz::TextureRef& ProgressBarWidget::GetBarTexture() const + { + return m_barSprite->GetMaterial()->GetDiffuseMap(); + } + + + inline void ProgressBarWidget::SetBarBackgroundColor(const Nz::Color& globalColor, const Nz::Color& cornerColor) + { + m_barBackgroundSprite->SetColor(globalColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_LeftTop, cornerColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_RightTop, cornerColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_LeftBottom, globalColor); + m_barBackgroundSprite->SetCornerColor(Nz::RectCorner_RightBottom, globalColor); + } + + inline void ProgressBarWidget::SetBarBackgroundTexture(Nz::TextureRef texture, bool resetColors) + { + m_barBackgroundSprite->SetTexture(texture, false); + + if (resetColors) + SetBarBackgroundColor(Nz::Color::White, Nz::Color::White); + } + + inline void ProgressBarWidget::SetBarColor(const Nz::Color& globalColor, const Nz::Color& cornerColor) + { + m_barSprite->SetColor(globalColor); + m_barSprite->SetCornerColor(Nz::RectCorner_LeftTop, cornerColor); + m_barSprite->SetCornerColor(Nz::RectCorner_RightTop, cornerColor); + m_barSprite->SetCornerColor(Nz::RectCorner_LeftBottom, globalColor); + m_barSprite->SetCornerColor(Nz::RectCorner_RightBottom, globalColor); + } + + inline void ProgressBarWidget::SetBarTexture(Nz::TextureRef texture, bool resetColors) + { + m_barSprite->SetTexture(texture, false); + + if (resetColors) + SetBarColor(Nz::Color::White, Nz::Color::White); + } + + + inline void ProgressBarWidget::SetPercentageValue(unsigned percentage) + { + m_value = percentage; + OnValueChanged(this); + Layout(); + } + + inline void ProgressBarWidget::SetTextMargin(float margin) + { + m_textMargin = margin; + + if (IsTextEnabled()) + Layout(); + } + + inline void ProgressBarWidget::SetTextColor(const Nz::Color& color) + { + m_textColor = color; + UpdateText(); + } + + inline void ProgressBarWidget::UpdateText() + { + if (IsTextEnabled()) + { + Nz::Vector2f size = GetContentSize(); + m_textSprite->Update(Nz::SimpleTextDrawer::Draw(Nz::String::Number(m_value).Append('%'), + static_cast(std::min(size.x, size.y) / 2.f), 0u, m_textColor)); + } + } +} diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.hpp b/SDK/include/NDK/Widgets/TextAreaWidget.hpp index 0bf5a3a59..7bab6f1bf 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.hpp +++ b/SDK/include/NDK/Widgets/TextAreaWidget.hpp @@ -32,7 +32,8 @@ namespace Ndk inline void EnableMultiline(bool enable = true); - inline std::size_t GetCursorPosition() const; + inline const Nz::Vector2ui& GetCursorPosition() const; + inline std::size_t GetGlyphUnderCursor() const; inline std::size_t GetLineCount() const; inline const Nz::String& GetText() const; inline const Nz::Color& GetTextColor() const; @@ -43,10 +44,12 @@ namespace Ndk inline bool IsReadOnly() const; inline void MoveCursor(int offset); + inline void MoveCursor(const Nz::Vector2i& offset); void ResizeToContent() override; - inline void SetCursorPosition(std::size_t cursorPosition); + inline void SetCursorPosition(std::size_t glyphIndex); + inline void SetCursorPosition(Nz::Vector2ui cursorPosition); inline void SetReadOnly(bool readOnly = true); inline void SetText(const Nz::String& text); inline void SetTextColor(const Nz::Color& text); @@ -82,7 +85,8 @@ namespace Ndk Nz::SimpleTextDrawer m_drawer; Nz::SpriteRef m_cursorSprite; Nz::TextSpriteRef m_textSprite; - std::size_t m_cursorPosition; + Nz::Vector2ui m_cursorPosition; + std::size_t m_cursorGlyph; bool m_multiLineEnabled; bool m_readOnly; }; diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.inl b/SDK/include/NDK/Widgets/TextAreaWidget.inl index 077f538ec..ffc75c8ba 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.inl +++ b/SDK/include/NDK/Widgets/TextAreaWidget.inl @@ -20,11 +20,16 @@ namespace Ndk m_multiLineEnabled = enable; } - inline std::size_t TextAreaWidget::GetCursorPosition() const + inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const { return m_cursorPosition; } + inline std::size_t Ndk::TextAreaWidget::GetGlyphUnderCursor() const + { + return m_cursorGlyph; + } + inline std::size_t TextAreaWidget::GetLineCount() const { return m_drawer.GetLineCount(); @@ -53,22 +58,84 @@ namespace Ndk inline void TextAreaWidget::MoveCursor(int offset) { if (offset >= 0) - SetCursorPosition(m_cursorPosition += static_cast(offset)); + SetCursorPosition(m_cursorGlyph + static_cast(offset)); else { std::size_t nOffset = static_cast(-offset); - if (nOffset >= m_cursorPosition) + if (nOffset >= m_cursorGlyph) SetCursorPosition(0); else - SetCursorPosition(m_cursorPosition - nOffset); + SetCursorPosition(m_cursorGlyph - nOffset); } } - inline void TextAreaWidget::SetCursorPosition(std::size_t cursorPosition) + inline void TextAreaWidget::MoveCursor(const Nz::Vector2i& offset) { - OnTextAreaCursorMove(this, &cursorPosition); + auto BoundOffset = [] (unsigned int cursorPosition, int offset) -> unsigned int + { + if (offset >= 0) + return cursorPosition + offset; + else + { + unsigned int nOffset = static_cast(-offset); + if (nOffset >= cursorPosition) + return 0; + else + return cursorPosition - nOffset; + } + }; - m_cursorPosition = std::min(cursorPosition, m_drawer.GetGlyphCount()); + Nz::Vector2ui cursorPosition = m_cursorPosition; + cursorPosition.x = BoundOffset(static_cast(cursorPosition.x), offset.x); + cursorPosition.y = BoundOffset(static_cast(cursorPosition.y), offset.y); + + SetCursorPosition(cursorPosition); + } + + inline void TextAreaWidget::SetCursorPosition(std::size_t glyphIndex) + { + OnTextAreaCursorMove(this, &glyphIndex); + + m_cursorGlyph = std::min(glyphIndex, m_drawer.GetGlyphCount()); + + std::size_t lineCount = m_drawer.GetLineCount(); + std::size_t line = 0U; + for (std::size_t i = line + 1; i < lineCount; ++i) + { + if (m_drawer.GetLine(i).glyphIndex > m_cursorGlyph) + break; + + line = i; + } + + const auto& lineInfo = m_drawer.GetLine(line); + + m_cursorPosition.y = line; + m_cursorPosition.x = m_cursorGlyph - lineInfo.glyphIndex; + + RefreshCursor(); + } + + inline void TextAreaWidget::SetCursorPosition(Nz::Vector2ui cursorPosition) + { + std::size_t lineCount = m_drawer.GetLineCount(); + if (cursorPosition.y >= lineCount) + cursorPosition.y = static_cast(lineCount - 1); + + m_cursorPosition = cursorPosition; + + const auto& lineInfo = m_drawer.GetLine(cursorPosition.y); + if (cursorPosition.y + 1 < lineCount) + { + const auto& nextLineInfo = m_drawer.GetLine(cursorPosition.y + 1); + cursorPosition.x = std::min(cursorPosition.x, static_cast(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1)); + } + + std::size_t glyphIndex = lineInfo.glyphIndex + cursorPosition.x; + + OnTextAreaCursorMove(this, &glyphIndex); + + m_cursorGlyph = std::min(glyphIndex, m_drawer.GetGlyphCount()); RefreshCursor(); } diff --git a/SDK/include/NDK/World.hpp b/SDK/include/NDK/World.hpp index 9b2546eda..29b9a4a9e 100644 --- a/SDK/include/NDK/World.hpp +++ b/SDK/include/NDK/World.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,7 @@ namespace Ndk friend Entity; public: - using EntityList = std::vector; + using EntityVector = std::vector; inline World(bool addDefaultSystems = true); World(const World&) = delete; @@ -41,21 +42,21 @@ namespace Ndk template SystemType& AddSystem(Args&&... args); const EntityHandle& CreateEntity(); - inline EntityList CreateEntities(unsigned int count); + inline EntityVector CreateEntities(unsigned int count); void Clear() noexcept; const EntityHandle& CloneEntity(EntityId id); - const EntityHandle& GetEntity(EntityId id); - inline const EntityList& GetEntities(); + inline const EntityHandle& GetEntity(EntityId id); + inline const EntityList& GetEntities() const; inline BaseSystem& GetSystem(SystemIndex index); template SystemType& GetSystem(); inline bool HasSystem(SystemIndex index) const; template bool HasSystem() const; - void KillEntity(Entity* entity); - inline void KillEntities(const EntityList& list); + inline void KillEntity(Entity* entity); + inline void KillEntities(const EntityVector& list); inline bool IsEntityValid(const Entity* entity) const; inline bool IsEntityIdValid(EntityId id) const; @@ -79,19 +80,22 @@ namespace Ndk struct EntityBlock { EntityBlock(Entity&& e) : - entity(std::move(e)) + entity(std::move(e)), + handle(&entity) { } EntityBlock(EntityBlock&& block) = default; Entity entity; - std::size_t aliveIndex; + EntityHandle handle; }; std::vector> m_systems; std::vector m_orderedSystems; std::vector m_entities; + std::vector m_entityBlocks; + std::vector> m_waitingEntities; std::vector m_freeIdList; EntityList m_aliveEntities; Nz::Bitset m_dirtyEntities; diff --git a/SDK/include/NDK/World.inl b/SDK/include/NDK/World.inl index dcdb0c057..d45f0ff1d 100644 --- a/SDK/include/NDK/World.inl +++ b/SDK/include/NDK/World.inl @@ -82,9 +82,9 @@ namespace Ndk * \param count Number of entities to create */ - inline World::EntityList World::CreateEntities(unsigned int count) + inline World::EntityVector World::CreateEntities(unsigned int count) { - EntityList list; + EntityVector list; list.reserve(count); for (unsigned int i = 0; i < count; ++i) @@ -98,7 +98,7 @@ namespace Ndk * \return A constant reference to the entities */ - inline const World::EntityList& World::GetEntities() + inline const EntityList& World::GetEntities() const { return m_aliveEntities; } @@ -164,18 +164,53 @@ namespace Ndk return HasSystem(index); } + /*! + * \brief Marks an entity for deletion + * + * \param Pointer to the entity + * + * \remark If the entity pointer is invalid, nothing is done + * \remark For safety, entities are not killed until the next world update + */ + inline void World::KillEntity(Entity* entity) + { + if (IsEntityValid(entity)) + m_killedEntities.UnboundedSet(entity->GetId(), true); + } + /*! * \brief Kills a set of entities * + * This function has the same effect as calling KillEntity for every entity contained in the vector + * * \param list Set of entities to kill */ - - inline void World::KillEntities(const EntityList& list) + inline void World::KillEntities(const EntityVector& list) { for (const EntityHandle& entity : list) KillEntity(entity); } + /*! + * \brief Gets an entity + * \return A constant reference to a handle of the entity + * + * \param id Identifier of the entity + * + * \remark Handle referenced by this function can move in memory when updating the world, do not keep a reference to a handle from a world update to another + * \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned + */ + inline const EntityHandle& World::GetEntity(EntityId id) + { + if (IsEntityIdValid(id)) + return m_entityBlocks[id]->handle; + else + { + NazaraError("Invalid ID"); + return EntityHandle::InvalidHandle; + } + } + /*! * \brief Checks whether or not an entity is valid * \return true If it is the case @@ -197,7 +232,7 @@ namespace Ndk inline bool World::IsEntityIdValid(EntityId id) const { - return id < m_entities.size() && m_entities[id].entity.IsValid(); + return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid(); } /*! @@ -266,10 +301,12 @@ namespace Ndk { m_aliveEntities = std::move(world.m_aliveEntities); m_dirtyEntities = std::move(world.m_dirtyEntities); + m_entityBlocks = std::move(world.m_entityBlocks); m_freeIdList = std::move(world.m_freeIdList); m_killedEntities = std::move(world.m_killedEntities); m_orderedSystems = std::move(world.m_orderedSystems); m_orderedSystemsUpdated = world.m_orderedSystemsUpdated; + m_waitingEntities = std::move(world.m_waitingEntities); m_entities = std::move(world.m_entities); for (EntityBlock& block : m_entities) @@ -284,7 +321,7 @@ namespace Ndk inline void World::Invalidate() { - m_dirtyEntities.Resize(m_entities.size(), false); + m_dirtyEntities.Resize(m_entityBlocks.size(), false); m_dirtyEntities.Set(true); // Activation of all bits } diff --git a/SDK/src/NDK/Application.cpp b/SDK/src/NDK/Application.cpp index e159c0101..c70ec181b 100644 --- a/SDK/src/NDK/Application.cpp +++ b/SDK/src/NDK/Application.cpp @@ -164,25 +164,25 @@ namespace Ndk LuaAPI::RegisterClasses(overlay->lua); // Override "print" function to add a line in the console - overlay->lua.PushFunction([&consoleRef] (Nz::LuaInstance& instance) + overlay->lua.PushFunction([&consoleRef] (Nz::LuaState& state) { Nz::StringStream stream; - unsigned int argCount = instance.GetStackTop(); - instance.GetGlobal("tostring"); + unsigned int argCount = state.GetStackTop(); + state.GetGlobal("tostring"); for (unsigned int i = 1; i <= argCount; ++i) { - instance.PushValue(-1); // tostring function - instance.PushValue(i); // argument - instance.Call(1, 1); + state.PushValue(-1); // tostring function + state.PushValue(i); // argument + state.Call(1, 1); std::size_t length; - const char* str = instance.CheckString(-1, &length); + const char* str = state.CheckString(-1, &length); if (i > 1) stream << '\t'; stream << Nz::String(str, length); - instance.Pop(1); + state.Pop(1); } consoleRef.AddLine(stream); diff --git a/SDK/src/NDK/BaseComponent.cpp b/SDK/src/NDK/BaseComponent.cpp index 4af8caed2..204076e54 100644 --- a/SDK/src/NDK/BaseComponent.cpp +++ b/SDK/src/NDK/BaseComponent.cpp @@ -54,6 +54,15 @@ namespace Ndk { } + /*! + * \brief Operation to perform when the entity is destroyed and we're still attached to it + * + * \remark This is always called before the entity proper destruction, and thus its components. + */ + void BaseComponent::OnEntityDestruction() + { + } + std::vector BaseComponent::s_entries; std::unordered_map BaseComponent::s_idToIndex; } diff --git a/SDK/src/NDK/BaseWidget.cpp b/SDK/src/NDK/BaseWidget.cpp index c4ef2d1f8..7368558d3 100644 --- a/SDK/src/NDK/BaseWidget.cpp +++ b/SDK/src/NDK/BaseWidget.cpp @@ -11,6 +11,20 @@ namespace Ndk { + /*! + * \ingroup NDK + * \class Ndk::BaseWidget + * \brief Abstract class serving as a base class for all widgets + */ + + /*! + * \brief Constructs a BaseWidget object using another widget as its parent + * + * \param parent Parent widget, must be valid and attached to a canvas + * + * Constructs a BaseWidget object using another widget as a base. + * This will also register the widget to the canvas owning the top-most widget. + */ BaseWidget::BaseWidget(BaseWidget* parent) : BaseWidget() { @@ -24,11 +38,19 @@ namespace Ndk RegisterToCanvas(); } + /*! + * \brief Frees the widget, unregistering it from its canvas + */ BaseWidget::~BaseWidget() { UnregisterFromCanvas(); } + /*! + * \brief Destroy the widget, deleting it in the process. + * + * Calling this function immediately destroys the widget, freeing its memory. + */ void BaseWidget::Destroy() { NazaraAssert(this != m_canvas, "Canvas cannot be destroyed by calling Destroy()"); @@ -36,6 +58,9 @@ namespace Ndk m_widgetParent->DestroyChild(this); //< This does delete us } + /*! + * \brief Enable or disables the widget background. + */ void BaseWidget::EnableBackground(bool enable) { if (m_backgroundEntity.IsValid() == enable) @@ -142,11 +167,11 @@ namespace Ndk m_canvas->NotifyWidgetBoxUpdate(m_canvasIndex); } - void BaseWidget::OnKeyPressed(const Nz::WindowEvent::KeyEvent& key) + void BaseWidget::OnKeyPressed(const Nz::WindowEvent::KeyEvent& /*key*/) { } - void BaseWidget::OnKeyReleased(const Nz::WindowEvent::KeyEvent& key) + void BaseWidget::OnKeyReleased(const Nz::WindowEvent::KeyEvent& /*key*/) { } @@ -154,15 +179,15 @@ namespace Ndk { } - void BaseWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY) + void BaseWidget::OnMouseMoved(int /*x*/, int /*y*/, int /*deltaX*/, int /*deltaY*/) { } - void BaseWidget::OnMouseButtonPress(int x, int y, Nz::Mouse::Button button) + void BaseWidget::OnMouseButtonPress(int /*x*/, int /*y*/, Nz::Mouse::Button /*button*/) { } - void BaseWidget::OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) + void BaseWidget::OnMouseButtonRelease(int /*x*/, int /*y*/, Nz::Mouse::Button /*button*/) { } @@ -170,11 +195,11 @@ namespace Ndk { } - void BaseWidget::OnParentResized(const Nz::Vector2f& newSize) + void BaseWidget::OnParentResized(const Nz::Vector2f& /*newSize*/) { } - void BaseWidget::OnTextEntered(char32_t character, bool repeated) + void BaseWidget::OnTextEntered(char32_t /*character*/, bool /*repeated*/) { } diff --git a/SDK/src/NDK/Canvas.cpp b/SDK/src/NDK/Canvas.cpp index 84e4b5bd8..11e9d1ce9 100644 --- a/SDK/src/NDK/Canvas.cpp +++ b/SDK/src/NDK/Canvas.cpp @@ -48,7 +48,7 @@ namespace Ndk m_widgetBoxes.pop_back(); } - void Canvas::OnMouseButtonPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent& event) + void Canvas::OnEventMouseButtonPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent& event) { if (m_hoveredWidget) { @@ -59,7 +59,7 @@ namespace Ndk } } - void Canvas::OnMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent & event) + void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent & event) { if (m_hoveredWidget) { @@ -70,7 +70,7 @@ namespace Ndk } } - void Canvas::OnMouseMoved(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseMoveEvent& event) + void Canvas::OnEventMouseMoved(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseMoveEvent& event) { const WidgetBox* bestEntry = nullptr; float bestEntryArea = std::numeric_limits::infinity(); @@ -120,7 +120,7 @@ namespace Ndk } } - void Canvas::OnMouseLeft(const Nz::EventHandler* /*eventHandler*/) + void Canvas::OnEventMouseLeft(const Nz::EventHandler* /*eventHandler*/) { if (m_hoveredWidget) { @@ -129,19 +129,19 @@ namespace Ndk } } - void Canvas::OnKeyPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event) + void Canvas::OnEventKeyPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event) { if (m_keyboardOwner) m_keyboardOwner->OnKeyPressed(event); } - void Canvas::OnKeyReleased(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event) + void Canvas::OnEventKeyReleased(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event) { if (m_keyboardOwner) m_keyboardOwner->OnKeyReleased(event); } - void Canvas::OnTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event) + void Canvas::OnEventTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event) { if (m_keyboardOwner) m_keyboardOwner->OnTextEntered(event.character, event.repeated); diff --git a/SDK/src/NDK/Components/CameraComponent.cpp b/SDK/src/NDK/Components/CameraComponent.cpp index 13b6bdd2b..2441dd7a8 100644 --- a/SDK/src/NDK/Components/CameraComponent.cpp +++ b/SDK/src/NDK/Components/CameraComponent.cpp @@ -93,6 +93,17 @@ namespace Ndk return m_projectionMatrix; } + + /*! + * \brief Gets the projection type of the camera + * \return Projection type of the camera + */ + Nz::ProjectionType CameraComponent::GetProjectionType() const + { + return m_projectionType; + } + + /*! * \brief Gets the target of the camera * \return A constant reference to the render target of the camera diff --git a/SDK/src/NDK/Components/PhysicsComponent2D.cpp b/SDK/src/NDK/Components/PhysicsComponent2D.cpp index b64ee37b5..58cab2982 100644 --- a/SDK/src/NDK/Components/PhysicsComponent2D.cpp +++ b/SDK/src/NDK/Components/PhysicsComponent2D.cpp @@ -88,5 +88,11 @@ namespace Ndk m_object.reset(); } + void PhysicsComponent2D::OnEntityDestruction() + { + // Kill rigidbody before entity destruction to force contact callbacks to be called while the entity is still valid + m_object.reset(); + } + ComponentIndex PhysicsComponent2D::componentIndex; } diff --git a/SDK/src/NDK/Components/PhysicsComponent3D.cpp b/SDK/src/NDK/Components/PhysicsComponent3D.cpp index 2581723a7..31b3fb6ac 100644 --- a/SDK/src/NDK/Components/PhysicsComponent3D.cpp +++ b/SDK/src/NDK/Components/PhysicsComponent3D.cpp @@ -88,5 +88,11 @@ namespace Ndk m_object.reset(); } + void PhysicsComponent3D::OnEntityDestruction() + { + // Kill rigid body before entity destruction to force contact callbacks to be called while the entity is still valid + m_object.reset(); + } + ComponentIndex PhysicsComponent3D::componentIndex; } diff --git a/SDK/src/NDK/Console.cpp b/SDK/src/NDK/Console.cpp index 9719e4b62..a59bfdf81 100644 --- a/SDK/src/NDK/Console.cpp +++ b/SDK/src/NDK/Console.cpp @@ -33,10 +33,10 @@ namespace Ndk * \param instance Lua instance that will interact with the world */ - Console::Console(World& world, const Nz::Vector2f& size, Nz::LuaInstance& instance) : + Console::Console(World& world, const Nz::Vector2f& size, Nz::LuaState& state) : m_historyPosition(0), m_defaultFont(Nz::Font::GetDefault()), - m_instance(instance), + m_state(state), m_size(size), m_opened(false), m_characterSize(24) @@ -300,7 +300,7 @@ namespace Ndk void Console::ExecuteInput() { Nz::String input = m_inputDrawer.GetText(); - Nz::String inputCmd = input.SubString(s_inputPrefixSize);; + Nz::String inputCmd = input.SubString(s_inputPrefixSize); m_inputDrawer.SetText(s_inputPrefix); if (m_commandHistory.empty() || m_commandHistory.back() != inputCmd) @@ -310,8 +310,8 @@ namespace Ndk AddLineInternal(input); //< With the input prefix - if (!m_instance.Execute(inputCmd)) - AddLineInternal(m_instance.GetLastError(), Nz::Color::Red); + if (!m_state.Execute(inputCmd)) + AddLineInternal(m_state.GetLastError(), Nz::Color::Red); RefreshHistory(); } diff --git a/SDK/src/NDK/Entity.cpp b/SDK/src/NDK/Entity.cpp index d88556a31..fab08b237 100644 --- a/SDK/src/NDK/Entity.cpp +++ b/SDK/src/NDK/Entity.cpp @@ -23,13 +23,16 @@ namespace Ndk Entity::Entity(Entity&& entity) : HandledObject(std::move(entity)), m_components(std::move(entity.m_components)), + m_containedInLists(std::move(entity.m_containedInLists)), m_componentBits(std::move(entity.m_componentBits)), + m_removedComponentBits(std::move(entity.m_removedComponentBits)), m_systemBits(std::move(entity.m_systemBits)), m_id(entity.m_id), m_world(entity.m_world), m_enabled(entity.m_enabled), m_valid(entity.m_valid) { + entity.m_world = nullptr; } /*! @@ -53,7 +56,8 @@ namespace Ndk Entity::~Entity() { - Destroy(); + if (m_world) + Destroy(); } /*! @@ -145,6 +149,17 @@ namespace Ndk void Entity::Destroy() { + OnEntityDestruction(this); + OnEntityDestruction.Clear(); + + // We prepare components for entity destruction (some components needs this to handle some final callbacks while the entity is still valid) + for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) + m_components[i]->OnEntityDestruction(); + + // Detach components while they're still attached to systems + for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) + m_components[i]->SetEntity(nullptr); + // We alert each system for (std::size_t index = m_systemBits.FindFirst(); index != m_systemBits.npos; index = m_systemBits.FindNext(index)) { @@ -158,16 +173,19 @@ namespace Ndk } m_systemBits.Clear(); - // We properly destroy each component - for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i)) - m_components[i]->SetEntity(nullptr); - + // Destroy components m_components.clear(); m_componentBits.Reset(); - // And then free every handle + // Free every handle UnregisterAllHandles(); + // Remove from every list + for (EntityList* list : m_containedInLists) + list->NotifyEntityDestruction(this); + + m_containedInLists.clear(); + m_valid = false; } diff --git a/SDK/src/NDK/EntityList.cpp b/SDK/src/NDK/EntityList.cpp new file mode 100644 index 000000000..03fd3afc3 --- /dev/null +++ b/SDK/src/NDK/EntityList.cpp @@ -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 +#include + +namespace Ndk +{ + const EntityHandle& EntityList::iterator::operator*() const + { + return m_list->GetWorld()->GetEntity(static_cast(m_nextEntityId)); + } +} diff --git a/SDK/src/NDK/Lua/LuaBinding.cpp b/SDK/src/NDK/Lua/LuaBinding.cpp index cb763b3b4..4bca51e19 100644 --- a/SDK/src/NDK/Lua/LuaBinding.cpp +++ b/SDK/src/NDK/Lua/LuaBinding.cpp @@ -22,9 +22,10 @@ namespace Ndk utility = LuaBinding_Base::BindUtility(*this); #ifndef NDK_SERVER - audio = LuaBinding_Base::BindAudio(*this); + audio = LuaBinding_Base::BindAudio(*this); renderer = LuaBinding_Base::BindRenderer(*this); graphics = LuaBinding_Base::BindGraphics(*this); + platform = LuaBinding_Base::BindPlatform(*this); #endif sdk = LuaBinding_Base::BindSDK(*this); @@ -36,31 +37,32 @@ namespace Ndk * \param instance Lua instance that will interact with the engine & SDK */ - void LuaBinding::RegisterClasses(Nz::LuaInstance& instance) + void LuaBinding::RegisterClasses(Nz::LuaState& state) { - core->Register(instance); - math->Register(instance); - network->Register(instance); - sdk->Register(instance); - utility->Register(instance); + core->Register(state); + math->Register(state); + network->Register(state); + sdk->Register(state); + utility->Register(state); #ifndef NDK_SERVER - audio->Register(instance); - graphics->Register(instance); - renderer->Register(instance); + audio->Register(state); + graphics->Register(state); + renderer->Register(state); + platform->Register(state); #endif // ComponentType (fake enumeration to expose component indexes) - instance.PushTable(0, m_componentBinding.size()); + state.PushTable(0, m_componentBinding.size()); { for (const ComponentBinding& entry : m_componentBinding) { if (entry.name.IsEmpty()) continue; - instance.PushField(entry.name, entry.index); + state.PushField(entry.name, entry.index); } } - instance.SetGlobal("ComponentType"); + state.SetGlobal("ComponentType"); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Audio.cpp b/SDK/src/NDK/Lua/LuaBinding_Audio.cpp index 619fe2850..1611c1b8c 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Audio.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Audio.cpp @@ -77,7 +77,7 @@ namespace Ndk music.BindMethod("Stop", &Nz::Music::Stop); // Manual - music.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Music& instance, std::size_t /*argumentCount*/) -> int + music.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Music& instance, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Music("); ss << instance.GetFilePath() << ')'; @@ -104,7 +104,7 @@ namespace Ndk sound.BindMethod("SetPlayingOffset", &Nz::Sound::SetPlayingOffset); // Manual - sound.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Sound& instance, std::size_t /*argumentCount*/) -> int + sound.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Sound& instance, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Sound("); if (const Nz::SoundBuffer* buffer = instance.GetBuffer()) @@ -120,7 +120,7 @@ namespace Ndk /*********************************** Nz::SoundBuffer **********************************/ soundBuffer.Reset("SoundBuffer"); { - soundBuffer.SetConstructor([] (Nz::LuaInstance& lua, Nz::SoundBufferRef* instance, std::size_t argumentCount) + soundBuffer.SetConstructor([] (Nz::LuaState& lua, Nz::SoundBufferRef* instance, std::size_t argumentCount) { NazaraUnused(lua); NazaraUnused(argumentCount); @@ -143,7 +143,7 @@ namespace Ndk soundBuffer.BindStaticMethod("IsFormatSupported", &Nz::SoundBuffer::IsFormatSupported); // Manual - soundBuffer.BindMethod("Create", [] (Nz::LuaInstance& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int + soundBuffer.BindMethod("Create", [] (Nz::LuaState& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int { int index = 2; Nz::AudioFormat format = lua.Check(&index); @@ -158,13 +158,13 @@ namespace Ndk return 1; }); - soundBuffer.BindMethod("GetSamples", [] (Nz::LuaInstance& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int + soundBuffer.BindMethod("GetSamples", [] (Nz::LuaState& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int { lua.PushString(reinterpret_cast(instance->GetSamples()), instance->GetSampleCount() * sizeof(Nz::Int16)); return 1; }); - soundBuffer.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int + soundBuffer.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::SoundBufferRef& instance, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("SoundBuffer("); if (instance->IsValid()) @@ -188,11 +188,11 @@ namespace Ndk * * \param instance Lua instance that will interact with the Audio classes */ - void LuaBinding_Audio::Register(Nz::LuaInstance& instance) + void LuaBinding_Audio::Register(Nz::LuaState& state) { - music.Register(instance); - sound.Register(instance); - soundBuffer.Register(instance); - soundEmitter.Register(instance); + music.Register(state); + sound.Register(state); + soundBuffer.Register(state); + soundEmitter.Register(state); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Core.cpp b/SDK/src/NDK/Lua/LuaBinding_Core.cpp index fc53f72c3..1e4a02e7f 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Core.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Core.cpp @@ -32,28 +32,28 @@ namespace Ndk stream.BindMethod("IsWritable", &Nz::Stream::IsWritable); stream.BindMethod("SetCursorPos", &Nz::Stream::SetCursorPos); - stream.BindMethod("Read", [] (Nz::LuaInstance& lua, Nz::Stream& instance, std::size_t /*argumentCount*/) -> int { + stream.BindMethod("Read", [] (Nz::LuaState& lua, Nz::Stream& stream, std::size_t /*argumentCount*/) -> int { int argIndex = 2; std::size_t length = lua.Check(&argIndex); std::unique_ptr buffer(new char[length]); - std::size_t readLength = instance.Read(buffer.get(), length); + std::size_t readLength = stream.Read(buffer.get(), length); lua.PushString(Nz::String(buffer.get(), readLength)); return 1; }); - stream.BindMethod("Write", [] (Nz::LuaInstance& lua, Nz::Stream& instance, std::size_t /*argumentCount*/) -> int { + stream.BindMethod("Write", [] (Nz::LuaState& lua, Nz::Stream& stream, std::size_t /*argumentCount*/) -> int { int argIndex = 2; std::size_t bufferSize = 0; const char* buffer = lua.CheckString(argIndex, &bufferSize); - if (instance.IsTextModeEnabled()) - lua.Push(instance.Write(Nz::String(buffer, bufferSize))); + if (stream.IsTextModeEnabled()) + lua.Push(stream.Write(Nz::String(buffer, bufferSize))); else - lua.Push(instance.Write(buffer, bufferSize)); + lua.Push(stream.Write(buffer, bufferSize)); return 1; }); } @@ -61,7 +61,7 @@ namespace Ndk /*********************************** Nz::Clock **********************************/ clock.Reset("Clock"); { - clock.SetConstructor([] (Nz::LuaInstance& lua, Nz::Clock* instance, std::size_t argumentCount) + clock.SetConstructor([] (Nz::LuaState& lua, Nz::Clock* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 2U); @@ -103,11 +103,11 @@ namespace Ndk clock.BindMethod("Unpause", &Nz::Clock::Unpause); // Manual - clock.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Clock& instance, std::size_t /*argumentCount*/) -> int { + clock.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Clock& clock, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Clock(Elapsed: "); - ss << instance.GetSeconds(); + ss << clock.GetSeconds(); ss << "s, Paused: "; - ss << instance.IsPaused(); + ss << clock.IsPaused(); ss << ')'; lua.PushString(ss); @@ -118,7 +118,7 @@ namespace Ndk /********************************* Nz::Directory ********************************/ directory.Reset("Directory"); { - directory.SetConstructor([] (Nz::LuaInstance& lua, Nz::Directory* instance, std::size_t argumentCount) + directory.SetConstructor([] (Nz::LuaState& lua, Nz::Directory* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 1U); @@ -159,9 +159,9 @@ namespace Ndk directory.BindStaticMethod("SetCurrent", Nz::Directory::SetCurrent); // Manual - directory.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::Directory& instance, std::size_t /*argumentCount*/) -> int { + directory.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::Directory& dir, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("Directory("); - ss << instance.GetPath(); + ss << dir.GetPath(); ss << ')'; lua.PushString(ss); @@ -174,7 +174,7 @@ namespace Ndk { file.Inherit(stream); - file.SetConstructor([] (Nz::LuaInstance& lua, Nz::File* instance, std::size_t argumentCount) + file.SetConstructor([] (Nz::LuaState& lua, Nz::File* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 1U); @@ -237,7 +237,7 @@ namespace Ndk file.BindStaticMethod("Rename", &Nz::File::Rename); // Manual - file.BindMethod("Open", [] (Nz::LuaInstance& lua, Nz::File& instance, std::size_t argumentCount) -> int + file.BindMethod("Open", [] (Nz::LuaState& lua, Nz::File& file, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 2U); @@ -246,13 +246,13 @@ namespace Ndk { case 0: case 1: - return lua.Push(instance.Open(lua.Check(&argIndex, Nz::OpenMode_NotOpen))); + return lua.Push(file.Open(lua.Check(&argIndex, Nz::OpenMode_NotOpen))); case 2: { Nz::String filePath = lua.Check(&argIndex); Nz::UInt32 openMode = lua.Check(&argIndex, Nz::OpenMode_NotOpen); - return lua.Push(instance.Open(filePath, openMode)); + return lua.Push(file.Open(filePath, openMode)); } } @@ -260,7 +260,7 @@ namespace Ndk return 0; }); - file.BindMethod("SetCursorPos", [] (Nz::LuaInstance& lua, Nz::File& instance, std::size_t argumentCount) -> int + file.BindMethod("SetCursorPos", [] (Nz::LuaState& lua, Nz::File& file, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 2U); @@ -268,13 +268,13 @@ namespace Ndk switch (argCount) { case 1: - return lua.Push(instance.SetCursorPos(lua.Check(&argIndex))); + return lua.Push(file.SetCursorPos(lua.Check(&argIndex))); case 2: { Nz::CursorPosition curPos = lua.Check(&argIndex); Nz::Int64 offset = lua.Check(&argIndex); - return lua.Push(instance.SetCursorPos(curPos, offset)); + return lua.Push(file.SetCursorPos(curPos, offset)); } } @@ -282,10 +282,10 @@ namespace Ndk return 0; }); - file.BindMethod("__tostring", [] (Nz::LuaInstance& lua, Nz::File& instance, std::size_t /*argumentCount*/) -> int { + file.BindMethod("__tostring", [] (Nz::LuaState& lua, Nz::File& file, std::size_t /*argumentCount*/) -> int { Nz::StringStream ss("File("); - if (instance.IsOpen()) - ss << "Path: " << instance.GetPath(); + if (file.IsOpen()) + ss << "Path: " << file.GetPath(); ss << ')'; @@ -300,55 +300,56 @@ namespace Ndk * * \param instance Lua instance that will interact with the Core classes */ - void LuaBinding_Core::Register(Nz::LuaInstance& instance) + void LuaBinding_Core::Register(Nz::LuaState& state) { // Classes - clock.Register(instance); - directory.Register(instance); - file.Register(instance); - stream.Register(instance); + clock.Register(state); + directory.Register(state); + file.Register(state); + stream.Register(state); // Enums // Nz::CursorPosition static_assert(Nz::CursorPosition_Max + 1 == 3, "Nz::CursorPosition has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 3); + state.PushTable(0, 3); { - instance.PushField("AtBegin", Nz::CursorPosition_AtBegin); - instance.PushField("AtCurrent", Nz::CursorPosition_AtCurrent); - instance.PushField("AtEnd", Nz::CursorPosition_AtEnd); + state.PushField("AtBegin", Nz::CursorPosition_AtBegin); + state.PushField("AtCurrent", Nz::CursorPosition_AtCurrent); + state.PushField("AtEnd", Nz::CursorPosition_AtEnd); } - instance.SetGlobal("CursorPosition"); + state.SetGlobal("CursorPosition"); // Nz::HashType - static_assert(Nz::HashType_Max + 1 == 9, "Nz::HashType has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 9); + static_assert(Nz::HashType_Max + 1 == 10, "Nz::HashType has been updated but change was not reflected to Lua binding"); + state.PushTable(0, 10); { - instance.PushField("CRC32", Nz::HashType_CRC32); - instance.PushField("Fletcher16", Nz::HashType_Fletcher16); - instance.PushField("MD5", Nz::HashType_MD5); - instance.PushField("SHA1", Nz::HashType_SHA1); - instance.PushField("SHA224", Nz::HashType_SHA224); - instance.PushField("SHA256", Nz::HashType_SHA256); - instance.PushField("SHA384", Nz::HashType_SHA384); - instance.PushField("SHA512", Nz::HashType_SHA512); - instance.PushField("Whirlpool", Nz::HashType_Whirlpool); + state.PushField("CRC32", Nz::HashType_CRC32); + state.PushField("CRC64", Nz::HashType_CRC64); + state.PushField("Fletcher16", Nz::HashType_Fletcher16); + state.PushField("MD5", Nz::HashType_MD5); + state.PushField("SHA1", Nz::HashType_SHA1); + state.PushField("SHA224", Nz::HashType_SHA224); + state.PushField("SHA256", Nz::HashType_SHA256); + state.PushField("SHA384", Nz::HashType_SHA384); + state.PushField("SHA512", Nz::HashType_SHA512); + state.PushField("Whirlpool", Nz::HashType_Whirlpool); } - instance.SetGlobal("HashType"); + state.SetGlobal("HashType"); // Nz::OpenMode static_assert(Nz::OpenMode_Max + 1 == 8, "Nz::OpenModeFlags has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, Nz::OpenMode_Max + 1); + state.PushTable(0, Nz::OpenMode_Max + 1); { - instance.PushField("Append", Nz::OpenMode_Append); - instance.PushField("NotOpen", Nz::OpenMode_NotOpen); - instance.PushField("Lock", Nz::OpenMode_Lock); - instance.PushField("ReadOnly", Nz::OpenMode_ReadOnly); - instance.PushField("ReadWrite", Nz::OpenMode_ReadWrite); - instance.PushField("Text", Nz::OpenMode_Text); - instance.PushField("Truncate", Nz::OpenMode_Truncate); - instance.PushField("WriteOnly", Nz::OpenMode_WriteOnly); + state.PushField("Append", Nz::OpenMode_Append); + state.PushField("NotOpen", Nz::OpenMode_NotOpen); + state.PushField("Lock", Nz::OpenMode_Lock); + state.PushField("ReadOnly", Nz::OpenMode_ReadOnly); + state.PushField("ReadWrite", Nz::OpenMode_ReadWrite); + state.PushField("Text", Nz::OpenMode_Text); + state.PushField("Truncate", Nz::OpenMode_Truncate); + state.PushField("WriteOnly", Nz::OpenMode_WriteOnly); } - instance.SetGlobal("OpenMode"); + state.SetGlobal("OpenMode"); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp b/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp index f87ac6556..d33811f49 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Graphics.cpp @@ -37,7 +37,7 @@ namespace Ndk /*********************************** Nz::Material ***********************************/ material.Reset("Material"); { - material.SetConstructor([] (Nz::LuaInstance& lua, Nz::MaterialRef* instance, std::size_t argumentCount) + material.SetConstructor([] (Nz::LuaState& lua, Nz::MaterialRef* instance, std::size_t argumentCount) { switch (argumentCount) { @@ -70,7 +70,7 @@ namespace Ndk return false; }); - material.BindMethod("Configure", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("Configure", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "MaterialPipeline")) @@ -168,7 +168,7 @@ namespace Ndk material.BindStaticMethod("GetDefault", &Nz::Material::GetDefault); - material.BindMethod("SetAlphaMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetAlphaMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -180,7 +180,7 @@ namespace Ndk return lua.Push(instance->SetAlphaMap(lua.Check(&argIndex))); }); - material.BindMethod("SetDiffuseMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetDiffuseMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -192,7 +192,7 @@ namespace Ndk return lua.Push(instance->SetDiffuseMap(lua.Check(&argIndex))); }); - material.BindMethod("SetEmissiveMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetEmissiveMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -204,7 +204,7 @@ namespace Ndk return lua.Push(instance->SetEmissiveMap(lua.Check(&argIndex))); }); - material.BindMethod("SetHeightMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetHeightMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -216,7 +216,7 @@ namespace Ndk return lua.Push(instance->SetHeightMap(lua.Check(&argIndex))); }); - material.BindMethod("SetNormalMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetNormalMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -228,7 +228,7 @@ namespace Ndk return lua.Push(instance->SetNormalMap(lua.Check(&argIndex))); }); - material.BindMethod("SetShader", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetShader", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "UberShader")) @@ -240,7 +240,7 @@ namespace Ndk return lua.Push(instance->SetShader(lua.Check(&argIndex))); }); - material.BindMethod("SetSpecularMap", [] (Nz::LuaInstance& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int + material.BindMethod("SetSpecularMap", [] (Nz::LuaState& lua, Nz::MaterialRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Texture")) @@ -261,7 +261,7 @@ namespace Ndk return reinterpret_cast(modelRef); //TODO: Make a ObjectRefCast }); - model.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::ModelRef* instance, std::size_t /*argumentCount*/) + model.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::ModelRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Model::New()); return true; @@ -293,7 +293,7 @@ namespace Ndk return reinterpret_cast(spriteRef); //TODO: Make a ObjectRefCast }); - sprite.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::SpriteRef* instance, std::size_t /*argumentCount*/) + sprite.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::SpriteRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Sprite::New()); return true; @@ -314,7 +314,7 @@ namespace Ndk sprite.BindMethod("SetTextureCoords", &Nz::Sprite::SetTextureCoords); sprite.BindMethod("SetTextureRect", &Nz::Sprite::SetTextureRect); - sprite.BindMethod("SetMaterial", [] (Nz::LuaInstance& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int + sprite.BindMethod("SetMaterial", [] (Nz::LuaState& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; bool resizeSprite = lua.CheckBoolean(argIndex + 1, true); @@ -327,7 +327,7 @@ namespace Ndk return 0; }); - sprite.BindMethod("SetTexture", [] (Nz::LuaInstance& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int + sprite.BindMethod("SetTexture", [] (Nz::LuaState& lua, Nz::SpriteRef& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; bool resizeSprite = lua.CheckBoolean(argIndex + 1, true); @@ -358,13 +358,13 @@ namespace Ndk * \param instance Lua instance that will interact with the Graphics classes */ - void LuaBinding_Graphics::Register(Nz::LuaInstance& instance) + void LuaBinding_Graphics::Register(Nz::LuaState& state) { - abstractViewer.Register(instance); - instancedRenderable.Register(instance); - material.Register(instance); - model.Register(instance); - sprite.Register(instance); - spriteLibrary.Register(instance); + abstractViewer.Register(state); + instancedRenderable.Register(state); + material.Register(state); + model.Register(state); + sprite.Register(state); + spriteLibrary.Register(state); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Math.cpp b/SDK/src/NDK/Lua/LuaBinding_Math.cpp index 42403a443..c218c2a66 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Math.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Math.cpp @@ -18,7 +18,7 @@ namespace Ndk /*********************************** Nz::EulerAngles **********************************/ eulerAngles.Reset("EulerAngles"); { - eulerAngles.SetConstructor([] (Nz::LuaInstance& lua, Nz::EulerAnglesd* instance, std::size_t argumentCount) + eulerAngles.SetConstructor([] (Nz::LuaState& lua, Nz::EulerAnglesd* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 3U); @@ -46,7 +46,7 @@ namespace Ndk eulerAngles.BindMethod("__tostring", &Nz::EulerAnglesd::ToString); - eulerAngles.SetGetter([] (Nz::LuaInstance& lua, Nz::EulerAnglesd& instance) + eulerAngles.SetGetter([] (Nz::LuaState& lua, Nz::EulerAnglesd& instance) { std::size_t length; const char* ypr = lua.CheckString(2, &length); @@ -103,7 +103,7 @@ namespace Ndk return false; }); - eulerAngles.SetSetter([] (Nz::LuaInstance& lua, Nz::EulerAnglesd& instance) + eulerAngles.SetSetter([] (Nz::LuaState& lua, Nz::EulerAnglesd& instance) { std::size_t length; const char* ypr = lua.CheckString(2, &length); @@ -165,7 +165,7 @@ namespace Ndk /*********************************** Nz::Matrix4 **********************************/ matrix4d.Reset("Matrix4"); { - matrix4d.SetConstructor([] (Nz::LuaInstance& lua, Nz::Matrix4d* matrix, std::size_t argumentCount) + matrix4d.SetConstructor([] (Nz::LuaState& lua, Nz::Matrix4d* matrix, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 3U); @@ -207,7 +207,7 @@ namespace Ndk matrix4d.BindMethod("GetDeterminant", &Nz::Matrix4d::GetDeterminant); matrix4d.BindMethod("GetDeterminantAffine", &Nz::Matrix4d::GetDeterminantAffine); - matrix4d.BindMethod("GetInverse", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("GetInverse", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { Nz::Matrix4d result; if (instance.GetInverse(&result)) @@ -216,7 +216,7 @@ namespace Ndk return lua.Push(false); }); - matrix4d.BindMethod("GetInverseAffine", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("GetInverseAffine", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { Nz::Matrix4d result; if (instance.GetInverseAffine(&result)) @@ -232,7 +232,7 @@ namespace Ndk matrix4d.BindMethod("GetSquaredScale", &Nz::Matrix4d::GetSquaredScale); matrix4d.BindMethod("GetTranslation", &Nz::Matrix4d::GetTranslation); - matrix4d.BindMethod("GetTransposed", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("GetTransposed", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { Nz::Matrix4d result; instance.GetTransposed(&result); @@ -243,7 +243,7 @@ namespace Ndk matrix4d.BindMethod("HasNegativeScale", &Nz::Matrix4d::HasNegativeScale); matrix4d.BindMethod("HasScale", &Nz::Matrix4d::HasScale); - matrix4d.BindMethod("Inverse", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("Inverse", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { bool succeeded; instance.Inverse(&succeeded); @@ -251,7 +251,7 @@ namespace Ndk return lua.Push(succeeded); }); - matrix4d.BindMethod("InverseAffine", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("InverseAffine", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { bool succeeded; instance.InverseAffine(&succeeded); @@ -273,7 +273,7 @@ namespace Ndk matrix4d.BindMethod("MakeViewMatrix", &Nz::Matrix4d::MakeViewMatrix); matrix4d.BindMethod("MakeZero", &Nz::Matrix4d::MakeZero); - matrix4d.BindMethod("Set", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t argumentCount) -> int + matrix4d.BindMethod("Set", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 3U); @@ -305,7 +305,7 @@ namespace Ndk matrix4d.BindMethod("SetScale", &Nz::Matrix4d::SetScale); matrix4d.BindMethod("SetTranslation", &Nz::Matrix4d::SetTranslation); - matrix4d.BindMethod("Transform", [] (Nz::LuaInstance& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int + matrix4d.BindMethod("Transform", [] (Nz::LuaState& lua, Nz::Matrix4d& instance, std::size_t /*argumentCount*/) -> int { int argIndex = 2; if (lua.IsOfType(argIndex, "Vector2")) @@ -345,7 +345,7 @@ namespace Ndk matrix4d.BindStaticMethod("ViewMatrix", &Nz::Matrix4d::ViewMatrix); matrix4d.BindStaticMethod("Zero", &Nz::Matrix4d::Zero); - matrix4d.SetGetter([] (Nz::LuaInstance& lua, Nz::Matrix4d& instance) + matrix4d.SetGetter([] (Nz::LuaState& lua, Nz::Matrix4d& instance) { bool succeeded = false; std::size_t index = static_cast(lua.ToInteger(2, &succeeded)); @@ -356,7 +356,7 @@ namespace Ndk return true; }); - matrix4d.SetSetter([] (Nz::LuaInstance& lua, Nz::Matrix4d& instance) + matrix4d.SetSetter([] (Nz::LuaState& lua, Nz::Matrix4d& instance) { bool succeeded = false; std::size_t index = static_cast(lua.ToInteger(2, &succeeded)); @@ -372,7 +372,7 @@ namespace Ndk /*********************************** Nz::Rect **********************************/ rect.Reset("Rect"); { - rect.SetConstructor([] (Nz::LuaInstance& lua, Nz::Rectd* instance, std::size_t argumentCount) + rect.SetConstructor([] (Nz::LuaState& lua, Nz::Rectd* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 4U); @@ -422,7 +422,7 @@ namespace Ndk rect.BindMethod("__tostring", &Nz::Rectd::ToString); - rect.SetGetter([] (Nz::LuaInstance& lua, Nz::Rectd& instance) + rect.SetGetter([] (Nz::LuaState& lua, Nz::Rectd& instance) { switch (lua.GetType(2)) { @@ -475,7 +475,7 @@ namespace Ndk return false; }); - rect.SetSetter([] (Nz::LuaInstance& lua, Nz::Rectd& instance) + rect.SetSetter([] (Nz::LuaState& lua, Nz::Rectd& instance) { switch (lua.GetType(2)) { @@ -531,7 +531,7 @@ namespace Ndk /*********************************** Nz::Quaternion **********************************/ quaternion.Reset("Quaternion"); { - quaternion.SetConstructor([] (Nz::LuaInstance& lua, Nz::Quaterniond* instance, std::size_t argumentCount) + quaternion.SetConstructor([] (Nz::LuaState& lua, Nz::Quaterniond* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 4U); @@ -587,7 +587,7 @@ namespace Ndk quaternion.BindStaticMethod("RotationBetween", &Nz::Quaterniond::RotationBetween); quaternion.BindStaticMethod("Slerp", &Nz::Quaterniond::Slerp); - quaternion.BindMethod("GetNormal", [] (Nz::LuaInstance& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int + quaternion.BindMethod("GetNormal", [] (Nz::LuaState& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int { double length; @@ -597,7 +597,7 @@ namespace Ndk return 2; }); - quaternion.BindMethod("Normalize", [] (Nz::LuaInstance& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int + quaternion.BindMethod("Normalize", [] (Nz::LuaState& lua, Nz::Quaterniond& instance, std::size_t /*argumentCount*/) -> int { double length; @@ -608,20 +608,20 @@ namespace Ndk return 2; }); - quaternion.BindStaticMethod("Normalize", [] (Nz::LuaInstance& instance) -> int + quaternion.BindStaticMethod("Normalize", [] (Nz::LuaState& state) -> int { int argIndex = 1; - Nz::Quaterniond quat = instance.Check(&argIndex); + Nz::Quaterniond quat = state.Check(&argIndex); double length; - instance.Push(Nz::Quaterniond::Normalize(quat, &length)); - instance.Push(length); + state.Push(Nz::Quaterniond::Normalize(quat, &length)); + state.Push(length); return 2; }); - quaternion.SetGetter([] (Nz::LuaInstance& lua, Nz::Quaterniond& instance) + quaternion.SetGetter([] (Nz::LuaState& lua, Nz::Quaterniond& instance) { std::size_t length; const char* wxyz = lua.CheckString(2, &length); @@ -651,7 +651,7 @@ namespace Ndk return false; }); - quaternion.SetSetter([] (Nz::LuaInstance& lua, Nz::Quaterniond& instance) + quaternion.SetSetter([] (Nz::LuaState& lua, Nz::Quaterniond& instance) { std::size_t length; const char* wxyz = lua.CheckString(2, &length); @@ -690,7 +690,7 @@ namespace Ndk /*********************************** Nz::Vector2 **********************************/ vector2d.Reset("Vector2"); { - vector2d.SetConstructor([] (Nz::LuaInstance& lua, Nz::Vector2d* vector, std::size_t argumentCount) + vector2d.SetConstructor([] (Nz::LuaState& lua, Nz::Vector2d* vector, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 2U); @@ -720,7 +720,7 @@ namespace Ndk vector2d.BindMethod("__tostring", &Nz::Vector2d::ToString); - vector2d.SetGetter([] (Nz::LuaInstance& lua, Nz::Vector2d& instance) + vector2d.SetGetter([] (Nz::LuaState& lua, Nz::Vector2d& instance) { switch (lua.GetType(2)) { @@ -765,7 +765,7 @@ namespace Ndk return false; }); - vector2d.SetSetter([] (Nz::LuaInstance& lua, Nz::Vector2d& instance) + vector2d.SetSetter([] (Nz::LuaState& lua, Nz::Vector2d& instance) { switch (lua.GetType(2)) { @@ -816,7 +816,7 @@ namespace Ndk /*********************************** Nz::Vector3 **********************************/ vector3d.Reset("Vector3"); { - vector3d.SetConstructor([] (Nz::LuaInstance& lua, Nz::Vector3d* vector, std::size_t argumentCount) + vector3d.SetConstructor([] (Nz::LuaState& lua, Nz::Vector3d* vector, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 3U); @@ -860,7 +860,7 @@ namespace Ndk vector3d.BindMethod("__tostring", &Nz::Vector3d::ToString); - vector3d.SetGetter([] (Nz::LuaInstance& lua, Nz::Vector3d& instance) + vector3d.SetGetter([] (Nz::LuaState& lua, Nz::Vector3d& instance) { switch (lua.GetType(2)) { @@ -909,7 +909,7 @@ namespace Ndk return false; }); - vector3d.SetSetter([] (Nz::LuaInstance& lua, Nz::Vector3d& instance) + vector3d.SetSetter([] (Nz::LuaState& lua, Nz::Vector3d& instance) { switch (lua.GetType(2)) { @@ -967,20 +967,20 @@ namespace Ndk * * \param instance Lua instance that will interact with the Math classes */ - void LuaBinding_Math::Register(Nz::LuaInstance& instance) + void LuaBinding_Math::Register(Nz::LuaState& state) { - eulerAngles.Register(instance); - matrix4d.Register(instance); - quaternion.Register(instance); - rect.Register(instance); - vector2d.Register(instance); - vector3d.Register(instance); + eulerAngles.Register(state); + matrix4d.Register(state); + quaternion.Register(state); + rect.Register(state); + vector2d.Register(state); + vector3d.Register(state); - quaternion.PushGlobalTable(instance); + quaternion.PushGlobalTable(state); { - instance.PushField("Identity", Nz::Quaterniond::Identity()); - instance.PushField("Zero", Nz::Quaterniond::Zero()); + state.PushField("Identity", Nz::Quaterniond::Identity()); + state.PushField("Zero", Nz::Quaterniond::Zero()); } - instance.Pop(); + state.Pop(); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Network.cpp b/SDK/src/NDK/Lua/LuaBinding_Network.cpp index d6f92cb40..c54ef89a0 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Network.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Network.cpp @@ -28,11 +28,11 @@ namespace Ndk /*********************************** Nz::IpAddress **********************************/ ipAddress.Reset("IpAddress"); { - ipAddress.SetConstructor([] (Nz::LuaInstance& lua, Nz::IpAddress* instance, std::size_t argumentCount) + ipAddress.SetConstructor([] (Nz::LuaState& lua, Nz::IpAddress* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 9U); - int argIndex = 2; + int argIndex = 1; switch (argCount) { case 0: @@ -85,63 +85,120 @@ namespace Ndk ipAddress.BindMethod("ToUInt32", &Nz::IpAddress::ToUInt32); ipAddress.BindMethod("__tostring", &Nz::IpAddress::ToString); - ipAddress.BindStaticMethod("ResolveAddress", [] (Nz::LuaInstance& instance) -> int + ipAddress.BindStaticMethod("ResolveAddress", [] (Nz::LuaState& state) -> int { Nz::String service; Nz::ResolveError error = Nz::ResolveError_Unknown; int argIndex = 2; - Nz::String hostName = Nz::IpAddress::ResolveAddress(instance.Check(&argIndex), &service, &error); + Nz::String hostName = Nz::IpAddress::ResolveAddress(state.Check(&argIndex), &service, &error); if (error == Nz::ResolveError_NoError) { - instance.Push(hostName); - instance.Push(service); + state.Push(hostName); + state.Push(service); return 2; } else { - instance.PushBoolean(false); - instance.Push(error); + state.PushBoolean(false); + state.Push(error); return 2; } }); - ipAddress.BindStaticMethod("ResolveHostname", [] (Nz::LuaInstance& instance) -> int + ipAddress.BindStaticMethod("ResolveHostname", [] (Nz::LuaState& state) -> int { Nz::ResolveError error = Nz::ResolveError_Unknown; int argIndex = 2; - Nz::NetProtocol protocol = instance.Check(&argIndex); - Nz::String hostname = instance.Check(&argIndex); - Nz::String service = instance.Check(&argIndex, "http"); + Nz::NetProtocol protocol = state.Check(&argIndex); + Nz::String hostname = state.Check(&argIndex); + Nz::String service = state.Check(&argIndex, "http"); std::vector addresses = Nz::IpAddress::ResolveHostname(protocol, hostname, service, &error); if (error == Nz::ResolveError_NoError) { int index = 1; - instance.PushTable(addresses.size()); + state.PushTable(addresses.size()); for (Nz::HostnameInfo& info : addresses) { - instance.PushInteger(index++); - instance.PushTable(0, 4); - instance.PushField("Address", std::move(info.address)); - instance.PushField("CanonicalName", std::move(info.canonicalName)); - instance.PushField("Protocol", std::move(info.protocol)); - instance.PushField("SocketType", std::move(info.socketType)); - instance.SetTable(); + state.PushInteger(index++); + state.PushTable(0, 4); + state.PushField("Address", std::move(info.address)); + state.PushField("CanonicalName", std::move(info.canonicalName)); + state.PushField("Protocol", std::move(info.protocol)); + state.PushField("SocketType", std::move(info.socketType)); + state.SetTable(); } return 1; } else { - instance.PushBoolean(false); - instance.Push(error); + state.PushBoolean(false); + state.Push(error); return 2; } }); } + + udpSocket.Reset("UdpSocket"); + { + udpSocket.Inherit(abstractSocket); + + udpSocket.BindDefaultConstructor(); + + udpSocket.BindMethod("Create", &Nz::UdpSocket::Create); + udpSocket.BindMethod("EnableBroadcasting", &Nz::UdpSocket::EnableBroadcasting); + udpSocket.BindMethod("GetBoundAddress", &Nz::UdpSocket::GetBoundAddress); + udpSocket.BindMethod("GetBoundPort", &Nz::UdpSocket::GetBoundPort); + udpSocket.BindMethod("IsBroadcastingEnabled", &Nz::UdpSocket::IsBroadcastingEnabled); + udpSocket.BindMethod("QueryMaxDatagramSize", &Nz::UdpSocket::QueryMaxDatagramSize); + + udpSocket.BindMethod("Bind", [](Nz::LuaState& lua, Nz::UdpSocket& socket, std::size_t /*argumentCount*/) -> int + { + int argIndex = 2; + if (lua.IsOfType(argIndex, "IpAddress")) + return lua.Push(socket.Bind(*static_cast(lua.ToUserdata(argIndex)))); + else + return lua.Push(socket.Bind(lua.Check(&argIndex))); + }); + + udpSocket.BindMethod("Receive", [](Nz::LuaState& lua, Nz::UdpSocket& socket, std::size_t /*argumentCount*/) -> int + { + Nz::IpAddress from; + + std::array buffer; + std::size_t received; + if (socket.Receive(buffer.data(), buffer.size(), &from, &received)) + { + lua.PushBoolean(true); + lua.PushString(from.ToString()); + lua.PushString(buffer.data(), received); + return 3; + } + + lua.PushBoolean(false); + return 1; + }); + + udpSocket.BindMethod("Send", [](Nz::LuaState& lua, Nz::UdpSocket& socket, std::size_t /*argumentCount*/) -> int + { + int argIndex = 2; + Nz::String to = lua.Check(&argIndex); + + std::size_t bufferLength; + const char* buffer = lua.CheckString(argIndex, &bufferLength); + + std::size_t sent; + bool ret; + if ((ret = socket.Send(Nz::IpAddress(to), buffer, bufferLength, &sent)) != true) + sent = 0; + + return lua.Push(std::make_pair(ret, sent)); + }); + } } /*! @@ -149,107 +206,108 @@ namespace Ndk * * \param instance Lua instance that will interact with the Network classes */ - void LuaBinding_Network::Register(Nz::LuaInstance& instance) + void LuaBinding_Network::Register(Nz::LuaState& state) { // Classes - abstractSocket.Register(instance); - ipAddress.Register(instance); + abstractSocket.Register(state); + ipAddress.Register(state); + udpSocket.Register(state); // Enums // Nz::NetProtocol static_assert(Nz::NetProtocol_Max + 1 == 4, "Nz::NetProtocol has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 4); + state.PushTable(0, 4); { - instance.PushField("Any", Nz::NetProtocol_Any); - instance.PushField("IPv4", Nz::NetProtocol_IPv4); - instance.PushField("IPv6", Nz::NetProtocol_IPv6); - instance.PushField("Unknown", Nz::NetProtocol_Unknown); + state.PushField("Any", Nz::NetProtocol_Any); + state.PushField("IPv4", Nz::NetProtocol_IPv4); + state.PushField("IPv6", Nz::NetProtocol_IPv6); + state.PushField("Unknown", Nz::NetProtocol_Unknown); } - instance.SetGlobal("NetProtocol"); + state.SetGlobal("NetProtocol"); // Nz::PacketPriority static_assert(Nz::PacketPriority_Max + 1 == 4, "Nz::PacketPriority has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 6); + state.PushTable(0, 6); { - instance.PushField("High", Nz::PacketPriority_High); - instance.PushField("Highest", Nz::PacketPriority_Highest); - instance.PushField("Immediate", Nz::PacketPriority_Immediate); - instance.PushField("Medium", Nz::PacketPriority_Medium); - instance.PushField("Low", Nz::PacketPriority_Low); - instance.PushField("Lowest", Nz::PacketPriority_Lowest); + state.PushField("High", Nz::PacketPriority_High); + state.PushField("Highest", Nz::PacketPriority_Highest); + state.PushField("Immediate", Nz::PacketPriority_Immediate); + state.PushField("Medium", Nz::PacketPriority_Medium); + state.PushField("Low", Nz::PacketPriority_Low); + state.PushField("Lowest", Nz::PacketPriority_Lowest); } - instance.SetGlobal("PacketPriority"); + state.SetGlobal("PacketPriority"); // Nz::PacketReliability static_assert(Nz::PacketReliability_Max + 1 == 3, "Nz::PacketReliability has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 3); + state.PushTable(0, 3); { - instance.PushField("Reliable", Nz::PacketReliability_Reliable); - instance.PushField("ReliableOrdered", Nz::PacketReliability_ReliableOrdered); - instance.PushField("Unreliable", Nz::PacketReliability_Unreliable); + state.PushField("Reliable", Nz::PacketReliability_Reliable); + state.PushField("ReliableOrdered", Nz::PacketReliability_ReliableOrdered); + state.PushField("Unreliable", Nz::PacketReliability_Unreliable); } - instance.SetGlobal("PacketReliability"); + state.SetGlobal("PacketReliability"); // Nz::ResolveError static_assert(Nz::ResolveError_Max + 1 == 9, "Nz::ResolveError has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 9); + state.PushTable(0, 9); { - instance.PushField("Internal", Nz::ResolveError_Internal); - instance.PushField("ResourceError", Nz::ResolveError_ResourceError); - instance.PushField("NoError", Nz::ResolveError_NoError); - instance.PushField("NonRecoverable", Nz::ResolveError_NonRecoverable); - instance.PushField("NotFound", Nz::ResolveError_NotFound); - instance.PushField("NotInitialized", Nz::ResolveError_NotInitialized); - instance.PushField("ProtocolNotSupported", Nz::ResolveError_ProtocolNotSupported); - instance.PushField("TemporaryFailure", Nz::ResolveError_TemporaryFailure); - instance.PushField("Unknown", Nz::ResolveError_Unknown); + state.PushField("Internal", Nz::ResolveError_Internal); + state.PushField("ResourceError", Nz::ResolveError_ResourceError); + state.PushField("NoError", Nz::ResolveError_NoError); + state.PushField("NonRecoverable", Nz::ResolveError_NonRecoverable); + state.PushField("NotFound", Nz::ResolveError_NotFound); + state.PushField("NotInitialized", Nz::ResolveError_NotInitialized); + state.PushField("ProtocolNotSupported", Nz::ResolveError_ProtocolNotSupported); + state.PushField("TemporaryFailure", Nz::ResolveError_TemporaryFailure); + state.PushField("Unknown", Nz::ResolveError_Unknown); } - instance.SetGlobal("ResolveError"); + state.SetGlobal("ResolveError"); // Nz::SocketError static_assert(Nz::SocketError_Max + 1 == 15, "Nz::ResolveError has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 15); + state.PushTable(0, 15); { - instance.PushField("AddressNotAvailable", Nz::SocketError_AddressNotAvailable); - instance.PushField("ConnectionClosed", Nz::SocketError_ConnectionClosed); - instance.PushField("ConnectionRefused", Nz::SocketError_ConnectionRefused); - instance.PushField("DatagramSize", Nz::SocketError_DatagramSize); - instance.PushField("Internal", Nz::SocketError_Internal); - instance.PushField("Packet", Nz::SocketError_Packet); - instance.PushField("NetworkError", Nz::SocketError_NetworkError); - instance.PushField("NoError", Nz::SocketError_NoError); - instance.PushField("NotInitialized", Nz::SocketError_NotInitialized); - instance.PushField("NotSupported", Nz::SocketError_NotSupported); - instance.PushField("ResolveError", Nz::SocketError_ResolveError); - instance.PushField("ResourceError", Nz::SocketError_ResourceError); - instance.PushField("TimedOut", Nz::SocketError_TimedOut); - instance.PushField("Unknown", Nz::SocketError_Unknown); - instance.PushField("UnreachableHost", Nz::SocketError_UnreachableHost); + state.PushField("AddressNotAvailable", Nz::SocketError_AddressNotAvailable); + state.PushField("ConnectionClosed", Nz::SocketError_ConnectionClosed); + state.PushField("ConnectionRefused", Nz::SocketError_ConnectionRefused); + state.PushField("DatagramSize", Nz::SocketError_DatagramSize); + state.PushField("Internal", Nz::SocketError_Internal); + state.PushField("Packet", Nz::SocketError_Packet); + state.PushField("NetworkError", Nz::SocketError_NetworkError); + state.PushField("NoError", Nz::SocketError_NoError); + state.PushField("NotInitialized", Nz::SocketError_NotInitialized); + state.PushField("NotSupported", Nz::SocketError_NotSupported); + state.PushField("ResolveError", Nz::SocketError_ResolveError); + state.PushField("ResourceError", Nz::SocketError_ResourceError); + state.PushField("TimedOut", Nz::SocketError_TimedOut); + state.PushField("Unknown", Nz::SocketError_Unknown); + state.PushField("UnreachableHost", Nz::SocketError_UnreachableHost); } - instance.SetGlobal("SocketError"); + state.SetGlobal("SocketError"); // Nz::SocketState static_assert(Nz::SocketState_Max + 1 == 5, "Nz::SocketState has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 5); + state.PushTable(0, 5); { - instance.PushField("Bound", Nz::SocketState_Bound); - instance.PushField("Connecting", Nz::SocketState_Connecting); - instance.PushField("Connected", Nz::SocketState_Connected); - instance.PushField("NotConnected", Nz::SocketState_NotConnected); - instance.PushField("Resolving", Nz::SocketState_Resolving); + state.PushField("Bound", Nz::SocketState_Bound); + state.PushField("Connecting", Nz::SocketState_Connecting); + state.PushField("Connected", Nz::SocketState_Connected); + state.PushField("NotConnected", Nz::SocketState_NotConnected); + state.PushField("Resolving", Nz::SocketState_Resolving); } - instance.SetGlobal("SocketState"); + state.SetGlobal("SocketState"); // Nz::SocketType static_assert(Nz::SocketType_Max + 1 == 4, "Nz::SocketState has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, 4); + state.PushTable(0, 4); { - instance.PushField("Raw", Nz::SocketType_Raw); - instance.PushField("TCP", Nz::SocketType_TCP); - instance.PushField("UDP", Nz::SocketType_UDP); - instance.PushField("Unknown", Nz::SocketType_Unknown); + state.PushField("Raw", Nz::SocketType_Raw); + state.PushField("TCP", Nz::SocketType_TCP); + state.PushField("UDP", Nz::SocketType_UDP); + state.PushField("Unknown", Nz::SocketType_Unknown); } - instance.SetGlobal("SocketType"); + state.SetGlobal("SocketType"); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Platform.cpp b/SDK/src/NDK/Lua/LuaBinding_Platform.cpp new file mode 100644 index 000000000..b910770fa --- /dev/null +++ b/SDK/src/NDK/Lua/LuaBinding_Platform.cpp @@ -0,0 +1,133 @@ +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +#include +#include + +namespace Ndk +{ + std::unique_ptr LuaBinding_Base::BindPlatform(LuaBinding& binding) + { + return std::make_unique(binding); + } + + LuaBinding_Platform::LuaBinding_Platform(LuaBinding& binding) : + LuaBinding_Base(binding) + { + /*********************************** Nz::Keyboard **********************************/ + keyboard.Reset("Keyboard"); + { + keyboard.BindStaticMethod("GetKeyName", &Nz::Keyboard::GetKeyName); + keyboard.BindStaticMethod("IsKeyPressed", &Nz::Keyboard::IsKeyPressed); + } + } + + /*! + * \brief Registers the classes that will be used by the Lua instance + * + * \param instance Lua instance that will interact with the Utility classes + */ + void LuaBinding_Platform::Register(Nz::LuaState& state) + { + keyboard.Register(state); + + keyboard.PushGlobalTable(state); + { + static_assert(Nz::Keyboard::Count == 121, "Nz::Keyboard::Key has been updated but change was not reflected to Lua binding"); + + state.PushField("Undefined", Nz::Keyboard::Undefined); + + // A-Z + for (std::size_t i = 0; i < 26; ++i) + state.PushField(Nz::String('A' + char(i)), Nz::Keyboard::A + i); + + // Numerical + for (std::size_t i = 0; i < 10; ++i) + { + state.PushField("Num" + Nz::String::Number(i), Nz::Keyboard::Num0 + i); + state.PushField("Numpad" + Nz::String::Number(i), Nz::Keyboard::Numpad0 + i); + } + + // F1-F15 + for (std::size_t i = 0; i < 15; ++i) + state.PushField('F' + Nz::String::Number(i+1), Nz::Keyboard::F1 + i); + + // And all the others... + state.PushField("Down", Nz::Keyboard::Down); + state.PushField("Left", Nz::Keyboard::Left); + state.PushField("Right", Nz::Keyboard::Right); + state.PushField("Up", Nz::Keyboard::Up); + + state.PushField("Add", Nz::Keyboard::Add); + state.PushField("Decimal", Nz::Keyboard::Decimal); + state.PushField("Divide", Nz::Keyboard::Divide); + state.PushField("Multiply", Nz::Keyboard::Multiply); + state.PushField("Subtract", Nz::Keyboard::Subtract); + + state.PushField("Backslash", Nz::Keyboard::Backslash); + state.PushField("Backspace", Nz::Keyboard::Backspace); + state.PushField("Clear", Nz::Keyboard::Clear); + state.PushField("Comma", Nz::Keyboard::Comma); + state.PushField("Dash", Nz::Keyboard::Dash); + state.PushField("Delete", Nz::Keyboard::Delete); + state.PushField("End", Nz::Keyboard::End); + state.PushField("Equal", Nz::Keyboard::Equal); + state.PushField("Escape", Nz::Keyboard::Escape); + state.PushField("Home", Nz::Keyboard::Home); + state.PushField("Insert", Nz::Keyboard::Insert); + state.PushField("LAlt", Nz::Keyboard::LAlt); + state.PushField("LBracket", Nz::Keyboard::LBracket); + state.PushField("LControl", Nz::Keyboard::LControl); + state.PushField("LShift", Nz::Keyboard::LShift); + state.PushField("LSystem", Nz::Keyboard::LSystem); + state.PushField("PageDown", Nz::Keyboard::PageDown); + state.PushField("PageUp", Nz::Keyboard::PageUp); + state.PushField("Pause", Nz::Keyboard::Pause); + state.PushField("Period", Nz::Keyboard::Period); + state.PushField("Print", Nz::Keyboard::Print); + state.PushField("PrintScreen", Nz::Keyboard::PrintScreen); + state.PushField("Quote", Nz::Keyboard::Quote); + state.PushField("RAlt", Nz::Keyboard::RAlt); + state.PushField("RBracket", Nz::Keyboard::RBracket); + state.PushField("RControl", Nz::Keyboard::RControl); + state.PushField("Return", Nz::Keyboard::Return); + state.PushField("RShift", Nz::Keyboard::RShift); + state.PushField("RSystem", Nz::Keyboard::RSystem); + state.PushField("Semicolon", Nz::Keyboard::Semicolon); + state.PushField("Slash", Nz::Keyboard::Slash); + state.PushField("Space", Nz::Keyboard::Space); + state.PushField("Tab", Nz::Keyboard::Tab); + state.PushField("Tilde", Nz::Keyboard::Tilde); + state.PushField("Browser_Back", Nz::Keyboard::Browser_Back); + state.PushField("Browser_Favorites", Nz::Keyboard::Browser_Favorites); + state.PushField("Browser_Forward", Nz::Keyboard::Browser_Forward); + state.PushField("Browser_Home", Nz::Keyboard::Browser_Home); + state.PushField("Browser_Refresh", Nz::Keyboard::Browser_Refresh); + state.PushField("Browser_Search", Nz::Keyboard::Browser_Search); + state.PushField("Browser_Stop", Nz::Keyboard::Browser_Stop); + state.PushField("Media_Next", Nz::Keyboard::Media_Next); + state.PushField("Media_Play", Nz::Keyboard::Media_Play); + state.PushField("Media_Previous", Nz::Keyboard::Media_Previous); + state.PushField("Media_Stop", Nz::Keyboard::Media_Stop); + state.PushField("Volume_Down", Nz::Keyboard::Volume_Down); + state.PushField("Volume_Mute", Nz::Keyboard::Volume_Mute); + state.PushField("Volume_Up", Nz::Keyboard::Volume_Up); + state.PushField("CapsLock", Nz::Keyboard::CapsLock); + state.PushField("NumLock", Nz::Keyboard::NumLock); + state.PushField("ScrollLock", Nz::Keyboard::ScrollLock); + } + state.Pop(); + + static_assert(Nz::WindowStyle_Max + 1 == 6, "Nz::WindowStyle has been updated but change was not reflected to Lua binding"); + state.PushTable(0, Nz::WindowStyle_Max + 1); + { + state.PushField("None", Nz::WindowStyle_None); + state.PushField("Fullscreen", Nz::WindowStyle_Fullscreen); + state.PushField("Closable", Nz::WindowStyle_Closable); + state.PushField("Resizable", Nz::WindowStyle_Resizable); + state.PushField("Titlebar", Nz::WindowStyle_Titlebar); + state.PushField("Threaded", Nz::WindowStyle_Threaded); + } + state.SetGlobal("WindowStyle"); + } +} diff --git a/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp b/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp index 00088ecb9..1ab24cedb 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Renderer.cpp @@ -27,7 +27,7 @@ namespace Ndk return reinterpret_cast(textureRef); //TODO: Make a ObjectRefCast }); - texture.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::TextureRef* instance, std::size_t /*argumentCount*/) + texture.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::TextureRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Texture::New()); return true; @@ -84,7 +84,7 @@ namespace Ndk } /*********************************** Nz::TextureManager ***********************************/ - textureManager.Reset("textureManager"); + textureManager.Reset("TextureManager"); { textureManager.BindStaticMethod("Clear", &Nz::TextureManager::Clear); textureManager.BindStaticMethod("Get", &Nz::TextureManager::Get); @@ -101,10 +101,10 @@ namespace Ndk * * \param instance Lua instance that will interact with the Renderer classes */ - void LuaBinding_Renderer::Register(Nz::LuaInstance& instance) + void LuaBinding_Renderer::Register(Nz::LuaState& state) { - texture.Register(instance); - textureLibrary.Register(instance); - textureManager.Register(instance); + texture.Register(state); + textureLibrary.Register(state); + textureManager.Register(state); } } diff --git a/SDK/src/NDK/Lua/LuaBinding_SDK.cpp b/SDK/src/NDK/Lua/LuaBinding_SDK.cpp index 0de791f85..8952ce7d9 100644 --- a/SDK/src/NDK/Lua/LuaBinding_SDK.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_SDK.cpp @@ -40,7 +40,7 @@ namespace Ndk application.BindMethod("IsFPSCounterEnabled", &Application::IsFPSCounterEnabled); #endif - application.BindMethod("AddWorld", [] (Nz::LuaInstance& lua, Application* instance, std::size_t /*argumentCount*/) -> int + application.BindMethod("AddWorld", [] (Nz::LuaState& lua, Application* instance, std::size_t /*argumentCount*/) -> int { lua.Push(instance->AddWorld().CreateHandle()); return 1; @@ -69,6 +69,7 @@ namespace Ndk console.BindMethod("GetSize", &Console::GetSize); console.BindMethod("GetTextFont", &Console::GetTextFont); + console.BindMethod("IsValidHandle", &ConsoleHandle::IsValid); console.BindMethod("IsVisible", &Console::IsVisible); console.BindMethod("SendCharacter", &Console::SendCharacter); @@ -91,28 +92,37 @@ namespace Ndk entity.BindMethod("Kill", &Entity::Kill); entity.BindMethod("IsEnabled", &Entity::IsEnabled); entity.BindMethod("IsValid", &Entity::IsValid); + entity.BindMethod("IsValidHandle", &EntityHandle::IsValid); entity.BindMethod("RemoveAllComponents", &Entity::RemoveAllComponents); entity.BindMethod("__tostring", &EntityHandle::ToString); - entity.BindMethod("AddComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + entity.BindMethod("AddComponent", [this] (Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int { - LuaBinding::ComponentBinding* binding = m_binding.QueryComponentIndex(instance); + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); - return binding->adder(instance, handle); + return bindingComponent->adder(state, handle); }); - entity.BindMethod("GetComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + entity.BindMethod("HasComponent", [this](Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int { - LuaBinding::ComponentBinding* binding = m_binding.QueryComponentIndex(instance); + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); - return binding->getter(instance, handle->GetComponent(binding->index)); + state.PushBoolean(handle->HasComponent(bindingComponent->index)); + return 1; }); - entity.BindMethod("RemoveComponent", [this] (Nz::LuaInstance& instance, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + entity.BindMethod("GetComponent", [this] (Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int { - LuaBinding::ComponentBinding* binding = m_binding.QueryComponentIndex(instance); + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); - handle->RemoveComponent(binding->index); + return bindingComponent->getter(state, handle->GetComponent(bindingComponent->index)); + }); + + entity.BindMethod("RemoveComponent", [this] (Nz::LuaState& state, EntityHandle& handle, std::size_t /*argumentCount*/) -> int + { + LuaBinding::ComponentBinding* bindingComponent = m_binding.QueryComponentIndex(state); + + handle->RemoveComponent(bindingComponent->index); return 0; }); } @@ -120,6 +130,8 @@ namespace Ndk /*********************************** Ndk::NodeComponent **********************************/ nodeComponent.Reset("NodeComponent"); { + nodeComponent.BindMethod("IsValidHandle", &NodeComponentHandle::IsValid); + nodeComponent.Inherit(utility.node, [] (NodeComponentHandle* handle) -> Nz::Node* { return handle->GetObject(); @@ -129,7 +141,9 @@ namespace Ndk /*********************************** Ndk::VelocityComponent **********************************/ velocityComponent.Reset("VelocityComponent"); { - velocityComponent.SetGetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance) + velocityComponent.BindMethod("IsValidHandle", &VelocityComponentHandle::IsValid); + + velocityComponent.SetGetter([] (Nz::LuaState& lua, VelocityComponentHandle& instance) { std::size_t length; const char* member = lua.CheckString(2, &length); @@ -143,7 +157,7 @@ namespace Ndk return false; }); - velocityComponent.SetSetter([] (Nz::LuaInstance& lua, VelocityComponentHandle& instance) + velocityComponent.SetSetter([] (Nz::LuaState& lua, VelocityComponentHandle& instance) { std::size_t length; const char* member = lua.CheckString(2, &length); @@ -165,6 +179,8 @@ namespace Ndk world.BindMethod("CreateEntity", &World::CreateEntity); world.BindMethod("CreateEntities", &World::CreateEntities); world.BindMethod("Clear", &World::Clear); + + world.BindMethod("IsValidHandle", &WorldHandle::IsValid); } #ifndef NDK_SERVER @@ -176,24 +192,26 @@ namespace Ndk return handle->GetObject(); }); - cameraComponent.BindMethod("GetFOV", &Ndk::CameraComponent::GetFOV); - cameraComponent.BindMethod("GetLayer", &Ndk::CameraComponent::GetLayer); + cameraComponent.BindMethod("GetFOV", &CameraComponent::GetFOV); + cameraComponent.BindMethod("GetLayer", &CameraComponent::GetLayer); - cameraComponent.BindMethod("SetFOV", &Ndk::CameraComponent::SetFOV); - cameraComponent.BindMethod("SetLayer", &Ndk::CameraComponent::SetLayer); - cameraComponent.BindMethod("SetProjectionType", &Ndk::CameraComponent::SetProjectionType); - cameraComponent.BindMethod("SetSize", (void(Ndk::CameraComponent::*)(const Nz::Vector2f&)) &Ndk::CameraComponent::SetSize); - //cameraComponent.BindMethod("SetTarget", &Ndk::CameraComponent::SetTarget); - cameraComponent.BindMethod("SetTargetRegion", &Ndk::CameraComponent::SetTargetRegion); - cameraComponent.BindMethod("SetViewport", &Ndk::CameraComponent::SetViewport); - cameraComponent.BindMethod("SetZFar", &Ndk::CameraComponent::SetZFar); - cameraComponent.BindMethod("SetZNear", &Ndk::CameraComponent::SetZNear); + cameraComponent.BindMethod("IsValidHandle", &CameraComponentHandle::IsValid); + + cameraComponent.BindMethod("SetFOV", &CameraComponent::SetFOV); + cameraComponent.BindMethod("SetLayer", &CameraComponent::SetLayer); + cameraComponent.BindMethod("SetProjectionType", &CameraComponent::SetProjectionType); + cameraComponent.BindMethod("SetSize", (void(CameraComponent::*)(const Nz::Vector2f&)) &CameraComponent::SetSize); + //cameraComponent.BindMethod("SetTarget", &CameraComponent::SetTarget); + cameraComponent.BindMethod("SetTargetRegion", &CameraComponent::SetTargetRegion); + cameraComponent.BindMethod("SetViewport", &CameraComponent::SetViewport); + cameraComponent.BindMethod("SetZFar", &CameraComponent::SetZFar); + cameraComponent.BindMethod("SetZNear", &CameraComponent::SetZNear); } /*********************************** Ndk::GraphicsComponent **********************************/ graphicsComponent.Reset("GraphicsComponent"); { - graphicsComponent.BindMethod("Attach", [] (Nz::LuaInstance& lua, Ndk::GraphicsComponent* instance, std::size_t argumentCount) -> int + graphicsComponent.BindMethod("Attach", [] (Nz::LuaState& lua, Ndk::GraphicsComponent* instance, std::size_t argumentCount) -> int { /* void Attach(Nz::InstancedRenderableRef renderable, int renderOrder = 0); @@ -249,6 +267,8 @@ namespace Ndk lua.Error("No matching overload for method GetMemoryUsage"); return 0; }); + + graphicsComponent.BindMethod("IsValidHandle", &GraphicsComponentHandle::IsValid); } #endif @@ -267,19 +287,19 @@ namespace Ndk * * \param instance Lua instance that will interact with the SDK classes */ - void LuaBinding_SDK::Register(Nz::LuaInstance& instance) + void LuaBinding_SDK::Register(Nz::LuaState& state) { // Classes - application.Register(instance); - entity.Register(instance); - nodeComponent.Register(instance); - velocityComponent.Register(instance); - world.Register(instance); + application.Register(state); + entity.Register(state); + nodeComponent.Register(state); + velocityComponent.Register(state); + world.Register(state); #ifndef NDK_SERVER - cameraComponent.Register(instance); - console.Register(instance); - graphicsComponent.Register(instance); + cameraComponent.Register(state); + console.Register(state); + graphicsComponent.Register(state); #endif // Enums @@ -292,23 +312,23 @@ namespace Ndk * \param instance Lua instance that will interact with the component * \param argIndex Index of the component */ - LuaBinding::ComponentBinding* LuaBinding::QueryComponentIndex(Nz::LuaInstance& instance, int argIndex) + LuaBinding::ComponentBinding* LuaBinding::QueryComponentIndex(Nz::LuaState& state, int argIndex) { - switch (instance.GetType(argIndex)) + switch (state.GetType(argIndex)) { case Nz::LuaType_Number: { - ComponentIndex componentIndex = instance.Check(&argIndex); + ComponentIndex componentIndex = state.Check(&argIndex); if (componentIndex > m_componentBinding.size()) { - instance.Error("Invalid component index"); + state.Error("Invalid component index"); return nullptr; } ComponentBinding& binding = m_componentBinding[componentIndex]; if (binding.name.IsEmpty()) { - instance.Error("Invalid component index"); + state.Error("Invalid component index"); return nullptr; } @@ -317,11 +337,11 @@ namespace Ndk case Nz::LuaType_String: { - const char* key = instance.CheckString(argIndex); + const char* key = state.CheckString(argIndex); auto it = m_componentBindingByName.find(key); if (it == m_componentBindingByName.end()) { - instance.Error("Invalid component name"); + state.Error("Invalid component name"); return nullptr; } @@ -332,7 +352,7 @@ namespace Ndk break; } - instance.Error("Invalid component index at #" + Nz::String::Number(argIndex)); + state.Error("Invalid component index at #" + Nz::String::Number(argIndex)); return nullptr; } } diff --git a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp index 173d6c3c5..65230a97a 100644 --- a/SDK/src/NDK/Lua/LuaBinding_Utility.cpp +++ b/SDK/src/NDK/Lua/LuaBinding_Utility.cpp @@ -29,7 +29,7 @@ namespace Ndk abstractImage.BindMethod("IsCompressed", &Nz::AbstractImage::IsCompressed); abstractImage.BindMethod("IsCubemap", &Nz::AbstractImage::IsCubemap); - abstractImage.BindMethod("GetMemoryUsage", [] (Nz::LuaInstance& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int + abstractImage.BindMethod("GetMemoryUsage", [] (Nz::LuaState& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 1U); switch (argCount) @@ -50,7 +50,7 @@ namespace Ndk return 0; }); - abstractImage.BindMethod("Update", [] (Nz::LuaInstance& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int + abstractImage.BindMethod("Update", [] (Nz::LuaState& lua, Nz::AbstractImage* instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 6U); int argIndex = 2; @@ -100,7 +100,7 @@ namespace Ndk /*********************************** Nz::Font **********************************/ font.Reset("Font"); { - font.SetConstructor([] (Nz::LuaInstance& /*lua*/, Nz::FontRef* instance, std::size_t /*argumentCount*/) + font.SetConstructor([] (Nz::LuaState& /*lua*/, Nz::FontRef* instance, std::size_t /*argumentCount*/) { Nz::PlacementNew(instance, Nz::Font::New()); return true; @@ -112,7 +112,7 @@ namespace Ndk font.BindMethod("Destroy", &Nz::Font::Destroy); - font.BindMethod("GetCachedGlyphCount", [] (Nz::LuaInstance& lua, Nz::FontRef& instance, std::size_t argumentCount) -> int + font.BindMethod("GetCachedGlyphCount", [] (Nz::LuaState& lua, Nz::FontRef& instance, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 2U); @@ -161,13 +161,6 @@ namespace Ndk font.BindStaticMethod("SetDefaultMinimumStepSize", &Nz::Font::SetDefaultMinimumStepSize); } - /*********************************** Nz::Keyboard **********************************/ - keyboard.Reset("Keyboard"); - { - keyboard.BindStaticMethod("GetKeyName", &Nz::Keyboard::GetKeyName); - keyboard.BindStaticMethod("IsKeyPressed", &Nz::Keyboard::IsKeyPressed); - } - /*********************************** Nz::Node **********************************/ node.Reset("Node"); { @@ -216,29 +209,29 @@ namespace Ndk node.BindMethod("SetPosition", (void(Nz::Node::*)(const Nz::Vector3f&, Nz::CoordSys)) &Nz::Node::SetPosition, Nz::CoordSys_Local); node.BindMethod("SetRotation", (void(Nz::Node::*)(const Nz::Quaternionf&, Nz::CoordSys)) &Nz::Node::SetRotation, Nz::CoordSys_Local); - node.BindMethod("Move", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t /*argumentCount*/) -> int + node.BindMethod("Move", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t /*argumentCount*/) -> int { int argIndex = 2; Nz::Vector3f offset = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.Move(offset, coordSys); + node.Move(offset, coordSys); return 0; }); - node.BindMethod("Rotate", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t /*argumentCount*/) -> int + node.BindMethod("Rotate", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t /*argumentCount*/) -> int { int argIndex = 2; Nz::Quaternionf rotation = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.Rotate(rotation, coordSys); + node.Rotate(rotation, coordSys); return 0; }); - node.BindMethod("Scale", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t argumentCount) -> int + node.BindMethod("Scale", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 4U); @@ -248,15 +241,15 @@ namespace Ndk case 1: { if (lua.IsOfType(argIndex, Nz::LuaType_Number)) - instance.Scale(lua.Check(&argIndex)); + node.Scale(lua.Check(&argIndex)); else - instance.Scale(lua.Check(&argIndex)); + node.Scale(lua.Check(&argIndex)); return 0; } case 3: - instance.Scale(lua.Check(&argIndex)); + node.Scale(lua.Check(&argIndex)); return 0; } @@ -264,7 +257,7 @@ namespace Ndk return 0; }); - node.BindMethod("SetScale", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t argumentCount) -> int + node.BindMethod("SetScale", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 4U); @@ -278,10 +271,10 @@ namespace Ndk { float scale = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.SetScale(scale, coordSys); + node.SetScale(scale, coordSys); } else - instance.SetScale(lua.Check(&argIndex)); + node.SetScale(lua.Check(&argIndex)); return 0; } @@ -292,7 +285,7 @@ namespace Ndk Nz::Vector3f scale = lua.Check(&argIndex); Nz::CoordSys coordSys = lua.Check(&argIndex, Nz::CoordSys_Local); - instance.SetScale(scale, coordSys); + node.SetScale(scale, coordSys); return 0; } } @@ -301,7 +294,7 @@ namespace Ndk return 0; }); - node.BindMethod("SetInitialScale", [] (Nz::LuaInstance& lua, Nz::Node& instance, std::size_t argumentCount) -> int + node.BindMethod("SetInitialScale", [] (Nz::LuaState& lua, Nz::Node& node, std::size_t argumentCount) -> int { std::size_t argCount = std::min(argumentCount, 4U); @@ -311,16 +304,16 @@ namespace Ndk case 1: { if (lua.IsOfType(argIndex, Nz::LuaType_Number)) - instance.SetInitialScale(lua.Check(&argIndex)); + node.SetInitialScale(lua.Check(&argIndex)); else - instance.SetInitialScale(lua.Check(&argIndex)); + node.SetInitialScale(lua.Check(&argIndex)); return 0; } case 2: case 3: - instance.SetInitialScale(lua.Check(&argIndex)); + node.SetInitialScale(lua.Check(&argIndex)); return 0; } @@ -335,112 +328,10 @@ namespace Ndk * * \param instance Lua instance that will interact with the Utility classes */ - void LuaBinding_Utility::Register(Nz::LuaInstance& instance) + void LuaBinding_Utility::Register(Nz::LuaState& state) { - abstractImage.Register(instance); - font.Register(instance); - keyboard.Register(instance); - node.Register(instance); - - keyboard.PushGlobalTable(instance); - { - static_assert(Nz::Keyboard::Count == 121, "Nz::Keyboard::Key has been updated but change was not reflected to Lua binding"); - - instance.PushField("Undefined", Nz::Keyboard::Undefined); - - // A-Z - for (std::size_t i = 0; i < 26; ++i) - instance.PushField(Nz::String('A' + char(i)), Nz::Keyboard::A + i); - - // Numerical - for (std::size_t i = 0; i < 10; ++i) - { - instance.PushField("Num" + Nz::String::Number(i), Nz::Keyboard::Num0 + i); - instance.PushField("Numpad" + Nz::String::Number(i), Nz::Keyboard::Numpad0 + i); - } - - // F1-F15 - for (std::size_t i = 0; i < 15; ++i) - instance.PushField('F' + Nz::String::Number(i+1), Nz::Keyboard::F1 + i); - - // And all the others... - instance.PushField("Down", Nz::Keyboard::Down); - instance.PushField("Left", Nz::Keyboard::Left); - instance.PushField("Right", Nz::Keyboard::Right); - instance.PushField("Up", Nz::Keyboard::Up); - - instance.PushField("Add", Nz::Keyboard::Add); - instance.PushField("Decimal", Nz::Keyboard::Decimal); - instance.PushField("Divide", Nz::Keyboard::Divide); - instance.PushField("Multiply", Nz::Keyboard::Multiply); - instance.PushField("Subtract", Nz::Keyboard::Subtract); - - instance.PushField("Backslash", Nz::Keyboard::Backslash); - instance.PushField("Backspace", Nz::Keyboard::Backspace); - instance.PushField("Clear", Nz::Keyboard::Clear); - instance.PushField("Comma", Nz::Keyboard::Comma); - instance.PushField("Dash", Nz::Keyboard::Dash); - instance.PushField("Delete", Nz::Keyboard::Delete); - instance.PushField("End", Nz::Keyboard::End); - instance.PushField("Equal", Nz::Keyboard::Equal); - instance.PushField("Escape", Nz::Keyboard::Escape); - instance.PushField("Home", Nz::Keyboard::Home); - instance.PushField("Insert", Nz::Keyboard::Insert); - instance.PushField("LAlt", Nz::Keyboard::LAlt); - instance.PushField("LBracket", Nz::Keyboard::LBracket); - instance.PushField("LControl", Nz::Keyboard::LControl); - instance.PushField("LShift", Nz::Keyboard::LShift); - instance.PushField("LSystem", Nz::Keyboard::LSystem); - instance.PushField("PageDown", Nz::Keyboard::PageDown); - instance.PushField("PageUp", Nz::Keyboard::PageUp); - instance.PushField("Pause", Nz::Keyboard::Pause); - instance.PushField("Period", Nz::Keyboard::Period); - instance.PushField("Print", Nz::Keyboard::Print); - instance.PushField("PrintScreen", Nz::Keyboard::PrintScreen); - instance.PushField("Quote", Nz::Keyboard::Quote); - instance.PushField("RAlt", Nz::Keyboard::RAlt); - instance.PushField("RBracket", Nz::Keyboard::RBracket); - instance.PushField("RControl", Nz::Keyboard::RControl); - instance.PushField("Return", Nz::Keyboard::Return); - instance.PushField("RShift", Nz::Keyboard::RShift); - instance.PushField("RSystem", Nz::Keyboard::RSystem); - instance.PushField("Semicolon", Nz::Keyboard::Semicolon); - instance.PushField("Slash", Nz::Keyboard::Slash); - instance.PushField("Space", Nz::Keyboard::Space); - instance.PushField("Tab", Nz::Keyboard::Tab); - instance.PushField("Tilde", Nz::Keyboard::Tilde); - instance.PushField("Browser_Back", Nz::Keyboard::Browser_Back); - instance.PushField("Browser_Favorites", Nz::Keyboard::Browser_Favorites); - instance.PushField("Browser_Forward", Nz::Keyboard::Browser_Forward); - instance.PushField("Browser_Home", Nz::Keyboard::Browser_Home); - instance.PushField("Browser_Refresh", Nz::Keyboard::Browser_Refresh); - instance.PushField("Browser_Search", Nz::Keyboard::Browser_Search); - instance.PushField("Browser_Stop", Nz::Keyboard::Browser_Stop); - instance.PushField("Media_Next", Nz::Keyboard::Media_Next); - instance.PushField("Media_Play", Nz::Keyboard::Media_Play); - instance.PushField("Media_Previous", Nz::Keyboard::Media_Previous); - instance.PushField("Media_Stop", Nz::Keyboard::Media_Stop); - instance.PushField("Volume_Down", Nz::Keyboard::Volume_Down); - instance.PushField("Volume_Mute", Nz::Keyboard::Volume_Mute); - instance.PushField("Volume_Up", Nz::Keyboard::Volume_Up); - instance.PushField("CapsLock", Nz::Keyboard::CapsLock); - instance.PushField("NumLock", Nz::Keyboard::NumLock); - instance.PushField("ScrollLock", Nz::Keyboard::ScrollLock); - } - instance.Pop(); - - static_assert(Nz::WindowStyle_Max + 1 == 6, "Nz::WindowStyle has been updated but change was not reflected to Lua binding"); - instance.PushTable(0, Nz::WindowStyle_Max + 1); - { - instance.PushField("None", Nz::WindowStyle_None); - instance.PushField("Fullscreen", Nz::WindowStyle_Fullscreen); - instance.PushField("Closable", Nz::WindowStyle_Closable); - instance.PushField("Resizable", Nz::WindowStyle_Resizable); - instance.PushField("Titlebar", Nz::WindowStyle_Titlebar); - instance.PushField("Threaded", Nz::WindowStyle_Threaded); - } - instance.SetGlobal("WindowStyle"); - - + abstractImage.Register(state); + font.Register(state); + node.Register(state); } } diff --git a/SDK/src/NDK/LuaAPI.cpp b/SDK/src/NDK/LuaAPI.cpp index a28fbb05f..3a82d2130 100644 --- a/SDK/src/NDK/LuaAPI.cpp +++ b/SDK/src/NDK/LuaAPI.cpp @@ -44,10 +44,10 @@ namespace Ndk * \param instance Lua instance that will interact with the engine & SDK */ - void LuaAPI::RegisterClasses(Nz::LuaInstance& instance) + void LuaAPI::RegisterClasses(Nz::LuaState& state) { Nz::ErrorFlags errFlags(Nz::ErrorFlag_ThrowException, true); - GetBinding()->RegisterClasses(instance); + GetBinding()->RegisterClasses(state); } /*! diff --git a/SDK/src/NDK/Resources/checkmark.png.h b/SDK/src/NDK/Resources/checkmark.png.h new file mode 100644 index 000000000..644161149 --- /dev/null +++ b/SDK/src/NDK/Resources/checkmark.png.h @@ -0,0 +1 @@ +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,133,0,0,0,138,8,6,0,0,0,132,140,137,233,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147,0,0,0,9,112,72,89,115,0,0,11,19,0,0,11,19,1,0,154,156,24,0,0,0,7,116,73,77,69,7,225,8,14,14,24,3,208,239,186,156,0,0,0,29,105,84,88,116,67,111,109,109,101,110,116,0,0,0,0,0,67,114,101,97,116,101,100,32,119,105,116,104,32,71,73,77,80,100,46,101,7,0,0,6,196,73,68,65,84,120,218,237,157,125,172,143,101,24,199,63,199,251,33,135,136,232,197,176,70,50,105,147,90,167,49,165,161,204,50,147,151,82,44,217,26,90,141,169,182,214,106,42,42,36,189,140,106,42,170,63,196,42,127,136,229,101,52,53,83,35,33,47,203,41,9,181,157,18,149,151,195,113,250,227,121,112,58,167,56,63,231,119,95,191,235,62,190,159,237,254,211,126,183,239,245,61,207,243,220,247,125,221,215,5,66,84,32,79,18,92,16,92,4,52,7,242,203,141,218,192,49,224,32,176,23,248,75,166,168,153,180,7,186,165,163,11,208,6,184,2,104,122,142,127,87,6,236,4,222,1,102,72,198,184,105,0,244,7,222,0,246,165,193,173,238,120,77,178,198,251,68,120,9,248,35,75,70,40,63,182,74,222,184,104,11,124,8,148,6,48,195,169,241,186,100,142,231,53,49,25,56,18,208,12,101,233,135,103,59,201,29,199,171,98,99,96,51,156,26,79,75,110,255,244,3,14,24,25,98,35,80,79,146,251,166,127,250,56,183,48,196,159,64,71,73,238,155,190,192,81,35,67,148,1,67,37,185,111,186,166,127,185,86,134,152,38,201,125,211,26,248,201,208,16,159,2,181,36,187,95,242,129,175,12,13,177,29,104,34,217,253,146,7,44,50,52,196,1,160,131,100,247,205,115,134,134,56,145,46,117,133,99,134,27,26,162,12,152,40,201,125,211,157,240,91,215,229,199,60,73,238,155,203,72,146,91,172,12,177,14,168,47,217,253,210,0,88,111,104,136,189,233,114,87,56,102,190,161,33,142,164,175,41,225,152,9,198,31,150,35,36,185,111,122,167,75,66,43,67,188,40,201,125,211,14,40,70,91,216,34,165,33,176,201,208,16,219,208,22,182,123,222,71,91,216,162,28,15,27,26,162,20,184,93,146,251,166,7,112,220,208,20,79,74,114,223,180,6,246,27,26,98,49,186,241,231,154,186,192,90,67,67,236,0,10,36,187,111,102,26,26,226,16,208,73,146,251,102,48,182,59,150,131,36,185,111,58,164,127,185,86,134,152,34,201,253,111,80,109,54,52,196,50,180,99,233,158,121,134,134,40,2,154,73,114,223,140,54,52,196,97,146,187,33,194,49,93,210,64,89,153,226,30,73,238,155,70,36,135,79,86,134,152,41,201,253,99,121,208,181,26,168,35,201,125,243,128,161,33,246,0,45,37,185,111,58,27,126,71,28,3,110,144,228,190,201,39,41,22,102,245,148,24,43,201,253,243,150,161,33,62,144,220,254,25,106,104,136,173,233,234,70,56,166,61,73,201,98,171,114,67,58,249,116,78,93,108,111,116,13,147,228,254,121,193,208,16,175,74,110,255,244,38,108,133,219,138,151,128,85,182,208,57,205,177,187,25,94,76,82,117,95,56,103,177,145,33,78,162,234,50,81,48,206,240,59,98,178,228,246,207,53,216,109,99,47,71,25,84,238,169,135,93,129,244,61,64,11,73,238,159,233,70,134,40,1,10,37,119,28,203,207,147,70,166,120,68,114,251,167,25,240,179,145,33,22,73,238,56,88,104,100,136,93,168,118,68,20,220,135,93,194,204,245,146,219,63,109,8,211,181,79,223,17,145,146,7,172,194,174,84,128,136,128,137,70,134,216,141,110,116,69,65,103,108,90,50,29,215,126,68,28,212,197,110,215,242,113,201,29,7,86,253,53,150,161,146,67,81,112,35,54,85,111,247,162,115,141,40,200,39,233,157,101,81,186,176,151,228,142,131,89,70,175,141,167,36,117,28,244,194,230,176,107,21,202,143,136,130,198,192,143,6,134,248,21,53,91,137,134,55,177,201,179,236,35,169,227,160,143,209,119,196,84,73,29,7,5,216,180,137,94,135,10,138,68,195,92,3,67,28,34,185,103,42,34,160,159,209,107,227,94,73,29,7,77,72,50,165,85,63,66,156,230,109,3,67,20,161,202,249,209,208,23,155,227,240,155,36,117,60,155,84,187,13,76,161,14,60,17,49,199,192,16,159,163,109,236,104,184,149,240,103,27,7,80,185,128,104,104,148,126,248,133,126,74,220,117,33,136,89,157,93,184,75,72,186,233,21,2,151,147,20,248,248,13,88,153,46,213,142,26,254,63,166,146,116,8,14,189,162,89,168,191,191,202,52,0,238,6,86,156,227,81,253,61,112,173,209,156,10,9,95,126,104,7,42,95,88,137,124,146,139,44,153,180,84,60,0,116,12,60,175,250,132,175,162,95,2,116,147,5,206,144,7,140,2,246,157,167,160,155,73,50,167,67,97,145,128,59,73,54,56,195,213,192,151,89,16,117,66,160,249,117,37,124,119,224,229,40,27,251,52,227,201,94,121,159,95,210,199,124,54,169,13,124,77,248,106,117,202,162,34,41,237,243,110,0,129,71,102,121,158,143,25,188,54,6,203,14,137,33,150,4,124,12,103,139,171,8,95,164,108,190,236,144,16,178,245,81,41,208,42,75,243,92,73,248,203,192,58,253,76,31,239,161,31,199,15,101,97,158,247,163,75,60,102,27,82,22,165,134,215,86,115,158,151,2,191,7,158,227,116,217,33,225,78,108,210,214,78,2,87,86,99,158,11,2,207,239,219,0,171,164,40,169,133,93,178,72,30,231,223,104,117,0,48,36,224,220,74,128,17,36,53,169,4,54,23,101,202,183,64,202,148,198,132,207,183,124,84,54,248,55,211,12,77,81,70,230,213,225,94,9,60,159,53,40,105,166,18,99,141,77,49,59,131,185,117,39,236,9,232,65,160,173,44,80,153,94,198,166,56,72,213,142,161,235,0,223,4,158,203,40,133,255,191,41,192,174,29,210,169,49,166,10,243,154,20,120,14,31,41,244,103,103,139,177,41,182,156,99,62,109,129,191,3,254,254,126,146,204,49,113,22,102,27,155,162,12,184,227,44,243,89,154,195,223,22,41,67,114,96,138,245,255,51,151,225,129,127,119,142,194,93,53,90,96,215,231,162,252,168,184,153,213,145,176,93,130,119,161,92,203,140,216,144,3,83,20,3,29,210,223,47,228,252,211,254,170,186,205,222,83,97,206,140,41,57,48,197,169,190,222,155,13,126,103,150,66,156,57,61,114,100,10,139,177,19,104,168,16,103,78,109,146,203,60,53,205,16,165,192,205,10,111,213,41,191,231,95,154,46,5,107,26,51,129,47,20,234,184,150,166,33,199,54,146,36,34,81,13,10,72,114,10,106,130,33,78,144,20,103,23,89,96,105,13,49,197,243,10,101,246,24,83,3,12,177,5,165,214,101,149,150,216,159,154,102,187,30,149,218,60,6,96,117,196,166,120,70,225,11,195,248,72,13,177,137,176,183,220,47,104,90,69,248,10,41,1,174,83,232,194,178,38,50,83,168,27,143,1,227,34,50,196,6,84,69,95,175,144,10,171,141,174,10,151,29,43,34,48,197,179,10,147,45,163,157,27,226,59,109,82,217,115,49,126,207,66,74,81,209,244,156,241,137,83,83,188,172,208,228,142,129,14,13,81,132,18,112,115,74,29,146,126,155,158,76,113,155,194,146,123,102,56,50,196,92,133,195,7,29,201,205,189,144,138,99,31,208,84,225,240,195,103,14,76,49,80,97,240,197,128,28,27,98,129,66,224,143,90,192,246,28,25,162,152,36,249,71,56,100,100,142,76,49,66,210,251,94,158,22,25,27,98,137,100,247,207,48,67,67,28,162,122,181,55,133,33,107,141,76,241,160,164,142,135,78,132,175,164,175,213,70,132,132,188,31,242,30,74,192,141,150,39,178,108,134,173,192,32,201,26,63,183,0,31,3,63,144,121,79,175,195,192,58,146,179,149,158,168,95,151,11,254,1,48,107,33,165,213,10,148,99,0,0,0,0,73,69,78,68,174,66,96,130, \ No newline at end of file diff --git a/SDK/src/NDK/Sdk.cpp b/SDK/src/NDK/Sdk.cpp index 312e9a777..637328eeb 100644 --- a/SDK/src/NDK/Sdk.cpp +++ b/SDK/src/NDK/Sdk.cpp @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -34,6 +36,7 @@ #include #include #include +#include #endif namespace Ndk @@ -63,13 +66,6 @@ namespace Ndk // Initialize the engine first // Shared modules - #ifdef NDK_SERVER - Nz::ParameterList parameters; - parameters.SetParameter("NoWindowSystem", true); - - Nz::Utility::SetParameters(parameters); - #endif - Nz::Lua::Initialize(); Nz::Noise::Initialize(); Nz::Physics2D::Initialize(); @@ -119,6 +115,13 @@ namespace Ndk InitializeSystem(); InitializeSystem(); InitializeSystem(); + + // Widgets + if (!CheckboxWidget::Initialize()) + { + NazaraError("Failed to initialize Checkbox Widget"); + return false; + } #endif NazaraNotice("Initialized: SDK"); @@ -127,7 +130,6 @@ namespace Ndk catch (const std::exception& e) { NazaraError("Failed to initialize NDK: " + Nz::String(e.what())); - return false; } } @@ -173,6 +175,11 @@ namespace Ndk Nz::Physics3D::Uninitialize(); Nz::Utility::Uninitialize(); + #ifndef NDK_SERVER + // Widgets + CheckboxWidget::Uninitialize(); + #endif + NazaraNotice("Uninitialized: SDK"); } diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index f586056a2..022621596 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -48,12 +48,14 @@ namespace Ndk { m_forceRenderQueueInvalidation = true; //< Hackfix until lights and particles are handled by culling list - m_cameras.Remove(entity); - m_directionalLights.Remove(entity); - m_drawables.Remove(entity); - m_lights.Remove(entity); - m_particleGroups.Remove(entity); - m_pointSpotLights.Remove(entity); + for (auto it = m_cameras.begin(); it != m_cameras.end(); ++it) + { + if (it->GetObject() == entity) + { + m_cameras.erase(it); + break; + } + } if (entity->HasComponent()) { @@ -74,14 +76,23 @@ namespace Ndk if (entity->HasComponent() && entity->HasComponent()) { - m_cameras.Insert(entity); + m_cameras.emplace_back(entity); std::sort(m_cameras.begin(), m_cameras.end(), [](const EntityHandle& handle1, const EntityHandle& handle2) { return handle1->GetComponent().GetLayer() < handle2->GetComponent().GetLayer(); }); } else - m_cameras.Remove(entity); + { + for (auto it = m_cameras.begin(); it != m_cameras.end(); ++it) + { + if (it->GetObject() == entity) + { + m_cameras.erase(it); + break; + } + } + } if (entity->HasComponent() && entity->HasComponent()) { @@ -181,7 +192,7 @@ namespace Ndk GraphicsComponent& graphicsComponent = drawable->GetComponent(); graphicsComponent.EnsureBoundingVolumeUpdate(); } - + bool forceInvalidation = false; std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation); diff --git a/SDK/src/NDK/Widgets/ButtonWidget.cpp b/SDK/src/NDK/Widgets/ButtonWidget.cpp index 8d3a69e33..a525d7a68 100644 --- a/SDK/src/NDK/Widgets/ButtonWidget.cpp +++ b/SDK/src/NDK/Widgets/ButtonWidget.cpp @@ -61,10 +61,6 @@ namespace Ndk m_gradientSprite->SetColor(Nz::Color(128, 128, 128)); } - void ButtonWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY) - { - } - void ButtonWidget::OnMouseExit() { m_gradientSprite->SetColor(Nz::Color(74, 74, 74)); diff --git a/SDK/src/NDK/Widgets/CheckboxWidget.cpp b/SDK/src/NDK/Widgets/CheckboxWidget.cpp new file mode 100644 index 000000000..ecc7cd478 --- /dev/null +++ b/SDK/src/NDK/Widgets/CheckboxWidget.cpp @@ -0,0 +1,185 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + Nz::Color CheckboxWidget::s_backgroundColor { Nz::Color::White }; + Nz::Color CheckboxWidget::s_disabledBackgroundColor { 201, 201, 201 }; + Nz::Color CheckboxWidget::s_disabledBorderColor { 62, 62, 62 }; + Nz::Color CheckboxWidget::s_borderColor { Nz::Color::Black }; + float CheckboxWidget::s_borderScale { 16.f }; + + CheckboxWidget::CheckboxWidget(BaseWidget* parent) : + BaseWidget(parent), + m_adaptativeMargin { true }, + m_checkboxEnabled { true }, + m_tristateEnabled { false }, + m_textMargin { 16.f }, + m_state { CheckboxState_Unchecked } + { + m_checkboxBorderSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + m_checkboxBackgroundSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + m_checkboxContentSprite = Nz::Sprite::New(Nz::Material::New("Translucent2D")); + m_textSprite = Nz::TextSprite::New(); + + m_checkboxBorderEntity = CreateEntity(); + m_checkboxBorderEntity->AddComponent().SetParent(this); + m_checkboxBorderEntity->AddComponent().Attach(m_checkboxBorderSprite); + + m_checkboxBackgroundEntity = CreateEntity(); + m_checkboxBackgroundEntity->AddComponent().SetParent(this); + m_checkboxBackgroundEntity->AddComponent().Attach(m_checkboxBackgroundSprite, 1); + + m_checkboxContentEntity = CreateEntity(); + m_checkboxContentEntity->AddComponent().SetParent(this); + m_checkboxContentEntity->AddComponent().Attach(m_checkboxContentSprite, 2); + + m_textEntity = CreateEntity(); + m_textEntity->AddComponent().SetParent(this); + m_textEntity->AddComponent().Attach(m_textSprite); + + m_checkMark = Nz::TextureLibrary::Get("Ndk::CheckboxWidget::checkmark"); + + SetCheckboxSize({ 32.f, 32.f }); + UpdateCheckbox(); + } + + bool CheckboxWidget::Initialize() + { + const Nz::UInt8 r_checkmark[] = + { + #include + }; + + Nz::TextureRef checkmarkTexture = Nz::Texture::New(); + if (!checkmarkTexture->LoadFromMemory(r_checkmark, sizeof(r_checkmark) / sizeof(r_checkmark[0]))) + { + NazaraError("Failed to load embedded checkmark"); + return false; + } + + Nz::TextureLibrary::Register("Ndk::CheckboxWidget::checkmark", checkmarkTexture); + return true; + } + + void CheckboxWidget::Uninitialize() + { + Nz::TextureLibrary::Unregister("Ndk::CheckboxWidget::checkmark"); + } + + void CheckboxWidget::SetState(CheckboxState state) + { + if (!m_checkboxEnabled) + return; + + if (state == CheckboxState_Tristate) + m_tristateEnabled = true; + + m_state = state; + UpdateCheckbox(); + } + + CheckboxState CheckboxWidget::SwitchToNextState() + { + if (!m_checkboxEnabled) + return m_state; + + switch (m_state) + { + case CheckboxState_Unchecked: + SetState(CheckboxState_Checked); + break; + + case CheckboxState_Checked: + SetState(m_tristateEnabled ? CheckboxState_Tristate : CheckboxState_Unchecked); + break; + + case CheckboxState_Tristate: + SetState(CheckboxState_Unchecked); + break; + } + + return m_state; + } + + void CheckboxWidget::ResizeToContent() + { + Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); + Nz::Vector2f checkboxSize = GetCheckboxSize(); + + Nz::Vector2f finalSize { checkboxSize.x + (m_adaptativeMargin ? checkboxSize.x / 2.f : m_textMargin) + textSize.x, std::max(textSize.y, checkboxSize.y) }; + SetContentSize(finalSize); + } + + void CheckboxWidget::Layout() + { + BaseWidget::Layout(); + + Nz::Vector2f origin = GetContentOrigin(); + Nz::Vector2f checkboxSize = GetCheckboxSize(); + Nz::Vector2f borderSize = GetCheckboxBorderSize(); + + m_checkboxBorderEntity->GetComponent().SetPosition(origin); + m_checkboxBackgroundEntity->GetComponent().SetPosition(origin + borderSize); + + Nz::Vector3f checkboxBox = m_checkboxContentSprite->GetBoundingVolume().obb.localBox.GetLengths(); + m_checkboxContentEntity->GetComponent().SetPosition(origin.x + checkboxSize.x / 2.f - checkboxBox.x / 2.f, + origin.y + checkboxSize.y / 2.f - checkboxBox.y / 2.f); + + Nz::Vector3f textBox = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); + m_textEntity->GetComponent().SetPosition(origin.x + checkboxSize.x + (m_adaptativeMargin ? checkboxSize.x / 2.f : m_textMargin), + origin.y + checkboxSize.y / 2.f - textBox.y / 2.f); + } + + void CheckboxWidget::OnMouseButtonRelease(int x, int y, Nz::Mouse::Button button) + { + if (button == Nz::Mouse::Left && ContainsCheckbox(x, y) && IsCheckboxEnabled()) + { + SwitchToNextState(); + OnStateChanged(this); + } + } + + void CheckboxWidget::UpdateCheckbox() + { + if (m_checkboxEnabled) + { + m_checkboxBorderSprite->SetColor(s_borderColor); + m_checkboxBackgroundSprite->SetColor(s_backgroundColor); + } + else + { + m_checkboxBorderSprite->SetColor(s_disabledBorderColor); + m_checkboxBackgroundSprite->SetColor(s_disabledBackgroundColor); + } + + + if (m_state == CheckboxState_Unchecked) + { + m_checkboxContentEntity->Enable(false); + return; + } + else if (m_state == CheckboxState_Checked) + { + m_checkboxContentEntity->Enable(); + m_checkboxContentSprite->SetColor(Nz::Color::White); + m_checkboxContentSprite->SetTexture(m_checkMark, false); + } + else // Tristate + { + m_checkboxContentEntity->Enable(); + m_checkboxContentSprite->SetColor(Nz::Color::Black); + m_checkboxContentSprite->SetTexture(Nz::TextureRef {}); + } + } +} diff --git a/SDK/src/NDK/Widgets/ProgressBarWidget.cpp b/SDK/src/NDK/Widgets/ProgressBarWidget.cpp new file mode 100644 index 000000000..f4cf9e0b8 --- /dev/null +++ b/SDK/src/NDK/Widgets/ProgressBarWidget.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2017 Samy Bensaid +// This file is part of the "Nazara Development Kit" +// For conditions of distribution and use, see copyright notice in Prerequesites.hpp + +#include +#include +#include +#include +#include + +namespace Ndk +{ + float ProgressBarWidget::s_borderScale { 16.f }; + Nz::Color ProgressBarWidget::s_borderColor { Nz::Color::Black }; + Nz::Color ProgressBarWidget::s_barBackgroundColor { Nz::Color { 225, 225, 225 } }; + Nz::Color ProgressBarWidget::s_barBackgroundCornerColor { Nz::Color { 255, 255, 255 } }; + Nz::Color ProgressBarWidget::s_barColor { Nz::Color { 0, 225, 0 } }; + Nz::Color ProgressBarWidget::s_barCornerColor { Nz::Color { 220, 255, 220 } }; + + ProgressBarWidget::ProgressBarWidget(BaseWidget* parent) : + BaseWidget(parent), + m_textColor { Nz::Color::Black }, + m_textMargin { 16.f }, + m_value { 0u } + { + m_borderSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + m_barBackgroundSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + m_barSprite = Nz::Sprite::New(Nz::Material::New("Basic2D")); + + m_borderSprite->SetColor(s_borderColor); + SetBarBackgroundColor(s_barBackgroundColor, s_barBackgroundCornerColor); + SetBarColor(s_barColor, s_barCornerColor); + + + m_borderEntity = CreateEntity(); + m_borderEntity->AddComponent().SetParent(this); + m_borderEntity->AddComponent().Attach(m_borderSprite); + + m_barEntity = CreateEntity(); + m_barEntity->AddComponent().SetParent(this); + GraphicsComponent& graphics = m_barEntity->AddComponent(); + + graphics.Attach(m_barBackgroundSprite, 1); + graphics.Attach(m_barSprite, 2); + + + m_textSprite = Nz::TextSprite::New(); + m_textEntity = CreateEntity(); + + m_textEntity->AddComponent().SetParent(this); + m_textEntity->AddComponent().Attach(m_textSprite); + + UpdateText(); + Layout(); + } + + + const Nz::Color& ProgressBarWidget::GetDefaultBarColor() + { + return s_barColor; + } + + const Nz::Color& ProgressBarWidget::GetDefaultBarCornerColor() + { + return s_barCornerColor; + } + + const Nz::Color& ProgressBarWidget::GetDefaultBarBackgroundColor() + { + return s_barBackgroundColor; + } + + const Nz::Color& ProgressBarWidget::GetDefaultBarBackgroundCornerColor() + { + return s_barBackgroundCornerColor; + } + + + void ProgressBarWidget::Layout() + { + Nz::Vector2f origin = GetContentOrigin(); + Nz::Vector2f size = GetContentSize(); + Nz::Vector2f progressBarSize = size; + + if (IsTextEnabled()) + { + UpdateText(); + + Nz::Vector3f textSize = m_textSprite->GetBoundingVolume().obb.localBox.GetLengths(); + m_textEntity->GetComponent().SetPosition(origin.x + size.x - textSize.x, origin.y + size.y / 2.f - textSize.y); + + progressBarSize -= { textSize.x + m_textMargin, 0.f }; + } + + m_borderSprite->SetSize(progressBarSize); + Nz::Vector2f borderSize = GetProgressBarBorderSize(); + + m_barBackgroundSprite->SetSize(progressBarSize - (borderSize * 2.f)); + m_barSprite->SetSize((progressBarSize.x - (borderSize.x * 2.f)) / 100.f * static_cast(m_value), progressBarSize.y - (borderSize.y * 2.f)); + + m_borderEntity->GetComponent().SetPosition(origin.x, origin.y); + m_barEntity->GetComponent().SetPosition(origin.x + borderSize.x, origin.y + borderSize.y); + } +} diff --git a/SDK/src/NDK/Widgets/TextAreaWidget.cpp b/SDK/src/NDK/Widgets/TextAreaWidget.cpp index 932757621..416975645 100644 --- a/SDK/src/NDK/Widgets/TextAreaWidget.cpp +++ b/SDK/src/NDK/Widgets/TextAreaWidget.cpp @@ -13,7 +13,8 @@ namespace Ndk { TextAreaWidget::TextAreaWidget(BaseWidget* parent) : BaseWidget(parent), - m_cursorPosition(0U), + m_cursorPosition(0U, 0U), + m_cursorGlyph(0), m_multiLineEnabled(false), m_readOnly(false) { @@ -81,7 +82,7 @@ namespace Ndk void TextAreaWidget::Write(const Nz::String& text) { - if (m_cursorPosition >= m_drawer.GetGlyphCount()) + if (m_cursorGlyph >= m_drawer.GetGlyphCount()) { AppendText(text); SetCursorPosition(m_drawer.GetGlyphCount()); @@ -89,10 +90,10 @@ namespace Ndk else { Nz::String currentText = m_drawer.GetText(); - currentText.Insert(currentText.GetCharacterPosition(m_cursorPosition), text); + currentText.Insert(currentText.GetCharacterPosition(m_cursorGlyph), text); SetText(currentText); - SetCursorPosition(m_cursorPosition + text.GetLength()); + SetCursorPosition(m_cursorGlyph + text.GetLength()); } } @@ -114,11 +115,11 @@ namespace Ndk const Nz::String& text = m_drawer.GetText(); Nz::String newText; - if (m_cursorPosition > 0) - newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorPosition) - 1)); + if (m_cursorGlyph > 0) + newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorGlyph) - 1)); - if (m_cursorPosition < m_drawer.GetGlyphCount()) - newText.Append(text.SubString(text.GetCharacterPosition(m_cursorPosition + 1))); + if (m_cursorGlyph < m_drawer.GetGlyphCount()) + newText.Append(text.SubString(text.GetCharacterPosition(m_cursorGlyph + 1))); m_drawer.SetText(newText); m_textSprite->Update(m_drawer); @@ -133,7 +134,7 @@ namespace Ndk if (ignoreDefaultAction) break; - //TODO + MoveCursor({0, 1}); break; } @@ -145,7 +146,7 @@ namespace Ndk if (ignoreDefaultAction) break; - MoveCursor(-1); + MoveCursor({-1, 0}); break; } @@ -157,7 +158,7 @@ namespace Ndk if (ignoreDefaultAction) break; - MoveCursor(1); + MoveCursor({1, 0}); break; } @@ -169,7 +170,7 @@ namespace Ndk if (ignoreDefaultAction) break; - //TODO + MoveCursor({0, -1}); break; } } @@ -221,13 +222,13 @@ namespace Ndk const Nz::String& text = m_drawer.GetText(); Nz::String newText; - if (m_cursorPosition > 1) - newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorPosition - 1) - 1)); + if (m_cursorGlyph > 1) + newText.Append(text.SubString(0, text.GetCharacterPosition(m_cursorGlyph - 1) - 1)); - if (m_cursorPosition < m_drawer.GetGlyphCount()) - newText.Append(text.SubString(text.GetCharacterPosition(m_cursorPosition))); + if (m_cursorGlyph < m_drawer.GetGlyphCount()) + newText.Append(text.SubString(text.GetCharacterPosition(m_cursorGlyph))); - MoveCursor(-1); + MoveCursor({-1, 0}); SetText(newText); break; } @@ -258,25 +259,15 @@ namespace Ndk void TextAreaWidget::RefreshCursor() { - std::size_t lineCount = m_drawer.GetLineCount(); - std::size_t line = 0U; - for (std::size_t i = line + 1; i < lineCount; ++i) - { - if (m_drawer.GetLine(i).glyphIndex > m_cursorPosition) - break; - - line = i; - } - - const auto& lineInfo = m_drawer.GetLine(line); + const auto& lineInfo = m_drawer.GetLine(m_cursorPosition.y); std::size_t glyphCount = m_drawer.GetGlyphCount(); float position; - if (glyphCount > 0 && lineInfo.glyphIndex < m_cursorPosition) + if (glyphCount > 0 && lineInfo.glyphIndex < m_cursorGlyph) { - const auto& glyph = m_drawer.GetGlyph(std::min(m_cursorPosition, glyphCount - 1)); + const auto& glyph = m_drawer.GetGlyph(std::min(m_cursorGlyph, glyphCount - 1)); position = glyph.bounds.x; - if (m_cursorPosition >= glyphCount) + if (m_cursorGlyph >= glyphCount) position += glyph.bounds.width; } else diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index 545fab499..702452fc4 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -60,29 +60,51 @@ namespace Ndk const EntityHandle& World::CreateEntity() { EntityId id; + EntityBlock* entBlock; if (!m_freeIdList.empty()) { // We get an identifier id = m_freeIdList.back(); m_freeIdList.pop_back(); + + entBlock = &m_entities[id]; + entBlock->handle.Reset(&entBlock->entity); //< Reset handle (as it was reset when entity got destroyed) + + m_entityBlocks[id] = entBlock; } else { // We allocate a new entity - id = static_cast(m_entities.size()); + id = static_cast(m_entityBlocks.size()); - // We can't use emplace_back due to the scope - m_entities.push_back(Entity(this, id)); + if (m_entities.capacity() > m_entities.size()) + { + NazaraAssert(m_waitingEntities.empty(), "There should be no waiting entities if space is available in main container"); + + m_entities.push_back(Entity(this, id)); //< We can't use emplace_back due to the scope + entBlock = &m_entities.back(); + } + else + { + // Pushing to entities would reallocate vector and thus, invalidate EntityHandles (which we don't want until world update) + // To prevent this, allocate them into a separate vector and move them at update + // For now, we are counting on m_entities grow strategy to keep allocation frequency low + m_waitingEntities.emplace_back(std::make_unique(Entity(this, id))); + entBlock = m_waitingEntities.back().get(); + } + + if (id >= m_entityBlocks.size()) + m_entityBlocks.resize(id + 1); + + m_entityBlocks[id] = entBlock; } - // We initialise the entity and we add it to the list of alive entities - Entity& entity = m_entities[id].entity; - entity.Create(); + // We initialize the entity and we add it to the list of alive entities + entBlock->entity.Create(); - m_aliveEntities.emplace_back(&entity); - m_entities[id].aliveIndex = m_aliveEntities.size() - 1; + m_aliveEntities.Insert(&entBlock->entity); - return m_aliveEntities.back(); + return entBlock->handle; } /*! @@ -96,8 +118,11 @@ namespace Ndk // First, destruction of entities, then handles // This is made to avoid that handle warn uselessly entities before their destruction m_entities.clear(); + m_entityBlocks.clear(); + m_freeIdList.clear(); + m_waitingEntities.clear(); - m_aliveEntities.clear(); + m_aliveEntities.Clear(); m_dirtyEntities.Clear(); m_killedEntities.Clear(); } @@ -120,7 +145,7 @@ namespace Ndk return EntityHandle::InvalidHandle; } - EntityHandle clone = CreateEntity(); + const EntityHandle& clone = CreateEntity(); const Nz::Bitset<>& componentBits = original->GetComponentBits(); for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i)) @@ -129,41 +154,7 @@ namespace Ndk clone->AddComponent(std::move(component)); } - return GetEntity(clone->GetId()); - } - - /*! - * \brief Kills an entity - * - * \param Pointer to the entity - * - * \remark No change is done if entity is invalid - */ - - void World::KillEntity(Entity* entity) - { - if (IsEntityValid(entity)) - m_killedEntities.UnboundedSet(entity->GetId(), true); - } - - /*! - * \brief Gets an entity - * \return A constant reference to the modified entity - * - * \param id Identifier of the entity - * - * \remark Produces a NazaraError if entity identifier is not valid - */ - - const EntityHandle& World::GetEntity(EntityId id) - { - if (IsEntityIdValid(id)) - return m_aliveEntities[m_entities[id].aliveIndex]; - else - { - NazaraError("Invalid ID"); - return EntityHandle::InvalidHandle; - } + return clone; } /*! @@ -177,45 +168,43 @@ namespace Ndk if (!m_orderedSystemsUpdated) ReorderSystems(); + // Move waiting entities to entity list + if (!m_waitingEntities.empty()) + { + constexpr std::size_t MinEntityCapacity = 10; //< We want to be able to grow maximum entity count by at least ten without going to the waiting list + + m_entities.reserve(m_entities.size() + m_waitingEntities.size() + MinEntityCapacity); + for (auto& blockPtr : m_waitingEntities) + m_entities.push_back(std::move(*blockPtr)); + + m_waitingEntities.clear(); + + // Update entity blocks pointers + for (std::size_t i = 0; i < m_entities.size(); ++i) + m_entityBlocks[i] = &m_entities[i]; + } + // Handle killed entities before last call for (std::size_t i = m_killedEntities.FindFirst(); i != m_killedEntities.npos; i = m_killedEntities.FindNext(i)) { - EntityBlock& block = m_entities[i]; - Entity& entity = block.entity; + NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range"); - NazaraAssert(entity.IsValid(), "Entity must be valid"); - - // Send back the identifier of the entity to the free queue - m_freeIdList.push_back(entity.GetId()); + Entity* entity = &m_entityBlocks[i]->entity; // Destruction of the entity (invalidation of handle by the same way) - entity.Destroy(); + entity->Destroy(); - // 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(); + // Send back the identifier of the entity to the free queue + m_freeIdList.push_back(entity->GetId()); } m_killedEntities.Reset(); // Handle of entities which need an update from the systems for (std::size_t i = m_dirtyEntities.FindFirst(); i != m_dirtyEntities.npos; i = m_dirtyEntities.FindNext(i)) { - NazaraAssert(i < m_entities.size(), "Entity index out of range"); + NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range"); - Entity* entity = &m_entities[i].entity; + Entity* entity = &m_entityBlocks[i]->entity; // Check entity validity (as it could have been reported as dirty and killed during the same iteration) if (!entity->IsValid()) @@ -242,7 +231,7 @@ namespace Ndk } else { - // No, it shouldn't, remove it if it's part of the system + // No it shouldn't, remove it if it's part of the system if (partOfSystem) system->RemoveEntity(entity); } diff --git a/build/config.lua b/build/config.lua index 8ecc7c24e..2db0f7622 100644 --- a/build/config.lua +++ b/build/config.lua @@ -1,6 +1,9 @@ -- This file contains special configurations values, such as directories to extern libraries (Qt) -- Editing this file is not required to use/compile the engine, as default values should be enough +-- Additionnal compilation options +--AdditionalCompilationOptions = "-fsanitize=address" -- Enable ASan + -- Builds Nazara extern libraries (such as lua/STB) BuildDependencies = true @@ -13,6 +16,9 @@ Configurations = "Debug,Release" -- "Debug,Release,ReleaseWithDebug" -- Setup additionnals install directories, separated by a semi-colon ; (library binaries will be copied there) --InstallDir = "/usr/local/lib64" +-- Adds a project which will recall premake with its original arguments when built (only works on Windows for now) +PremakeProject = true + -- Excludes client-only modules/tools/examples ServerMode = false diff --git a/build/scripts/actions/encodesresources.lua b/build/scripts/actions/encodesresources.lua index 5e5376fee..f508c5c69 100644 --- a/build/scripts/actions/encodesresources.lua +++ b/build/scripts/actions/encodesresources.lua @@ -5,8 +5,14 @@ ACTION.Function = function () print("Encoding resources ...") local startClock = os.clock() local modules = os.matchdirs("../src/Nazara/*") + table.insert(modules, "../SDK/src/NDK") for k, modulePath in pairs(modules) do - local moduleName = modulePath:sub(15, -1) + local moduleName + if (modulePath:sub(4, 6) == "src") then + moduleName = modulePath:sub(15, -1) + else + moduleName = "SDK" + end local files = os.matchfiles(modulePath .. "/Resources/**") for k, filePath in pairs(files) do if (filePath:sub(-2) ~= ".h") then diff --git a/build/scripts/actions/package.lua b/build/scripts/actions/package.lua index 62d4792b3..bc86c4ba4 100644 --- a/build/scripts/actions/package.lua +++ b/build/scripts/actions/package.lua @@ -85,7 +85,7 @@ ACTION.Function = function () local exeFileExt local exeFilterFunc if (os.is("windows")) then - binFileMasks = {"**.dll"} + binFileMasks = {"**.dll", "**.pdb"} libFileMasks = {"**.lib", "**.a"} exeFileExt = ".exe" exeFilterFunc = function (filePath) return true end diff --git a/build/scripts/common.lua b/build/scripts/common.lua index e3ea13d62..68b15b38a 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -42,7 +42,7 @@ end function NazaraBuild:Execute() if (_ACTION == nil) then -- If no action is specified, the user probably only wants to know how all of this works - return -- Alors l'utilisateur voulait probablement savoir comment utiliser le programme, on ne fait rien + return end local platformData @@ -74,7 +74,6 @@ function NazaraBuild:Execute() includedirs("../extlibs/include") libdirs("../extlibs/lib/common") location(_ACTION) - kind("StaticLib") for k, libTable in ipairs(self.OrderedExtLibs) do project(libTable.Name) @@ -129,6 +128,13 @@ function NazaraBuild:Execute() language("C++") location(_ACTION) + if (self.Config["PremakeProject"] and os.is("windows")) then + local commandLine = "premake5.exe " .. table.concat(_ARGV, ' ') + project("_PremakeProject") + kind("Utility") + prebuildcommands("cd .. && " .. commandLine) + end + -- Modules if (_OPTIONS["united"]) then project("NazaraEngine") @@ -505,11 +511,47 @@ function NazaraBuild:LoadConfig() end end + local AddStringOption = function (option, name, description) + newoption({ + trigger = name, + description = description + }) + + local str = _OPTIONS[name] + if (str) then + configTable[option] = str + end + end + AddBoolOption("BuildDependencies", "with-extlibs", "Builds the extern libraries") AddBoolOption("BuildExamples", "with-examples", "Builds the examples") + AddBoolOption("PremakeProject", "premakeproject", "Add a PremakeProject as a shortcut to call Premake") AddBoolOption("ServerMode", "server", "Excludes client-only modules/tools/examples") AddBoolOption("UniteModules", "united", "Builds all the modules as one united library") + -- AdditionalCompilationOptions + do + newoption({ + trigger = "compile-options", + description = "Specify additionnal compilation options to be added to every generated project." + }) + + configTable["AdditionalCompilationOptions"] = configTable["AdditionalCompilationOptions"] or "" + if (_OPTIONS["compile-options"] ~= nil) then + configTable["AdditionalCompilationOptions"] = configTable["AdditionalCompilationOptions"] .. ";" .. _OPTIONS["compile-options"] + end + + local configs = {} + local paths = string.explode(configTable["AdditionalCompilationOptions"], ";") + for k,v in pairs(paths) do + if (#v > 0) then + table.insert(configs, v) + end + end + + configTable["AdditionalCompilationOptions"] = configs + end + -- Configurations do newoption({ @@ -792,6 +834,8 @@ function NazaraBuild:PrepareGeneric() buildoptions("-ftree-vectorize") filter({}) + + buildoptions(self.Config["AdditionalCompilationOptions"]) end function NazaraBuild:PrepareMainWorkspace() diff --git a/build/scripts/modules/graphics.lua b/build/scripts/modules/graphics.lua index 9d393d3a7..5c0bf4224 100644 --- a/build/scripts/modules/graphics.lua +++ b/build/scripts/modules/graphics.lua @@ -3,5 +3,6 @@ MODULE.Name = "Graphics" MODULE.Libraries = { "NazaraCore", "NazaraUtility", + "NazaraPlatform", "NazaraRenderer" } diff --git a/build/scripts/modules/platform.lua b/build/scripts/modules/platform.lua new file mode 100644 index 000000000..c90f6663a --- /dev/null +++ b/build/scripts/modules/platform.lua @@ -0,0 +1,31 @@ +MODULE.Name = "Platform" + +MODULE.Libraries = { + "NazaraCore", + "NazaraUtility" +} + +MODULE.OsFiles.Windows = { + "../src/Nazara/Platform/Win32/**.hpp", + "../src/Nazara/Platform/Win32/**.cpp" +} + +MODULE.OsFiles.Posix = { + "../src/Nazara/Platform/X11/**.hpp", + "../src/Nazara/Platform/X11/**.cpp" +} + +MODULE.OsLibraries.Windows = { + "gdi32" +} + +MODULE.OsLibraries.Posix = { + "X11", + "xcb", + "xcb-cursor", + "xcb-ewmh", + "xcb-icccm", + "xcb-keysyms", + "xcb-randr" +} + diff --git a/build/scripts/modules/renderer.lua b/build/scripts/modules/renderer.lua index bbc472b75..11b378d2b 100644 --- a/build/scripts/modules/renderer.lua +++ b/build/scripts/modules/renderer.lua @@ -8,7 +8,8 @@ MODULE.Defines = { MODULE.Libraries = { "NazaraCore", - "NazaraUtility" + "NazaraUtility", + "NazaraPlatform" } MODULE.OsFiles.Windows = { diff --git a/build/scripts/modules/utility.lua b/build/scripts/modules/utility.lua index c1bc186c0..fc4c989d8 100644 --- a/build/scripts/modules/utility.lua +++ b/build/scripts/modules/utility.lua @@ -5,29 +5,11 @@ MODULE.Libraries = { "stb_image" } -MODULE.OsFiles.Windows = { - "../src/Nazara/Utility/Win32/**.hpp", - "../src/Nazara/Utility/Win32/**.cpp" -} - -MODULE.OsFiles.Posix = { - "../src/Nazara/Utility/X11/**.hpp", - "../src/Nazara/Utility/X11/**.cpp" -} - MODULE.OsLibraries.Windows = { - "freetype-s", - "gdi32" + "freetype-s" } MODULE.OsLibraries.Posix = { - "freetype", - "X11", - "xcb", - "xcb-cursor", - "xcb-ewmh", - "xcb-icccm", - "xcb-keysyms", - "xcb-randr" + "freetype" } diff --git a/build/scripts/tools/ndk_server.lua b/build/scripts/tools/ndk_server.lua index c439e47b1..cea295f7e 100644 --- a/build/scripts/tools/ndk_server.lua +++ b/build/scripts/tools/ndk_server.lua @@ -37,7 +37,8 @@ TOOL.FilesExcluded = { "../SDK/**/*Widget*.*", "../SDK/**/LuaBinding_Audio.*", "../SDK/**/LuaBinding_Graphics.*", - "../SDK/**/LuaBinding_Renderer.*" + "../SDK/**/LuaBinding_Renderer.*", + "../SDK/**/LuaBinding_Platform.*" } diff --git a/build/scripts/tools/unittests_server.lua b/build/scripts/tools/unittests_server.lua index c94a54d6d..63c268347 100644 --- a/build/scripts/tools/unittests_server.lua +++ b/build/scripts/tools/unittests_server.lua @@ -25,7 +25,7 @@ TOOL.Files = { TOOL.FilesExcluded = { "../tests/Engine/Audio/**", "../tests/Engine/Graphics/**", - "../tests/Engine/Utility/**", + "../tests/Engine/Platform/**", "../tests/SDK/NDK/Application.cpp", "../tests/SDK/NDK/Systems/ListenerSystem.cpp", "../tests/SDK/NDK/Systems/RenderSystem.cpp" diff --git a/examples/DopplerEffect/build.lua b/examples/DopplerEffect/build.lua index 302011b81..837f62af4 100644 --- a/examples/DopplerEffect/build.lua +++ b/examples/DopplerEffect/build.lua @@ -9,5 +9,6 @@ EXAMPLE.Files = { EXAMPLE.Libraries = { "NazaraAudio", "NazaraCore", + "NazaraPlatform", "NazaraUtility" -} \ No newline at end of file +} diff --git a/examples/DopplerEffect/main.cpp b/examples/DopplerEffect/main.cpp index b6d2d034b..24120a2f5 100644 --- a/examples/DopplerEffect/main.cpp +++ b/examples/DopplerEffect/main.cpp @@ -12,14 +12,14 @@ #include #include // Thread::Sleep #include -#include -#include +#include +#include #include int main() { // NzKeyboard nécessite l'initialisation du module Utilitaire - Nz::Initializer audio; + Nz::Initializer audio; if (!audio) { std::cout << "Failed to initialize audio module" << std::endl; diff --git a/examples/FirstScene/main.cpp b/examples/FirstScene/main.cpp index b7e7d1198..4acbdf5a1 100644 --- a/examples/FirstScene/main.cpp +++ b/examples/FirstScene/main.cpp @@ -16,6 +16,7 @@ #include // Module de scripting #include // Module graphique #include // Module de rendu +#include // Module utilitaire #include // Module utilitaire #include #include @@ -33,6 +34,7 @@ int main() { // Ndk::Application est une classe s'occupant de l'initialisation du moteur ainsi que de la gestion de beaucoup de choses Ndk::Application application; + Nz::Initializer network; // Nazara étant initialisé, nous pouvons créer le monde pour contenir notre scène. // Dans un ECS, le monde représente bien ce que son nom indique, c'est l'ensemble de ce qui existe au niveau de l'application. diff --git a/examples/HardwareInfo/build.lua b/examples/HardwareInfo/build.lua index afcc7b544..953cba7d9 100644 --- a/examples/HardwareInfo/build.lua +++ b/examples/HardwareInfo/build.lua @@ -12,6 +12,7 @@ EXAMPLE.Files = { EXAMPLE.Libraries = { "NazaraCore", + "NazaraPlatform", "NazaraRenderer", "NazaraUtility" } diff --git a/examples/MeshInfos/build.lua b/examples/MeshInfos/build.lua index 4e26f318b..74616762e 100644 --- a/examples/MeshInfos/build.lua +++ b/examples/MeshInfos/build.lua @@ -8,6 +8,7 @@ EXAMPLE.Files = { EXAMPLE.Libraries = { "NazaraCore", + "NazaraPlatform", "NazaraUtility" } diff --git a/examples/Particles/LogoDemo.cpp b/examples/Particles/LogoDemo.cpp index cc0c2a610..831fcffd5 100644 --- a/examples/Particles/LogoDemo.cpp +++ b/examples/Particles/LogoDemo.cpp @@ -1,4 +1,5 @@ #include "LogoDemo.hpp" +#include #include #include #include @@ -8,12 +9,22 @@ namespace { const float duration = 10.f; - const float maxVel = 50.f; + const float maxSpeed = 100.f; + const float maxMouseForce = 1000.f; + const float mouseForce = 500.f; const float pauseTime = 3.f; const float startTime = 2.f; const float speed = 3.f; } +struct ParticleData +{ + Nz::Color color; + Nz::Vector2f destination; + Nz::Vector2f position; + Nz::Vector2f velocity; +}; + struct SpriteController : public Nz::ParticleController { void Apply(Nz::ParticleGroup& system, Nz::ParticleMapper& mapper, unsigned int startId, unsigned int endId, float elapsedTime) override @@ -21,15 +32,70 @@ struct SpriteController : public Nz::ParticleController if (!enabled) return; - auto posPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Position); - auto velPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Velocity); + auto destPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Userdata0); + auto posPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Position); + auto velPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Velocity); + + std::uniform_real_distribution dis(-1.f, 1.f); for (unsigned int i = startId; i <= endId; ++i) - posPtr[i] += velPtr[i] * elapsedTime * factor; + { + Nz::Vector2f newVel = destPtr[i] - posPtr[i]; + float length; + newVel.Normalize(&length); + + float distance = SquaredDistancePointSegment(oldMousePos, actualMousePos, posPtr[i]); + if (distance < 250.f) + { + Nz::Vector2f mouseLine = actualMousePos - oldMousePos; + float mouseLength; + mouseLine.Normalize(&mouseLength); + if (mouseLength > 5.f) + { + velPtr[i] += mouseLine * std::min(mouseLength * mouseForce, maxMouseForce) * elapsedTime; + velPtr[i] += Nz::Vector2f(dis(randomGen), dis(randomGen)) * std::min(mouseLength, maxMouseForce * 0.1f); + } + } + + if (length > 1.f || velPtr[i].GetSquaredLength() > Nz::IntegralPow(30.f, 2)) + { + newVel *= maxSpeed; + + velPtr[i] = Nz::Lerp(velPtr[i], newVel, 0.4f * elapsedTime); + posPtr[i] += velPtr[i] * elapsedTime; + } + else + { + velPtr[i] = Nz::Vector2f::Zero(); + posPtr[i] = destPtr[i]; + } + } } + static float SquaredDistancePointSegment(const Nz::Vector2f& s0, const Nz::Vector2f& s1, const Nz::Vector2f& point) + { + // http://geomalgorithms.com/a02-_lines.html + Nz::Vector2f v = s1 - s0; + Nz::Vector2f w = point - s0; + + float c1 = Nz::Vector2f::DotProduct(w, v); + if (c1 <= 0.f) + return point.SquaredDistance(s0); + + float c2 = Nz::Vector2f::DotProduct(v, v); + if (c2 <= c1) + return point.SquaredDistance(s1); + + float b = c1 / c2; + Nz::Vector2f projPoint = s0 + b * v; + return projPoint.SquaredDistance(point); + } + + std::mt19937 randomGen; bool enabled = false; - float factor = 1.f; + float factor = 1000.f; + Nz::Vector2f actualMousePos; + Nz::Vector2f oldMousePos; }; @@ -67,9 +133,9 @@ ParticleDemo("Logo", sharedData) unsigned int height = m_logo.GetHeight(); m_pixels.reserve(width * height); - for (unsigned int y = 0; y < height; ++y) + for (unsigned int x = 0; x < width; ++x) { - for (unsigned int x = 0; x < width; ++x) + for (unsigned int y = 0; y < height; ++y) { Nz::Color color = m_logo.GetPixelColor(x, y); if (color.a == 0) @@ -93,6 +159,12 @@ ParticleDemo("Logo", sharedData) m_controller = new SpriteController; m_renderer = new SpriteRenderer(std::move(material)); + + m_declaration = Nz::ParticleDeclaration::New(); + m_declaration->EnableComponent(Nz::ParticleComponent_Color, Nz::ComponentType_Color, NazaraOffsetOf(ParticleData, color)); + m_declaration->EnableComponent(Nz::ParticleComponent_Position, Nz::ComponentType_Float2, NazaraOffsetOf(ParticleData, position)); + m_declaration->EnableComponent(Nz::ParticleComponent_Userdata0, Nz::ComponentType_Float2, NazaraOffsetOf(ParticleData, destination)); + m_declaration->EnableComponent(Nz::ParticleComponent_Velocity, Nz::ComponentType_Float2, NazaraOffsetOf(ParticleData, velocity)); } void LogoExample::Enter(Ndk::StateMachine& fsm) @@ -106,17 +178,20 @@ void LogoExample::Enter(Ndk::StateMachine& fsm) m_shared.world2D->GetSystem().SetDefaultBackground(Nz::TextureBackground::New(std::move(backgroundTexture))); Ndk::EntityHandle particleGroupEntity = m_shared.world2D->CreateEntity(); - Ndk::ParticleGroupComponent& particleGroup = particleGroupEntity->AddComponent(m_pixels.size(), Nz::ParticleLayout_Sprite); + Ndk::ParticleGroupComponent& particleGroup = particleGroupEntity->AddComponent(m_pixels.size(), m_declaration); RegisterParticleGroup(particleGroupEntity); particleGroup.AddController(m_controller); particleGroup.SetRenderer(m_renderer); - m_particles = static_cast(particleGroup.CreateParticles(m_pixels.size())); + m_particles = particleGroup.CreateParticles(m_pixels.size()); ResetParticles(-duration * (speed / 2.f)); m_accumulator = pauseTime + duration; m_totalAccumulator = 0.f; + + SpriteController* controller = static_cast(m_controller.Get()); + controller->actualMousePos = controller->oldMousePos = Nz::Vector2f(Nz::Mouse::GetPosition(*m_shared.target)); } void LogoExample::Leave(Ndk::StateMachine & fsm) @@ -136,35 +211,62 @@ bool LogoExample::Update(Ndk::StateMachine& fsm, float elapsedTime) m_accumulator += elapsedTime; SpriteController* controller = static_cast(m_controller.Get()); - if (m_accumulator > pauseTime + 2.f * duration) + controller->enabled = (m_accumulator > pauseTime); + + if (m_mouseClock.GetMilliseconds() > 1000/30) { - ResetParticles(0.f); - m_accumulator = 0.f; + m_mouseClock.Restart(); + + controller->oldMousePos = controller->actualMousePos; + controller->actualMousePos = Nz::Vector2f(Nz::Mouse::GetPosition(*m_shared.target)); } - controller->enabled = (m_accumulator > pauseTime); - controller->factor = -speed + speed * (m_accumulator - pauseTime) / (duration); + if (Nz::Mouse::IsButtonPressed(Nz::Mouse::Left)) + { + if (!m_hasClicked) + { + m_hasClicked = true; + std::uniform_real_distribution dis(50.f, 60.f); + + ParticleData* sprite = static_cast(m_particles); + for (std::size_t i = 0; i < m_pixels.size(); ++i) + { + Nz::Vector2f particleToMouse = sprite[i].position - controller->actualMousePos; + float sqDist = particleToMouse.GetSquaredLength(); + if (sqDist < 10000.f) + { + float dist = std::sqrt(sqDist); + particleToMouse /= std::max(dist, 1.f); + + sprite[i].velocity += particleToMouse * dis(m_shared.randomGen); + } + } + } + } + else + m_hasClicked = false; return true; } void LogoExample::ResetParticles(float elapsed) { - Nz::Vector2f center = {m_shared.target->GetWidth() / 2.f, m_shared.target->GetHeight() / 2.f}; + unsigned int width = m_shared.target->GetWidth(); + unsigned int height = m_shared.target->GetHeight(); + + Nz::Vector2f center = {width / 2.f, height / 2.f}; Nz::Vector2f offset = center - Nz::Vector2f(Nz::Vector2ui(m_logo.GetSize()) / 2); - float ratio = float(m_shared.target->GetWidth()) / m_shared.target->GetHeight(); - std::uniform_real_distribution disX(-maxVel * ratio, maxVel * ratio); - std::uniform_real_distribution disY(-maxVel, maxVel); + std::uniform_real_distribution disX(0.f, float(width)); + std::uniform_real_distribution disY(-float(height) * 0.5f, float(height) * 1.5f); - Nz::ParticleStruct_Sprite* sprite = m_particles; + ParticleData* sprite = static_cast(m_particles); for (PixelData& data : m_pixels) { sprite->color = data.color; - sprite->position = offset + Nz::Vector2f(data.pos); - sprite->rotation = 0.f; - sprite->velocity.Set(disX(m_shared.randomGen), disY(m_shared.randomGen), 0.f); - sprite->position += sprite->velocity * elapsed; + sprite->destination = offset + Nz::Vector2f(data.pos); + sprite->position.Set(disX(m_shared.randomGen) - float(width), disY(m_shared.randomGen)); + sprite->velocity = Nz::Vector2f::Zero(); sprite++; } } diff --git a/examples/Particles/LogoDemo.hpp b/examples/Particles/LogoDemo.hpp index d5c374d32..7ce594080 100644 --- a/examples/Particles/LogoDemo.hpp +++ b/examples/Particles/LogoDemo.hpp @@ -30,10 +30,13 @@ class LogoExample : public ParticleDemo std::vector m_pixels; Nz::BackgroundRef m_oldBackground; - Nz::ParticleStruct_Sprite* m_particles; + void* m_particles; + Nz::Clock m_mouseClock; Nz::Image m_logo; Nz::ParticleControllerRef m_controller; + Nz::ParticleDeclarationRef m_declaration; Nz::ParticleRendererRef m_renderer; + bool m_hasClicked; float m_accumulator; float m_totalAccumulator; }; diff --git a/examples/Particles/SpacebattleDemo.cpp b/examples/Particles/SpacebattleDemo.cpp index 7f2cd6b4c..e2c2f62ba 100644 --- a/examples/Particles/SpacebattleDemo.cpp +++ b/examples/Particles/SpacebattleDemo.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include diff --git a/examples/Particles/SpacebattleDemo.hpp b/examples/Particles/SpacebattleDemo.hpp index 44852a61f..a41be7504 100644 --- a/examples/Particles/SpacebattleDemo.hpp +++ b/examples/Particles/SpacebattleDemo.hpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/examples/Particles/main.cpp b/examples/Particles/main.cpp index bf230bfe7..f4754c136 100644 --- a/examples/Particles/main.cpp +++ b/examples/Particles/main.cpp @@ -105,7 +105,7 @@ int main() fpsNode.SetPosition(5.f, window.GetHeight() - fpsCountBox.height - particleCountBox.height - 5.f); - //shared.demos.push_back(std::make_shared(shared)); + shared.demos.push_back(std::make_shared(shared)); shared.demos.push_back(std::make_shared(shared)); std::size_t demoIndex = 0; diff --git a/examples/Tut00/build.lua b/examples/Tut00/build.lua index 678aa3394..baf738d1d 100644 --- a/examples/Tut00/build.lua +++ b/examples/Tut00/build.lua @@ -15,6 +15,7 @@ EXAMPLE.Libraries = { "NazaraNoise", "NazaraPhysics2D", "NazaraPhysics3D", + "NazaraPlatform", "NazaraRenderer", "NazaraUtility", "NazaraSDK" diff --git a/examples/Tut01/main.cpp b/examples/Tut01/main.cpp index b5e07074d..b1d962e1e 100644 --- a/examples/Tut01/main.cpp +++ b/examples/Tut01/main.cpp @@ -1,4 +1,4 @@ -// Sources pour https://github.com/DigitalPulseSoftware/NazaraEngine/wiki/(FR)-Tutoriel-01---Hello-World +// Sources pour https://github.com/DigitalPulseSoftware/NazaraEngine/wiki/(FR)-Tutoriel:-%5B01%5D-Hello-World #include #include diff --git a/examples/Tut02/build.lua b/examples/Tut02/build.lua new file mode 100644 index 000000000..dbb8a8c9f --- /dev/null +++ b/examples/Tut02/build.lua @@ -0,0 +1,11 @@ +EXAMPLE.Name = "Tut02_Events" + +EXAMPLE.EnableConsole = true + +EXAMPLE.Files = { + "main.cpp" +} + +EXAMPLE.Libraries = { + "NazaraSDK" +} diff --git a/examples/Tut02/main.cpp b/examples/Tut02/main.cpp new file mode 100644 index 000000000..83de624c6 --- /dev/null +++ b/examples/Tut02/main.cpp @@ -0,0 +1,50 @@ +// Sources pour https://github.com/DigitalPulseSoftware/NazaraEngine/wiki/(FR)-Tutoriel:-%5B02%5D-Gestion-des-événements + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + Ndk::Application application(argc, argv); + + Nz::RenderWindow& mainWindow = application.AddWindow(); + mainWindow.Create(Nz::VideoMode(800, 600, 32), "Test"); + + mainWindow.EnableCloseOnQuit(false); + + Ndk::World& world = application.AddWorld(); + world.GetSystem().SetGlobalUp(Nz::Vector3f::Down()); + world.GetSystem().SetDefaultBackground(Nz::ColorBackground::New(Nz::Color(117, 122, 214))); + + Ndk::EntityHandle viewEntity = world.CreateEntity(); + viewEntity->AddComponent(); + + Ndk::CameraComponent& viewer = viewEntity->AddComponent(); + viewer.SetTarget(&mainWindow); + viewer.SetProjectionType(Nz::ProjectionType_Orthogonal); + + + Nz::EventHandler& eventHandler = mainWindow.GetEventHandler(); + eventHandler.OnKeyPressed.Connect([](const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& e) + { + std::cout << Nz::Keyboard::GetKeyName(e.code) << std::endl; + + // Profitons-en aussi pour nous donner un moyen de quitter le programme + if (e.code == Nz::Keyboard::Escape) + Ndk::Application::Instance()->Quit(); // Cette ligne casse la boucle Run() de l'application + }); + + + while (application.Run()) + { + mainWindow.Display(); + } + + return EXIT_SUCCESS; +} diff --git a/include/Nazara/Audio/Music.hpp b/include/Nazara/Audio/Music.hpp index 74d315d19..86ccc6906 100644 --- a/include/Nazara/Audio/Music.hpp +++ b/include/Nazara/Audio/Music.hpp @@ -43,27 +43,27 @@ namespace Nz bool Create(SoundStream* soundStream); void Destroy(); - void EnableLooping(bool loop); + void EnableLooping(bool loop) override; - UInt32 GetDuration() const; + UInt32 GetDuration() const override; AudioFormat GetFormat() const; - UInt32 GetPlayingOffset() const; + UInt32 GetPlayingOffset() const override; UInt64 GetSampleCount() const; UInt32 GetSampleRate() const; - SoundStatus GetStatus() const; + SoundStatus GetStatus() const override; - bool IsLooping() const; + bool IsLooping() const override; bool OpenFromFile(const String& filePath, const MusicParams& params = MusicParams()); bool OpenFromMemory(const void* data, std::size_t size, const MusicParams& params = MusicParams()); bool OpenFromStream(Stream& stream, const MusicParams& params = MusicParams()); - void Pause(); - void Play(); + void Pause() override; + void Play() override; void SetPlayingOffset(UInt32 offset); - void Stop(); + void Stop() override; Music& operator=(const Music&) = delete; Music& operator=(Music&&) = delete; ///TODO diff --git a/include/Nazara/Audio/Sound.hpp b/include/Nazara/Audio/Sound.hpp index c5083387f..114b177ab 100644 --- a/include/Nazara/Audio/Sound.hpp +++ b/include/Nazara/Audio/Sound.hpp @@ -23,14 +23,14 @@ namespace Nz Sound(Sound&&) = default; ~Sound(); - void EnableLooping(bool loop); + void EnableLooping(bool loop) override; const SoundBuffer* GetBuffer() const; - UInt32 GetDuration() const; - UInt32 GetPlayingOffset() const; - SoundStatus GetStatus() const; + UInt32 GetDuration() const override; + UInt32 GetPlayingOffset() const override; + SoundStatus GetStatus() const override; - bool IsLooping() const; + bool IsLooping() const override; bool IsPlayable() const; bool IsPlaying() const; @@ -38,13 +38,13 @@ namespace Nz bool LoadFromMemory(const void* data, std::size_t size, const SoundBufferParams& params = SoundBufferParams()); bool LoadFromStream(Stream& stream, const SoundBufferParams& params = SoundBufferParams()); - void Pause(); - void Play(); + void Pause() override; + void Play() override; void SetBuffer(const SoundBuffer* buffer); void SetPlayingOffset(UInt32 offset); - void Stop(); + void Stop() override; Sound& operator=(const Sound&) = delete; ///TODO? Sound& operator=(Sound&&) = default; diff --git a/include/Nazara/Core.hpp b/include/Nazara/Core.hpp index 419ddaae9..606d6969a 100644 --- a/include/Nazara/Core.hpp +++ b/include/Nazara/Core.hpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Core/Bitset.hpp b/include/Nazara/Core/Bitset.hpp index 2ea0502a4..04fb2f3c6 100644 --- a/include/Nazara/Core/Bitset.hpp +++ b/include/Nazara/Core/Bitset.hpp @@ -145,7 +145,7 @@ namespace Nz template void* operator&() const; - operator bool() const; + explicit operator bool() const; Bit& operator=(bool val); Bit& operator=(const Bit& bit); diff --git a/include/Nazara/Core/ByteStream.hpp b/include/Nazara/Core/ByteStream.hpp index a49b08eff..eed461205 100644 --- a/include/Nazara/Core/ByteStream.hpp +++ b/include/Nazara/Core/ByteStream.hpp @@ -24,7 +24,7 @@ namespace Nz ByteStream(const void* ptr, Nz::UInt64 size); ByteStream(const ByteStream&) = delete; inline ByteStream(ByteStream&& stream); - ~ByteStream(); + virtual ~ByteStream(); inline Endianness GetDataEndianness() const; inline Nz::UInt64 GetSize() const; diff --git a/include/Nazara/Core/Config.hpp b/include/Nazara/Core/Config.hpp index 2ad2513ac..5aa9fccec 100644 --- a/include/Nazara/Core/Config.hpp +++ b/include/Nazara/Core/Config.hpp @@ -73,7 +73,7 @@ #define NAZARA_CORE_WINDOWS_CS_SPINLOCKS 4096 // Optimize the Windows implementation with technologies of Windows NT 6.0 (and greater) (Break the compatibility with Windows XP) -#define NAZARA_CORE_WINDOWS_NT6 0 +#define NAZARA_CORE_WINDOWS_NT6 1 /* diff --git a/include/Nazara/Core/Enums.hpp b/include/Nazara/Core/Enums.hpp index 5a6e67565..937c01a44 100644 --- a/include/Nazara/Core/Enums.hpp +++ b/include/Nazara/Core/Enums.hpp @@ -63,6 +63,7 @@ namespace Nz enum HashType { HashType_CRC32, + HashType_CRC64, HashType_Fletcher16, HashType_MD5, HashType_SHA1, @@ -105,7 +106,7 @@ namespace Nz { ParameterType_Boolean, ParameterType_Color, - ParameterType_Float, + ParameterType_Double, ParameterType_Integer, ParameterType_None, ParameterType_Pointer, diff --git a/include/Nazara/Core/Flags.hpp b/include/Nazara/Core/Flags.hpp index cb336def6..b7dff544b 100644 --- a/include/Nazara/Core/Flags.hpp +++ b/include/Nazara/Core/Flags.hpp @@ -54,12 +54,20 @@ namespace Nz private: BitField m_value; }; + + // Little hack to have them in both Nz and global scope + namespace FlagsOperators + { + template constexpr std::enable_if_t::value, Flags> operator~(E lhs); + template constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs); + template constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs); + template constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs); + } + + using namespace FlagsOperators; } -template constexpr std::enable_if_t::value, Nz::Flags> operator~(E lhs); -template constexpr std::enable_if_t::value, Nz::Flags> operator|(E lhs, E rhs); -template constexpr std::enable_if_t::value, Nz::Flags> operator&(E lhs, E rhs); -template constexpr std::enable_if_t::value, Nz::Flags> operator^(E lhs, E rhs); +using namespace Nz::FlagsOperators; #include diff --git a/include/Nazara/Core/Flags.inl b/include/Nazara/Core/Flags.inl index 973da958d..1899e7576 100644 --- a/include/Nazara/Core/Flags.inl +++ b/include/Nazara/Core/Flags.inl @@ -209,67 +209,71 @@ namespace Nz { return 1U << static_cast(enumValue); } -} -/*! -* \brief Override binary NOT operator on enum to turns into a Flags object. -* \return A Flags object with reversed bits. -* -* \param lhs Enumeration value to reverse. -* -* Returns a Flags object with all state enabled except for the enum one. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator~(E lhs) -{ - return ~Nz::Flags(lhs); -} -/*! -* \brief Override binary OR operator on enum to turns into a Flags object. -* \return A Flags object with combined enum states. -* -* \param lhs First enumeration value to combine. -* \param rhs Second enumeration value to combine. -* -* Returns a Flags object with combined states from the two enumeration values. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator|(E lhs, E rhs) -{ - return Nz::Flags(lhs) | rhs; -} + namespace FlagsOperators + { + /*! + * \brief Override binary NOT operator on enum to turns into a Flags object. + * \return A Flags object with reversed bits. + * + * \param lhs Enumeration value to reverse. + * + * Returns a Flags object with all state enabled except for the enum one. + */ + template + constexpr std::enable_if_t::value, Flags> operator~(E lhs) + { + return ~Flags(lhs); + } -/*! -* \brief Override binary AND operator on enum to turns into a Flags object. -* \return A Flags object with compare enum states. -* -* \param lhs First enumeration value to compare. -* \param rhs Second enumeration value to compare. -* -* Returns a Flags object with compared states from the two enumeration values. -* In this case, only one flag will be enabled if both enumeration values are the same. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator&(E lhs, E rhs) -{ - return Nz::Flags(lhs) & rhs; -} + /*! + * \brief Override binary OR operator on enum to turns into a Flags object. + * \return A Flags object with combined enum states. + * + * \param lhs First enumeration value to combine. + * \param rhs Second enumeration value to combine. + * + * Returns a Flags object with combined states from the two enumeration values. + */ + template + constexpr std::enable_if_t::value, Flags> operator|(E lhs, E rhs) + { + return Flags(lhs) | rhs; + } -/*! -* \brief Override binary XOR operator on enum to turns into a Flags object. -* \return A Flags object with XORed enum states. -* -* \param lhs First enumeration value to compare. -* \param rhs Second enumeration value to compare. -* -* Returns a Flags object with XORed states from the two enumeration values. -* In this case, two flags will be enabled if both the enumeration values are different. -*/ -template -constexpr std::enable_if_t::value, Nz::Flags> operator^(E lhs, E rhs) -{ - return Nz::Flags(lhs) ^ rhs; + /*! + * \brief Override binary AND operator on enum to turns into a Flags object. + * \return A Flags object with compare enum states. + * + * \param lhs First enumeration value to compare. + * \param rhs Second enumeration value to compare. + * + * Returns a Flags object with compared states from the two enumeration values. + * In this case, only one flag will be enabled if both enumeration values are the same. + */ + template + constexpr std::enable_if_t::value, Flags> operator&(E lhs, E rhs) + { + return Flags(lhs) & rhs; + } + + /*! + * \brief Override binary XOR operator on enum to turns into a Flags object. + * \return A Flags object with XORed enum states. + * + * \param lhs First enumeration value to compare. + * \param rhs Second enumeration value to compare. + * + * Returns a Flags object with XORed states from the two enumeration values. + * In this case, two flags will be enabled if both the enumeration values are different. + */ + template + constexpr std::enable_if_t::value, Flags> operator^(E lhs, E rhs) + { + return Flags(lhs) ^ rhs; + } + } } #include diff --git a/include/Nazara/Core/Functor.hpp b/include/Nazara/Core/Functor.hpp index b392cc591..17578474c 100644 --- a/include/Nazara/Core/Functor.hpp +++ b/include/Nazara/Core/Functor.hpp @@ -25,7 +25,7 @@ namespace Nz { FunctorWithoutArgs(F func); - void Run(); + void Run() override; private: F m_func; @@ -36,7 +36,7 @@ namespace Nz { FunctorWithArgs(F func, Args&&... args); - void Run(); + void Run() override; private: F m_func; @@ -48,7 +48,7 @@ namespace Nz { MemberWithoutArgs(void (C::*func)(), C* object); - void Run(); + void Run() override; private: void (C::*m_func)(); diff --git a/include/Nazara/Core/Hash/CRC64.hpp b/include/Nazara/Core/Hash/CRC64.hpp new file mode 100644 index 000000000..1c9819e5f --- /dev/null +++ b/include/Nazara/Core/Hash/CRC64.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_HASH_CRC64_HPP +#define NAZARA_HASH_CRC64_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_CORE_API HashCRC64 : public AbstractHash + { + public: + HashCRC64() = default; + ~HashCRC64() = default; + + void Append(const UInt8* data, std::size_t len) override; + void Begin() override; + ByteArray End() override; + + std::size_t GetDigestLength() const override; + const char* GetHashName() const override; + + private: + Nz::UInt64 m_crc; + }; +} + +#endif // NAZARA_HASH_CRC64_HPP diff --git a/include/Nazara/Core/Initializer.hpp b/include/Nazara/Core/Initializer.hpp index 7fb19e69e..c09ae55af 100644 --- a/include/Nazara/Core/Initializer.hpp +++ b/include/Nazara/Core/Initializer.hpp @@ -24,7 +24,7 @@ namespace Nz bool IsInitialized() const; void Uninitialize(); - operator bool() const; + explicit operator bool() const; Initializer& operator=(const Initializer&) = delete; Initializer& operator=(Initializer&&) = delete; ///TODO diff --git a/include/Nazara/Core/ObjectHandle.hpp b/include/Nazara/Core/ObjectHandle.hpp index bf22734d3..022344488 100644 --- a/include/Nazara/Core/ObjectHandle.hpp +++ b/include/Nazara/Core/ObjectHandle.hpp @@ -38,7 +38,7 @@ namespace Nz Nz::String ToString() const; - operator bool() const; + explicit operator bool() const; operator T*() const; T* operator->() const; diff --git a/include/Nazara/Core/ObjectHandle.inl b/include/Nazara/Core/ObjectHandle.inl index 920d407a6..f4c70ae85 100644 --- a/include/Nazara/Core/ObjectHandle.inl +++ b/include/Nazara/Core/ObjectHandle.inl @@ -128,6 +128,9 @@ namespace Nz template void ObjectHandle::Reset(ObjectHandle&& handle) noexcept { + if (this == &handle) + return; + if (m_object) m_object->UnregisterHandle(this); diff --git a/include/Nazara/Core/ObjectRef.hpp b/include/Nazara/Core/ObjectRef.hpp index 1414e5d78..3a9e57628 100644 --- a/include/Nazara/Core/ObjectRef.hpp +++ b/include/Nazara/Core/ObjectRef.hpp @@ -31,7 +31,7 @@ namespace Nz bool Reset(T* object = nullptr); ObjectRef& Swap(ObjectRef& ref); - operator bool() const; + explicit operator bool() const; operator T*() const; T* operator->() const; diff --git a/include/Nazara/Core/ParameterList.hpp b/include/Nazara/Core/ParameterList.hpp index 75972b49c..d6b3985b4 100644 --- a/include/Nazara/Core/ParameterList.hpp +++ b/include/Nazara/Core/ParameterList.hpp @@ -27,10 +27,13 @@ namespace Nz void Clear(); + inline void ForEach(const std::function& callback); + inline void ForEach(const std::function& callback) const; + bool GetBooleanParameter(const String& name, bool* value) const; bool GetColorParameter(const String& name, Color* value) const; - bool GetFloatParameter(const String& name, float* value) const; - bool GetIntegerParameter(const String& name, int* value) const; + bool GetDoubleParameter(const String& name, double* value) const; + bool GetIntegerParameter(const String& name, long long* value) const; bool GetParameterType(const String& name, ParameterType* type) const; bool GetPointerParameter(const String& name, void** value) const; bool GetStringParameter(const String& name, String* value) const; @@ -45,8 +48,8 @@ namespace Nz void SetParameter(const String& name, const String& value); void SetParameter(const String& name, const char* value); void SetParameter(const String& name, bool value); - void SetParameter(const String& name, float value); - void SetParameter(const String& name, int value); + void SetParameter(const String& name, double value); + void SetParameter(const String& name, long long value); void SetParameter(const String& name, void* value); void SetParameter(const String& name, void* value, Destructor destructor); @@ -81,8 +84,8 @@ namespace Nz ~Value() {} bool boolVal; - float floatVal; - int intVal; + double doubleVal; + long long intVal; void* ptrVal; Color colorVal; String stringVal; @@ -102,4 +105,6 @@ namespace Nz std::ostream& operator<<(std::ostream& out, const Nz::ParameterList& parameterList); +#include + #endif // NAZARA_PARAMETERLIST_HPP diff --git a/include/Nazara/Core/ParameterList.inl b/include/Nazara/Core/ParameterList.inl new file mode 100644 index 000000000..b1983b49b --- /dev/null +++ b/include/Nazara/Core/ParameterList.inl @@ -0,0 +1,42 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + /*! + * \brief Iterates over every value of the parameter list + * + * \param callback Callback function called with every parameter contained in the list, which can return true to remove the key (or false to keep it) + * + * \remark Changing the ParameterList while iterating on it may cause bugs, but querying data is safe. + */ + inline void ParameterList::ForEach(const std::function& callback) + { + for (auto it = m_parameters.begin(); it != m_parameters.end();) + { + if (callback(*this, it->first)) + it = m_parameters.erase(it); + else + ++it; + } + } + + /*! + * \brief Iterates over every value of the parameter list + * + * \param callback Callback function called with every parameter contained in the list + * + * \remark Changing the ParameterList while iterating on it may cause bugs, but querying data is safe. + */ + inline void ParameterList::ForEach(const std::function& callback) const + { + for (auto& pair : m_parameters) + callback(*this, pair.first); + } +} + +#include diff --git a/include/Nazara/Core/Signal.hpp b/include/Nazara/Core/Signal.hpp index c325b40ce..1569c5d0e 100644 --- a/include/Nazara/Core/Signal.hpp +++ b/include/Nazara/Core/Signal.hpp @@ -69,7 +69,7 @@ namespace Nz SlotListIndex index; }; - void Disconnect(const SlotPtr& slot); + void Disconnect(const SlotPtr& slot) noexcept; SlotList m_slots; mutable SlotListIndex m_slotIterator; @@ -84,17 +84,17 @@ namespace Nz public: Connection() = default; Connection(const Connection& connection) = default; - Connection(Connection&& connection) = default; + Connection(Connection&& connection) noexcept; ~Connection() = default; template void Connect(BaseClass& signal, ConnectArgs&&... args); - void Disconnect(); + void Disconnect() noexcept; bool IsConnected() const; Connection& operator=(const Connection& connection) = default; - Connection& operator=(Connection&& connection) = default; + Connection& operator=(Connection&& connection) noexcept; private: Connection(const SlotPtr& slot); @@ -113,12 +113,12 @@ namespace Nz ConnectionGuard(const Connection& connection); ConnectionGuard(const ConnectionGuard& connection) = delete; ConnectionGuard(Connection&& connection); - ConnectionGuard(ConnectionGuard&& connection) = default; + ConnectionGuard(ConnectionGuard&& connection) noexcept = default; ~ConnectionGuard(); template void Connect(BaseClass& signal, ConnectArgs&&... args); - void Disconnect(); + void Disconnect() noexcept; Connection& GetConnection(); @@ -127,7 +127,7 @@ namespace Nz ConnectionGuard& operator=(const Connection& connection); ConnectionGuard& operator=(const ConnectionGuard& connection) = delete; ConnectionGuard& operator=(Connection&& connection); - ConnectionGuard& operator=(ConnectionGuard&& connection); + ConnectionGuard& operator=(ConnectionGuard&& connection) noexcept; private: Connection m_connection; diff --git a/include/Nazara/Core/Signal.inl b/include/Nazara/Core/Signal.inl index 9e711a65f..c4e89bd40 100644 --- a/include/Nazara/Core/Signal.inl +++ b/include/Nazara/Core/Signal.inl @@ -205,7 +205,7 @@ namespace Nz */ template - void Signal::Disconnect(const SlotPtr& slot) + void Signal::Disconnect(const SlotPtr& slot) noexcept { NazaraAssert(slot, "Invalid slot pointer"); NazaraAssert(slot->index < m_slots.size(), "Invalid slot index"); @@ -246,6 +246,18 @@ namespace Nz * \brief Core class that represents a connection attached to a signal */ + /*! + * \brief Constructs a Signal::Connection object with by move semantic + * + * \param connection Connection object to move + */ + template + Signal::Connection::Connection(Connection&& connection) noexcept : + m_ptr(std::move(connection.m_ptr)) + { + connection.m_ptr.reset(); //< Fuck you GCC 4.9 + } + /*! * \brief Constructs a Signal::Connection object with a slot * @@ -277,7 +289,7 @@ namespace Nz */ template - void Signal::Connection::Disconnect() + void Signal::Connection::Disconnect() noexcept { if (SlotPtr ptr = m_ptr.lock()) ptr->signal->Disconnect(ptr); @@ -294,6 +306,20 @@ namespace Nz return !m_ptr.expired(); } + /*! + * \brief Constructs a Signal::ConnectionGuard object by move semantic + * + * \param connection Connection to move + */ + template + typename Signal::Connection& Signal::Connection::operator=(Connection&& connection) noexcept + { + m_ptr = std::move(connection.m_ptr); + connection.m_ptr.reset(); //< Fuck you GCC 4.9 + + return *this; + } + /*! * \class Nz::Signal::ConnectionGuard * \brief Core class that represents a RAII for a connection attached to a signal @@ -353,7 +379,7 @@ namespace Nz */ template - void Signal::ConnectionGuard::Disconnect() + void Signal::ConnectionGuard::Disconnect() noexcept { m_connection.Disconnect(); } @@ -406,8 +432,11 @@ namespace Nz template typename Signal::ConnectionGuard& Signal::ConnectionGuard::operator=(Connection&& connection) { - m_connection.Disconnect(); - m_connection = std::move(connection); + if (&connection != this) + { + m_connection.Disconnect(); + m_connection = std::move(connection); + } return *this; } @@ -420,10 +449,13 @@ namespace Nz */ template - typename Signal::ConnectionGuard& Signal::ConnectionGuard::operator=(ConnectionGuard&& connection) + typename Signal::ConnectionGuard& Signal::ConnectionGuard::operator=(ConnectionGuard&& connection) noexcept { - m_connection.Disconnect(); - m_connection = std::move(connection.m_connection); + if (&connection != this) + { + m_connection.Disconnect(); + m_connection = std::move(connection.m_connection); + } return *this; } diff --git a/include/Nazara/Core/SparsePtr.hpp b/include/Nazara/Core/SparsePtr.hpp index f4d777fa8..10e76c9c3 100644 --- a/include/Nazara/Core/SparsePtr.hpp +++ b/include/Nazara/Core/SparsePtr.hpp @@ -41,7 +41,7 @@ namespace Nz void SetPtr(VoidPtr ptr); void SetStride(int stride); - operator bool() const; + explicit operator bool() const; operator T*() const; T& operator*() const; T* operator->() const; diff --git a/include/Nazara/Core/Thread.hpp b/include/Nazara/Core/Thread.hpp index a4b4d92f6..e129cbe40 100644 --- a/include/Nazara/Core/Thread.hpp +++ b/include/Nazara/Core/Thread.hpp @@ -32,11 +32,13 @@ namespace Nz Id GetId() const; bool IsJoinable() const; void Join(); + void SetName(const String& name); Thread& operator=(const Thread&) = delete; Thread& operator=(Thread&& thread); static unsigned int HardwareConcurrency(); + static void SetCurrentThreadName(const String& name); static void Sleep(UInt32 milliseconds); private: diff --git a/include/Nazara/Graphics/AbstractRenderQueue.hpp b/include/Nazara/Graphics/AbstractRenderQueue.hpp index f0074cd50..0e3b94f2f 100644 --- a/include/Nazara/Graphics/AbstractRenderQueue.hpp +++ b/include/Nazara/Graphics/AbstractRenderQueue.hpp @@ -51,7 +51,7 @@ namespace Nz virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) = 0; virtual void AddPointLight(const PointLight& light); virtual void AddSpotLight(const SpotLight& light); - virtual void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) = 0; + virtual void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) = 0; virtual void Clear(bool fully = false); diff --git a/include/Nazara/Graphics/AbstractViewer.hpp b/include/Nazara/Graphics/AbstractViewer.hpp index 9bef56373..21a62a890 100644 --- a/include/Nazara/Graphics/AbstractViewer.hpp +++ b/include/Nazara/Graphics/AbstractViewer.hpp @@ -33,6 +33,7 @@ namespace Nz virtual Vector3f GetForward() const = 0; virtual const Frustumf& GetFrustum() const = 0; virtual const Matrix4f& GetProjectionMatrix() const = 0; + virtual Nz::ProjectionType GetProjectionType() const = 0; virtual const RenderTarget* GetTarget() const = 0; virtual const Matrix4f& GetViewMatrix() const = 0; virtual const Recti& GetViewport() const = 0; diff --git a/include/Nazara/Graphics/ColorBackground.hpp b/include/Nazara/Graphics/ColorBackground.hpp index 57de236f9..d76a92977 100644 --- a/include/Nazara/Graphics/ColorBackground.hpp +++ b/include/Nazara/Graphics/ColorBackground.hpp @@ -26,9 +26,9 @@ namespace Nz ColorBackground(const ColorBackground&) = default; ColorBackground(ColorBackground&&) = delete; - void Draw(const AbstractViewer* viewer) const; + void Draw(const AbstractViewer* viewer) const override; - BackgroundType GetBackgroundType() const; + BackgroundType GetBackgroundType() const override; Color GetColor() const; void SetColor(const Color& color); diff --git a/include/Nazara/Graphics/ConfigCheck.hpp b/include/Nazara/Graphics/ConfigCheck.hpp index 3ec60640d..8aa8164db 100644 --- a/include/Nazara/Graphics/ConfigCheck.hpp +++ b/include/Nazara/Graphics/ConfigCheck.hpp @@ -12,7 +12,7 @@ #include #define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) -// We fore the value of MANAGE_MEMORY in debug +// We force the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_GRAPHICS_MANAGE_MEMORY #undef NAZARA_GRAPHICS_MANAGE_MEMORY #define NAZARA_GRAPHICS_MANAGE_MEMORY 0 diff --git a/include/Nazara/Graphics/DeferredBloomPass.hpp b/include/Nazara/Graphics/DeferredBloomPass.hpp index 5246f45c2..c00cc3c4c 100644 --- a/include/Nazara/Graphics/DeferredBloomPass.hpp +++ b/include/Nazara/Graphics/DeferredBloomPass.hpp @@ -29,8 +29,8 @@ namespace Nz float GetBrightThreshold() const; Texture* GetTexture(unsigned int i) const; - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; - bool Resize(const Vector2ui& dimensions); + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; + bool Resize(const Vector2ui& dimensions) override; void SetBlurPassCount(unsigned int passCount); void SetBrightLuminance(float luminance); diff --git a/include/Nazara/Graphics/DeferredDOFPass.hpp b/include/Nazara/Graphics/DeferredDOFPass.hpp index 6a0b213da..b4025be7d 100644 --- a/include/Nazara/Graphics/DeferredDOFPass.hpp +++ b/include/Nazara/Graphics/DeferredDOFPass.hpp @@ -23,8 +23,8 @@ namespace Nz DeferredDOFPass(); virtual ~DeferredDOFPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; - bool Resize(const Vector2ui& dimensions); + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; + bool Resize(const Vector2ui& dimensions) override; protected: RenderTexture m_dofRTT; diff --git a/include/Nazara/Graphics/DeferredFXAAPass.hpp b/include/Nazara/Graphics/DeferredFXAAPass.hpp index 696450796..e8179f46d 100644 --- a/include/Nazara/Graphics/DeferredFXAAPass.hpp +++ b/include/Nazara/Graphics/DeferredFXAAPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredFXAAPass(); virtual ~DeferredFXAAPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; protected: RenderStates m_states; diff --git a/include/Nazara/Graphics/DeferredFinalPass.hpp b/include/Nazara/Graphics/DeferredFinalPass.hpp index 52c7e8233..d99c8ed30 100644 --- a/include/Nazara/Graphics/DeferredFinalPass.hpp +++ b/include/Nazara/Graphics/DeferredFinalPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredFinalPass(); virtual ~DeferredFinalPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; protected: RenderStates m_states; diff --git a/include/Nazara/Graphics/DeferredFogPass.hpp b/include/Nazara/Graphics/DeferredFogPass.hpp index 807f0752d..c1ccbdc88 100644 --- a/include/Nazara/Graphics/DeferredFogPass.hpp +++ b/include/Nazara/Graphics/DeferredFogPass.hpp @@ -21,7 +21,7 @@ namespace Nz DeferredFogPass(); virtual ~DeferredFogPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; protected: RenderStates m_states; diff --git a/include/Nazara/Graphics/DeferredForwardPass.hpp b/include/Nazara/Graphics/DeferredForwardPass.hpp index 5bf53f107..7fc619da2 100644 --- a/include/Nazara/Graphics/DeferredForwardPass.hpp +++ b/include/Nazara/Graphics/DeferredForwardPass.hpp @@ -20,8 +20,8 @@ namespace Nz DeferredForwardPass(); virtual ~DeferredForwardPass(); - void Initialize(DeferredRenderTechnique* technique); - bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const; + void Initialize(DeferredRenderTechnique* technique) override; + bool Process(const SceneData& sceneData, unsigned int workTexture, unsigned int sceneTexture) const override; protected: const ForwardRenderTechnique* m_forwardTechnique; diff --git a/include/Nazara/Graphics/DeferredGeometryPass.hpp b/include/Nazara/Graphics/DeferredGeometryPass.hpp index dcfa47f90..b390263b6 100644 --- a/include/Nazara/Graphics/DeferredGeometryPass.hpp +++ b/include/Nazara/Graphics/DeferredGeometryPass.hpp @@ -21,8 +21,8 @@ namespace Nz DeferredGeometryPass(); virtual ~DeferredGeometryPass(); - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; - bool Resize(const Vector2ui& dimensions); + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; + bool Resize(const Vector2ui& dimensions) override; protected: struct ShaderUniforms; diff --git a/include/Nazara/Graphics/DeferredPhongLightingPass.hpp b/include/Nazara/Graphics/DeferredPhongLightingPass.hpp index 4b14900d7..cbff41041 100644 --- a/include/Nazara/Graphics/DeferredPhongLightingPass.hpp +++ b/include/Nazara/Graphics/DeferredPhongLightingPass.hpp @@ -28,7 +28,7 @@ namespace Nz bool IsLightMeshesDrawingEnabled() const; - bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const; + bool Process(const SceneData& sceneData, unsigned int firstWorkTexture, unsigned int secondWorkTexture) const override; protected: LightUniforms m_directionalLightUniforms; diff --git a/include/Nazara/Graphics/DeferredRenderQueue.hpp b/include/Nazara/Graphics/DeferredRenderQueue.hpp index 982469873..5f9f7538e 100644 --- a/include/Nazara/Graphics/DeferredRenderQueue.hpp +++ b/include/Nazara/Graphics/DeferredRenderQueue.hpp @@ -37,7 +37,7 @@ namespace Nz void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; void AddDrawable(int renderOrder, const Drawable* drawable) override; void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; - void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; + void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override; void Clear(bool fully = false) override; diff --git a/include/Nazara/Graphics/DepthRenderQueue.hpp b/include/Nazara/Graphics/DepthRenderQueue.hpp index ed7c9f3c3..871cefa66 100644 --- a/include/Nazara/Graphics/DepthRenderQueue.hpp +++ b/include/Nazara/Graphics/DepthRenderQueue.hpp @@ -38,7 +38,7 @@ namespace Nz void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; void AddPointLight(const PointLight& light) override; void AddSpotLight(const SpotLight& light) override; - void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; + void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override; private: inline bool IsMaterialSuitable(const Material* material) const; diff --git a/include/Nazara/Graphics/ForwardRenderQueue.hpp b/include/Nazara/Graphics/ForwardRenderQueue.hpp index f0ac6edda..bc5c2456e 100644 --- a/include/Nazara/Graphics/ForwardRenderQueue.hpp +++ b/include/Nazara/Graphics/ForwardRenderQueue.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,7 @@ namespace Nz void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; void AddDrawable(int renderOrder, const Drawable* drawable) override; void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; - void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay = nullptr) override; + void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay = nullptr) override; void Clear(bool fully = false) override; @@ -73,7 +74,7 @@ namespace Nz std::vector billboards; }; - typedef std::map BatchedBillboardContainer; + using BatchedBillboardContainer = std::map; struct BatchedBillboardPipelineEntry { @@ -81,7 +82,7 @@ namespace Nz bool enabled = false; }; - typedef std::map BillboardPipelineBatches; + using BillboardPipelineBatches = std::map; /// Sprites struct SpriteChain_XYZ_Color_UV @@ -97,7 +98,7 @@ namespace Nz std::vector spriteChains; }; - typedef std::map SpriteOverlayBatches; + using SpriteOverlayBatches = std::map; struct BatchedBasicSpriteEntry { @@ -107,7 +108,7 @@ namespace Nz bool enabled = false; }; - typedef std::map SpriteMaterialBatches; + using SpriteMaterialBatches = std::map; struct BatchedSpritePipelineEntry { @@ -115,7 +116,7 @@ namespace Nz bool enabled = false; }; - typedef std::map SpritePipelineBatches; + using SpritePipelineBatches = std::map; /// Meshes struct MeshDataComparator @@ -132,7 +133,7 @@ namespace Nz Spheref squaredBoundingSphere; }; - typedef std::map MeshInstanceContainer; + using MeshInstanceContainer = std::map; struct BatchedModelEntry { @@ -142,7 +143,7 @@ namespace Nz bool enabled = false; }; - typedef std::map MeshMaterialBatches; + using MeshMaterialBatches = std::map; struct BatchedMaterialEntry { @@ -150,25 +151,33 @@ namespace Nz MeshMaterialBatches materialMap; }; - typedef std::map MeshPipelineBatches; + using MeshPipelineBatches = std::map; - struct TransparentModelData + struct UnbatchedModelData { Matrix4f transformMatrix; MeshData meshData; - Spheref squaredBoundingSphere; + Spheref obbSphere; const Material* material; }; - typedef std::vector TransparentModelContainer; + struct UnbatchedSpriteData + { + std::size_t spriteCount; + const Material* material; + const Texture* overlay; + const VertexStruct_XYZ_Color_UV* vertices; + }; struct Layer { BillboardPipelineBatches billboards; - SpritePipelineBatches basicSprites; + SpritePipelineBatches opaqueSprites; MeshPipelineBatches opaqueModels; - TransparentModelContainer transparentModels; - std::vector transparentModelData; + std::vector depthSortedMeshes; + std::vector depthSortedSprites; + std::vector depthSortedMeshData; + std::vector depthSortedSpriteData; std::vector otherDrawables; unsigned int clearCount = 0; }; @@ -179,6 +188,10 @@ namespace Nz BillboardData* GetBillboardData(int renderOrder, const Material* material, unsigned int count); Layer& GetLayer(int i); ///TODO: Inline + void SortBillboards(Layer& layer, const Planef& nearPlane); + void SortForOrthographic(const AbstractViewer* viewer); + void SortForPerspective(const AbstractViewer* viewer); + void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer); void OnMaterialInvalidation(const Material* material); void OnTextureInvalidation(const Texture* texture); diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.hpp b/include/Nazara/Graphics/ForwardRenderTechnique.hpp index 9b5c152df..cadb60473 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.hpp +++ b/include/Nazara/Graphics/ForwardRenderTechnique.hpp @@ -43,6 +43,7 @@ namespace Nz void DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; + void DrawOrderedSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; void DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const; const ShaderUniforms* GetShaderUniforms(const Shader* shader) const; void OnShaderInvalidated(const Shader* shader) const; diff --git a/include/Nazara/Graphics/TextureBackground.hpp b/include/Nazara/Graphics/TextureBackground.hpp index 272bcc63f..bdb088812 100644 --- a/include/Nazara/Graphics/TextureBackground.hpp +++ b/include/Nazara/Graphics/TextureBackground.hpp @@ -24,9 +24,9 @@ namespace Nz public: TextureBackground(TextureRef texture = TextureRef()); - void Draw(const AbstractViewer* viewer) const; + void Draw(const AbstractViewer* viewer) const override; - BackgroundType GetBackgroundType() const; + BackgroundType GetBackgroundType() const override; inline const TextureRef& GetTexture() const; inline void SetTexture(TextureRef texture); diff --git a/include/Nazara/Lua.hpp b/include/Nazara/Lua.hpp index a0e68204c..bd7ddb24c 100644 --- a/include/Nazara/Lua.hpp +++ b/include/Nazara/Lua.hpp @@ -33,6 +33,8 @@ #include #include #include +#include #include +#include #endif // NAZARA_GLOBAL_LUA_HPP diff --git a/include/Nazara/Lua/LuaClass.hpp b/include/Nazara/Lua/LuaClass.hpp index 13dcbb828..451f91c08 100644 --- a/include/Nazara/Lua/LuaClass.hpp +++ b/include/Nazara/Lua/LuaClass.hpp @@ -26,13 +26,13 @@ namespace Nz friend class LuaClass; public: - using ClassFunc = std::function; - using ClassIndexFunc = std::function; - using ConstructorFunc = std::function; + using ClassFunc = std::function; + using ClassIndexFunc = std::function; + using ConstructorFunc = std::function; template using ConvertToParent = std::function; - using FinalizerFunc = std::function; - using StaticIndexFunc = std::function; - using StaticFunc = std::function; + using FinalizerFunc = std::function; + using StaticIndexFunc = std::function; + using StaticFunc = std::function; LuaClass() = default; LuaClass(const String& name); @@ -54,9 +54,9 @@ namespace Nz void Reset(); void Reset(const String& name); - void Register(LuaInstance& lua); + void Register(LuaState& state); - void PushGlobalTable(LuaInstance& lua); + void PushGlobalTable(LuaState& state); void SetConstructor(ConstructorFunc constructor); void SetFinalizer(FinalizerFunc finalizer); @@ -69,18 +69,18 @@ namespace Nz template friend struct LuaClassImplFinalizerSetupProxy; - void PushClassInfo(LuaInstance& lua); - void SetupConstructor(LuaInstance& lua); - void SetupDefaultToString(LuaInstance& lua); - void SetupFinalizer(LuaInstance& lua); - void SetupGetter(LuaInstance& lua, LuaCFunction proxy); - void SetupGlobalTable(LuaInstance& lua); - void SetupMetatable(LuaInstance& lua); - void SetupMethod(LuaInstance& lua, LuaCFunction proxy, const String& name, std::size_t methodIndex); - void SetupSetter(LuaInstance& lua, LuaCFunction proxy); + void PushClassInfo(LuaState& state); + void SetupConstructor(LuaState& state); + void SetupDefaultToString(LuaState& state); + void SetupFinalizer(LuaState& state); + void SetupGetter(LuaState& state, LuaCFunction proxy); + void SetupGlobalTable(LuaState& state); + void SetupMetatable(LuaState& state); + void SetupMethod(LuaState& state, LuaCFunction proxy, const String& name, std::size_t methodIndex); + void SetupSetter(LuaState& state, LuaCFunction proxy); - using ParentFunc = std::function; - using InstanceGetter = std::function; + using ParentFunc = std::function; + using InstanceGetter = std::function; struct ClassInfo { @@ -98,17 +98,17 @@ namespace Nz int globalTableRef = -1; }; - static int ConstructorProxy(lua_State* state); - static int FinalizerProxy(lua_State* state); - static int InfoDestructor(lua_State* state); - static void Get(const std::shared_ptr& info, LuaInstance& lua, T* instance); - static int GetterProxy(lua_State* state); - static int MethodProxy(lua_State* state); - static int SetterProxy(lua_State* state); - static int StaticGetterProxy(lua_State* state); - static int StaticMethodProxy(lua_State* state); - static int StaticSetterProxy(lua_State* state); - static int ToStringProxy(lua_State* state); + static int ConstructorProxy(lua_State* internalState); + static int FinalizerProxy(lua_State* internalState); + static int InfoDestructor(lua_State* internalState); + static void Get(const std::shared_ptr& info, LuaState& state, T* instance); + static int GetterProxy(lua_State* internalState); + static int MethodProxy(lua_State* internalState); + static int SetterProxy(lua_State* internalState); + static int StaticGetterProxy(lua_State* internalState); + static int StaticMethodProxy(lua_State* internalState); + static int StaticSetterProxy(lua_State* internalState); + static int ToStringProxy(lua_State* internalState); std::map m_methods; std::map m_staticMethods; diff --git a/include/Nazara/Lua/LuaClass.inl b/include/Nazara/Lua/LuaClass.inl index 94c1f8125..40b7374bc 100644 --- a/include/Nazara/Lua/LuaClass.inl +++ b/include/Nazara/Lua/LuaClass.inl @@ -19,9 +19,9 @@ namespace Nz template inline void LuaClass::BindDefaultConstructor() { - SetConstructor([] (Nz::LuaInstance& lua, T* instance, std::size_t argumentCount) + SetConstructor([] (Nz::LuaState& state, T* instance, std::size_t argumentCount) { - NazaraUnused(lua); + NazaraUnused(state); NazaraUnused(argumentCount); PlacementNew(instance); @@ -47,14 +47,14 @@ namespace Nz std::shared_ptr::ClassInfo>& parentInfo = parent.m_info; - parentInfo->instanceGetters[m_info->name] = [info = m_info, convertFunc] (LuaInstance& lua) -> P* + parentInfo->instanceGetters[m_info->name] = [info = m_info, convertFunc] (LuaState& state) -> P* { - return convertFunc(static_cast(lua.CheckUserdata(1, info->name))); + return convertFunc(static_cast(state.CheckUserdata(1, info->name))); }; - m_info->parentGetters.emplace_back([parentInfo, convertFunc] (LuaInstance& lua, T* instance) + m_info->parentGetters.emplace_back([parentInfo, convertFunc] (LuaState& state, T* instance) { - LuaClass

::Get(parentInfo, lua, convertFunc(instance)); + LuaClass

::Get(parentInfo, state, convertFunc(instance)); }); } @@ -71,30 +71,30 @@ namespace Nz m_info = std::make_shared(); m_info->name = name; - m_info->instanceGetters[m_info->name] = [info = m_info] (LuaInstance& instance) + m_info->instanceGetters[m_info->name] = [info = m_info] (LuaState& state) { - return static_cast(instance.CheckUserdata(1, info->name)); + return static_cast(state.CheckUserdata(1, info->name)); }; } template - void LuaClass::Register(LuaInstance& lua) + void LuaClass::Register(LuaState& state) { - PushClassInfo(lua); + PushClassInfo(state); - // Let's create the metatable which will be associated with every instance. - SetupMetatable(lua); + // Let's create the metatable which will be associated with every state. + SetupMetatable(state); if (m_info->constructor || m_info->staticGetter || m_info->staticSetter || !m_staticMethods.empty()) - SetupGlobalTable(lua); + SetupGlobalTable(state); - lua.Pop(); // Pop our ClassInfo, which is now referenced by all our functions + state.Pop(); // Pop our ClassInfo, which is now referenced by all our functions } template - void LuaClass::PushGlobalTable(LuaInstance& lua) + void LuaClass::PushGlobalTable(LuaState& state) { - lua.PushReference(m_info->globalTableRef); + state.PushReference(m_info->globalTableRef); } template @@ -127,11 +127,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -141,11 +141,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -155,11 +155,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -169,11 +169,11 @@ namespace Nz { typename LuaImplMethodProxy::template Impl handler(std::forward(defArgs)...); - BindMethod(name, [func, handler] (LuaInstance& lua, T& object, std::size_t /*argumentCount*/) -> int + BindMethod(name, [func, handler] (LuaState& state, T& object, std::size_t /*argumentCount*/) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, object, func); + return handler.Invoke(state, object, func); }); } @@ -201,11 +201,11 @@ namespace Nz { typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); - BindStaticMethod(name, [func, handler] (LuaInstance& lua) -> int + BindStaticMethod(name, [func, handler] (LuaState& state) -> int { - handler.ProcessArguments(lua); + handler.ProcessArguments(state); - return handler.Invoke(lua, func); + return handler.Invoke(state, func); }); } @@ -216,37 +216,37 @@ namespace Nz } template - void LuaClass::PushClassInfo(LuaInstance& lua) + void LuaClass::PushClassInfo(LuaState& state) { // Our ClassInfo has to outlive the LuaClass, because we don't want to force the user to keep the LuaClass alive // To do that, each Registration creates a tiny shared_ptr wrapper whose life is directly managed by Lua. // This shared_ptr object gets pushed as a up-value for every proxy function set in the metatable. // This way, there is no way our ClassInfo gets freed before any instance and the global class gets destroyed. - std::shared_ptr* info = static_cast*>(lua.PushUserdata(sizeof(std::shared_ptr))); + std::shared_ptr* info = static_cast*>(state.PushUserdata(sizeof(std::shared_ptr))); PlacementNew(info, m_info); // Setup a tiny metatable to let Lua know how to destroy our ClassInfo - lua.PushTable(0, 1); - lua.PushLightUserdata(info); - lua.PushCFunction(InfoDestructor, 1); - lua.SetField("__gc"); - lua.SetMetatable(-2); + state.PushTable(0, 1); + state.PushLightUserdata(info); + state.PushCFunction(InfoDestructor, 1); + state.SetField("__gc"); + state.SetMetatable(-2); } template - void LuaClass::SetupConstructor(LuaInstance& lua) + void LuaClass::SetupConstructor(LuaState& state) { - lua.PushValue(1); // ClassInfo - lua.PushCFunction(ConstructorProxy, 1); - lua.SetField("__call"); // ClassMeta.__call = ConstructorProxy + state.PushValue(1); // ClassInfo + state.PushCFunction(ConstructorProxy, 1); + state.SetField("__call"); // ClassMeta.__call = ConstructorProxy } template - void LuaClass::SetupDefaultToString(LuaInstance& lua) + void LuaClass::SetupDefaultToString(LuaState& state) { - lua.PushValue(1); // shared_ptr on UserData - lua.PushCFunction(ToStringProxy, 1); - lua.SetField("__tostring"); + state.PushValue(1); // shared_ptr on UserData + state.PushCFunction(ToStringProxy, 1); + state.SetField("__tostring"); } template @@ -255,61 +255,61 @@ namespace Nz template struct LuaClassImplFinalizerSetupProxy { - static void Setup(LuaInstance& lua) + static void Setup(LuaState& state) { - lua.PushValue(1); // ClassInfo - lua.PushCFunction(LuaClass::FinalizerProxy, 1); - lua.SetField("__gc"); + state.PushValue(1); // ClassInfo + state.PushCFunction(LuaClass::FinalizerProxy, 1); + state.SetField("__gc"); } }; template struct LuaClassImplFinalizerSetupProxy { - static void Setup(LuaInstance&) + static void Setup(LuaState&) { } }; template - void LuaClass::SetupFinalizer(LuaInstance& lua) + void LuaClass::SetupFinalizer(LuaState& state) { - LuaClassImplFinalizerSetupProxy::value>::Setup(lua); + LuaClassImplFinalizerSetupProxy::value>::Setup(state); } template - void LuaClass::SetupGetter(LuaInstance& lua, LuaCFunction proxy) + void LuaClass::SetupGetter(LuaState& state, LuaCFunction proxy) { - lua.PushValue(1); // ClassInfo - lua.PushValue(-2); // Metatable - lua.PushCFunction(proxy, 2); + state.PushValue(1); // ClassInfo + state.PushValue(-2); // Metatable + state.PushCFunction(proxy, 2); - lua.SetField("__index"); // Getter + state.SetField("__index"); // Getter } template - void LuaClass::SetupGlobalTable(LuaInstance& lua) + void LuaClass::SetupGlobalTable(LuaState& state) { // Create the global table - lua.PushTable(); // Class = {} + state.PushTable(); // Class = {} // Create a metatable which will be used for our global table - lua.PushTable(); // ClassMeta = {} + state.PushTable(); // ClassMeta = {} if (m_info->constructor) - SetupConstructor(lua); + SetupConstructor(state); if (m_info->staticGetter) - SetupGetter(lua, StaticGetterProxy); + SetupGetter(state, StaticGetterProxy); else { // Optimize by assigning the metatable instead of a search function - lua.PushValue(-1); // Metatable - lua.SetField("__index"); + state.PushValue(-1); // Metatable + state.SetField("__index"); } if (m_info->staticSetter) - SetupSetter(lua, StaticSetterProxy); + SetupSetter(state, StaticSetterProxy); m_info->staticMethods.reserve(m_staticMethods.size()); for (auto& pair : m_staticMethods) @@ -317,41 +317,41 @@ namespace Nz std::size_t methodIndex = m_info->staticMethods.size(); m_info->staticMethods.push_back(pair.second); - SetupMethod(lua, StaticMethodProxy, pair.first, methodIndex); + SetupMethod(state, StaticMethodProxy, pair.first, methodIndex); } - lua.SetMetatable(-2); // setmetatable(Class, ClassMeta), pops ClassMeta + state.SetMetatable(-2); // setmetatable(Class, ClassMeta), pops ClassMeta - lua.PushValue(-1); // As CreateReference() pops the table, push a copy - m_info->globalTableRef = lua.CreateReference(); + state.PushValue(-1); // As CreateReference() pops the table, push a copy + m_info->globalTableRef = state.CreateReference(); - lua.SetGlobal(m_info->name); // _G["Class"] = Class + state.SetGlobal(m_info->name); // _G["Class"] = Class } template - void LuaClass::SetupMetatable(LuaInstance& lua) + void LuaClass::SetupMetatable(LuaState& state) { - if (!lua.NewMetatable(m_info->name)) + if (!state.NewMetatable(m_info->name)) NazaraWarning("Class \"" + m_info->name + "\" already registred in this instance"); { - SetupFinalizer(lua); + SetupFinalizer(state); if (m_info->getter || !m_info->parentGetters.empty()) - SetupGetter(lua, GetterProxy); + SetupGetter(state, GetterProxy); else { // Optimize by assigning the metatable instead of a search function // This is only possible if we have no custom getter nor parent - lua.PushValue(-1); // Metatable - lua.SetField("__index"); + state.PushValue(-1); // Metatable + state.SetField("__index"); } if (m_info->setter) - SetupSetter(lua, SetterProxy); + SetupSetter(state, SetterProxy); // In case a __tostring method is missing, add a default implementation returning the class name if (m_methods.find("__tostring") == m_methods.end()) - SetupDefaultToString(lua); + SetupDefaultToString(state); m_info->methods.reserve(m_methods.size()); for (auto& pair : m_methods) @@ -359,80 +359,80 @@ namespace Nz std::size_t methodIndex = m_info->methods.size(); m_info->methods.push_back(pair.second); - SetupMethod(lua, MethodProxy, pair.first, methodIndex); + SetupMethod(state, MethodProxy, pair.first, methodIndex); } } - lua.Pop(); //< Pops the metatable, it won't be collected before it's referenced by the Lua registry. + state.Pop(); //< Pops the metatable, it won't be collected before it's referenced by the Lua registry. } template - void LuaClass::SetupMethod(LuaInstance& lua, LuaCFunction proxy, const String& name, std::size_t methodIndex) + void LuaClass::SetupMethod(LuaState& state, LuaCFunction proxy, const String& name, std::size_t methodIndex) { - lua.PushValue(1); // ClassInfo - lua.PushInteger(methodIndex); - lua.PushCFunction(proxy, 2); + state.PushValue(1); // ClassInfo + state.PushInteger(methodIndex); + state.PushCFunction(proxy, 2); - lua.SetField(name); // Method name + state.SetField(name); // Method name } template - void LuaClass::SetupSetter(LuaInstance& lua, LuaCFunction proxy) + void LuaClass::SetupSetter(LuaState& state, LuaCFunction proxy) { - lua.PushValue(1); // ClassInfo - lua.PushCFunction(proxy, 1); + state.PushValue(1); // ClassInfo + state.PushCFunction(proxy, 1); - lua.SetField("__newindex"); // Setter + state.SetField("__newindex"); // Setter } template - int LuaClass::ConstructorProxy(lua_State* state) + int LuaClass::ConstructorProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const ConstructorFunc& constructor = info->constructor; - lua.Remove(1); // On enlève l'argument "table" du stack + state.Remove(1); // On enlève l'argument "table" du stack - std::size_t argCount = lua.GetStackTop(); + std::size_t argCount = state.GetStackTop(); - T* instance = static_cast(lua.PushUserdata(sizeof(T))); + T* instance = static_cast(state.PushUserdata(sizeof(T))); - if (!constructor(lua, instance, argCount)) + if (!constructor(state, instance, argCount)) { - lua.Error("Constructor failed"); + state.Error("Constructor failed"); return 0; // Normalement jamais exécuté (l'erreur provoquant une exception) } - lua.SetMetatable(info->name); + state.SetMetatable(info->name); return 1; } template - int LuaClass::FinalizerProxy(lua_State* state) + int LuaClass::FinalizerProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const FinalizerFunc& finalizer = info->finalizer; - T* instance = static_cast(lua.CheckUserdata(1, info->name)); - lua.Remove(1); //< Remove the instance from the Lua stack + T* instance = static_cast(state.CheckUserdata(1, info->name)); + state.Remove(1); //< Remove the instance from the Lua stack - if (!finalizer || finalizer(lua, *instance)) + if (!finalizer || finalizer(state, *instance)) instance->~T(); return 0; } template - int LuaClass::InfoDestructor(lua_State* state) + int LuaClass::InfoDestructor(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); - lua.DestroyReference(info->globalTableRef); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); + state.DestroyReference(info->globalTableRef); using namespace std; // Obligatoire pour le destructeur info.~shared_ptr(); // Si vous voyez une autre façon de faire, je suis preneur @@ -441,27 +441,27 @@ namespace Nz } template - void LuaClass::Get(const std::shared_ptr& info, LuaInstance& lua, T* instance) + void LuaClass::Get(const std::shared_ptr& info, LuaState& state, T* instance) { const ClassIndexFunc& getter = info->getter; - if (!getter || !getter(lua, *instance)) + if (!getter || !getter(state, *instance)) { // Query from the metatable - lua.GetMetatable(info->name); //< Metatable - lua.PushValue(2); //< Field - lua.GetTable(); // Metatable[Field] + state.GetMetatable(info->name); //< Metatable + state.PushValue(2); //< Field + state.GetTable(); // Metatable[Field] - lua.Remove(-2); // Remove Metatable + state.Remove(-2); // Remove Metatable - if (!lua.IsValid(-1)) + if (!state.IsValid(-1)) { for (const ParentFunc& parentGetter : info->parentGetters) { - lua.Pop(); //< Pop the last nil value + state.Pop(); //< Pop the last nil value - parentGetter(lua, instance); - if (lua.IsValid(-1)) + parentGetter(state, instance); + if (state.IsValid(-1)) return; } } @@ -469,131 +469,131 @@ namespace Nz } template - int LuaClass::GetterProxy(lua_State* state) + int LuaClass::GetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); - T* instance = static_cast(lua.CheckUserdata(1, info->name)); + T* instance = static_cast(state.CheckUserdata(1, info->name)); - Get(info, lua, instance); + Get(info, state, instance); return 1; } template - int LuaClass::MethodProxy(lua_State* state) + int LuaClass::MethodProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); T* instance = nullptr; - if (lua.GetMetatable(1)) + if (state.GetMetatable(1)) { - LuaType type = lua.GetField("__name"); + LuaType type = state.GetField("__name"); if (type == LuaType_String) { - String name = lua.ToString(-1); + String name = state.ToString(-1); auto it = info->instanceGetters.find(name); if (it != info->instanceGetters.end()) - instance = it->second(lua); + instance = it->second(state); } - lua.Pop(2); + state.Pop(2); } if (!instance) { - lua.Error("Method cannot be called without an object"); + state.Error("Method cannot be called without an object"); return 0; } - std::size_t argCount = lua.GetStackTop() - 1U; + std::size_t argCount = state.GetStackTop() - 1U; - unsigned int index = static_cast(lua.ToInteger(lua.GetIndexOfUpValue(2))); + unsigned int index = static_cast(state.ToInteger(state.GetIndexOfUpValue(2))); const ClassFunc& method = info->methods[index]; - return method(lua, *instance, argCount); + return method(state, *instance, argCount); } template - int LuaClass::SetterProxy(lua_State* state) + int LuaClass::SetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const ClassIndexFunc& setter = info->setter; - T& instance = *static_cast(lua.CheckUserdata(1, info->name)); + T& instance = *static_cast(state.CheckUserdata(1, info->name)); - if (!setter(lua, instance)) + if (!setter(state, instance)) { std::size_t length; - const char* str = lua.ToString(2, &length); + const char* str = state.ToString(2, &length); - lua.Error("Class \"" + info->name + "\" has no field \"" + String(str, length) + "\")"); + state.Error("Class \"" + info->name + "\" has no field \"" + String(str, length) + "\")"); } return 1; } template - int LuaClass::StaticGetterProxy(lua_State* state) + int LuaClass::StaticGetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const StaticIndexFunc& getter = info->staticGetter; - if (!getter(lua)) + if (!getter(state)) { // On accède alors à la table - lua.PushValue(lua.GetIndexOfUpValue(2)); - lua.PushValue(-2); - lua.GetTable(); + state.PushValue(state.GetIndexOfUpValue(2)); + state.PushValue(-2); + state.GetTable(); } return 1; } template - int LuaClass::StaticMethodProxy(lua_State* state) + int LuaClass::StaticMethodProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); - unsigned int index = static_cast(lua.ToInteger(lua.GetIndexOfUpValue(2))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); + unsigned int index = static_cast(state.ToInteger(state.GetIndexOfUpValue(2))); const StaticFunc& method = info->staticMethods[index]; - return method(lua); + return method(state); } template - int LuaClass::StaticSetterProxy(lua_State* state) + int LuaClass::StaticSetterProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); const StaticIndexFunc& setter = info->staticSetter; - if (!setter(lua)) + if (!setter(state)) { std::size_t length; - const char* str = lua.ToString(2, &length); + const char* str = state.ToString(2, &length); - lua.Error("Class \"" + info->name + "\" has no static field \"" + String(str, length) + ')'); + state.Error("Class \"" + info->name + "\" has no static field \"" + String(str, length) + ')'); } return 1; } template - int LuaClass::ToStringProxy(lua_State* state) + int LuaClass::ToStringProxy(lua_State* internalState) { - LuaInstance& lua = *LuaInstance::GetInstance(state); + LuaState state = LuaInstance::GetState(internalState); - std::shared_ptr& info = *static_cast*>(lua.ToUserdata(lua.GetIndexOfUpValue(1))); + std::shared_ptr& info = *static_cast*>(state.ToUserdata(state.GetIndexOfUpValue(1))); - lua.PushString(info->name); + state.PushString(info->name); return 1; } } diff --git a/include/Nazara/Lua/LuaCoroutine.hpp b/include/Nazara/Lua/LuaCoroutine.hpp new file mode 100644 index 000000000..a740f635b --- /dev/null +++ b/include/Nazara/Lua/LuaCoroutine.hpp @@ -0,0 +1,44 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LUACOROUTINE_HPP +#define NAZARA_LUACOROUTINE_HPP + +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_LUA_API LuaCoroutine : public LuaState + { + friend class LuaState; + + public: + LuaCoroutine(const LuaCoroutine&) = delete; + inline LuaCoroutine(LuaCoroutine&& instance); + ~LuaCoroutine(); + + bool CanResume() const; + + Ternary Resume(unsigned int argCount = 0); + + LuaCoroutine& operator=(const LuaCoroutine&) = delete; + inline LuaCoroutine& operator=(LuaCoroutine&& instance); + + private: + LuaCoroutine(lua_State* internalState, int refIndex); + + bool Run(int argCount, int resultCount) override; + + int m_ref; + }; +} + +#include + +#endif // NAZARA_LUACOROUTINE_HPP diff --git a/include/Nazara/Lua/LuaCoroutine.inl b/include/Nazara/Lua/LuaCoroutine.inl new file mode 100644 index 000000000..7dcdd0e07 --- /dev/null +++ b/include/Nazara/Lua/LuaCoroutine.inl @@ -0,0 +1,25 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + inline LuaCoroutine::LuaCoroutine(LuaCoroutine&& instance) : + LuaState(std::move(instance)), + m_ref(instance.m_ref) + { + instance.m_ref = -1; + } + + inline LuaCoroutine& LuaCoroutine::operator=(LuaCoroutine&& instance) + { + LuaState::operator=(std::move(instance)); + + m_ref = instance.m_ref; + instance.m_ref = -1; + + return *this; + } +} diff --git a/include/Nazara/Lua/LuaInstance.hpp b/include/Nazara/Lua/LuaInstance.hpp index 5f27c76e6..93374958b 100644 --- a/include/Nazara/Lua/LuaInstance.hpp +++ b/include/Nazara/Lua/LuaInstance.hpp @@ -4,198 +4,51 @@ #pragma once -#ifndef NAZARA_LUASTATE_HPP -#define NAZARA_LUASTATE_HPP +#ifndef NAZARA_LUAINSTANCE_HPP +#define NAZARA_LUAINSTANCE_HPP #include -#include -#include -#include -#include -#include +#include #include #include -struct lua_Debug; -struct lua_State; - namespace Nz { - class LuaInstance; - - using LuaCFunction = int (*)(lua_State* state); - using LuaFunction = std::function; - - class NAZARA_LUA_API LuaInstance + class NAZARA_LUA_API LuaInstance : public LuaState { + friend class LuaCoroutine; + friend class LuaState; + public: LuaInstance(); LuaInstance(const LuaInstance&) = delete; - inline LuaInstance(LuaInstance&& instance) noexcept; + LuaInstance(LuaInstance&& instance) = default; ~LuaInstance(); - void ArgCheck(bool condition, unsigned int argNum, const char* error) const; - void ArgCheck(bool condition, unsigned int argNum, const String& error) const; - int ArgError(unsigned int argNum, const char* error) const; - int ArgError(unsigned int argNum, const String& error) const; - - bool Call(unsigned int argCount); - bool Call(unsigned int argCount, unsigned int resultCount); - - template T Check(int* index) const; - template T Check(int* index, T defValue) const; - void CheckAny(int index) const; - bool CheckBoolean(int index) const; - bool CheckBoolean(int index, bool defValue) const; - template T CheckBoundInteger(int index) const; - template T CheckBoundInteger(int index, T defValue) const; - template T CheckField(const char* fieldName, int tableIndex = -1) const; - template T CheckField(const String& fieldName, int tableIndex = -1) const; - template T CheckField(const char* fieldName, T defValue, int tableIndex = -1) const; - template T CheckField(const String& fieldName, T defValue, int tableIndex = -1) const; - long long CheckInteger(int index) const; - long long CheckInteger(int index, long long defValue) const; - template T CheckGlobal(const char* fieldName) const; - template T CheckGlobal(const String& fieldName) const; - template T CheckGlobal(const char* fieldName, T defValue) const; - template T CheckGlobal(const String& fieldName, T defValue) const; - double CheckNumber(int index) const; - double CheckNumber(int index, double defValue) const; - void CheckStack(int space, const char* error = nullptr) const; - void CheckStack(int space, const String& error) const; - const char* CheckString(int index, std::size_t* length = nullptr) const; - const char* CheckString(int index, const char* defValue, std::size_t* length = nullptr) const; - void CheckType(int index, LuaType type) const; - void* CheckUserdata(int index, const char* tname) const; - void* CheckUserdata(int index, const String& tname) const; - - bool Compare(int index1, int index2, LuaComparison comparison) const; - void Compute(LuaOperation operation) const; - - void Concatenate(int count) const; - - int CreateReference(); - void DestroyReference(int ref); - - String DumpStack() const; - - void Error(const char* message) const; - void Error(const String& message) const; - - bool Execute(const String& code); - bool ExecuteFromFile(const String& filePath); - bool ExecuteFromMemory(const void* data, std::size_t size); - bool ExecuteFromStream(Stream& stream); - - int GetAbsIndex(int index) const; - LuaType GetField(const char* fieldName, int tableIndex = -1) const; - LuaType GetField(const String& fieldName, int tableIndex = -1) const; - LuaType GetGlobal(const char* name) const; - LuaType GetGlobal(const String& name) const; - inline lua_State* GetInternalState() const; - inline String GetLastError() const; inline std::size_t GetMemoryLimit() const; inline std::size_t GetMemoryUsage() const; - LuaType GetMetatable(const char* tname) const; - LuaType GetMetatable(const String& tname) const; - bool GetMetatable(int index) const; - unsigned int GetStackTop() const; - LuaType GetTable(int index = -2) const; inline UInt32 GetTimeLimit() const; - LuaType GetType(int index) const; - const char* GetTypeName(LuaType type) const; - void Insert(int index) const; - - bool IsOfType(int index, LuaType type) const; - bool IsOfType(int index, const char* tname) const; - bool IsOfType(int index, const String& tname) const; - bool IsValid(int index) const; - - long long Length(int index) const; - - void MoveTo(LuaInstance* instance, int n) const; - - bool NewMetatable(const char* str); - bool NewMetatable(const String& str); - bool Next(int index = -2) const; - - void Pop(unsigned int n = 1U) const; - - template int Push(T arg) const; - template int Push(T firstArg, T2 secondArg, Args... args) const; - void PushBoolean(bool value) const; - void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0) const; - template void PushField(const char* name, T&& arg, int tableIndex = -2) const; - template void PushField(const String& name, T&& arg, int tableIndex = -2) const; - void PushFunction(LuaFunction func) const; - template void PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const; - template void PushGlobal(const char* name, T&& arg); - template void PushGlobal(const String& name, T&& arg); - template void PushInstance(const char* tname, const T& instance) const; - template void PushInstance(const char* tname, T&& instance) const; - template void PushInstance(const char* tname, Args&&... args) const; - void PushInteger(long long value) const; - void PushLightUserdata(void* value) const; - void PushMetatable(const char* str) const; - void PushMetatable(const String& str) const; - void PushNil() const; - void PushNumber(double value) const; - void PushReference(int ref) const; - void PushString(const char* str) const; - void PushString(const char* str, std::size_t size) const; - void PushString(const String& str) const; - void PushTable(std::size_t sequenceElementCount = 0, std::size_t arrayElementCount = 0) const; - void* PushUserdata(std::size_t size) const; - void PushValue(int index) const; - - void Remove(int index) const; - void Replace(int index) const; - - void SetField(const char* name, int tableIndex = -2) const; - void SetField(const String& name, int tableIndex = -2) const; - void SetGlobal(const char* name); - void SetGlobal(const String& name); - void SetMetatable(const char* tname) const; - void SetMetatable(const String& tname) const; - void SetMetatable(int index) const; - void SetMemoryLimit(std::size_t memoryLimit); - void SetTable(int index = -3) const; - void SetTimeLimit(UInt32 timeLimit); - - bool ToBoolean(int index) const; - long long ToInteger(int index, bool* succeeded = nullptr) const; - double ToNumber(int index, bool* succeeded = nullptr) const; - const void* ToPointer(int index) const; - const char* ToString(int index, std::size_t* length = nullptr) const; - void* ToUserdata(int index) const; - void* ToUserdata(int index, const char* tname) const; - void* ToUserdata(int index, const String& tname) const; + inline void SetMemoryLimit(std::size_t memoryLimit); + inline void SetTimeLimit(UInt32 limit); LuaInstance& operator=(const LuaInstance&) = delete; - inline LuaInstance& operator=(LuaInstance&& instance) noexcept; - - static int GetIndexOfUpValue(int upValue); - static LuaInstance* GetInstance(lua_State* state); + LuaInstance& operator=(LuaInstance&& instance) = default; private: - template T CheckBounds(int index, long long value) const; - bool Run(int argCount, int resultCount); + inline void SetMemoryUsage(std::size_t memoryUsage); static void* MemoryAllocator(void *ud, void *ptr, std::size_t osize, std::size_t nsize); - static int ProxyFunc(lua_State* state); - static void TimeLimiter(lua_State* state, lua_Debug* debug); + static void TimeLimiter(lua_State* internalState, lua_Debug* debug); std::size_t m_memoryLimit; std::size_t m_memoryUsage; UInt32 m_timeLimit; Clock m_clock; - String m_lastError; - lua_State* m_state; unsigned int m_level; }; } #include -#endif // NAZARA_LUASTATE_HPP +#endif // NAZARA_LUAINSTANCE_HPP diff --git a/include/Nazara/Lua/LuaInstance.inl b/include/Nazara/Lua/LuaInstance.inl index 9c54982e4..59bf8d79e 100644 --- a/include/Nazara/Lua/LuaInstance.inl +++ b/include/Nazara/Lua/LuaInstance.inl @@ -3,39 +3,10 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include -#include -#include -#include -#include -#include -#include -#include +#include namespace Nz { - inline LuaInstance::LuaInstance(LuaInstance&& instance) noexcept : - m_memoryLimit(instance.m_memoryLimit), - m_memoryUsage(instance.m_memoryUsage), - m_timeLimit(instance.m_timeLimit), - m_clock(std::move(instance.m_clock)), - m_lastError(std::move(instance.m_lastError)), - m_state(instance.m_state), - m_level(instance.m_level) - { - instance.m_state = nullptr; - } - - inline lua_State* LuaInstance::GetInternalState() const - { - return m_state; - } - - inline String LuaInstance::GetLastError() const - { - return m_lastError; - } - inline std::size_t LuaInstance::GetMemoryLimit() const { return m_memoryLimit; @@ -51,773 +22,15 @@ namespace Nz return m_timeLimit; } - inline LuaInstance& LuaInstance::operator=(LuaInstance&& instance) noexcept + inline void LuaInstance::SetMemoryLimit(std::size_t memoryLimit) { - m_clock = std::move(instance.m_clock); - m_lastError = std::move(instance.m_lastError); - m_level = instance.m_level; - m_memoryLimit = instance.m_memoryLimit; - m_memoryUsage = instance.m_memoryUsage; - m_state = instance.m_state; - m_timeLimit = instance.m_timeLimit; - - instance.m_state = nullptr; - - return *this; + m_memoryLimit = memoryLimit; } - // Functions args - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, bool* arg, TypeTag) + inline void LuaInstance::SetTimeLimit(UInt32 limit) { - *arg = instance.CheckBoolean(index); - return 1; - } - - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, bool* arg, bool defValue, TypeTag) - { - *arg = instance.CheckBoolean(index, defValue); - return 1; - } - - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, std::string* arg, TypeTag) - { - std::size_t strLength = 0; - const char* str = instance.CheckString(index, &strLength); - - arg->assign(str, strLength); - - return 1; - } - - inline unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, String* arg, TypeTag) - { - std::size_t strLength = 0; - const char* str = instance.CheckString(index, &strLength); - - arg->Set(str, strLength); - - return 1; - } - - template - std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - return LuaImplQueryArg(instance, index, reinterpret_cast(arg), TypeTag()); - } - - template - std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - return LuaImplQueryArg(instance, index, reinterpret_cast(arg), static_cast(defValue), TypeTag()); - } - - template - std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - - UnderlyingT pot2Val; - unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, TypeTag()); - - *arg = static_cast(IntegralLog2Pot(pot2Val)); - return ret; - } - - template - std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - using UnderlyingT = std::underlying_type_t; - - UnderlyingT pot2Val; - unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, 1U << static_cast(defValue), TypeTag()); - - *arg = static_cast(IntegralLog2Pot(pot2Val)); - return ret; - } - - template - unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, Flags* arg, TypeTag>) - { - *arg = Flags(instance.CheckBoundInteger(index)); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - *arg = static_cast(instance.CheckNumber(index)); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - *arg = static_cast(instance.CheckNumber(index, static_cast(defValue))); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - *arg = instance.CheckBoundInteger(index); - return 1; - } - - template - std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, T defValue, TypeTag) - { - *arg = instance.CheckBoundInteger(index, defValue); - return 1; - } - - template - std::enable_if_t::value && !std::is_enum::value && !std::is_floating_point::value, unsigned int> LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, const T& defValue, TypeTag tag) - { - if (instance.IsValid(index)) - return LuaImplQueryArg(instance, index, arg, tag); - else - { - *arg = defValue; - return 1; - } - } - - template - unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, TypeTag) - { - return LuaImplQueryArg(instance, index, arg, TypeTag()); - } - - template - unsigned int LuaImplQueryArg(const LuaInstance& instance, int index, T* arg, const T& defValue, TypeTag) - { - return LuaImplQueryArg(instance, index, arg, defValue, TypeTag()); - } - - // Function returns - inline int LuaImplReplyVal(const LuaInstance& instance, bool val, TypeTag) - { - instance.PushBoolean(val); - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, double val, TypeTag) - { - instance.PushNumber(val); - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, float val, TypeTag) - { - instance.PushNumber(val); - return 1; - } - - template - std::enable_if_t::value && !EnumAsFlags::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - using EnumT = typename std::underlying_type::type; - return LuaImplReplyVal(instance, static_cast(val), TypeTag()); - } - - template - std::enable_if_t::value && EnumAsFlags::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - Flags flags(val); - return LuaImplReplyVal(instance, flags, TypeTag()); - } - - template - int LuaImplReplyVal(const LuaInstance& instance, Flags val, TypeTag>) - { - instance.PushInteger(UInt32(val)); - return 1; - } - - template - std::enable_if_t::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - instance.PushInteger(val); - return 1; - } - - template - std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, val, TypeTag()); - } - - template - std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, val, TypeTag()); - } - - template - std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, std::move(val), TypeTag()); - } - - template - std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaInstance& instance, T val, TypeTag) - { - return LuaImplReplyVal(instance, std::move(val), TypeTag()); - } - - template - int LuaImplReplyVal(const LuaInstance& instance, T&& val, TypeTag) - { - return LuaImplReplyVal(instance, std::forward(val), TypeTag()); - } - - inline int LuaImplReplyVal(const LuaInstance& instance, std::string&& val, TypeTag) - { - instance.PushString(val.c_str(), val.size()); - return 1; - } - - template - inline int LuaImplReplyVal(const LuaInstance& instance, std::vector&& valContainer, TypeTag>) - { - std::size_t index = 1; - instance.PushTable(valContainer.size()); - for (T& val : valContainer) - { - instance.PushInteger(index++); - if (LuaImplReplyVal(instance, std::move(val), TypeTag()) != 1) - { - instance.Error("Couldn't create table: type need more than one place to store"); - return 0; - } - instance.SetTable(); - } - - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, ByteArray&& val, TypeTag) - { - instance.PushString(reinterpret_cast(val.GetConstBuffer()), val.GetSize()); - return 1; - } - - inline int LuaImplReplyVal(const LuaInstance& instance, String&& val, TypeTag) - { - instance.PushString(std::move(val)); - return 1; - } - - template - int LuaImplReplyVal(const LuaInstance& instance, std::pair&& val, TypeTag>) - { - int retVal = 0; - - retVal += LuaImplReplyVal(instance, std::move(val.first), TypeTag()); - retVal += LuaImplReplyVal(instance, std::move(val.second), TypeTag()); - - return retVal; - } - - template - struct LuaImplArgProcesser; - - template<> - struct LuaImplArgProcesser - { - template - static unsigned int Process(const LuaInstance& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) - { - return LuaImplQueryArg(instance, argIndex, &std::get(args), std::get() - N - 1>(defArgs), TypeTag()); - } - }; - - template<> - struct LuaImplArgProcesser - { - template - static unsigned int Process(const LuaInstance& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) - { - NazaraUnused(defArgs); - - return LuaImplQueryArg(instance, argIndex, &std::get(args), TypeTag()); - } - }; - - template - class LuaImplFunctionProxy - { - public: - template - class Impl - { - static constexpr std::size_t ArgCount = sizeof...(Args); - static constexpr std::size_t DefArgCount = sizeof...(DefArgs); - - static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); - - static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; - - public: - Impl(DefArgs... defArgs) : - m_defaultArgs(std::forward(defArgs)...) - { - } - - void ProcessArguments(const LuaInstance& instance) const - { - m_index = 1; - ProcessArgs<0, Args...>(instance); - } - - int Invoke(const LuaInstance& instance, void(*func)(Args...)) const - { - NazaraUnused(instance); - - Apply(func, m_args); - return 0; - } - - template - int Invoke(const LuaInstance& instance, Ret(*func)(Args...)) const - { - return LuaImplReplyVal(instance, std::move(Apply(func, m_args)), TypeTag()); - } - - private: - using ArgContainer = std::tuple>...>; - using DefArgContainer = std::tuple>...>; - - template - void ProcessArgs(const LuaInstance& instance) const - { - NazaraUnused(instance); - - // No argument to process - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - ProcessArgs(instance); - ProcessArgs(instance); - } - - mutable ArgContainer m_args; - DefArgContainer m_defaultArgs; - mutable unsigned int m_index; - }; - }; - - template - class LuaImplMethodProxy - { - public: - template - class Impl - { - static constexpr std::size_t ArgCount = sizeof...(Args); - static constexpr std::size_t DefArgCount = sizeof...(DefArgs); - - static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); - - static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; - - public: - Impl(DefArgs... defArgs) : - m_defaultArgs(std::forward(defArgs)...) - { - } - - void ProcessArguments(const LuaInstance& instance) const - { - m_index = 2; //< 1 being the instance - ProcessArgs<0, Args...>(instance); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, void(P::*func)(Args...)) const - { - NazaraUnused(instance); - - Apply(object, func, m_args); - return 0; - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, Ret(P::*func)(Args...)) const - { - return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, T& object, T&(P::*func)(Args...)) const - { - T& r = Apply(object, func, m_args); - if (&r == &object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, void(P::*func)(Args...) const) const - { - NazaraUnused(instance); - - Apply(object, func, m_args); - return 0; - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, Ret(P::*func)(Args...) const) const - { - return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::value, int> Invoke(const LuaInstance& instance, const T& object, const T&(P::*func)(Args...) const) const - { - const T& r = Apply(object, func, m_args); - if (&r == &object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, void(P::*func)(Args...)) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - Apply(*object, func, m_args); - return 0; - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, Ret(P::*func)(Args...)) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, T& object, typename PointedType::type&(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - const typename PointedType::type& r = Apply(*object, func, m_args); - if (&r == &*object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, void(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - Apply(*object, func, m_args); - return 0; - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, Ret(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); - } - - template - std::enable_if_t::type>::value, int> Invoke(const LuaInstance& instance, const T& object, const typename PointedType::type&(P::*func)(Args...) const) const - { - if (!object) - { - instance.Error("Invalid object"); - return 0; - } - - const typename PointedType::type& r = Apply(*object, func, m_args); - if (&r == &*object) - { - instance.PushValue(1); //< Userdata - return 1; - } - else - return LuaImplReplyVal(instance, r, TypeTag()); - } - - private: - using ArgContainer = std::tuple>...>; - using DefArgContainer = std::tuple>...>; - - template - void ProcessArgs(const LuaInstance& instance) const - { - NazaraUnused(instance); - - // No argument to process - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - m_index += LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); - } - - template - void ProcessArgs(const LuaInstance& instance) const - { - ProcessArgs(instance); - ProcessArgs(instance); - } - - mutable ArgContainer m_args; - DefArgContainer m_defaultArgs; - mutable unsigned int m_index; - }; - }; - - template - T LuaInstance::Check(int* index) const - { - NazaraAssert(index, "Invalid index pointer"); - - T object; - *index += LuaImplQueryArg(*this, *index, &object, TypeTag()); - - return object; - } - - template - T LuaInstance::Check(int* index, T defValue) const - { - NazaraAssert(index, "Invalid index pointer"); - - T object; - *index += LuaImplQueryArg(*this, *index, &object, defValue, TypeTag()); - - return object; - } - - template - inline T LuaInstance::CheckBoundInteger(int index) const - { - return CheckBounds(index, CheckInteger(index)); - } - - template - inline T LuaInstance::CheckBoundInteger(int index, T defValue) const - { - return CheckBounds(index, CheckInteger(index, defValue)); - } - - template - T LuaInstance::CheckField(const char* fieldName, int tableIndex) const - { - T object; - - GetField(fieldName, tableIndex); - tableIndex += LuaImplQueryArg(*this, -1, &object, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckField(const String& fieldName, int tableIndex) const - { - return CheckField(fieldName.GetConstBuffer(), tableIndex); - } - - template - T LuaInstance::CheckField(const char* fieldName, T defValue, int tableIndex) const - { - T object; - - GetField(fieldName, tableIndex); - tableIndex += LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckField(const String& fieldName, T defValue, int tableIndex) const - { - return CheckField(fieldName.GetConstBuffer(), defValue, tableIndex); - } - - template - T LuaInstance::CheckGlobal(const char* fieldName) const - { - T object; - - GetGlobal(fieldName); - LuaImplQueryArg(*this, -1, &object, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckGlobal(const String& fieldName) const - { - return CheckGlobal(fieldName.GetConstBuffer()); - } - - template - T LuaInstance::CheckGlobal(const char* fieldName, T defValue) const - { - T object; - - GetGlobal(fieldName); - LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); - Pop(); - - return object; - } - - template - T LuaInstance::CheckGlobal(const String& fieldName, T defValue) const - { - return CheckGlobal(fieldName.GetConstBuffer(), defValue); - } - - template - int LuaInstance::Push(T arg) const - { - return LuaImplReplyVal(*this, std::move(arg), TypeTag()); - } - - template - int LuaInstance::Push(T firstArg, T2 secondArg, Args... args) const - { - int valCount = 0; - valCount += Push(std::move(firstArg)); - valCount += Push(secondArg, std::forward(args)...); - - return valCount; - } - - template - void LuaInstance::PushField(const char* name, T&& arg, int tableIndex) const - { - Push(std::forward(arg)); - SetField(name, tableIndex); - } - - template - void LuaInstance::PushField(const String& name, T&& arg, int tableIndex) const - { - PushField(name.GetConstBuffer(), std::forward(arg), tableIndex); - } - - template - void LuaInstance::PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const - { - typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); - - PushFunction([func, handler] (LuaInstance& lua) -> int - { - handler.ProcessArguments(lua); - - return handler.Invoke(lua, func); - }); - } - - template - void LuaInstance::PushGlobal(const char* name, T&& arg) - { - Push(std::forward(arg)); - SetGlobal(name); - } - - template - void LuaInstance::PushGlobal(const String& name, T&& arg) - { - PushGlobal(name.GetConstBuffer(), std::forward(arg)); - } - - template - void LuaInstance::PushInstance(const char* tname, const T& instance) const - { - T* userdata = static_cast(PushUserdata(sizeof(T))); - PlacementNew(userdata, instance); - - SetMetatable(tname); - } - - template - void LuaInstance::PushInstance(const char* tname, T&& instance) const - { - T* userdata = static_cast(PushUserdata(sizeof(T))); - PlacementNew(userdata, std::move(instance)); - - SetMetatable(tname); - } - - template - void LuaInstance::PushInstance(const char* tname, Args&&... args) const - { - T* userdata = static_cast(PushUserdata(sizeof(T))); - PlacementNew(userdata, std::forward(args)...); - - SetMetatable(tname); - } - - template - T LuaInstance::CheckBounds(int index, long long value) const - { - constexpr long long minBounds = std::numeric_limits::min(); - constexpr long long maxBounds = std::numeric_limits::max(); - if (value < minBounds || value > maxBounds) - { - Nz::StringStream stream; - stream << "Argument #" << index << " is outside value range [" << minBounds << ", " << maxBounds << "] (" << value << ')'; - Error(stream); - } - - return static_cast(value); + m_timeLimit = limit; } } + +#include diff --git a/include/Nazara/Lua/LuaState.hpp b/include/Nazara/Lua/LuaState.hpp new file mode 100644 index 000000000..fe34d794a --- /dev/null +++ b/include/Nazara/Lua/LuaState.hpp @@ -0,0 +1,199 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_LUASTATE_HPP +#define NAZARA_LUASTATE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct lua_Debug; +struct lua_State; + +namespace Nz +{ + class LuaCoroutine; + class LuaInstance; + class LuaState; + + using LuaCFunction = int (*)(lua_State* internalState); + using LuaFunction = std::function; + + class NAZARA_LUA_API LuaState + { + public: + LuaState(const LuaState&) = default; + LuaState(LuaState&& instance) noexcept; + ~LuaState() = default; + + void ArgCheck(bool condition, unsigned int argNum, const char* error) const; + void ArgCheck(bool condition, unsigned int argNum, const String& error) const; + int ArgError(unsigned int argNum, const char* error) const; + int ArgError(unsigned int argNum, const String& error) const; + + bool Call(unsigned int argCount); + bool Call(unsigned int argCount, unsigned int resultCount); + + template T Check(int* index) const; + template T Check(int* index, T defValue) const; + void CheckAny(int index) const; + bool CheckBoolean(int index) const; + bool CheckBoolean(int index, bool defValue) const; + template T CheckBoundInteger(int index) const; + template T CheckBoundInteger(int index, T defValue) const; + template T CheckField(const char* fieldName, int tableIndex = -1) const; + template T CheckField(const String& fieldName, int tableIndex = -1) const; + template T CheckField(const char* fieldName, T defValue, int tableIndex = -1) const; + template T CheckField(const String& fieldName, T defValue, int tableIndex = -1) const; + long long CheckInteger(int index) const; + long long CheckInteger(int index, long long defValue) const; + template T CheckGlobal(const char* fieldName) const; + template T CheckGlobal(const String& fieldName) const; + template T CheckGlobal(const char* fieldName, T defValue) const; + template T CheckGlobal(const String& fieldName, T defValue) const; + double CheckNumber(int index) const; + double CheckNumber(int index, double defValue) const; + void CheckStack(int space, const char* error = nullptr) const; + void CheckStack(int space, const String& error) const; + const char* CheckString(int index, std::size_t* length = nullptr) const; + const char* CheckString(int index, const char* defValue, std::size_t* length = nullptr) const; + void CheckType(int index, LuaType type) const; + void* CheckUserdata(int index, const char* tname) const; + void* CheckUserdata(int index, const String& tname) const; + + bool Compare(int index1, int index2, LuaComparison comparison) const; + void Compute(LuaOperation operation) const; + + void Concatenate(int count) const; + + int CreateReference(); + void DestroyReference(int ref); + + String DumpStack() const; + + void Error(const char* message) const; + void Error(const String& message) const; + + bool Execute(const String& code); + bool ExecuteFromFile(const String& filePath); + bool ExecuteFromMemory(const void* data, std::size_t size); + bool ExecuteFromStream(Stream& stream); + + int GetAbsIndex(int index) const; + LuaType GetField(const char* fieldName, int tableIndex = -1) const; + LuaType GetField(const String& fieldName, int tableIndex = -1) const; + LuaType GetGlobal(const char* name) const; + LuaType GetGlobal(const String& name) const; + inline lua_State* GetInternalState() const; + inline String GetLastError() const; + LuaType GetMetatable(const char* tname) const; + LuaType GetMetatable(const String& tname) const; + bool GetMetatable(int index) const; + unsigned int GetStackTop() const; + LuaType GetTable(int index = -2) const; + LuaType GetTableRaw(int index = -2) const; + LuaType GetType(int index) const; + const char* GetTypeName(LuaType type) const; + + void Insert(int index) const; + + bool IsOfType(int index, LuaType type) const; + bool IsOfType(int index, const char* tname) const; + bool IsOfType(int index, const String& tname) const; + bool IsValid(int index) const; + + long long Length(int index) const; + std::size_t LengthRaw(int index) const; + + void MoveTo(LuaState* instance, int n) const; + + LuaCoroutine NewCoroutine(); + bool NewMetatable(const char* str); + bool NewMetatable(const String& str); + bool Next(int index = -2) const; + + void Pop(unsigned int n = 1U) const; + + template int Push(T arg) const; + template int Push(T firstArg, T2 secondArg, Args... args) const; + void PushBoolean(bool value) const; + void PushCFunction(LuaCFunction func, unsigned int upvalueCount = 0) const; + template void PushField(const char* name, T&& arg, int tableIndex = -2) const; + template void PushField(const String& name, T&& arg, int tableIndex = -2) const; + void PushFunction(LuaFunction func) const; + template void PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const; + template void PushGlobal(const char* name, T&& arg); + template void PushGlobal(const String& name, T&& arg); + template void PushInstance(const char* tname, const T& instance) const; + template void PushInstance(const char* tname, T&& instance) const; + template void PushInstance(const char* tname, Args&&... args) const; + void PushInteger(long long value) const; + void PushLightUserdata(void* value) const; + void PushMetatable(const char* str) const; + void PushMetatable(const String& str) const; + void PushNil() const; + void PushNumber(double value) const; + void PushReference(int ref) const; + void PushString(const char* str) const; + void PushString(const char* str, std::size_t size) const; + void PushString(const String& str) const; + void PushTable(std::size_t sequenceElementCount = 0, std::size_t arrayElementCount = 0) const; + void* PushUserdata(std::size_t size) const; + void PushValue(int index) const; + + void Remove(int index) const; + void Replace(int index) const; + + void SetField(const char* name, int tableIndex = -2) const; + void SetField(const String& name, int tableIndex = -2) const; + void SetGlobal(const char* name); + void SetGlobal(const String& name); + void SetMetatable(const char* tname) const; + void SetMetatable(const String& tname) const; + void SetMetatable(int index) const; + void SetTable(int index = -3) const; + void SetTableRaw(int index = -3) const; + + bool ToBoolean(int index) const; + long long ToInteger(int index, bool* succeeded = nullptr) const; + double ToNumber(int index, bool* succeeded = nullptr) const; + const void* ToPointer(int index) const; + const char* ToString(int index, std::size_t* length = nullptr) const; + void* ToUserdata(int index) const; + void* ToUserdata(int index, const char* tname) const; + void* ToUserdata(int index, const String& tname) const; + + LuaState& operator=(const LuaState&) = default; + LuaState& operator=(LuaState&& instance) noexcept; + + static int GetIndexOfUpValue(int upValue); + static LuaInstance& GetInstance(lua_State* internalState); + static inline LuaState GetState(lua_State* internalState); + + protected: + LuaState(lua_State* internalState); + + template std::enable_if_t::value, T> CheckBounds(int index, long long value) const; + template std::enable_if_t::value, T> CheckBounds(int index, long long value) const; + virtual bool Run(int argCount, int resultCount); + + static int ProxyFunc(lua_State* internalState); + + String m_lastError; + lua_State* m_state; + }; +} + +#include + +#endif // NAZARA_LUASTATE_HPP diff --git a/include/Nazara/Lua/LuaState.inl b/include/Nazara/Lua/LuaState.inl new file mode 100644 index 000000000..a5fa57f8c --- /dev/null +++ b/include/Nazara/Lua/LuaState.inl @@ -0,0 +1,808 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + inline LuaState::LuaState(lua_State* internalState) : + m_state(internalState) + { + } + + inline lua_State* LuaState::GetInternalState() const + { + return m_state; + } + + inline String LuaState::GetLastError() const + { + return m_lastError; + } + + // Functions args + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, bool* arg, TypeTag) + { + *arg = instance.CheckBoolean(index); + return 1; + } + + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, bool* arg, bool defValue, TypeTag) + { + *arg = instance.CheckBoolean(index, defValue); + return 1; + } + + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, std::string* arg, TypeTag) + { + std::size_t strLength = 0; + const char* str = instance.CheckString(index, &strLength); + + arg->assign(str, strLength); + + return 1; + } + + inline unsigned int LuaImplQueryArg(const LuaState& instance, int index, String* arg, TypeTag) + { + std::size_t strLength = 0; + const char* str = instance.CheckString(index, &strLength); + + arg->Set(str, strLength); + + return 1; + } + + template + std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + return LuaImplQueryArg(instance, index, reinterpret_cast(arg), TypeTag()); + } + + template + std::enable_if_t::value && !EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + return LuaImplQueryArg(instance, index, reinterpret_cast(arg), static_cast(defValue), TypeTag()); + } + + template + std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + + UnderlyingT pot2Val; + unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, TypeTag()); + + *arg = static_cast(IntegralLog2Pot(pot2Val)); + return ret; + } + + template + std::enable_if_t::value && EnumAsFlags::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + using UnderlyingT = std::underlying_type_t; + + UnderlyingT pot2Val; + unsigned int ret = LuaImplQueryArg(instance, index, &pot2Val, 1U << static_cast(defValue), TypeTag()); + + *arg = static_cast(IntegralLog2Pot(pot2Val)); + return ret; + } + + template + unsigned int LuaImplQueryArg(const LuaState& instance, int index, Flags* arg, TypeTag>) + { + *arg = Flags(instance.CheckBoundInteger(index)); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + *arg = static_cast(instance.CheckNumber(index)); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + *arg = static_cast(instance.CheckNumber(index, static_cast(defValue))); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + *arg = instance.CheckBoundInteger(index); + return 1; + } + + template + std::enable_if_t::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, T defValue, TypeTag) + { + *arg = instance.CheckBoundInteger(index, defValue); + return 1; + } + + template + std::enable_if_t::value && !std::is_enum::value && !std::is_floating_point::value, unsigned int> LuaImplQueryArg(const LuaState& instance, int index, T* arg, const T& defValue, TypeTag tag) + { + if (instance.IsValid(index)) + return LuaImplQueryArg(instance, index, arg, tag); + else + { + *arg = defValue; + return 1; + } + } + + template + unsigned int LuaImplQueryArg(const LuaState& instance, int index, T* arg, TypeTag) + { + return LuaImplQueryArg(instance, index, arg, TypeTag()); + } + + template + unsigned int LuaImplQueryArg(const LuaState& instance, int index, T* arg, const T& defValue, TypeTag) + { + return LuaImplQueryArg(instance, index, arg, defValue, TypeTag()); + } + + // Function returns + inline int LuaImplReplyVal(const LuaState& instance, bool val, TypeTag) + { + instance.PushBoolean(val); + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, double val, TypeTag) + { + instance.PushNumber(val); + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, float val, TypeTag) + { + instance.PushNumber(val); + return 1; + } + + template + std::enable_if_t::value && !EnumAsFlags::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + using EnumT = typename std::underlying_type::type; + return LuaImplReplyVal(instance, static_cast(val), TypeTag()); + } + + template + std::enable_if_t::value && EnumAsFlags::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + Flags flags(val); + return LuaImplReplyVal(instance, flags, TypeTag()); + } + + template + int LuaImplReplyVal(const LuaState& instance, Flags val, TypeTag>) + { + instance.PushInteger(UInt32(val)); + return 1; + } + + template + std::enable_if_t::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + instance.PushInteger(val); + return 1; + } + + template + std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, val, TypeTag()); + } + + template + std::enable_if_t::value || std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, val, TypeTag()); + } + + template + std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, std::move(val), TypeTag()); + } + + template + std::enable_if_t::value && !std::is_enum::value, int> LuaImplReplyVal(const LuaState& instance, T val, TypeTag) + { + return LuaImplReplyVal(instance, std::move(val), TypeTag()); + } + + template + int LuaImplReplyVal(const LuaState& instance, T&& val, TypeTag) + { + return LuaImplReplyVal(instance, std::forward(val), TypeTag()); + } + + inline int LuaImplReplyVal(const LuaState& instance, std::string&& val, TypeTag) + { + instance.PushString(val.c_str(), val.size()); + return 1; + } + + template + inline int LuaImplReplyVal(const LuaState& instance, std::vector&& valContainer, TypeTag>) + { + std::size_t index = 1; + instance.PushTable(valContainer.size()); + for (T& val : valContainer) + { + instance.PushInteger(index++); + if (LuaImplReplyVal(instance, std::move(val), TypeTag()) != 1) + { + instance.Error("Couldn't create table: type need more than one place to store"); + return 0; + } + instance.SetTable(); + } + + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, ByteArray&& val, TypeTag) + { + instance.PushString(reinterpret_cast(val.GetConstBuffer()), val.GetSize()); + return 1; + } + + inline int LuaImplReplyVal(const LuaState& instance, String&& val, TypeTag) + { + instance.PushString(std::move(val)); + return 1; + } + + template + int LuaImplReplyVal(const LuaState& instance, std::pair&& val, TypeTag>) + { + int retVal = 0; + + retVal += LuaImplReplyVal(instance, std::move(val.first), TypeTag()); + retVal += LuaImplReplyVal(instance, std::move(val.second), TypeTag()); + + return retVal; + } + + template + struct LuaImplArgProcesser; + + template<> + struct LuaImplArgProcesser + { + template + static unsigned int Process(const LuaState& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) + { + return LuaImplQueryArg(instance, argIndex, &std::get(args), std::get() - N - 1>(defArgs), TypeTag()); + } + }; + + template<> + struct LuaImplArgProcesser + { + template + static unsigned int Process(const LuaState& instance, unsigned int argIndex, ArgContainer& args, DefArgContainer& defArgs) + { + NazaraUnused(defArgs); + + return LuaImplQueryArg(instance, argIndex, &std::get(args), TypeTag()); + } + }; + + template + class LuaImplFunctionProxy + { + public: + template + class Impl + { + static constexpr std::size_t ArgCount = sizeof...(Args); + static constexpr std::size_t DefArgCount = sizeof...(DefArgs); + + static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); + + static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; + + public: + Impl(DefArgs... defArgs) : + m_defaultArgs(std::forward(defArgs)...) + { + } + + void ProcessArguments(const LuaState& instance) const + { + m_index = 1; + ProcessArgs<0, Args...>(instance); + } + + int Invoke(const LuaState& instance, void(*func)(Args...)) const + { + NazaraUnused(instance); + + Apply(func, m_args); + return 0; + } + + template + int Invoke(const LuaState& instance, Ret(*func)(Args...)) const + { + return LuaImplReplyVal(instance, std::move(Apply(func, m_args)), TypeTag()); + } + + private: + using ArgContainer = std::tuple>...>; + using DefArgContainer = std::tuple>...>; + + template + void ProcessArgs(const LuaState& instance) const + { + NazaraUnused(instance); + + // No argument to process + } + + template + void ProcessArgs(const LuaState& instance) const + { + LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); + } + + template + void ProcessArgs(const LuaState& instance) const + { + ProcessArgs(instance); + ProcessArgs(instance); + } + + mutable ArgContainer m_args; + DefArgContainer m_defaultArgs; + mutable unsigned int m_index; + }; + }; + + template + class LuaImplMethodProxy + { + public: + template + class Impl + { + static constexpr std::size_t ArgCount = sizeof...(Args); + static constexpr std::size_t DefArgCount = sizeof...(DefArgs); + + static_assert(ArgCount >= DefArgCount, "There cannot be more default arguments than argument"); + + static constexpr std::size_t FirstDefArg = ArgCount - DefArgCount; + + public: + Impl(DefArgs... defArgs) : + m_defaultArgs(std::forward(defArgs)...) + { + } + + void ProcessArguments(const LuaState& instance) const + { + m_index = 2; //< 1 being the instance + ProcessArgs<0, Args...>(instance); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, T& object, void(P::*func)(Args...)) const + { + NazaraUnused(instance); + + Apply(object, func, m_args); + return 0; + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, T& object, Ret(P::*func)(Args...)) const + { + return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, T& object, T&(P::*func)(Args...)) const + { + T& r = Apply(object, func, m_args); + if (&r == &object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, const T& object, void(P::*func)(Args...) const) const + { + NazaraUnused(instance); + + Apply(object, func, m_args); + return 0; + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, const T& object, Ret(P::*func)(Args...) const) const + { + return LuaImplReplyVal(instance, std::move(Apply(object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::value, int> Invoke(const LuaState& instance, const T& object, const T&(P::*func)(Args...) const) const + { + const T& r = Apply(object, func, m_args); + if (&r == &object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, T& object, void(P::*func)(Args...)) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + Apply(*object, func, m_args); + return 0; + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, T& object, Ret(P::*func)(Args...)) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, T& object, typename PointedType::type&(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + const typename PointedType::type& r = Apply(*object, func, m_args); + if (&r == &*object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, const T& object, void(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + Apply(*object, func, m_args); + return 0; + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, const T& object, Ret(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + return LuaImplReplyVal(instance, std::move(Apply(*object, func, m_args)), TypeTag()); + } + + template + std::enable_if_t::type>::value, int> Invoke(const LuaState& instance, const T& object, const typename PointedType::type&(P::*func)(Args...) const) const + { + if (!object) + { + instance.Error("Invalid object"); + return 0; + } + + const typename PointedType::type& r = Apply(*object, func, m_args); + if (&r == &*object) + { + instance.PushValue(1); //< Userdata + return 1; + } + else + return LuaImplReplyVal(instance, r, TypeTag()); + } + + private: + using ArgContainer = std::tuple>...>; + using DefArgContainer = std::tuple>...>; + + template + void ProcessArgs(const LuaState& instance) const + { + NazaraUnused(instance); + + // No argument to process + } + + template + void ProcessArgs(const LuaState& instance) const + { + m_index += LuaImplArgProcesser<(N >= FirstDefArg)>::template Process(instance, m_index, m_args, m_defaultArgs); + } + + template + void ProcessArgs(const LuaState& instance) const + { + ProcessArgs(instance); + ProcessArgs(instance); + } + + mutable ArgContainer m_args; + DefArgContainer m_defaultArgs; + mutable unsigned int m_index; + }; + }; + + template + T LuaState::Check(int* index) const + { + NazaraAssert(index, "Invalid index pointer"); + + T object; + *index += LuaImplQueryArg(*this, *index, &object, TypeTag()); + + return object; + } + + template + T LuaState::Check(int* index, T defValue) const + { + NazaraAssert(index, "Invalid index pointer"); + + T object; + *index += LuaImplQueryArg(*this, *index, &object, defValue, TypeTag()); + + return object; + } + + template + inline T LuaState::CheckBoundInteger(int index) const + { + return CheckBounds(index, CheckInteger(index)); + } + + template + inline T LuaState::CheckBoundInteger(int index, T defValue) const + { + return CheckBounds(index, CheckInteger(index, defValue)); + } + + template + T LuaState::CheckField(const char* fieldName, int tableIndex) const + { + T object; + + GetField(fieldName, tableIndex); + tableIndex += LuaImplQueryArg(*this, -1, &object, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckField(const String& fieldName, int tableIndex) const + { + return CheckField(fieldName.GetConstBuffer(), tableIndex); + } + + template + T LuaState::CheckField(const char* fieldName, T defValue, int tableIndex) const + { + T object; + + GetField(fieldName, tableIndex); + tableIndex += LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckField(const String& fieldName, T defValue, int tableIndex) const + { + return CheckField(fieldName.GetConstBuffer(), defValue, tableIndex); + } + + template + T LuaState::CheckGlobal(const char* fieldName) const + { + T object; + + GetGlobal(fieldName); + LuaImplQueryArg(*this, -1, &object, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckGlobal(const String& fieldName) const + { + return CheckGlobal(fieldName.GetConstBuffer()); + } + + template + T LuaState::CheckGlobal(const char* fieldName, T defValue) const + { + T object; + + GetGlobal(fieldName); + LuaImplQueryArg(*this, -1, &object, defValue, TypeTag()); + Pop(); + + return object; + } + + template + T LuaState::CheckGlobal(const String& fieldName, T defValue) const + { + return CheckGlobal(fieldName.GetConstBuffer(), defValue); + } + + template + int LuaState::Push(T arg) const + { + return LuaImplReplyVal(*this, std::move(arg), TypeTag()); + } + + template + int LuaState::Push(T firstArg, T2 secondArg, Args... args) const + { + int valCount = 0; + valCount += Push(std::move(firstArg)); + valCount += Push(secondArg, std::forward(args)...); + + return valCount; + } + + template + void LuaState::PushField(const char* name, T&& arg, int tableIndex) const + { + Push(std::forward(arg)); + SetField(name, tableIndex); + } + + template + void LuaState::PushField(const String& name, T&& arg, int tableIndex) const + { + PushField(name.GetConstBuffer(), std::forward(arg), tableIndex); + } + + template + void LuaState::PushFunction(R(*func)(Args...), DefArgs&&... defArgs) const + { + typename LuaImplFunctionProxy::template Impl handler(std::forward(defArgs)...); + + PushFunction([func, handler] (LuaState& lua) -> int + { + handler.ProcessArguments(lua); + + return handler.Invoke(lua, func); + }); + } + + template + void LuaState::PushGlobal(const char* name, T&& arg) + { + Push(std::forward(arg)); + SetGlobal(name); + } + + template + void LuaState::PushGlobal(const String& name, T&& arg) + { + PushGlobal(name.GetConstBuffer(), std::forward(arg)); + } + + template + void LuaState::PushInstance(const char* tname, const T& instance) const + { + T* userdata = static_cast(PushUserdata(sizeof(T))); + PlacementNew(userdata, instance); + + SetMetatable(tname); + } + + template + void LuaState::PushInstance(const char* tname, T&& instance) const + { + T* userdata = static_cast(PushUserdata(sizeof(T))); + PlacementNew(userdata, std::move(instance)); + + SetMetatable(tname); + } + + template + void LuaState::PushInstance(const char* tname, Args&&... args) const + { + T* userdata = static_cast(PushUserdata(sizeof(T))); + PlacementNew(userdata, std::forward(args)...); + + SetMetatable(tname); + } + + template + std::enable_if_t::value, T> LuaState::CheckBounds(int index, long long value) const + { + constexpr long long minBounds = std::numeric_limits::min(); + constexpr long long maxBounds = std::numeric_limits::max(); + if (value < minBounds || value > maxBounds) + { + Nz::StringStream stream; + stream << "Argument #" << index << " is outside value range [" << minBounds << ", " << maxBounds << "] (" << value << ')'; + Error(stream); + } + + return static_cast(value); + } + + template + std::enable_if_t::value, T> LuaState::CheckBounds(int index, long long value) const + { + unsigned long long uValue = static_cast(value); + constexpr unsigned long long minBounds = 0; + constexpr unsigned long long maxBounds = std::numeric_limits::max(); + if (uValue < minBounds || uValue > maxBounds) + { + Nz::StringStream stream; + stream << "Argument #" << index << " is outside value range [" << minBounds << ", " << maxBounds << "] (" << value << ')'; + Error(stream); + } + + return static_cast(uValue); + } + + inline LuaState LuaState::GetState(lua_State* internalState) + { + return LuaState(internalState); + } +} diff --git a/include/Nazara/Math/Algorithm.inl b/include/Nazara/Math/Algorithm.inl index 9a0eaabfb..e50385c78 100644 --- a/include/Nazara/Math/Algorithm.inl +++ b/include/Nazara/Math/Algorithm.inl @@ -97,6 +97,30 @@ namespace Nz return 0; } + + template /*constexpr*/ std::enable_if_t::value, bool> NumberEquals(T a, T b, T maxDifference) + { + T diff = std::abs(a - b); + return diff <= maxDifference; + } + + template /*constexpr*/ std::enable_if_t::value || (!std::is_integral::value && !std::is_floating_point::value), bool> NumberEquals(T a, T b, T maxDifference) + { + if (b > a) + std::swap(a, b); + + T diff = a - b; + return diff <= maxDifference; + } + + template /*constexpr*/ std::enable_if_t::value && std::is_integral::value, bool> NumberEquals(T a, T b, T maxDifference) + { + if (b > a) + std::swap(a, b); + + using UnsignedT = std::make_unsigned_t; + return static_cast(a) - static_cast(b) <= static_cast(maxDifference); + } } /*! @@ -464,7 +488,7 @@ namespace Nz template constexpr T Lerp(const T& from, const T& to, const T2& interpolation) { - return from + interpolation * (to - from); + return static_cast(from + interpolation * (to - from)); } /*! @@ -565,11 +589,7 @@ namespace Nz //TODO: Mark as constexpr when supported by all major compilers /*constexpr*/ inline bool NumberEquals(T a, T b, T maxDifference) { - if (b > a) - std::swap(a, b); - - T diff = a - b; - return diff <= maxDifference; + return Detail::NumberEquals(a, b, maxDifference); } /*! diff --git a/include/Nazara/Math/Box.hpp b/include/Nazara/Math/Box.hpp index b3f0aed2b..9434cda27 100644 --- a/include/Nazara/Math/Box.hpp +++ b/include/Nazara/Math/Box.hpp @@ -74,8 +74,8 @@ namespace Nz Box& Transform(const Matrix4& matrix, bool applyTranslation = true); Box& Translate(const Vector3& translation); - T& operator[](unsigned int i); - T operator[](unsigned int i) const; + T& operator[](std::size_t i); + T operator[](std::size_t i) const; Box operator*(T scalar) const; Box operator*(const Vector3& vec) const; diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index fb22039ba..60275b206 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -133,9 +133,9 @@ namespace Nz template bool Box::Contains(T X, T Y, T Z) const { - return X >= x && X <= x + width && - Y >= y && Y <= y + height && - Z >= z && Z <= z + depth; + return X >= x && X < x + width && + Y >= y && Y < y + height && + Z >= z && Z < z + depth; } /*! @@ -735,24 +735,15 @@ namespace Nz * \brief Returns the ith element of the box * \return A reference to the ith element of the box * - * \remark Access to index greather than 6 is undefined behavior - * \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined + * \remark Access to index greater than 6 is undefined behavior + * \remark Produce a NazaraError if you try to access to index greater than 6 with NAZARA_MATH_SAFE defined * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6 */ template - T& Box::operator[](unsigned int i) + T& Box::operator[](std::size_t i) { - #if NAZARA_MATH_SAFE - if (i >= 6) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 6)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 6, "Index out of range"); return *(&x+i); } @@ -761,24 +752,15 @@ namespace Nz * \brief Returns the ith element of the box * \return A value to the ith element of the box * - * \remark Access to index greather than 6 is undefined behavior - * \remark Produce a NazaraError if you try to acces to index greather than 6 with NAZARA_MATH_SAFE defined + * \remark Access to index greater than 6 is undefined behavior + * \remark Produce a NazaraError if you try to access to index greater than 6 with NAZARA_MATH_SAFE defined * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 6 */ template - T Box::operator[](unsigned int i) const + T Box::operator[](std::size_t i) const { - #if NAZARA_MATH_SAFE - if (i >= 6) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 6)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 6, "Index out of range"); return *(&x+i); } diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index def663ee4..553dedad8 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -481,11 +481,11 @@ namespace Nz T test = x * y + z * w; if (test > F(0.499)) // singularity at north pole - return EulerAngles(FromDegrees(F(90.0)), FromRadians(F(2.0) * std::atan2(x, w)), F(0.0)); + return EulerAngles(F(0.0), FromRadians(F(2.0) * std::atan2(x, w)), FromDegrees(F(90.0))); if (test < F(-0.499)) // singularity at south pole - return EulerAngles(FromDegrees(F(-90.0)), FromRadians(F(-2.0) * std::atan2(x, w)), F(0.0)); + return EulerAngles(F(0.0), FromRadians(F(-2.0) * std::atan2(x, w)), FromDegrees(F(-90.0))); return EulerAngles(FromRadians(std::atan2(F(2.0) * x * w - F(2.0) * y * z, F(1.0) - F(2.0) * x * x - F(2.0) * z * z)), FromRadians(std::atan2(F(2.0) * y * w - F(2.0) * x * z, F(1.0) - F(2.0) * y * y - F(2.0) * z * z)), diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index f297cddd3..9ca7f2ef5 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -64,8 +64,8 @@ namespace Nz Rect& Translate(const Vector2& translation); - T& operator[](unsigned int i); - T operator[](unsigned int i) const; + T& operator[](std::size_t i); + T operator[](std::size_t i) const; Rect operator*(T scalar) const; Rect operator*(const Vector2& vec) const; diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index 0365ebf54..f5d96c249 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -117,8 +117,8 @@ namespace Nz template bool Rect::Contains(T X, T Y) const { - return X >= x && X <= (x + width) && - Y >= y && Y <= (y + height); + return X >= x && X < (x + width) && + Y >= y && Y < (y + height); } /*! @@ -578,23 +578,14 @@ namespace Nz * \return A reference to the ith element of the rectangle * * \remark Access to index greather than 4 is undefined behavior - * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 */ template - T& Rect::operator[](unsigned int i) + T& Rect::operator[](std::size_t i) { - #if NAZARA_MATH_SAFE - if (i >= 4) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 4)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 4, "Index out of range"); return *(&x+i); } @@ -603,24 +594,15 @@ namespace Nz * \brief Returns the ith element of the rectangle * \return A value to the ith element of the rectangle * - * \remark Access to index greather than 4 is undefined behavior - * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \remark Access to index greater than 4 is undefined behavior + * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 */ template - T Rect::operator[](unsigned int i) const + T Rect::operator[](std::size_t i) const { - #if NAZARA_MATH_SAFE - if (i >= 4) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 4)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 4, "Index out of range"); return *(&x+i); } diff --git a/include/Nazara/Math/Sphere.hpp b/include/Nazara/Math/Sphere.hpp index 57d2d6765..cfa693507 100644 --- a/include/Nazara/Math/Sphere.hpp +++ b/include/Nazara/Math/Sphere.hpp @@ -60,8 +60,8 @@ namespace Nz String ToString() const; - T& operator[](unsigned int i); - T operator[](unsigned int i) const; + T& operator[](std::size_t i); + T operator[](std::size_t i) const; Sphere operator*(T scalar) const; Sphere& operator=(const Sphere& other) = default; diff --git a/include/Nazara/Math/Sphere.inl b/include/Nazara/Math/Sphere.inl index 8d803c2e0..5aede77c2 100644 --- a/include/Nazara/Math/Sphere.inl +++ b/include/Nazara/Math/Sphere.inl @@ -466,24 +466,15 @@ namespace Nz * \brief Returns the ith element of the sphere * \return A reference to the ith element of the sphere * - * \remark Access to index greather than 4 is undefined behavior - * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \remark Access to index greater than 4 is undefined behavior + * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 */ template - T& Sphere::operator[](unsigned int i) + T& Sphere::operator[](std::size_t i) { - #if NAZARA_MATH_SAFE - if (i >= 4) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 4)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 4, "Index out of range"); return *(&x+i); } @@ -492,24 +483,15 @@ namespace Nz * \brief Returns the ith element of the sphere * \return A value to the ith element of the sphere * - * \remark Access to index greather than 4 is undefined behavior - * \remark Produce a NazaraError if you try to acces to index greather than 4 with NAZARA_MATH_SAFE defined + * \remark Access to index greater than 4 is undefined behavior + * \remark Produce a NazaraError if you try to access to index greater than 4 with NAZARA_MATH_SAFE defined * \throw std::domain_error if NAZARA_MATH_SAFE is defined and one of you try to acces to index greather than 4 */ template - T Sphere::operator[](unsigned int i) const + T Sphere::operator[](std::size_t i) const { - #if NAZARA_MATH_SAFE - if (i >= 4) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 4)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 4, "Index out of range"); return *(&x+i); } diff --git a/include/Nazara/Network.hpp b/include/Nazara/Network.hpp index 41b7fce71..151bc3f52 100644 --- a/include/Nazara/Network.hpp +++ b/include/Nazara/Network.hpp @@ -32,8 +32,13 @@ #include #include #include +#include +#include +#include +#include #include #include +#include #include #include #include diff --git a/include/Nazara/Network/Algorithm.hpp b/include/Nazara/Network/Algorithm.hpp index 001d98059..2c0467e64 100644 --- a/include/Nazara/Network/Algorithm.hpp +++ b/include/Nazara/Network/Algorithm.hpp @@ -9,12 +9,23 @@ #include #include +#include #include #include +#include namespace Nz { + NAZARA_NETWORK_API const char* ErrorToString(Nz::ResolveError resolveError); + NAZARA_NETWORK_API const char* ErrorToString(Nz::SocketError socketError); + NAZARA_NETWORK_API bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port = nullptr, bool* isIPv6 = nullptr, const char** endOfRead = nullptr); + + template + std::enable_if_t::value, T> HostToNet(T value); + + template + std::enable_if_t::value, T> NetToHost(T value); } #include diff --git a/include/Nazara/Network/Algorithm.inl b/include/Nazara/Network/Algorithm.inl index 5364298d4..4cba24136 100644 --- a/include/Nazara/Network/Algorithm.inl +++ b/include/Nazara/Network/Algorithm.inl @@ -2,6 +2,31 @@ // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include +#include #include +namespace Nz +{ + template + std::enable_if_t::value, T> HostToNet(T value) + { +#ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); +#else + return value; +#endif + } + + template + std::enable_if_t::value, T> NetToHost(T value) + { +#ifdef NAZARA_LITTLE_ENDIAN + return SwapBytes(value); +#else + return value; +#endif + } +} + #include diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp new file mode 100644 index 000000000..eb5c7d6de --- /dev/null +++ b/include/Nazara/Network/ENetHost.hpp @@ -0,0 +1,166 @@ +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETHOST_HPP +#define NAZARA_ENETHOST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class NAZARA_NETWORK_API ENetHost + { + friend ENetPeer; + friend class Network; + + public: + inline ENetHost(); + ENetHost(const ENetHost&) = delete; + ENetHost(ENetHost&&) = default; + inline ~ENetHost(); + + void Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + + bool CheckEvents(ENetEvent* event); + + ENetPeer* Connect(const IpAddress& remoteAddress, std::size_t channelCount = 0, UInt32 data = 0); + ENetPeer* Connect(const String& hostName, NetProtocol protocol = NetProtocol_Any, const String& service = "http", ResolveError* error = nullptr, std::size_t channelCount = 0, UInt32 data = 0); + + inline bool Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount = 0); + bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount = 0); + bool Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount, UInt32 incomingBandwidth, UInt32 outgoingBandwidth); + void Destroy(); + + void Flush(); + + inline Nz::IpAddress GetBoundAddress() const; + inline UInt32 GetServiceTime() const; + + int Service(ENetEvent* event, UInt32 timeout); + + void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); + + ENetHost& operator=(const ENetHost&) = delete; + ENetHost& operator=(ENetHost&&) = default; + + private: + ENetPacketRef AllocatePacket(ENetPacketFlags flags); + inline ENetPacketRef AllocatePacket(ENetPacketFlags flags, NetPacket&& data); + + bool InitSocket(const IpAddress& address); + + void AddToDispatchQueue(ENetPeer* peer); + void RemoveFromDispatchQueue(ENetPeer* peer); + + bool DispatchIncomingCommands(ENetEvent* event); + + ENetPeer* HandleConnect(ENetProtocolHeader* header, ENetProtocol* command); + bool HandleIncomingCommands(ENetEvent* event); + + int ReceiveIncomingCommands(ENetEvent* event); + + void NotifyConnect(ENetPeer* peer, ENetEvent* event, bool incoming); + void NotifyDisconnect(ENetPeer*, ENetEvent* event); + + void SendAcknowledgements(ENetPeer* peer); + bool SendReliableOutgoingCommands(ENetPeer* peer); + int SendOutgoingCommands(ENetEvent* event, bool checkForTimeouts); + void SendUnreliableOutgoingCommands(ENetPeer* peer); + + void ThrottleBandwidth(); + + static std::size_t GetCommandSize(UInt8 commandNumber); + static bool Initialize(); + static void Uninitialize(); + + struct PendingIncomingPacket + { + IpAddress from; + NetPacket data; + UInt32 deliveryTime; + }; + + struct PendingOutgoingPacket + { + IpAddress to; + NetPacket data; + UInt32 deliveryTime; + }; + + std::array m_commands; + std::array m_buffers; + std::array m_packetData[2]; + std::bernoulli_distribution m_packetLossProbability; + std::size_t m_bandwidthLimitedPeers; + std::size_t m_bufferCount; + std::size_t m_channelLimit; + std::size_t m_commandCount; + std::size_t m_duplicatePeers; + std::size_t m_maximumPacketSize; + std::size_t m_maximumWaitingData; + std::size_t m_packetSize; + std::size_t m_peerCount; + std::size_t m_receivedDataLength; + std::uniform_int_distribution m_packetDelayDistribution; + std::vector m_peers; + std::vector m_pendingIncomingPackets; + std::vector m_pendingOutgoingPackets; + UInt8* m_receivedData; + Bitset m_dispatchQueue; + MemoryPool m_packetPool; + IpAddress m_address; + IpAddress m_receivedAddress; + SocketPoller m_poller; + UdpSocket m_socket; + UInt16 m_headerFlags; + UInt32 m_bandwidthThrottleEpoch; + UInt32 m_connectedPeers; + UInt32 m_mtu; + UInt32 m_randomSeed; + UInt32 m_incomingBandwidth; + UInt32 m_outgoingBandwidth; + UInt32 m_serviceTime; + UInt32 m_totalSentPackets; + UInt32 m_totalReceivedPackets; + UInt64 m_totalSentData; + UInt64 m_totalReceivedData; + bool m_continueSending; + bool m_isSimulationEnabled; + bool m_recalculateBandwidthLimits; + + static std::mt19937 s_randomGenerator; + static std::mt19937_64 s_randomGenerator64; + }; +} + +#include + +#endif // NAZARA_ENETHOST_HPP diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl new file mode 100644 index 000000000..3f35a8f39 --- /dev/null +++ b/include/Nazara/Network/ENetHost.inl @@ -0,0 +1,74 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline ENetHost::ENetHost() : + m_packetPool(sizeof(ENetPacket)), + m_isSimulationEnabled(false) + { + } + + inline ENetHost::~ENetHost() + { + Destroy(); + } + + inline bool ENetHost::Create(NetProtocol protocol, UInt16 port, std::size_t peerCount, std::size_t channelCount) + { + NazaraAssert(protocol != NetProtocol_Any, "Any protocol not supported for Listen"); //< TODO + NazaraAssert(protocol != NetProtocol_Unknown, "Invalid protocol"); + + IpAddress any; + switch (protocol) + { + case NetProtocol_Any: + case NetProtocol_Unknown: + NazaraInternalError("Invalid protocol Any at this point"); + return false; + + case NetProtocol_IPv4: + any = IpAddress::AnyIpV4; + break; + + case NetProtocol_IPv6: + any = IpAddress::AnyIpV6; + break; + } + + any.SetPort(port); + return Create(any, peerCount, channelCount); + } + + inline void ENetHost::Destroy() + { + m_poller.Clear(); + m_peers.clear(); + m_socket.Close(); + } + + inline Nz::IpAddress ENetHost::GetBoundAddress() const + { + return m_address; + } + + inline UInt32 Nz::ENetHost::GetServiceTime() const + { + return m_serviceTime; + } + + inline ENetPacketRef ENetHost::AllocatePacket(ENetPacketFlags flags, NetPacket&& data) + { + ENetPacketRef ref = AllocatePacket(flags); + ref->data = std::move(data); + + return ref; + } +} + +#include diff --git a/include/Nazara/Network/ENetPacket.hpp b/include/Nazara/Network/ENetPacket.hpp new file mode 100644 index 000000000..54b0c42c6 --- /dev/null +++ b/include/Nazara/Network/ENetPacket.hpp @@ -0,0 +1,107 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPACKET_HPP +#define NAZARA_ENETPACKET_HPP + +#include +#include + +namespace Nz +{ + enum ENetPacketFlag + { + ENetPacketFlag_Reliable, + ENetPacketFlag_Unsequenced, + ENetPacketFlag_UnreliableFragment + }; + + template<> + struct EnumAsFlags + { + static constexpr bool value = true; + static constexpr int max = ENetPacketFlag_UnreliableFragment; + }; + + using ENetPacketFlags = Flags; + + constexpr ENetPacketFlags ENetPacketFlag_Unreliable = 0; + + class MemoryPool; + + struct ENetPacket + { + MemoryPool* owner; + ENetPacketFlags flags; + NetPacket data; + std::size_t referenceCount = 0; + }; + + struct NAZARA_NETWORK_API ENetPacketRef + { + ENetPacketRef() = default; + + ENetPacketRef(ENetPacket* packet) + { + Reset(packet); + } + + ENetPacketRef(const ENetPacketRef& packet) : + ENetPacketRef() + { + Reset(packet); + } + + ENetPacketRef(ENetPacketRef&& packet) : + m_packet(packet.m_packet) + { + packet.m_packet = nullptr; + } + + ~ENetPacketRef() + { + Reset(); + } + + void Reset(ENetPacket* packet = nullptr); + + operator ENetPacket*() const + { + return m_packet; + } + + ENetPacket* operator->() const + { + return m_packet; + } + + ENetPacketRef& operator=(ENetPacket* packet) + { + Reset(packet); + + return *this; + } + + ENetPacketRef& operator=(const ENetPacketRef& packet) + { + Reset(packet); + + return *this; + } + + ENetPacketRef& operator=(ENetPacketRef&& packet) + { + m_packet = packet.m_packet; + packet.m_packet = nullptr; + + return *this; + } + + ENetPacket* m_packet = nullptr; + }; +} + +#endif // NAZARA_ENETPACKET_HPP diff --git a/include/Nazara/Network/ENetPeer.hpp b/include/Nazara/Network/ENetPeer.hpp new file mode 100644 index 000000000..4e36378a5 --- /dev/null +++ b/include/Nazara/Network/ENetPeer.hpp @@ -0,0 +1,248 @@ +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPEER_HPP +#define NAZARA_ENETPEER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class ENetHost; + + class NAZARA_NETWORK_API ENetPeer + { + friend ENetHost; + friend struct PacketRef; + + public: + inline ENetPeer(ENetHost* host, UInt16 peerId); + ENetPeer(const ENetPeer&) = delete; + ENetPeer(ENetPeer&&) = default; + ~ENetPeer() = default; + + void Disconnect(UInt32 data); + void DisconnectLater(UInt32 data); + void DisconnectNow(UInt32 data); + + inline const IpAddress& GetAddress() const; + inline UInt32 GetMtu() const; + inline UInt32 GetPacketThrottleAcceleration() const; + inline UInt32 GetPacketThrottleDeceleration() const; + inline UInt32 GetPacketThrottleInterval() const; + inline UInt16 GetPeerId() const; + inline UInt32 GetRoundTripTime() const; + inline ENetPeerState GetState() const; + + inline bool HasPendingCommands(); + + inline bool IsConnected() const; + inline bool IsSimulationEnabled() const; + + void Ping(); + + bool Receive(ENetPacketRef* packet, UInt8* channelId); + void Reset(); + + bool Send(UInt8 channelId, ENetPacketRef packetRef); + bool Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet); + + void SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay); + + void ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration); + + ENetPeer& operator=(const ENetPeer&) = delete; + ENetPeer& operator=(ENetPeer&&) = default; + + private: + void InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand); + void InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize); + + struct Acknowledgement; + struct Channel; + struct IncomingCommmand; + struct OutgoingCommand; + + inline void ChangeState(ENetPeerState state); + + bool CheckTimeouts(ENetEvent* event); + + void DispatchState(ENetPeerState state); + + void DispatchIncomingReliableCommands(Channel& channel); + void DispatchIncomingUnreliableCommands(Channel& channel); + + bool HandleAcknowledge(const ENetProtocol* command, ENetEvent* event); + bool HandleBandwidthLimit(const ENetProtocol* command); + bool HandleDisconnect(const ENetProtocol* command); + bool HandlePing(const ENetProtocol* command); + bool HandleSendFragment(const ENetProtocol* command, UInt8** data); + bool HandleSendReliable(const ENetProtocol* command, UInt8** data); + bool HandleSendUnreliable(const ENetProtocol* command, UInt8** data); + bool HandleSendUnreliableFragment(const ENetProtocol* command, UInt8** data); + bool HandleSendUnsequenced(const ENetProtocol* command, UInt8** data); + bool HandleThrottleConfigure(const ENetProtocol* command); + bool HandleVerifyConnect(const ENetProtocol* command, ENetEvent* event); + + void OnConnect(); + void OnDisconnect(); + + ENetProtocolCommand RemoveSentReliableCommand(UInt16 reliableSequenceNumber, UInt8 channelId); + void RemoveSentUnreliableCommands(); + + void ResetQueues(); + + bool QueueAcknowledgement(ENetProtocol* command, UInt16 sentTime); + IncomingCommmand* QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount); + inline void QueueOutgoingCommand(ENetProtocol& command); + void QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length); + + void SetupOutgoingCommand(OutgoingCommand& outgoingCommand); + + int Throttle(UInt32 rtt); + + struct Acknowledgement + { + ENetProtocol command; + UInt32 sentTime; + }; + + struct Channel + { + Channel() + { + incomingReliableSequenceNumber = 0; + incomingUnreliableSequenceNumber = 0; + outgoingReliableSequenceNumber = 0; + outgoingUnreliableSequenceNumber = 0; + usedReliableWindows = 0; + reliableWindows.fill(0); + } + + std::array reliableWindows; + std::list incomingReliableCommands; + std::list incomingUnreliableCommands; + UInt16 incomingReliableSequenceNumber; + UInt16 incomingUnreliableSequenceNumber; + UInt16 outgoingReliableSequenceNumber; + UInt16 outgoingUnreliableSequenceNumber; + UInt16 usedReliableWindows; + }; + + struct IncomingCommmand + { + ENetProtocol command; + Bitset<> fragments; + ENetPacketRef packet; + UInt16 reliableSequenceNumber; + UInt16 unreliableSequenceNumber; + UInt32 fragmentsRemaining; + }; + + struct OutgoingCommand + { + ENetProtocol command; + ENetPacketRef packet; + UInt16 fragmentLength; + UInt16 reliableSequenceNumber; + UInt16 sendAttempts; + UInt16 unreliableSequenceNumber; + UInt32 fragmentOffset; + UInt32 roundTripTimeout; + UInt32 roundTripTimeoutLimit; + UInt32 sentTime; + }; + + static constexpr std::size_t unsequencedWindow = ENetPeer_ReliableWindowSize / 32; + + ENetHost* m_host; + IpAddress m_address; /**< Internet address of the peer */ + std::array m_unsequencedWindow; + std::bernoulli_distribution m_packetLossProbability; + std::list m_dispatchedCommands; + std::list m_outgoingReliableCommands; + std::list m_outgoingUnreliableCommands; + std::list m_sentReliableCommands; + std::list m_sentUnreliableCommands; + std::size_t m_totalWaitingData; + std::uniform_int_distribution m_packetDelayDistribution; + std::vector m_acknowledgements; + std::vector m_channels; + ENetPeerState m_state; + UInt8 m_incomingSessionID; + UInt8 m_outgoingSessionID; + UInt16 m_incomingPeerID; + UInt16 m_incomingUnsequencedGroup; + UInt16 m_outgoingPeerID; + UInt16 m_outgoingReliableSequenceNumber; + UInt16 m_outgoingUnsequencedGroup; + UInt32 m_connectID; + UInt32 m_earliestTimeout; + UInt32 m_eventData; + UInt32 m_highestRoundTripTimeVariance; + UInt32 m_incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + UInt32 m_incomingBandwidthThrottleEpoch; + UInt32 m_incomingDataTotal; + UInt32 m_lastReceiveTime; + UInt32 m_lastRoundTripTime; + UInt32 m_lastRoundTripTimeVariance; + UInt32 m_lastSendTime; + UInt32 m_lowestRoundTripTime; + UInt32 m_mtu; + UInt32 m_nextTimeout; + UInt32 m_outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + UInt32 m_outgoingBandwidthThrottleEpoch; + UInt32 m_outgoingDataTotal; + UInt32 m_packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + UInt32 m_packetLossEpoch; + UInt32 m_packetLossVariance; + UInt32 m_packetThrottle; + UInt32 m_packetThrottleAcceleration; + UInt32 m_packetThrottleCounter; + UInt32 m_packetThrottleDeceleration; + UInt32 m_packetThrottleEpoch; + UInt32 m_packetThrottleInterval; + UInt32 m_packetThrottleLimit; + UInt32 m_packetsLost; + UInt32 m_packetsSent; + UInt32 m_pingInterval; + UInt32 m_reliableDataInTransit; + UInt32 m_roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgment */ + UInt32 m_roundTripTimeVariance; + UInt32 m_timeoutLimit; + UInt32 m_timeoutMaximum; + UInt32 m_timeoutMinimum; + UInt32 m_windowSize; + UInt64 m_totalPacketLost; + UInt64 m_totalPacketSent; + bool m_isSimulationEnabled; + }; +} + +#include + +#endif // NAZARA_ENETPEER_HPP diff --git a/include/Nazara/Network/ENetPeer.inl b/include/Nazara/Network/ENetPeer.inl new file mode 100644 index 000000000..d831b4d0d --- /dev/null +++ b/include/Nazara/Network/ENetPeer.inl @@ -0,0 +1,92 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + inline ENetPeer::ENetPeer(ENetHost* host, UInt16 peerId) : + m_host(host), + m_incomingSessionID(0xFF), + m_outgoingSessionID(0xFF), + m_incomingPeerID(peerId), + m_isSimulationEnabled(false) + { + Reset(); + } + + inline const IpAddress& ENetPeer::GetAddress() const + { + return m_address; + } + + inline UInt32 ENetPeer::GetMtu() const + { + return m_mtu; + } + + inline UInt32 ENetPeer::GetPacketThrottleAcceleration() const + { + return m_packetThrottleAcceleration; + } + + inline UInt32 ENetPeer::GetPacketThrottleDeceleration() const + { + return m_packetThrottleDeceleration; + } + + inline UInt32 ENetPeer::GetPacketThrottleInterval() const + { + return m_packetThrottleInterval; + } + + inline UInt16 ENetPeer::GetPeerId() const + { + return m_incomingPeerID; + } + + inline UInt32 ENetPeer::GetRoundTripTime() const + { + return m_roundTripTime; + } + + inline ENetPeerState ENetPeer::GetState() const + { + return m_state; + } + + inline bool ENetPeer::HasPendingCommands() + { + return m_outgoingReliableCommands.empty() && m_outgoingUnreliableCommands.empty() && m_sentReliableCommands.empty(); + } + + inline bool ENetPeer::IsConnected() const + { + return m_state == ENetPeerState::Connected || m_state == ENetPeerState::DisconnectLater; + } + + inline bool ENetPeer::IsSimulationEnabled() const + { + return m_isSimulationEnabled; + } + + inline void ENetPeer::ChangeState(ENetPeerState state) + { + if (state == ENetPeerState::Connected || state == ENetPeerState::DisconnectLater) + OnConnect(); + else + OnDisconnect(); + + m_state = state; + } + + inline void ENetPeer::QueueOutgoingCommand(ENetProtocol& command) + { + QueueOutgoingCommand(command, ENetPacketRef(), 0, 0); + } +} + +#include diff --git a/include/Nazara/Network/ENetProtocol.hpp b/include/Nazara/Network/ENetProtocol.hpp new file mode 100644 index 000000000..dab014aa2 --- /dev/null +++ b/include/Nazara/Network/ENetProtocol.hpp @@ -0,0 +1,311 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENETPROTOCOL_HPP +#define NAZARA_ENETPROTOCOL_HPP + +#include +#include +#include + +namespace Nz +{ + constexpr UInt32 ENetTimeOverflow = 24 * 60 * 60 * 1000; + + inline UInt32 ENetTimeDifference(UInt32 a, UInt32 b); + inline bool ENetTimeLess(UInt32 a, UInt32 b); + inline bool ENetTimeLessEqual(UInt32 a, UInt32 b); + inline bool ENetTimeGreater(UInt32 a, UInt32 b); + inline bool ENetTimeGreaterEqual(UInt32 a, UInt32 b); + + class ENetPeer; + + // Constants for the ENet implementation and protocol + enum ENetConstants + { + ENetHost_BandwidthThrottleInterval = 1000, + ENetHost_DefaultMaximumPacketSize = 32 * 1024 * 1024, + ENetHost_DefaultMaximumWaitingData = 32 * 1024 * 1024, + ENetHost_DefaultMTU = 1400, + ENetHost_ReceiveBufferSize = 256 * 1024, + ENetHost_SendBufferSize = 256 * 1024, + + ENetPeer_DefaultPacketThrottle = 32, + ENetPeer_DefaultRoundTripTime = 500, + ENetPeer_FreeReliableWindows = 8, + ENetPeer_FreeUnsequencedWindows = 32, + ENetPeer_PacketLossInterval = 10000, + ENetPeer_PacketLossScale = (1 << 16), + ENetPeer_PacketThrottleAcceleration = 2, + ENetPeer_PacketThrottleCounter = 7, + ENetPeer_PacketThrottleDeceleration = 2, + ENetPeer_PacketThrottleInterval = 5000, + ENetPeer_PacketThrottleScale = 32, + ENetPeer_PingInterval = 500, + ENetPeer_ReliableWindows = 16, + ENetPeer_ReliableWindowSize = 0x1000, + ENetPeer_TimeoutLimit = 32, + ENetPeer_TimeoutMaximum = 30000, + ENetPeer_TimeoutMinimum = 5000, + ENetPeer_UnsequencedWindows = 64, + ENetPeer_UnsequencedWindowSize = 1024, + ENetPeer_WindowSizeScale = 64 * 1024, + + ENetProtocol_MaximumChannelCount = 255, + ENetProtocol_MaximumFragmentCount = 1024 * 1024, + ENetProtocol_MaximumMTU = 4096, + ENetProtocol_MaximumPacketCommands = 32, + ENetProtocol_MaximumPeerId = 0xFFF, + ENetProtocol_MaximumWindowSize = 65536, + ENetProtocol_MinimumChannelCount = 1, + ENetProtocol_MinimumMTU = 576, + ENetProtocol_MinimumWindowSize = 4096 + }; + + enum class ENetPeerState + { + AcknowledgingConnect = 2, + AcknowledgingDisconnect = 8, + Connecting = 1, + ConnectionPending = 3, + ConnectionSucceeded = 4, + Connected = 5, + Disconnected = 0, + Disconnecting = 7, + DisconnectLater = 6, + Zombie = 9 + }; + + enum ENetProtocolCommand + { + // Keeping the values is important for compatibility with the native ENet protocol + ENetProtocolCommand_Acknowledge = 1, + ENetProtocolCommand_BandwidthLimit = 10, + ENetProtocolCommand_Connect = 2, + ENetProtocolCommand_Disconnect = 4, + ENetProtocolCommand_None = 0, + ENetProtocolCommand_Ping = 5, + ENetProtocolCommand_SendFragment = 8, + ENetProtocolCommand_SendReliable = 6, + ENetProtocolCommand_SendUnreliable = 7, + ENetProtocolCommand_SendUnreliableFragment = 12, + ENetProtocolCommand_SendUnsequenced = 9, + ENetProtocolCommand_ThrottleConfigure = 11, + ENetProtocolCommand_VerifyConnect = 3, + ENetProtocolCommand_Count = 13, + + ENetProtocolCommand_Mask = 0x0F + }; + + enum ENetProtocolFlag + { + ENetProtocolFlag_Acknowledge = (1 << 7), + ENetProtocolFlag_Unsequenced = (1 << 6), + + ENetProtocolHeaderFlag_Compressed = (1 << 14), + ENetProtocolHeaderFlag_SentTime = (1 << 15), + ENetProtocolHeaderFlag_Mask = ENetProtocolHeaderFlag_Compressed | ENetProtocolHeaderFlag_SentTime, + + ENetProtocolHeaderSessionMask = (3 << 12), + ENetProtocolHeaderSessionShift = 12 + }; + + enum class ENetEventType + { + /** no event occurred within the specified time limit */ + None, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_peer_disconnect, if + * a peer has timed out, or if a connection request initialized by + * enet_host_connect has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + Disconnect, + + /** a connection request initiated by enet_host_connect from this host has completed. + * The peer field contains the peer which successfully connected. + */ + OutgoingConnect, + + /** a connection request initiated by enet_host_connect from another host has completed. + * The peer field contains the peer which successfully connected. + */ + IncomingConnect, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; + */ + Receive + }; + + struct ENetEvent + { + ENetEventType type; + ENetPeer* peer; + UInt8 channelId; + UInt32 data; + ENetPacketRef packet; + }; + + + #ifdef _MSC_VER + #pragma pack(push, 1) + #define NAZARA_PACKED + #elif defined(__GNUC__) || defined(__clang__) + #define NAZARA_PACKED __attribute__ ((packed)) + #else + #define NAZARA_PACKED + #endif + + + struct NAZARA_PACKED ENetProtocolHeader + { + UInt16 peerID; + UInt16 sentTime; + }; + + struct NAZARA_PACKED ENetProtocolCommandHeader + { + UInt8 command; + UInt8 channelID; + UInt16 reliableSequenceNumber; + }; + + struct NAZARA_PACKED ENetProtocolAcknowledge + { + ENetProtocolCommandHeader header; + UInt16 receivedReliableSequenceNumber; + UInt16 receivedSentTime; + }; + + struct NAZARA_PACKED ENetProtocolConnect + { + ENetProtocolCommandHeader header; + UInt16 outgoingPeerID; + UInt8 incomingSessionID; + UInt8 outgoingSessionID; + UInt32 mtu; + UInt32 windowSize; + UInt32 channelCount; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + UInt32 connectID; + UInt32 data; + }; + + struct NAZARA_PACKED ENetProtocolBandwidthLimit + { + ENetProtocolCommandHeader header; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + }; + + struct NAZARA_PACKED ENetProtocolDisconnect + { + ENetProtocolCommandHeader header; + UInt32 data; + }; + + struct NAZARA_PACKED ENetProtocolPing + { + ENetProtocolCommandHeader header; + }; + + struct NAZARA_PACKED ENetProtocolSendFragment + { + ENetProtocolCommandHeader header; + UInt16 startSequenceNumber; + UInt16 dataLength; + UInt32 fragmentCount; + UInt32 fragmentNumber; + UInt32 totalLength; + UInt32 fragmentOffset; + }; + + struct NAZARA_PACKED ENetProtocolSendReliable + { + ENetProtocolCommandHeader header; + UInt16 dataLength; + }; + + struct NAZARA_PACKED ENetProtocolSendUnreliable + { + ENetProtocolCommandHeader header; + UInt16 unreliableSequenceNumber; + UInt16 dataLength; + }; + + struct NAZARA_PACKED ENetProtocolSendUnsequenced + { + ENetProtocolCommandHeader header; + UInt16 unsequencedGroup; + UInt16 dataLength; + }; + + struct NAZARA_PACKED ENetProtocolThrottleConfigure + { + ENetProtocolCommandHeader header; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + }; + + struct NAZARA_PACKED ENetProtocolVerifyConnect + { + ENetProtocolCommandHeader header; + UInt16 outgoingPeerID; + UInt8 incomingSessionID; + UInt8 outgoingSessionID; + UInt32 mtu; + UInt32 windowSize; + UInt32 channelCount; + UInt32 incomingBandwidth; + UInt32 outgoingBandwidth; + UInt32 packetThrottleInterval; + UInt32 packetThrottleAcceleration; + UInt32 packetThrottleDeceleration; + UInt32 connectID; + }; + + union NAZARA_PACKED ENetProtocol + { + ENetProtocol() = default; + + ENetProtocol(UInt8 command, UInt8 channel) + { + header.command = command; + header.channelID = channel; + } + + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolConnect connect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolThrottleConfigure throttleConfigure; + ENetProtocolVerifyConnect verifyConnect; + }; + + #ifdef _MSC_VER + #pragma pack(pop) + #endif +} + +#include + +#endif // NAZARA_ENETPROTOCOL_HPP diff --git a/include/Nazara/Network/ENetProtocol.inl b/include/Nazara/Network/ENetProtocol.inl new file mode 100644 index 000000000..b854f26c8 --- /dev/null +++ b/include/Nazara/Network/ENetProtocol.inl @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + UInt32 ENetTimeDifference(UInt32 a, UInt32 b) + { + return (ENetTimeLess(a, b)) ? b - a : a - b; + } + + bool ENetTimeLess(UInt32 a, UInt32 b) + { + return (a - b >= ENetTimeOverflow); + } + + bool ENetTimeLessEqual(UInt32 a, UInt32 b) + { + return !ENetTimeGreater(a, b); + } + + bool ENetTimeGreater(UInt32 a, UInt32 b) + { + return ENetTimeLess(b, a); + } + + bool ENetTimeGreaterEqual(UInt32 a, UInt32 b) + { + return !ENetTimeLess(a, b); + } +} diff --git a/include/Nazara/Network/Enums.hpp b/include/Nazara/Network/Enums.hpp index f80ba6cd9..39bce0dd0 100644 --- a/include/Nazara/Network/Enums.hpp +++ b/include/Nazara/Network/Enums.hpp @@ -7,7 +7,7 @@ #ifndef NAZARA_ENUMS_NETWORK_HPP #define NAZARA_ENUMS_NETWORK_HPP -#include +#include namespace Nz { @@ -91,6 +91,23 @@ namespace Nz SocketError_Max = SocketError_UnreachableHost }; + enum SocketPollEvent + { + SocketPollEvent_Read, //< One or more sockets is ready for a read operation + SocketPollEvent_Write, //< One or more sockets is ready for a write operation + + SocketPollEvent_Max = SocketPollEvent_Write + }; + + template<> + struct EnumAsFlags + { + static constexpr bool value = true; + static constexpr int max = SocketPollEvent_Max; + }; + + using SocketPollEventFlags = Flags; + enum SocketState { SocketState_Bound, //< The socket is currently bound diff --git a/include/Nazara/Network/IpAddress.hpp b/include/Nazara/Network/IpAddress.hpp index c3775effd..f5e1ca9d8 100644 --- a/include/Nazara/Network/IpAddress.hpp +++ b/include/Nazara/Network/IpAddress.hpp @@ -50,7 +50,7 @@ namespace Nz String ToString() const; inline UInt32 ToUInt32() const; - inline operator bool() const; + inline explicit operator bool() const; IpAddress& operator=(const IpAddress&) = default; IpAddress& operator=(IpAddress&&) = default; diff --git a/include/Nazara/Network/NetPacket.inl b/include/Nazara/Network/NetPacket.inl index 6d55831d4..eb68d1e53 100644 --- a/include/Nazara/Network/NetPacket.inl +++ b/include/Nazara/Network/NetPacket.inl @@ -155,7 +155,9 @@ namespace Nz { InitStream(HeaderSize + size, HeaderSize, OpenMode_ReadOnly); m_buffer->Resize(HeaderSize + size); - std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); + + if (ptr) + std::memcpy(m_buffer->GetBuffer() + HeaderSize, ptr, size); m_netCode = netCode; } diff --git a/include/Nazara/Network/SocketPoller.hpp b/include/Nazara/Network/SocketPoller.hpp index 74f90c17f..5b583fa0f 100644 --- a/include/Nazara/Network/SocketPoller.hpp +++ b/include/Nazara/Network/SocketPoller.hpp @@ -24,13 +24,14 @@ namespace Nz void Clear(); - bool IsReady(const AbstractSocket& socket) const; + bool IsReadyToRead(const AbstractSocket& socket) const; + bool IsReadyToWrite(const AbstractSocket& socket) const; bool IsRegistered(const AbstractSocket& socket) const; - bool RegisterSocket(AbstractSocket& socket); + bool RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags); void UnregisterSocket(AbstractSocket& socket); - bool Wait(UInt64 msTimeout); + bool Wait(int msTimeout); inline SocketPoller& operator=(SocketPoller&& socketPoller); @@ -41,4 +42,4 @@ namespace Nz #include -#endif // NAZARA_SOCKETPOLLER_HPP \ No newline at end of file +#endif // NAZARA_SOCKETPOLLER_HPP diff --git a/include/Nazara/Network/UdpSocket.hpp b/include/Nazara/Network/UdpSocket.hpp index 04ca41db0..2934758aa 100644 --- a/include/Nazara/Network/UdpSocket.hpp +++ b/include/Nazara/Network/UdpSocket.hpp @@ -33,13 +33,13 @@ namespace Nz inline IpAddress GetBoundAddress() const; inline UInt16 GetBoundPort() const; - inline SocketState GetState() const; inline bool IsBroadcastingEnabled() const; std::size_t QueryMaxDatagramSize(); bool Receive(void* buffer, std::size_t size, IpAddress* from, std::size_t* received); + bool ReceiveMultiple(NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, std::size_t* received); bool ReceivePacket(NetPacket* packet, IpAddress* from); bool Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent); diff --git a/include/Nazara/Network/UdpSocket.inl b/include/Nazara/Network/UdpSocket.inl index 3e4dee4df..2925c1935 100644 --- a/include/Nazara/Network/UdpSocket.inl +++ b/include/Nazara/Network/UdpSocket.inl @@ -103,16 +103,6 @@ namespace Nz return m_boundAddress.GetPort(); } - /*! - * \brief Gets the state of the socket - * \return State of the socket - */ - - inline SocketState UdpSocket::GetState() const - { - return m_state; - } - /*! * \brief Checks whether the broadcasting is enabled * \return true If it is the case diff --git a/include/Nazara/Noise/MixerBase.hpp b/include/Nazara/Noise/MixerBase.hpp index 61df26543..954932114 100644 --- a/include/Nazara/Noise/MixerBase.hpp +++ b/include/Nazara/Noise/MixerBase.hpp @@ -15,7 +15,7 @@ namespace Nz { public: MixerBase(); - ~MixerBase() = default; + virtual ~MixerBase() = default; virtual float Get(float x, float y, float scale) const = 0; virtual float Get(float x, float y, float z, float scale) const = 0; diff --git a/include/Nazara/Noise/NoiseBase.hpp b/include/Nazara/Noise/NoiseBase.hpp index cdf068083..dc57a6e40 100644 --- a/include/Nazara/Noise/NoiseBase.hpp +++ b/include/Nazara/Noise/NoiseBase.hpp @@ -19,7 +19,7 @@ namespace Nz { public: NoiseBase(unsigned int seed = 0); - ~NoiseBase() = default; + virtual ~NoiseBase() = default; virtual float Get(float x, float y, float scale) const = 0; virtual float Get(float x, float y, float z, float scale) const = 0; diff --git a/include/Nazara/Physics2D/Collider2D.hpp b/include/Nazara/Physics2D/Collider2D.hpp index 610d1a00f..06d55300b 100644 --- a/include/Nazara/Physics2D/Collider2D.hpp +++ b/include/Nazara/Physics2D/Collider2D.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -33,17 +34,31 @@ namespace Nz { friend Collider2DLibrary; friend RigidBody2D; + friend class CompoundCollider2D; //< See CompoundCollider2D::CreateShapes public: - Collider2D() = default; + inline Collider2D(); Collider2D(const Collider2D&) = delete; Collider2D(Collider2D&&) = delete; virtual ~Collider2D(); - virtual float ComputeInertialMatrix(float mass) const = 0; + virtual float ComputeMomentOfInertia(float mass) const = 0; + + inline Nz::UInt32 GetCategoryMask() const; + inline Nz::UInt32 GetCollisionGroup() const; + inline unsigned int GetCollisionId() const; + inline Nz::UInt32 GetCollisionMask() const; virtual ColliderType2D GetType() const = 0; + inline bool IsTrigger() const; + + inline void SetCategoryMask(Nz::UInt32 categoryMask); + inline void SetCollisionGroup(Nz::UInt32 groupId); + inline void SetCollisionId(unsigned int typeId); + inline void SetCollisionMask(Nz::UInt32 mask); + inline void SetTrigger(bool trigger); + Collider2D& operator=(const Collider2D&) = delete; Collider2D& operator=(Collider2D&&) = delete; @@ -51,7 +66,16 @@ namespace Nz NazaraSignal(OnColliderRelease, const Collider2D* /*collider*/); protected: - virtual std::vector CreateShapes(RigidBody2D* body) const = 0; + virtual void CreateShapes(RigidBody2D* body, std::vector& shapes) const = 0; + + bool m_trigger; + Nz::UInt32 m_categoryMask; + Nz::UInt32 m_collisionGroup; + unsigned int m_collisionId; + Nz::UInt32 m_collisionMask; + + private: + virtual std::vector GenerateShapes(RigidBody2D* body) const; static Collider2DLibrary::LibraryMap s_library; }; @@ -67,7 +91,7 @@ namespace Nz BoxCollider2D(const Vector2f& size, float radius = 0.f); BoxCollider2D(const Rectf& rect, float radius = 0.f); - float ComputeInertialMatrix(float mass) const override; + float ComputeMomentOfInertia(float mass) const override; inline const Rectf& GetRect() const; inline Vector2f GetSize() const; @@ -76,7 +100,7 @@ namespace Nz template static BoxCollider2DRef New(Args&&... args); private: - std::vector CreateShapes(RigidBody2D* body) const override; + void CreateShapes(RigidBody2D* body, std::vector& shapes) const override; Rectf m_rect; float m_radius; @@ -92,7 +116,7 @@ namespace Nz public: CircleCollider2D(float radius, const Vector2f& offset = Vector2f::Zero()); - float ComputeInertialMatrix(float mass) const override; + float ComputeMomentOfInertia(float mass) const override; inline float GetRadius() const; ColliderType2D GetType() const override; @@ -100,12 +124,58 @@ namespace Nz template static CircleCollider2DRef New(Args&&... args); private: - std::vector CreateShapes(RigidBody2D* body) const override; + void CreateShapes(RigidBody2D* body, std::vector& shapes) const override; Vector2f m_offset; float m_radius; }; + class CompoundCollider2D; + + using CompoundCollider2DConstRef = ObjectRef; + using CompoundCollider2DRef = ObjectRef; + + class NAZARA_PHYSICS2D_API CompoundCollider2D : public Collider2D + { + public: + CompoundCollider2D(std::vector geoms); + + float ComputeMomentOfInertia(float mass) const override; + + inline const std::vector& GetGeoms() const; + ColliderType2D GetType() const override; + + template static CompoundCollider2DRef New(Args&&... args); + + private: + void CreateShapes(RigidBody2D* body, std::vector& shapes) const override; + + std::vector m_geoms; + }; + + class ConvexCollider2D; + + using ConvexCollider2DConstRef = ObjectRef; + using ConvexCollider2DRef = ObjectRef; + + class NAZARA_PHYSICS2D_API ConvexCollider2D : public Collider2D + { + public: + ConvexCollider2D(SparsePtr vertices, std::size_t vertexCount, float radius = 0.f); + + float ComputeMomentOfInertia(float mass) const override; + + ColliderType2D GetType() const override; + + template static ConvexCollider2DRef New(Args&&... args); + + private: + void CreateShapes(RigidBody2D* body, std::vector& shapes) const override; + + std::vector m_vertices; + float m_radius; + }; + class NullCollider2D; using NullCollider2DConstRef = ObjectRef; @@ -116,14 +186,14 @@ namespace Nz public: NullCollider2D() = default; - float ComputeInertialMatrix(float mass) const override; + float ComputeMomentOfInertia(float mass) const override; ColliderType2D GetType() const override; template static NullCollider2DRef New(Args&&... args); private: - std::vector CreateShapes(RigidBody2D* body) const override; + void CreateShapes(RigidBody2D* body, std::vector& shapes) const override; }; class SegmentCollider2D; @@ -136,7 +206,7 @@ namespace Nz public: inline SegmentCollider2D(const Vector2f& first, const Vector2f& second, float thickness = 1.f); - float ComputeInertialMatrix(float mass) const override; + float ComputeMomentOfInertia(float mass) const override; inline const Vector2f& GetFirstPoint() const; inline float GetLength() const; @@ -146,7 +216,7 @@ namespace Nz template static SegmentCollider2DRef New(Args&&... args); private: - std::vector CreateShapes(RigidBody2D* body) const override; + void CreateShapes(RigidBody2D* body, std::vector& shapes) const override; Vector2f m_first; Vector2f m_second; diff --git a/include/Nazara/Physics2D/Collider2D.inl b/include/Nazara/Physics2D/Collider2D.inl index f5b222875..d41537a7c 100644 --- a/include/Nazara/Physics2D/Collider2D.inl +++ b/include/Nazara/Physics2D/Collider2D.inl @@ -2,11 +2,71 @@ // This file is part of the "Nazara Engine - Physics 2D module" // For conditions of distribution and use, see copyright notice in Config.hpp +#include #include #include namespace Nz { + inline Collider2D::Collider2D() : + m_trigger(false), + m_categoryMask(0xFFFFFFFF), + m_collisionGroup(0), + m_collisionId(0), + m_collisionMask(0xFFFFFFFF) + { + } + + inline Nz::UInt32 Collider2D::GetCategoryMask() const + { + return m_categoryMask; + } + + inline Nz::UInt32 Collider2D::GetCollisionGroup() const + { + return m_collisionGroup; + } + + inline unsigned int Collider2D::GetCollisionId() const + { + return m_collisionId; + } + + inline Nz::UInt32 Collider2D::GetCollisionMask() const + { + return m_collisionMask; + } + + inline bool Collider2D::IsTrigger() const + { + return m_trigger; + } + + inline void Collider2D::SetCategoryMask(Nz::UInt32 categoryMask) + { + m_categoryMask = categoryMask; + } + + inline void Collider2D::SetCollisionGroup(Nz::UInt32 groupId) + { + m_collisionGroup = groupId; + } + + inline void Collider2D::SetCollisionId(unsigned int typeId) + { + m_collisionId = typeId; + } + + inline void Collider2D::SetCollisionMask(Nz::UInt32 mask) + { + m_collisionMask = mask; + } + + inline void Collider2D::SetTrigger(bool trigger) + { + m_trigger = trigger; + } + inline const Rectf& BoxCollider2D::GetRect() const { return m_rect; @@ -40,6 +100,29 @@ namespace Nz return object.release(); } + inline const std::vector& Nz::CompoundCollider2D::GetGeoms() const + { + return m_geoms; + } + + template + CompoundCollider2DRef CompoundCollider2D::New(Args&&... args) + { + std::unique_ptr object(new CompoundCollider2D(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); + } + + template + ConvexCollider2DRef ConvexCollider2D::New(Args&&... args) + { + std::unique_ptr object(new ConvexCollider2D(std::forward(args)...)); + object->SetPersistent(false); + + return object.release(); + } + template NullCollider2DRef NullCollider2D::New(Args&&... args) { diff --git a/include/Nazara/Physics2D/Enums.hpp b/include/Nazara/Physics2D/Enums.hpp index 86c1411f4..8cbb73d39 100644 --- a/include/Nazara/Physics2D/Enums.hpp +++ b/include/Nazara/Physics2D/Enums.hpp @@ -12,6 +12,7 @@ namespace Nz enum ColliderType2D { ColliderType2D_Box, + ColliderType2D_Compound, ColliderType2D_Convex, ColliderType2D_Circle, ColliderType2D_Null, diff --git a/include/Nazara/Physics2D/PhysWorld2D.hpp b/include/Nazara/Physics2D/PhysWorld2D.hpp index c2ffb437c..36a0c5c42 100644 --- a/include/Nazara/Physics2D/PhysWorld2D.hpp +++ b/include/Nazara/Physics2D/PhysWorld2D.hpp @@ -8,16 +8,33 @@ #define NAZARA_PHYSWORLD2D_HPP #include +#include #include #include +#include +#include +#include +#include +struct cpCollisionHandler; struct cpSpace; namespace Nz { class NAZARA_PHYSICS2D_API PhysWorld2D { + friend RigidBody2D; + + using ContactEndCallback = std::function; + using ContactPreSolveCallback = std::function; + using ContactPostSolveCallback = std::function; + using ContactStartCallback = std::function; + public: + struct Callback; + struct NearestQueryResult; + struct RaycastHit; + PhysWorld2D(); PhysWorld2D(const PhysWorld2D&) = delete; PhysWorld2D(PhysWorld2D&&) = delete; ///TODO @@ -27,8 +44,18 @@ namespace Nz cpSpace* GetHandle() const; float GetStepSize() const; + bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody = nullptr); + bool NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result); + + bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos); + bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr); + + void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies); + + void RegisterCallbacks(unsigned int collisionId, const Callback& callbacks); + void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks); + void SetGravity(const Vector2f& gravity); - void SetSolverModel(unsigned int model); void SetStepSize(float stepSize); void Step(float timestep); @@ -36,7 +63,56 @@ namespace Nz PhysWorld2D& operator=(const PhysWorld2D&) = delete; PhysWorld2D& operator=(PhysWorld2D&&) = delete; ///TODO + struct Callback + { + ContactEndCallback endCallback = nullptr; + ContactPreSolveCallback preSolveCallback = nullptr; + ContactPostSolveCallback postSolveCallback = nullptr; + ContactStartCallback startCallback = nullptr; + void* userdata; + }; + + struct NearestQueryResult + { + Nz::RigidBody2D* nearestBody; + Nz::Vector2f closestPoint; + Nz::Vector2f fraction; + float distance; + }; + + struct RaycastHit + { + Nz::RigidBody2D* nearestBody; + Nz::Vector2f hitPos; + Nz::Vector2f hitNormal; + float fraction; + }; + + NazaraSignal(OnPhysWorld2DPreStep, const PhysWorld2D* /*physWorld*/); + NazaraSignal(OnPhysWorld2DPostStep, const PhysWorld2D* /*physWorld*/); + private: + void InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks); + + using PostStep = std::function; + + void OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer); + void OnRigidBodyRelease(RigidBody2D* rigidBody); + + void RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func); + + struct PostStepContainer + { + NazaraSlot(RigidBody2D, OnRigidBody2DMove, onMovedSlot); + NazaraSlot(RigidBody2D, OnRigidBody2DRelease, onReleaseSlot); + + std::vector funcs; + }; + + static_assert(std::is_nothrow_move_constructible::value, "PostStepContainer should be noexcept MoveConstructible"); + + std::unordered_map> m_callbacks; + std::unordered_map m_rigidPostSteps; cpSpace* m_handle; float m_stepSize; float m_timestepAccumulator; diff --git a/include/Nazara/Physics2D/RigidBody2D.hpp b/include/Nazara/Physics2D/RigidBody2D.hpp index 5f14d8ff9..f2b3da2d7 100644 --- a/include/Nazara/Physics2D/RigidBody2D.hpp +++ b/include/Nazara/Physics2D/RigidBody2D.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -33,6 +34,8 @@ namespace Nz void AddForce(const Vector2f& force, CoordSys coordSys = CoordSys_Global); void AddForce(const Vector2f& force, const Vector2f& point, CoordSys coordSys = CoordSys_Global); + void AddImpulse(const Vector2f& impulse, CoordSys coordSys = CoordSys_Global); + void AddImpulse(const Vector2f& impulse, const Vector2f& point, CoordSys coordSys = CoordSys_Global); void AddTorque(float torque); Rectf GetAABB() const; @@ -43,7 +46,9 @@ namespace Nz float GetMass() const; Vector2f GetPosition() const; float GetRotation() const; + void* GetUserdata() const; Vector2f GetVelocity() const; + PhysWorld2D* GetWorld() const; bool IsMoveable() const; bool IsSleeping() const; @@ -52,13 +57,18 @@ namespace Nz void SetGeom(Collider2DRef geom); void SetMass(float mass); void SetMassCenter(const Vector2f& center); + void SetMomentOfInertia(float moment); void SetPosition(const Vector2f& position); void SetRotation(float rotation); + void SetUserdata(void* ud); void SetVelocity(const Vector2f& velocity); RigidBody2D& operator=(const RigidBody2D& object); RigidBody2D& operator=(RigidBody2D&& object); + NazaraSignal(OnRigidBody2DMove, RigidBody2D* /*oldPointer*/, RigidBody2D* /*newPointer*/); + NazaraSignal(OnRigidBody2DRelease, RigidBody2D* /*rigidBody*/); + private: void Create(float mass = 1.f, float moment = 1.f); void Destroy(); @@ -66,6 +76,7 @@ namespace Nz std::vector m_shapes; Collider2DRef m_geom; cpBody* m_handle; + void* m_userData; PhysWorld2D* m_world; float m_gravityFactor; float m_mass; diff --git a/include/Nazara/Physics3D/Collider3D.hpp b/include/Nazara/Physics3D/Collider3D.hpp index 13bf32c2f..d8300bdf2 100644 --- a/include/Nazara/Physics3D/Collider3D.hpp +++ b/include/Nazara/Physics3D/Collider3D.hpp @@ -135,7 +135,7 @@ namespace Nz class NAZARA_PHYSICS3D_API CompoundCollider3D : public Collider3D { public: - CompoundCollider3D(Collider3D** geoms, std::size_t geomCount); + CompoundCollider3D(std::vector geoms); const std::vector& GetGeoms() const; ColliderType3D GetType() const override; diff --git a/include/Nazara/Physics3D/RigidBody3D.hpp b/include/Nazara/Physics3D/RigidBody3D.hpp index 502fd21a7..bc7f668b0 100644 --- a/include/Nazara/Physics3D/RigidBody3D.hpp +++ b/include/Nazara/Physics3D/RigidBody3D.hpp @@ -47,6 +47,7 @@ namespace Nz Vector3f GetPosition() const; Quaternionf GetRotation() const; Vector3f GetVelocity() const; + PhysWorld3D* GetWorld() const; bool IsAutoSleepEnabled() const; bool IsMoveable() const; diff --git a/include/Nazara/Platform.hpp b/include/Nazara/Platform.hpp new file mode 100644 index 000000000..fc2b3c0d3 --- /dev/null +++ b/include/Nazara/Platform.hpp @@ -0,0 +1,48 @@ +// This file was automatically generated + +/* + Nazara Engine - Platform module + + Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_GLOBAL_PLATFORM_HPP +#define NAZARA_GLOBAL_PLATFORM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // NAZARA_GLOBAL_PLATFORM_HPP + diff --git a/include/Nazara/Platform/Config.hpp b/include/Nazara/Platform/Config.hpp new file mode 100644 index 000000000..6bb056f27 --- /dev/null +++ b/include/Nazara/Platform/Config.hpp @@ -0,0 +1,54 @@ +/* + Nazara Engine - Platform module + + Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com) + + Permission is hereby granted, free of charge, to any person obtaining a copy of + this software and associated documentation files (the "Software"), to deal in + the Software without restriction, including without limitation the rights to + use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is furnished to do + so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. +*/ + +#pragma once + +#ifndef NAZARA_CONFIG_PLATFORM_HPP +#define NAZARA_CONFIG_PLATFORM_HPP + +/// Each modification of a parameter needs a recompilation of the module + +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) +#define NAZARA_PLATFORM_MANAGE_MEMORY 0 + +// Activate the security tests based on the code (Advised for development) +#define NAZARA_PLATFORM_SAFE 1 + +// Protect the classes against data race +//#define NAZARA_PLATFORM_THREADSAFE 1 + +// On Windows, ALT and F10 keys do not activate the window menu +#define NAZARA_PLATFORM_WINDOWS_DISABLE_MENU_KEYS 1 + +#if defined(NAZARA_STATIC) + #define NAZARA_PLATFORM_API +#else + #ifdef NAZARA_PLATFORM_BUILD + #define NAZARA_PLATFORM_API NAZARA_EXPORT + #else + #define NAZARA_PLATFORM_API NAZARA_IMPORT + #endif +#endif + +#endif // NAZARA_CONFIG_PLATFORM_HPP diff --git a/include/Nazara/Platform/ConfigCheck.hpp b/include/Nazara/Platform/ConfigCheck.hpp new file mode 100644 index 000000000..2b58e4586 --- /dev/null +++ b/include/Nazara/Platform/ConfigCheck.hpp @@ -0,0 +1,23 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CONFIG_CHECK_PLATFORM_HPP +#define NAZARA_CONFIG_CHECK_PLATFORM_HPP + +/// This file is used to check the constant values defined in Config.hpp + +#include +#define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) + +// We force the value of MANAGE_MEMORY in debug +#if defined(NAZARA_DEBUG) && !NAZARA_PLATFORM_MANAGE_MEMORY + #undef NAZARA_PLATFORM_MANAGE_MEMORY + #define NAZARA_PLATFORM_MANAGE_MEMORY 0 +#endif + +#undef NazaraCheckTypeAndVal + +#endif // NAZARA_CONFIG_CHECK_PLATFORM_HPP diff --git a/include/Nazara/Utility/Cursor.hpp b/include/Nazara/Platform/Cursor.hpp similarity index 85% rename from include/Nazara/Utility/Cursor.hpp rename to include/Nazara/Platform/Cursor.hpp index 870b17b55..7cf5c979d 100644 --- a/include/Nazara/Utility/Cursor.hpp +++ b/include/Nazara/Platform/Cursor.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -10,7 +10,8 @@ #include #include #include -#include +#include +#include #include #include @@ -23,9 +24,9 @@ namespace Nz using CursorConstRef = ObjectRef; using CursorRef = ObjectRef; - class NAZARA_UTILITY_API Cursor : public RefCounted + class NAZARA_PLATFORM_API Cursor : public RefCounted { - friend class Utility; + friend class Platform; friend class WindowImpl; public: @@ -66,6 +67,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_CURSOR_HPP diff --git a/include/Nazara/Utility/Cursor.inl b/include/Nazara/Platform/Cursor.inl similarity index 88% rename from include/Nazara/Utility/Cursor.inl rename to include/Nazara/Platform/Cursor.inl index 58d15bdec..36d089e3c 100644 --- a/include/Nazara/Utility/Cursor.inl +++ b/include/Nazara/Platform/Cursor.inl @@ -1,10 +1,10 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include +#include namespace Nz { @@ -66,4 +66,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Utility/CursorController.hpp b/include/Nazara/Platform/CursorController.hpp similarity index 85% rename from include/Nazara/Utility/CursorController.hpp rename to include/Nazara/Platform/CursorController.hpp index 0c2943356..07c86e92b 100644 --- a/include/Nazara/Utility/CursorController.hpp +++ b/include/Nazara/Platform/CursorController.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include +#include namespace Nz { @@ -37,6 +37,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_CURSORCONTROLLER_HPP diff --git a/include/Nazara/Utility/CursorController.inl b/include/Nazara/Platform/CursorController.inl similarity index 56% rename from include/Nazara/Utility/CursorController.inl rename to include/Nazara/Platform/CursorController.inl index b1f54d05a..75260b66d 100644 --- a/include/Nazara/Utility/CursorController.inl +++ b/include/Nazara/Platform/CursorController.inl @@ -1,9 +1,9 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include -#include +#include +#include namespace Nz { @@ -13,4 +13,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Platform/Debug.hpp b/include/Nazara/Platform/Debug.hpp new file mode 100644 index 000000000..94d6e9134 --- /dev/null +++ b/include/Nazara/Platform/Debug.hpp @@ -0,0 +1,8 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#if NAZARA_PLATFORM_MANAGE_MEMORY + #include +#endif diff --git a/include/Nazara/Platform/DebugOff.hpp b/include/Nazara/Platform/DebugOff.hpp new file mode 100644 index 000000000..d6072e479 --- /dev/null +++ b/include/Nazara/Platform/DebugOff.hpp @@ -0,0 +1,9 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +// We suppose that Debug.hpp is already included, same goes for Config.hpp +#if NAZARA_PLATFORM_MANAGE_MEMORY + #undef delete + #undef new +#endif diff --git a/include/Nazara/Platform/Enums.hpp b/include/Nazara/Platform/Enums.hpp new file mode 100644 index 000000000..252412904 --- /dev/null +++ b/include/Nazara/Platform/Enums.hpp @@ -0,0 +1,85 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ENUMS_PLATFORM_HPP +#define NAZARA_ENUMS_PLATFORM_HPP + +#include + +namespace Nz +{ + enum SystemCursor + { + SystemCursor_Crosshair, + SystemCursor_Default, + SystemCursor_Hand, + SystemCursor_Help, + SystemCursor_Move, + SystemCursor_None, + SystemCursor_Pointer, + SystemCursor_Progress, + SystemCursor_ResizeE, + SystemCursor_ResizeN, + SystemCursor_ResizeNE, + SystemCursor_ResizeNW, + SystemCursor_ResizeS, + SystemCursor_ResizeSE, + SystemCursor_ResizeSW, + SystemCursor_ResizeW, + SystemCursor_Text, + SystemCursor_Wait, + + SystemCursor_Max = SystemCursor_Wait + }; + + enum WindowEventType + { + WindowEventType_GainedFocus, + WindowEventType_LostFocus, + WindowEventType_KeyPressed, + WindowEventType_KeyReleased, + WindowEventType_MouseButtonDoubleClicked, + WindowEventType_MouseButtonPressed, + WindowEventType_MouseButtonReleased, + WindowEventType_MouseEntered, + WindowEventType_MouseLeft, + WindowEventType_MouseMoved, + WindowEventType_MouseWheelMoved, + WindowEventType_Moved, + WindowEventType_Quit, + WindowEventType_Resized, + WindowEventType_TextEntered, + + WindowEventType_Max = WindowEventType_TextEntered + }; + + enum WindowStyle + { + WindowStyle_None, ///< Window has no border nor titlebar. + WindowStyle_Fullscreen, ///< At the window creation, the OS tries to set it in fullscreen. + + WindowStyle_Closable, ///< Allows the window to be closed by a button in the titlebar, generating a Quit event. + WindowStyle_Resizable, ///< Allows the window to be resized by dragging its corners or by a button of the titlebar. + WindowStyle_Titlebar, ///< Adds a titlebar to the window, this option is automatically enabled if buttons of the titlebar are enabled. + + WindowStyle_Threaded, ///< Runs the window into a thread, allowing the application to keep updating while resizing/dragging the window. + + WindowStyle_Max = WindowStyle_Threaded + }; + + template<> + struct EnumAsFlags + { + static constexpr bool value = true; + static constexpr int max = WindowStyle_Max; + }; + + using WindowStyleFlags = Flags; + + constexpr WindowStyleFlags WindowStyle_Default = WindowStyle_Closable | WindowStyle_Resizable | WindowStyle_Titlebar; +} + +#endif // NAZARA_ENUMS_PLATFORM_HPP diff --git a/include/Nazara/Utility/Event.hpp b/include/Nazara/Platform/Event.hpp similarity index 77% rename from include/Nazara/Utility/Event.hpp rename to include/Nazara/Platform/Event.hpp index b67eedc0c..ece401890 100644 --- a/include/Nazara/Utility/Event.hpp +++ b/include/Nazara/Platform/Event.hpp @@ -1,23 +1,23 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -// Interface inspirée de la SFML par Laurent Gomila +// Interface inspired by the SFML of Laurent Gomila (and its team) #pragma once #ifndef NAZARA_EVENT_HPP #define NAZARA_EVENT_HPP -#include -#include -#include +#include +#include +#include namespace Nz { struct WindowEvent { - // Utilisé par: + // Used by: // -WindowEventType_KeyPressed // -WindowEventType_KeyReleased struct KeyEvent @@ -30,7 +30,7 @@ namespace Nz bool system; }; - // Utilisé par: + // Used by: // -WindowEventType_MouseButtonDoubleClicked // -WindowEventType_MouseButtonPressed struct MouseButtonEvent @@ -40,7 +40,7 @@ namespace Nz unsigned int y; }; - // Utilisé par: + // Used by: // -WindowEventType_MouseMoved struct MouseMoveEvent { @@ -50,14 +50,14 @@ namespace Nz unsigned int y; }; - // Utilisé par: + // Used by: // -WindowEventType_MouseWheelMoved struct MouseWheelEvent { float delta; }; - // Utilisé par: + // Used by: // -WindowEventType_Moved struct PositionEvent { @@ -65,7 +65,7 @@ namespace Nz int y; }; - // Utilisé par: + // Used by: // -WindowEventType_Resized struct SizeEvent { @@ -73,7 +73,7 @@ namespace Nz unsigned int width; }; - // Utilisé par: + // Used by: // -WindowEventType_TextEntered struct TextEvent { @@ -85,33 +85,33 @@ namespace Nz union { - // Utilisé par: + // Used by: // -WindowEventType_KeyPressed // -WindowEventType_KeyReleased KeyEvent key; - // Utilisé par: + // Used by: // -WindowEventType_MouseButtonDoubleClicked // -WindowEventType_MouseButtonPressed MouseButtonEvent mouseButton; - // Utilisé par: + // Used by: // -WindowEventType_MouseMoved MouseMoveEvent mouseMove; - // Utilisé par: + // Used by: // -WindowEventType_MouseWheelMoved MouseWheelEvent mouseWheel; - // Utilisé par: + // Used by: // -WindowEventType_Moved PositionEvent position; - // Utilisé par: + // Used by: // -WindowEventType_Resized SizeEvent size; - // Utilisé par: + // Used by: // -WindowEventType_TextEntered TextEvent text; }; diff --git a/include/Nazara/Utility/EventHandler.hpp b/include/Nazara/Platform/EventHandler.hpp similarity index 93% rename from include/Nazara/Utility/EventHandler.hpp rename to include/Nazara/Platform/EventHandler.hpp index 78cba94bc..b2390c35e 100644 --- a/include/Nazara/Utility/EventHandler.hpp +++ b/include/Nazara/Platform/EventHandler.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -11,8 +11,8 @@ #include #include #include -#include -#include +#include +#include namespace Nz { @@ -52,6 +52,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_EVENTHANDLER_HPP diff --git a/include/Nazara/Utility/EventHandler.inl b/include/Nazara/Platform/EventHandler.inl similarity index 85% rename from include/Nazara/Utility/EventHandler.inl rename to include/Nazara/Platform/EventHandler.inl index 4ba3f49bd..6cc31efe5 100644 --- a/include/Nazara/Utility/EventHandler.inl +++ b/include/Nazara/Platform/EventHandler.inl @@ -1,14 +1,15 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include +#include namespace Nz { - inline EventHandler::EventHandler(const EventHandler&) + inline EventHandler::EventHandler(const EventHandler& other) : + HandledObject(other) { } @@ -81,4 +82,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Utility/Icon.hpp b/include/Nazara/Platform/Icon.hpp similarity index 79% rename from include/Nazara/Utility/Icon.hpp rename to include/Nazara/Platform/Icon.hpp index db93e9495..a1acfe98f 100644 --- a/include/Nazara/Utility/Icon.hpp +++ b/include/Nazara/Platform/Icon.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -10,7 +10,7 @@ #include #include #include -#include +#include namespace Nz { @@ -21,7 +21,7 @@ namespace Nz using IconRef = ObjectRef; - class NAZARA_UTILITY_API Icon : public RefCounted + class NAZARA_PLATFORM_API Icon : public RefCounted { friend class WindowImpl; @@ -42,6 +42,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_ICON_HPP diff --git a/include/Nazara/Utility/Icon.inl b/include/Nazara/Platform/Icon.inl similarity index 77% rename from include/Nazara/Utility/Icon.inl rename to include/Nazara/Platform/Icon.inl index 5c6b60068..b8c597e48 100644 --- a/include/Nazara/Utility/Icon.inl +++ b/include/Nazara/Platform/Icon.inl @@ -1,10 +1,10 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include +#include namespace Nz { @@ -39,4 +39,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Utility/Joystick.hpp b/include/Nazara/Platform/Joystick.hpp similarity index 82% rename from include/Nazara/Utility/Joystick.hpp rename to include/Nazara/Platform/Joystick.hpp index f80b4b590..eb961b87d 100644 --- a/include/Nazara/Utility/Joystick.hpp +++ b/include/Nazara/Platform/Joystick.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -12,7 +12,7 @@ namespace Nz { - class NAZARA_UTILITY_API Joystick + class NAZARA_PLATFORM_API Joystick { public: Joystick() = delete; diff --git a/include/Nazara/Utility/Keyboard.hpp b/include/Nazara/Platform/Keyboard.hpp similarity index 81% rename from include/Nazara/Utility/Keyboard.hpp rename to include/Nazara/Platform/Keyboard.hpp index bfd050d73..df0513c2d 100644 --- a/include/Nazara/Utility/Keyboard.hpp +++ b/include/Nazara/Platform/Keyboard.hpp @@ -1,8 +1,8 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -// Interface inspirée de la SFML par Laurent Gomila +// Interface inspired by the SFML of Laurent Gomila (and its team) #pragma once @@ -11,11 +11,11 @@ #include #include -#include +#include namespace Nz { - class NAZARA_UTILITY_API Keyboard + class NAZARA_PLATFORM_API Keyboard { public: enum Key @@ -50,7 +50,7 @@ namespace Nz Y, Z, - // Touches de fonction + // Functional keys F1, F2, F3, @@ -67,13 +67,13 @@ namespace Nz F14, F15, - // Flèches directionnelles + // Directional keys Down, Left, Right, Up, - // Pavé numérique + // Numerical pad Add, Decimal, Divide, @@ -90,7 +90,7 @@ namespace Nz Numpad9, Subtract, - // Divers + // Various Backslash, Backspace, Clear, @@ -136,7 +136,7 @@ namespace Nz Tab, Tilde, - // Touches navigateur + // Navigator keys Browser_Back, Browser_Favorites, Browser_Forward, @@ -145,18 +145,18 @@ namespace Nz Browser_Search, Browser_Stop, - // Touches de contrôle de lecture + // Lecture control keys Media_Next, Media_Play, Media_Previous, Media_Stop, - // Touches de contrôle du volume + // Volume control keys Volume_Down, Volume_Mute, Volume_Up, - // Touches à verrouillage + // Locking keys CapsLock, NumLock, ScrollLock, diff --git a/include/Nazara/Utility/Mouse.hpp b/include/Nazara/Platform/Mouse.hpp similarity index 82% rename from include/Nazara/Utility/Mouse.hpp rename to include/Nazara/Platform/Mouse.hpp index 552011904..74af3a419 100644 --- a/include/Nazara/Utility/Mouse.hpp +++ b/include/Nazara/Platform/Mouse.hpp @@ -1,8 +1,8 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -// Interface inspirée de la SFML par Laurent Gomila +// Interface inspired by the SFML of Laurent Gomila (and its team) #pragma once @@ -11,13 +11,13 @@ #include #include -#include +#include namespace Nz { class Window; - class NAZARA_UTILITY_API Mouse + class NAZARA_PLATFORM_API Mouse { public: enum Button diff --git a/include/Nazara/Platform/Platform.hpp b/include/Nazara/Platform/Platform.hpp new file mode 100644 index 000000000..36c456782 --- /dev/null +++ b/include/Nazara/Platform/Platform.hpp @@ -0,0 +1,33 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_PLATFORM_HPP +#define NAZARA_PLATFORM_HPP + +#include +#include +#include + +namespace Nz +{ + class NAZARA_PLATFORM_API Platform + { + public: + Platform() = delete; + ~Platform() = delete; + + static bool Initialize(); + + static bool IsInitialized(); + + static void Uninitialize(); + + private: + static unsigned int s_moduleReferenceCounter; + }; +} + +#endif // NAZARA_PLATFORM_HPP diff --git a/include/Nazara/Utility/VideoMode.hpp b/include/Nazara/Platform/VideoMode.hpp similarity index 88% rename from include/Nazara/Utility/VideoMode.hpp rename to include/Nazara/Platform/VideoMode.hpp index 4d6a77768..364da9488 100644 --- a/include/Nazara/Utility/VideoMode.hpp +++ b/include/Nazara/Platform/VideoMode.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp // Interface inspirée de la SFML par Laurent Gomila @@ -10,12 +10,12 @@ #define NAZARA_VIDEOMODE_HPP #include -#include +#include #include namespace Nz { - class NAZARA_UTILITY_API VideoMode + class NAZARA_PLATFORM_API VideoMode { public: VideoMode(); diff --git a/include/Nazara/Utility/Window.hpp b/include/Nazara/Platform/Window.hpp similarity index 87% rename from include/Nazara/Utility/Window.hpp rename to include/Nazara/Platform/Window.hpp index 32487370a..3010bb91f 100644 --- a/include/Nazara/Utility/Window.hpp +++ b/include/Nazara/Platform/Window.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp // Interface inspirée de la SFML par Laurent Gomila @@ -14,14 +14,14 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include #include namespace Nz @@ -29,16 +29,16 @@ namespace Nz class Image; class WindowImpl; - class NAZARA_UTILITY_API Window + class NAZARA_PLATFORM_API Window { friend WindowImpl; friend class Mouse; - friend class Utility; + friend class Platform; public: Window(); inline Window(VideoMode mode, const String& title, WindowStyleFlags style = WindowStyle_Default); - inline Window(WindowHandle handle); + inline explicit Window(WindowHandle handle); Window(const Window&) = delete; inline Window(Window&& window) noexcept; virtual ~Window(); @@ -138,6 +138,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_WINDOW_HPP diff --git a/include/Nazara/Utility/Window.inl b/include/Nazara/Platform/Window.inl similarity index 95% rename from include/Nazara/Utility/Window.inl rename to include/Nazara/Platform/Window.inl index c81c89b80..f217ac10c 100644 --- a/include/Nazara/Utility/Window.inl +++ b/include/Nazara/Platform/Window.inl @@ -1,11 +1,11 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Core module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include -#include +#include namespace Nz { @@ -173,4 +173,4 @@ namespace Nz } } -#include +#include diff --git a/include/Nazara/Utility/WindowHandle.hpp b/include/Nazara/Platform/WindowHandle.hpp similarity index 91% rename from include/Nazara/Utility/WindowHandle.hpp rename to include/Nazara/Platform/WindowHandle.hpp index f49a400e0..ea034d4e8 100644 --- a/include/Nazara/Utility/WindowHandle.hpp +++ b/include/Nazara/Platform/WindowHandle.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once diff --git a/include/Nazara/Renderer/Config.hpp b/include/Nazara/Renderer/Config.hpp index f4458216f..873008941 100644 --- a/include/Nazara/Renderer/Config.hpp +++ b/include/Nazara/Renderer/Config.hpp @@ -30,7 +30,7 @@ /// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci // La taille du buffer d'Instancing (définit le nombre maximum d'instances en un rendu) -#define NAZARA_RENDERER_INSTANCE_BUFFER_SIZE 524288 // 8192 matrices 4x4 flottantes +#define NAZARA_RENDERER_INSTANCE_BUFFER_SIZE 1 * 1024 * 1024 // Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) #define NAZARA_RENDERER_MANAGE_MEMORY 0 diff --git a/include/Nazara/Renderer/ContextParameters.hpp b/include/Nazara/Renderer/ContextParameters.hpp index 99940a24f..830a1bdcf 100644 --- a/include/Nazara/Renderer/ContextParameters.hpp +++ b/include/Nazara/Renderer/ContextParameters.hpp @@ -9,8 +9,8 @@ #include #include -#include -#include +#include +#include namespace Nz { diff --git a/include/Nazara/Renderer/RenderWindow.hpp b/include/Nazara/Renderer/RenderWindow.hpp index c71ad2b34..7360777dd 100644 --- a/include/Nazara/Renderer/RenderWindow.hpp +++ b/include/Nazara/Renderer/RenderWindow.hpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include namespace Nz @@ -31,7 +31,7 @@ namespace Nz public: RenderWindow() = default; RenderWindow(VideoMode mode, const String& title, WindowStyleFlags style = WindowStyle_Default, const ContextParameters& parameters = ContextParameters()); - RenderWindow(WindowHandle handle, const ContextParameters& parameters = ContextParameters()); + explicit RenderWindow(WindowHandle handle, const ContextParameters& parameters = ContextParameters()); RenderWindow(const RenderWindow&) = delete; RenderWindow(RenderWindow&&) = delete; ///TODO virtual ~RenderWindow(); diff --git a/include/Nazara/Renderer/UberShaderInstancePreprocessor.hpp b/include/Nazara/Renderer/UberShaderInstancePreprocessor.hpp index 5f0a16900..ee44950a0 100644 --- a/include/Nazara/Renderer/UberShaderInstancePreprocessor.hpp +++ b/include/Nazara/Renderer/UberShaderInstancePreprocessor.hpp @@ -18,7 +18,7 @@ namespace Nz UberShaderInstancePreprocessor(const Shader* shader); virtual ~UberShaderInstancePreprocessor(); - bool Activate() const; + bool Activate() const override; }; } diff --git a/include/Nazara/Renderer/UberShaderPreprocessor.hpp b/include/Nazara/Renderer/UberShaderPreprocessor.hpp index 6732fab23..710835ec2 100644 --- a/include/Nazara/Renderer/UberShaderPreprocessor.hpp +++ b/include/Nazara/Renderer/UberShaderPreprocessor.hpp @@ -29,7 +29,7 @@ namespace Nz UberShaderPreprocessor() = default; ~UberShaderPreprocessor(); - UberShaderInstance* Get(const ParameterList& parameters) const; + UberShaderInstance* Get(const ParameterList& parameters) const override; void SetShader(ShaderStageType stage, const String& source, const String& shaderFlags, const String& requiredFlags = String()); bool SetShaderFromFile(ShaderStageType stage, const String& filePath, const String& shaderFlags, const String& requiredFlags = String()); diff --git a/include/Nazara/Utility.hpp b/include/Nazara/Utility.hpp index 3734b919e..2ccf84080 100644 --- a/include/Nazara/Utility.hpp +++ b/include/Nazara/Utility.hpp @@ -39,32 +39,26 @@ #include #include #include -#include #include -#include -#include #include #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -73,8 +67,5 @@ #include #include #include -#include -#include -#include #endif // NAZARA_GLOBAL_UTILITY_HPP diff --git a/include/Nazara/Utility/Config.hpp b/include/Nazara/Utility/Config.hpp index 39aa014af..489a6192b 100644 --- a/include/Nazara/Utility/Config.hpp +++ b/include/Nazara/Utility/Config.hpp @@ -27,32 +27,29 @@ #ifndef NAZARA_CONFIG_UTILITY_HPP #define NAZARA_CONFIG_UTILITY_HPP -/// Chaque modification d'un paramètre du module nécessite une recompilation de celui-ci +/// Each modification of a parameter needs a recompilation of the module -// Utilise un manager de mémoire pour gérer les allocations dynamiques (détecte les leaks au prix d'allocations/libérations dynamiques plus lentes) +// Use the MemoryManager to manage dynamic allocations (can detect memory leak but allocations/frees are slower) #define NAZARA_UTILITY_MANAGE_MEMORY 0 -// Active les tests de sécurité basés sur le code (Conseillé pour le développement) +// Activate the security tests based on the code (Advised for development) #define NAZARA_UTILITY_SAFE 1 -// Lors du parsage d'une ressource, déclenche un avertissement si une erreur non-critique est repérée dans une ressource (Plus lent) +// When a resource is being parsed, it triggers a warning if a non-critical error is found in the resource (Slower) #define NAZARA_UTILITY_STRICT_RESOURCE_PARSING 1 -// Protège les classes des accès concurrentiels +// Protect the classes against data race //#define NAZARA_UTILITY_THREADSAFE 1 -// Force les buffers à posséder un stride multiple de 32 bytes (Gain de performances sur certaines cartes/plus de consommation mémoire) -#define NAZARA_UTILITY_VERTEX_DECLARATION_FORCE_STRIDE_MULTIPLE_OF_32 0 ///FIXME: Ne peut pas être utilisé pour l'instant +// Force the buffers to have a stride which is a multiple of 32 bytes (Gain of performances on certain cards/more memory consumption) +#define NAZARA_UTILITY_VERTEX_DECLARATION_FORCE_STRIDE_MULTIPLE_OF_32 0 ///FIXME: Can not be used for the moment -// Sous Windows, fait en sorte que les touches ALT et F10 n'activent pas le menu de la fenêtre -#define NAZARA_UTILITY_WINDOWS_DISABLE_MENU_KEYS 1 +/// Each modification of a parameter following implies a modification (often minor) of the code -/// Chaque modification d'un paramètre ci-dessous implique une modification (souvent mineure) du code - -// Le nombre maximum de poids affectant un sommet (En cas de dépassement, les poids supplémentaires seront ignorés et les autres renormalisés) +// The maximal number of weights acting on a vertex (In case of overflow, the surnumerous weights would be ignored and the others renormalized) #define NAZARA_UTILITY_SKINNING_MAX_WEIGHTS 4 -/// Vérification des valeurs et types de certaines constantes +/// Checking the values and types of certain constants #include #if defined(NAZARA_STATIC) diff --git a/include/Nazara/Utility/ConfigCheck.hpp b/include/Nazara/Utility/ConfigCheck.hpp index bbfd6ea66..42aa5f92c 100644 --- a/include/Nazara/Utility/ConfigCheck.hpp +++ b/include/Nazara/Utility/ConfigCheck.hpp @@ -7,12 +7,12 @@ #ifndef NAZARA_CONFIG_CHECK_UTILITY_HPP #define NAZARA_CONFIG_CHECK_UTILITY_HPP -/// Ce fichier sert à vérifier la valeur des constantes du fichier Config.hpp +/// This file is used to check the constant values defined in Config.hpp #include #define NazaraCheckTypeAndVal(name, type, op, val, err) static_assert(std::is_ ##type ::value && name op val, #type err) -// On force la valeur de MANAGE_MEMORY en mode debug +// We force the value of MANAGE_MEMORY in debug #if defined(NAZARA_DEBUG) && !NAZARA_UTILITY_MANAGE_MEMORY #undef NAZARA_UTILITY_MANAGE_MEMORY #define NAZARA_UTILITY_MANAGE_MEMORY 0 diff --git a/include/Nazara/Utility/Enums.hpp b/include/Nazara/Utility/Enums.hpp index d72b90d6c..2fda92e70 100644 --- a/include/Nazara/Utility/Enums.hpp +++ b/include/Nazara/Utility/Enums.hpp @@ -92,8 +92,8 @@ namespace Nz enum CubemapFace { - // Cette énumération est prévue pour remplacer l'argument "z" des méthodes de Image contenant un cubemap - // L'ordre est X, -X, Y, -Y, Z, -Z + // This enumeration is intended to replace the "z" argument of Image's methods containing cubemap + // The order is X, -X, Y, -Y, Z, -Z CubemapFace_PositiveX = 0, CubemapFace_PositiveY = 2, CubemapFace_PositiveZ = 4, @@ -307,30 +307,6 @@ namespace Nz SamplerWrap_Max = SamplerWrap_Repeat }; - enum SystemCursor - { - SystemCursor_Crosshair, - SystemCursor_Default, - SystemCursor_Hand, - SystemCursor_Help, - SystemCursor_Move, - SystemCursor_None, - SystemCursor_Pointer, - SystemCursor_Progress, - SystemCursor_ResizeE, - SystemCursor_ResizeN, - SystemCursor_ResizeNE, - SystemCursor_ResizeNW, - SystemCursor_ResizeS, - SystemCursor_ResizeSE, - SystemCursor_ResizeSW, - SystemCursor_ResizeW, - SystemCursor_Text, - SystemCursor_Wait, - - SystemCursor_Max = SystemCursor_Wait - }; - enum StencilOperation { StencilOperation_Decrement, @@ -370,7 +346,7 @@ namespace Nz { VertexComponent_Unused = -1, - // Nous nous limitons à 16 composants de sommets car c'est le minimum supporté par le GPU + // We limit to 16 components by vertex since it's the minimal number supported by the GPU VertexComponent_InstanceData0, VertexComponent_InstanceData1, VertexComponent_InstanceData2, @@ -398,7 +374,7 @@ namespace Nz enum VertexLayout { - // Déclarations destinées au rendu + // Declarations meant for the rendering VertexLayout_XY, VertexLayout_XY_Color, VertexLayout_XY_UV, @@ -411,57 +387,11 @@ namespace Nz VertexLayout_XYZ_Normal_UV_Tangent_Skinning, VertexLayout_XYZ_UV, - // Déclarations destinées à l'instancing + // Declarations meant for the instancing VertexLayout_Matrix4, VertexLayout_Max = VertexLayout_Matrix4 }; - - enum WindowEventType - { - WindowEventType_GainedFocus, - WindowEventType_LostFocus, - WindowEventType_KeyPressed, - WindowEventType_KeyReleased, - WindowEventType_MouseButtonDoubleClicked, - WindowEventType_MouseButtonPressed, - WindowEventType_MouseButtonReleased, - WindowEventType_MouseEntered, - WindowEventType_MouseLeft, - WindowEventType_MouseMoved, - WindowEventType_MouseWheelMoved, - WindowEventType_Moved, - WindowEventType_Quit, - WindowEventType_Resized, - WindowEventType_TextEntered, - - WindowEventType_Max = WindowEventType_TextEntered - }; - - enum WindowStyle - { - WindowStyle_None, ///< Window has no border nor titlebar. - WindowStyle_Fullscreen, ///< At the window creation, the OS tries to set it in fullscreen. - - WindowStyle_Closable, ///< Allows the window to be closed by a button in the titlebar, generating a Quit event. - WindowStyle_Resizable, ///< Allows the window to be resized by dragging its corners or by a button of the titlebar. - WindowStyle_Titlebar, ///< Adds a titlebar to the window, this option is automatically enabled if buttons of the titlebar are enabled. - - WindowStyle_Threaded, ///< Runs the window into a thread, allowing the application to keep updating while resizing/dragging the window. - - WindowStyle_Max = WindowStyle_Threaded - }; - - template<> - struct EnumAsFlags - { - static constexpr bool value = true; - static constexpr int max = WindowStyle_Max; - }; - - using WindowStyleFlags = Flags; - - constexpr WindowStyleFlags WindowStyle_Default = WindowStyle_Closable | WindowStyle_Resizable | WindowStyle_Titlebar; } #endif // NAZARA_ENUMS_UTILITY_HPP diff --git a/include/Nazara/Utility/Image.hpp b/include/Nazara/Utility/Image.hpp index 4e5b094cc..cbae97f9a 100644 --- a/include/Nazara/Utility/Image.hpp +++ b/include/Nazara/Utility/Image.hpp @@ -78,18 +78,18 @@ namespace Nz bool FlipVertically(); const UInt8* GetConstPixels(unsigned int x = 0, unsigned int y = 0, unsigned int z = 0, UInt8 level = 0) const; - unsigned int GetDepth(UInt8 level = 0) const; - PixelFormatType GetFormat() const; - unsigned int GetHeight(UInt8 level = 0) const; - UInt8 GetLevelCount() const; - UInt8 GetMaxLevel() const; - std::size_t GetMemoryUsage() const; - std::size_t GetMemoryUsage(UInt8 level) const; + unsigned int GetDepth(UInt8 level = 0) const override; + PixelFormatType GetFormat() const override; + unsigned int GetHeight(UInt8 level = 0) const override; + UInt8 GetLevelCount() const override; + UInt8 GetMaxLevel() const override; + std::size_t GetMemoryUsage() const override; + std::size_t GetMemoryUsage(UInt8 level) const override; Color GetPixelColor(unsigned int x, unsigned int y = 0, unsigned int z = 0) const; UInt8* GetPixels(unsigned int x = 0, unsigned int y = 0, unsigned int z = 0, UInt8 level = 0); - Vector3ui GetSize(UInt8 level = 0) const; - ImageType GetType() const; - unsigned int GetWidth(UInt8 level = 0) const; + Vector3ui GetSize(UInt8 level = 0) const override; + ImageType GetType() const override; + unsigned int GetWidth(UInt8 level = 0) const override; bool HasAlpha() const; @@ -126,9 +126,9 @@ namespace Nz void SetLevelCount(UInt8 levelCount); bool SetPixelColor(const Color& color, unsigned int x, unsigned int y = 0, unsigned int z = 0); - bool Update(const UInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0); - bool Update(const UInt8* pixels, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0); - bool Update(const UInt8* pixels, const Rectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0); + bool Update(const UInt8* pixels, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) override; + bool Update(const UInt8* pixels, const Boxui& box, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) override; + bool Update(const UInt8* pixels, const Rectui& rect, unsigned int z = 0, unsigned int srcWidth = 0, unsigned int srcHeight = 0, UInt8 level = 0) override; Image& operator=(const Image& image); diff --git a/include/Nazara/Utility/IndexBuffer.inl b/include/Nazara/Utility/IndexBuffer.inl index b439623eb..0ae918db7 100644 --- a/include/Nazara/Utility/IndexBuffer.inl +++ b/include/Nazara/Utility/IndexBuffer.inl @@ -45,7 +45,7 @@ namespace Nz inline bool IndexBuffer::IsValid() const { - return m_buffer; + return m_buffer.IsValid(); } inline void* IndexBuffer::Map(BufferAccess access, UInt32 startIndex, UInt32 length) diff --git a/include/Nazara/Utility/IndexIterator.hpp b/include/Nazara/Utility/IndexIterator.hpp index 5c15bbdc2..63f9d96b9 100644 --- a/include/Nazara/Utility/IndexIterator.hpp +++ b/include/Nazara/Utility/IndexIterator.hpp @@ -26,15 +26,15 @@ namespace Nz Reference operator*() const; - Reference operator[](unsigned int index) const; + Reference operator[](std::size_t index) const; IndexIterator& operator=(const IndexIterator& iterator); - IndexIterator operator+(unsigned int indexCount) const; - IndexIterator operator-(unsigned int indexCount) const; + IndexIterator operator+(std::size_t indexCount) const; + IndexIterator operator-(std::size_t indexCount) const; - IndexIterator& operator+=(unsigned int indexCount); - IndexIterator& operator-=(unsigned int indexCount); + IndexIterator& operator+=(std::size_t indexCount); + IndexIterator& operator-=(std::size_t indexCount); IndexIterator& operator++(); IndexIterator operator++(int); @@ -50,10 +50,10 @@ namespace Nz friend bool operator>=(const IndexIterator& lhs, const IndexIterator& rhs); private: - IndexIterator(IndexMapper* mapper, unsigned int index); + IndexIterator(IndexMapper* mapper, std::size_t index); IndexMapper* m_mapper; - unsigned int m_index; + std::size_t m_index; }; class IndexIterator::Reference @@ -70,10 +70,10 @@ namespace Nz operator UInt32() const; private: - Reference(IndexMapper* mapper, unsigned int index); + Reference(IndexMapper* mapper, std::size_t index); IndexMapper* m_mapper; - unsigned int m_index; + std::size_t m_index; }; } diff --git a/include/Nazara/Utility/IndexIterator.inl b/include/Nazara/Utility/IndexIterator.inl index df1613d67..0398059f6 100644 --- a/include/Nazara/Utility/IndexIterator.inl +++ b/include/Nazara/Utility/IndexIterator.inl @@ -20,7 +20,7 @@ namespace Nz { } - inline IndexIterator::IndexIterator(IndexMapper* mapper, unsigned int index) : + inline IndexIterator::IndexIterator(IndexMapper* mapper, std::size_t index) : m_mapper(mapper), m_index(index) { @@ -31,7 +31,7 @@ namespace Nz return Reference(m_mapper, m_index); } - inline IndexIterator::Reference IndexIterator::operator[](unsigned int index) const + inline IndexIterator::Reference IndexIterator::operator[](std::size_t index) const { return Reference(m_mapper, m_index+index); } @@ -44,24 +44,24 @@ namespace Nz return *this; } - inline IndexIterator IndexIterator::operator+(unsigned int indexCount) const + inline IndexIterator IndexIterator::operator+(std::size_t indexCount) const { return IndexIterator(m_mapper, m_index + indexCount); } - inline IndexIterator IndexIterator::operator-(unsigned int indexCount) const + inline IndexIterator IndexIterator::operator-(std::size_t indexCount) const { return IndexIterator(m_mapper, m_index - indexCount); } - inline IndexIterator& IndexIterator::operator+=(unsigned int indexCount) + inline IndexIterator& IndexIterator::operator+=(std::size_t indexCount) { m_index += indexCount; return *this; } - inline IndexIterator& IndexIterator::operator-=(unsigned int indexCount) + inline IndexIterator& IndexIterator::operator-=(std::size_t indexCount) { m_index += indexCount; @@ -133,7 +133,7 @@ namespace Nz /**************************IndexIterator::Reference*************************/ - inline IndexIterator::Reference::Reference(IndexMapper* mapper, unsigned int index) : + inline IndexIterator::Reference::Reference(IndexMapper* mapper, std::size_t index) : m_mapper(mapper), m_index(index) { @@ -148,7 +148,7 @@ namespace Nz inline IndexIterator::Reference& IndexIterator::Reference::operator=(const IndexIterator::Reference& reference) { - m_mapper->Set(m_index, reference); // Conversion implicite en UInt32 + m_mapper->Set(m_index, reference); // Implicit conversion to UInt32 return *this; } diff --git a/include/Nazara/Utility/IndexMapper.hpp b/include/Nazara/Utility/IndexMapper.hpp index 84c73bc53..b18e8989f 100644 --- a/include/Nazara/Utility/IndexMapper.hpp +++ b/include/Nazara/Utility/IndexMapper.hpp @@ -17,9 +17,6 @@ namespace Nz class IndexIterator; class SubMesh; - using IndexMapperGetter = UInt32 (*)(const void* buffer, unsigned int i); - using IndexMapperSetter = void (*)(void* buffer, unsigned int i, UInt32 value); - class NAZARA_UTILITY_API IndexMapper { public: @@ -29,11 +26,11 @@ namespace Nz IndexMapper(const SubMesh* subMesh, BufferAccess access = BufferAccess_ReadOnly); ~IndexMapper() = default; - UInt32 Get(unsigned int i) const; + UInt32 Get(std::size_t i) const; const IndexBuffer* GetBuffer() const; - unsigned int GetIndexCount() const; + std::size_t GetIndexCount() const; - void Set(unsigned int i, UInt32 value); + void Set(std::size_t i, UInt32 value); void Unmap(); @@ -45,10 +42,13 @@ namespace Nz // Méthodes STD private: + using Getter = UInt32(*)(const void* buffer, std::size_t i); + using Setter = void(*)(void* buffer, std::size_t i, UInt32 value); + BufferMapper m_mapper; - IndexMapperGetter m_getter; - IndexMapperSetter m_setter; - unsigned int m_indexCount; + Getter m_getter; + Setter m_setter; + std::size_t m_indexCount; }; } diff --git a/include/Nazara/Utility/Joint.hpp b/include/Nazara/Utility/Joint.hpp index f82668986..fad4b3d22 100644 --- a/include/Nazara/Utility/Joint.hpp +++ b/include/Nazara/Utility/Joint.hpp @@ -35,7 +35,7 @@ namespace Nz void SetName(const String& name); private: - void InvalidateNode(); + void InvalidateNode() override; void UpdateSkinningMatrix() const; Matrix4f m_inverseBindMatrix; diff --git a/include/Nazara/Utility/PixelFormat.hpp b/include/Nazara/Utility/PixelFormat.hpp index 8731ad29f..f6c3a36a4 100644 --- a/include/Nazara/Utility/PixelFormat.hpp +++ b/include/Nazara/Utility/PixelFormat.hpp @@ -65,7 +65,7 @@ namespace Nz static inline bool Convert(PixelFormatType srcFormat, PixelFormatType dstFormat, const void* src, void* dst); static inline bool Convert(PixelFormatType srcFormat, PixelFormatType dstFormat, const void* start, const void* end, void* dst); - static inline bool Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst); + static bool Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst); static inline UInt8 GetBitsPerPixel(PixelFormatType format); static inline PixelFormatContent GetContent(PixelFormatType format); diff --git a/include/Nazara/Utility/PixelFormat.inl b/include/Nazara/Utility/PixelFormat.inl index b4dfd95ee..4fe75c8b5 100644 --- a/include/Nazara/Utility/PixelFormat.inl +++ b/include/Nazara/Utility/PixelFormat.inl @@ -227,102 +227,6 @@ namespace Nz return true; } - inline bool PixelFormat::Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst) - { - #if NAZARA_UTILITY_SAFE - if (!IsValid(format)) - { - NazaraError("Invalid pixel format"); - return false; - } - #endif - - auto it = s_flipFunctions[flipping].find(format); - if (it != s_flipFunctions[flipping].end()) - it->second(width, height, depth, reinterpret_cast(src), reinterpret_cast(dst)); - else - { - // Flipping générique - - #if NAZARA_UTILITY_SAFE - if (IsCompressed(format)) - { - NazaraError("No function to flip compressed format"); - return false; - } - #endif - - UInt8 bpp = GetBytesPerPixel(format); - unsigned int lineStride = width*bpp; - switch (flipping) - { - case PixelFlipping_Horizontally: - { - if (src == dst) - { - for (unsigned int z = 0; z < depth; ++z) - { - UInt8* ptr = reinterpret_cast(dst) + width*height*z; - for (unsigned int y = 0; y < height/2; ++y) - std::swap_ranges(&ptr[y*lineStride], &ptr[(y+1)*lineStride-1], &ptr[(height-y-1)*lineStride]); - } - } - else - { - for (unsigned int z = 0; z < depth; ++z) - { - const UInt8* srcPtr = reinterpret_cast(src); - UInt8* dstPtr = reinterpret_cast(dst) + (width-1)*height*depth*bpp; - for (unsigned int y = 0; y < height; ++y) - { - std::memcpy(dstPtr, srcPtr, lineStride); - - srcPtr += lineStride; - dstPtr -= lineStride; - } - } - } - break; - } - - case PixelFlipping_Vertically: - { - if (src == dst) - { - for (unsigned int z = 0; z < depth; ++z) - { - UInt8* ptr = reinterpret_cast(dst) + width*height*z; - for (unsigned int y = 0; y < height; ++y) - { - for (unsigned int x = 0; x < width/2; ++x) - std::swap_ranges(&ptr[x*bpp], &ptr[(x+1)*bpp], &ptr[(width-x)*bpp]); - - ptr += lineStride; - } - } - } - else - { - for (unsigned int z = 0; z < depth; ++z) - { - UInt8* ptr = reinterpret_cast(dst) + width*height*z; - for (unsigned int y = 0; y < height; ++y) - { - for (unsigned int x = 0; x < width; ++x) - std::memcpy(&ptr[x*bpp], &ptr[(width-x)*bpp], bpp); - - ptr += lineStride; - } - } - } - break; - } - } - } - - return true; - } - inline UInt8 PixelFormat::GetBitsPerPixel(PixelFormatType format) { return s_pixelFormatInfos[format].bitsPerPixel; diff --git a/include/Nazara/Utility/SkeletalMesh.hpp b/include/Nazara/Utility/SkeletalMesh.hpp index 3efe704da..d67210c74 100644 --- a/include/Nazara/Utility/SkeletalMesh.hpp +++ b/include/Nazara/Utility/SkeletalMesh.hpp @@ -29,13 +29,13 @@ namespace Nz void Destroy(); const Boxf& GetAABB() const override; - AnimationType GetAnimationType() const final; + AnimationType GetAnimationType() const final override; const IndexBuffer* GetIndexBuffer() const override; VertexBuffer* GetVertexBuffer(); const VertexBuffer* GetVertexBuffer() const; unsigned int GetVertexCount() const override; - bool IsAnimated() const final; + bool IsAnimated() const final override; bool IsValid() const; void SetAABB(const Boxf& aabb); diff --git a/include/Nazara/Utility/StaticMesh.hpp b/include/Nazara/Utility/StaticMesh.hpp index 066bcee45..125af6301 100644 --- a/include/Nazara/Utility/StaticMesh.hpp +++ b/include/Nazara/Utility/StaticMesh.hpp @@ -32,13 +32,13 @@ namespace Nz bool GenerateAABB(); const Boxf& GetAABB() const override; - AnimationType GetAnimationType() const final; + AnimationType GetAnimationType() const final override; const IndexBuffer* GetIndexBuffer() const override; VertexBuffer* GetVertexBuffer(); const VertexBuffer* GetVertexBuffer() const; unsigned int GetVertexCount() const override; - bool IsAnimated() const final; + bool IsAnimated() const final override; bool IsValid() const; void SetAABB(const Boxf& aabb); diff --git a/include/Nazara/Utility/TriangleIterator.hpp b/include/Nazara/Utility/TriangleIterator.hpp index bfc5a01fc..8bf17a2eb 100644 --- a/include/Nazara/Utility/TriangleIterator.hpp +++ b/include/Nazara/Utility/TriangleIterator.hpp @@ -24,7 +24,7 @@ namespace Nz bool Advance(); - UInt32 operator[](unsigned int i) const; + UInt32 operator[](std::size_t i) const; void Unmap(); @@ -32,8 +32,8 @@ namespace Nz PrimitiveMode m_primitiveMode; UInt32 m_triangleIndices[3]; IndexMapper m_indexMapper; - unsigned int m_currentIndex; - unsigned int m_indexCount; + std::size_t m_currentIndex; + std::size_t m_indexCount; }; } diff --git a/include/Nazara/Utility/Utility.hpp b/include/Nazara/Utility/Utility.hpp index d78121f2c..a0d8ec723 100644 --- a/include/Nazara/Utility/Utility.hpp +++ b/include/Nazara/Utility/Utility.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -25,15 +24,12 @@ namespace Nz static bool IsInitialized(); - static void SetParameters(const ParameterList& parameters); - static void Uninitialize(); static unsigned int ComponentCount[ComponentType_Max+1]; static std::size_t ComponentStride[ComponentType_Max+1]; private: - static ParameterList s_initializationParameters; static unsigned int s_moduleReferenceCounter; }; } diff --git a/include/Nazara/Utility/VertexBuffer.inl b/include/Nazara/Utility/VertexBuffer.inl index 588289f92..09f701d12 100644 --- a/include/Nazara/Utility/VertexBuffer.inl +++ b/include/Nazara/Utility/VertexBuffer.inl @@ -39,7 +39,7 @@ namespace Nz inline bool VertexBuffer::IsValid() const { - return m_buffer && m_vertexDeclaration; + return m_buffer.IsValid() && m_vertexDeclaration.IsValid(); } template diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index e65d460db..7834e0019 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -108,21 +108,21 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) if (parameters.optimizeIndexBuffers) postProcess |= aiProcess_ImproveCacheLocality; - float smoothingAngle = 80.f; - parameters.custom.GetFloatParameter("AssimpLoader_SmoothingAngle", &smoothingAngle); + double smoothingAngle = 80.f; + parameters.custom.GetDoubleParameter("AssimpLoader_SmoothingAngle", &smoothingAngle); - int triangleLimit = 1'000'000; + long long triangleLimit = 1'000'000; parameters.custom.GetIntegerParameter("AssimpLoader_TriangleLimit", &triangleLimit); - int vertexLimit = 1'000'000; + long long vertexLimit = 1'000'000; parameters.custom.GetIntegerParameter("AssimpLoader_VertexLimit", &vertexLimit); aiPropertyStore* properties = aiCreatePropertyStore(); - aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, smoothingAngle); + aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, float(smoothingAngle)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SBP_REMOVE, ~aiPrimitiveType_TRIANGLE); //< We only want triangles - aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, triangleLimit); - aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_VERTEX_LIMIT, vertexLimit); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_TRIANGLE_LIMIT, int(triangleLimit)); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SLM_VERTEX_LIMIT, int(vertexLimit)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, aiComponent_COLORS); const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties); @@ -141,19 +141,19 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) { for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { - aiMesh* mesh = scene->mMeshes[i]; - if (mesh->HasBones()) // Inline functions can be safely called + aiMesh* currentMesh = scene->mMeshes[i]; + if (currentMesh->HasBones()) // Inline functions can be safely called { animatedMesh = true; - for (unsigned int j = 0; j < mesh->mNumBones; ++j) - joints.insert(mesh->mBones[j]->mName.C_Str()); + for (unsigned int j = 0; j < currentMesh->mNumBones; ++j) + joints.insert(currentMesh->mBones[j]->mName.C_Str()); } } } if (animatedMesh) { - mesh->CreateSkeletal(joints.size()); + mesh->CreateSkeletal(UInt32(joints.size())); Skeleton* skeleton = mesh->GetSkeleton(); @@ -171,7 +171,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) mesh->CreateStatic(); // aiMaterial index in scene => Material index and data in Mesh - std::unordered_map> materials; + std::unordered_map> materials; for (unsigned int i = 0; i < scene->mNumMeshes; ++i) { @@ -202,6 +202,12 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) indexMapper.Unmap(); // Vertex buffer + + // Make sure the normal/tangent matrix won't rescale our vectors + Nz::Matrix4f normalTangentMatrix = parameters.matrix; + if (normalTangentMatrix.HasScale()) + normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); + VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0); BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); @@ -214,8 +220,8 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) aiVector3D uv = (iMesh->HasTextureCoords(0)) ? iMesh->mTextureCoords[0][j] : aiVector3D(0.f); vertex->position = parameters.matrix * Vector3f(position.x, position.y, position.z); - vertex->normal.Set(normal.x, normal.y, normal.z); - vertex->tangent.Set(tangent.x, tangent.y, tangent.z); + vertex->normal = normalTangentMatrix.Transform({normal.x, normal.y, normal.z}, 0.f); + vertex->tangent = normalTangentMatrix.Transform({tangent.x, tangent.y, tangent.z}, 0.f); vertex->uv.Set(parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale); vertex++; } @@ -276,7 +282,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) break; } - matData.SetParameter(wrapKey, static_cast(wrap)); + matData.SetParameter(wrapKey, static_cast(wrap)); } } }; @@ -300,7 +306,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) matData.SetParameter(MaterialData::FaceCulling, !iValue); - matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(materials.size(), std::move(matData)))).first; + matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first; } subMesh->SetMaterialIndex(matIt->first); @@ -308,7 +314,7 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) mesh->AddSubMesh(subMesh); } - mesh->SetMaterialCount(std::max(materials.size(), 1)); + mesh->SetMaterialCount(std::max(UInt32(materials.size()), 1)); for (const auto& pair : materials) mesh->SetMaterialData(pair.second.first, pair.second.second); } diff --git a/readme_fr.md b/readme_fr.md index 808788b0d..22215c42c 100644 --- a/readme_fr.md +++ b/readme_fr.md @@ -43,7 +43,7 @@ Vous pouvez lire des tutoriaux sur l'installation, la compilation et l'utilisati [Wiki](https://github.com/DigitalPulseSoftware/NazaraEngine/wiki) [Forum](https://forum.digitalpulsesoftware.net) -###Remerciements: +### Remerciements: - **RafBill** et **Raakz:** Recherche de bugs et/ou tests - **Fissal "DrFisher" Hannoun**: Aide et conseils lors de la conception de l'architecture du moteur diff --git a/src/Nazara/Core/AbstractHash.cpp b/src/Nazara/Core/AbstractHash.cpp index ae2cb63b5..39e5a2ef2 100644 --- a/src/Nazara/Core/AbstractHash.cpp +++ b/src/Nazara/Core/AbstractHash.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,9 @@ namespace Nz case HashType_CRC32: return std::make_unique(); + case HashType_CRC64: + return std::make_unique(); + case HashType_MD5: return std::make_unique(); diff --git a/src/Nazara/Core/GuillotineBinPack.cpp b/src/Nazara/Core/GuillotineBinPack.cpp index 0f74bab5b..85270a562 100644 --- a/src/Nazara/Core/GuillotineBinPack.cpp +++ b/src/Nazara/Core/GuillotineBinPack.cpp @@ -312,9 +312,9 @@ namespace Nz while (!remainingRects.empty()) { // Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better. - bool bestFlipped; - std::size_t bestFreeRect; - std::size_t bestRect; + bool bestFlipped = false; + std::size_t bestFreeRect = m_freeRectangles.size(); + std::size_t bestRect = std::numeric_limits::min(); int bestScore = std::numeric_limits::max(); for (std::size_t i = 0; i < m_freeRectangles.size(); ++i) diff --git a/src/Nazara/Core/Hash/CRC64.cpp b/src/Nazara/Core/Hash/CRC64.cpp new file mode 100644 index 000000000..3001009a3 --- /dev/null +++ b/src/Nazara/Core/Hash/CRC64.cpp @@ -0,0 +1,115 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Core module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + struct HashCRC64_state + { + UInt64 crc; + }; + + namespace + { + static const UInt64 crc64_table[256] = { + 0x0000000000000000ULL, 0x7ad870c830358979ULL, 0xf5b0e190606b12f2ULL, 0x8f689158505e9b8bULL, + 0xc038e5739841b68fULL, 0xbae095bba8743ff6ULL, 0x358804e3f82aa47dULL, 0x4f50742bc81f2d04ULL, + 0xab28ecb46814fe75ULL, 0xd1f09c7c5821770cULL, 0x5e980d24087fec87ULL, 0x24407dec384a65feULL, + 0x6b1009c7f05548faULL, 0x11c8790fc060c183ULL, 0x9ea0e857903e5a08ULL, 0xe478989fa00bd371ULL, + 0x7d08ff3b88be6f81ULL, 0x07d08ff3b88be6f8ULL, 0x88b81eabe8d57d73ULL, 0xf2606e63d8e0f40aULL, + 0xbd301a4810ffd90eULL, 0xc7e86a8020ca5077ULL, 0x4880fbd87094cbfcULL, 0x32588b1040a14285ULL, + 0xd620138fe0aa91f4ULL, 0xacf86347d09f188dULL, 0x2390f21f80c18306ULL, 0x594882d7b0f40a7fULL, + 0x1618f6fc78eb277bULL, 0x6cc0863448deae02ULL, 0xe3a8176c18803589ULL, 0x997067a428b5bcf0ULL, + 0xfa11fe77117cdf02ULL, 0x80c98ebf2149567bULL, 0x0fa11fe77117cdf0ULL, 0x75796f2f41224489ULL, + 0x3a291b04893d698dULL, 0x40f16bccb908e0f4ULL, 0xcf99fa94e9567b7fULL, 0xb5418a5cd963f206ULL, + 0x513912c379682177ULL, 0x2be1620b495da80eULL, 0xa489f35319033385ULL, 0xde51839b2936bafcULL, + 0x9101f7b0e12997f8ULL, 0xebd98778d11c1e81ULL, 0x64b116208142850aULL, 0x1e6966e8b1770c73ULL, + 0x8719014c99c2b083ULL, 0xfdc17184a9f739faULL, 0x72a9e0dcf9a9a271ULL, 0x08719014c99c2b08ULL, + 0x4721e43f0183060cULL, 0x3df994f731b68f75ULL, 0xb29105af61e814feULL, 0xc849756751dd9d87ULL, + 0x2c31edf8f1d64ef6ULL, 0x56e99d30c1e3c78fULL, 0xd9810c6891bd5c04ULL, 0xa3597ca0a188d57dULL, + 0xec09088b6997f879ULL, 0x96d1784359a27100ULL, 0x19b9e91b09fcea8bULL, 0x636199d339c963f2ULL, + 0xdf7adabd7a6e2d6fULL, 0xa5a2aa754a5ba416ULL, 0x2aca3b2d1a053f9dULL, 0x50124be52a30b6e4ULL, + 0x1f423fcee22f9be0ULL, 0x659a4f06d21a1299ULL, 0xeaf2de5e82448912ULL, 0x902aae96b271006bULL, + 0x74523609127ad31aULL, 0x0e8a46c1224f5a63ULL, 0x81e2d7997211c1e8ULL, 0xfb3aa75142244891ULL, + 0xb46ad37a8a3b6595ULL, 0xceb2a3b2ba0eececULL, 0x41da32eaea507767ULL, 0x3b024222da65fe1eULL, + 0xa2722586f2d042eeULL, 0xd8aa554ec2e5cb97ULL, 0x57c2c41692bb501cULL, 0x2d1ab4dea28ed965ULL, + 0x624ac0f56a91f461ULL, 0x1892b03d5aa47d18ULL, 0x97fa21650afae693ULL, 0xed2251ad3acf6feaULL, + 0x095ac9329ac4bc9bULL, 0x7382b9faaaf135e2ULL, 0xfcea28a2faafae69ULL, 0x8632586aca9a2710ULL, + 0xc9622c4102850a14ULL, 0xb3ba5c8932b0836dULL, 0x3cd2cdd162ee18e6ULL, 0x460abd1952db919fULL, + 0x256b24ca6b12f26dULL, 0x5fb354025b277b14ULL, 0xd0dbc55a0b79e09fULL, 0xaa03b5923b4c69e6ULL, + 0xe553c1b9f35344e2ULL, 0x9f8bb171c366cd9bULL, 0x10e3202993385610ULL, 0x6a3b50e1a30ddf69ULL, + 0x8e43c87e03060c18ULL, 0xf49bb8b633338561ULL, 0x7bf329ee636d1eeaULL, 0x012b592653589793ULL, + 0x4e7b2d0d9b47ba97ULL, 0x34a35dc5ab7233eeULL, 0xbbcbcc9dfb2ca865ULL, 0xc113bc55cb19211cULL, + 0x5863dbf1e3ac9decULL, 0x22bbab39d3991495ULL, 0xadd33a6183c78f1eULL, 0xd70b4aa9b3f20667ULL, + 0x985b3e827bed2b63ULL, 0xe2834e4a4bd8a21aULL, 0x6debdf121b863991ULL, 0x1733afda2bb3b0e8ULL, + 0xf34b37458bb86399ULL, 0x8993478dbb8deae0ULL, 0x06fbd6d5ebd3716bULL, 0x7c23a61ddbe6f812ULL, + 0x3373d23613f9d516ULL, 0x49aba2fe23cc5c6fULL, 0xc6c333a67392c7e4ULL, 0xbc1b436e43a74e9dULL, + 0x95ac9329ac4bc9b5ULL, 0xef74e3e19c7e40ccULL, 0x601c72b9cc20db47ULL, 0x1ac40271fc15523eULL, + 0x5594765a340a7f3aULL, 0x2f4c0692043ff643ULL, 0xa02497ca54616dc8ULL, 0xdafce7026454e4b1ULL, + 0x3e847f9dc45f37c0ULL, 0x445c0f55f46abeb9ULL, 0xcb349e0da4342532ULL, 0xb1eceec59401ac4bULL, + 0xfebc9aee5c1e814fULL, 0x8464ea266c2b0836ULL, 0x0b0c7b7e3c7593bdULL, 0x71d40bb60c401ac4ULL, + 0xe8a46c1224f5a634ULL, 0x927c1cda14c02f4dULL, 0x1d148d82449eb4c6ULL, 0x67ccfd4a74ab3dbfULL, + 0x289c8961bcb410bbULL, 0x5244f9a98c8199c2ULL, 0xdd2c68f1dcdf0249ULL, 0xa7f41839ecea8b30ULL, + 0x438c80a64ce15841ULL, 0x3954f06e7cd4d138ULL, 0xb63c61362c8a4ab3ULL, 0xcce411fe1cbfc3caULL, + 0x83b465d5d4a0eeceULL, 0xf96c151de49567b7ULL, 0x76048445b4cbfc3cULL, 0x0cdcf48d84fe7545ULL, + 0x6fbd6d5ebd3716b7ULL, 0x15651d968d029fceULL, 0x9a0d8ccedd5c0445ULL, 0xe0d5fc06ed698d3cULL, + 0xaf85882d2576a038ULL, 0xd55df8e515432941ULL, 0x5a3569bd451db2caULL, 0x20ed197575283bb3ULL, + 0xc49581ead523e8c2ULL, 0xbe4df122e51661bbULL, 0x3125607ab548fa30ULL, 0x4bfd10b2857d7349ULL, + 0x04ad64994d625e4dULL, 0x7e7514517d57d734ULL, 0xf11d85092d094cbfULL, 0x8bc5f5c11d3cc5c6ULL, + 0x12b5926535897936ULL, 0x686de2ad05bcf04fULL, 0xe70573f555e26bc4ULL, 0x9ddd033d65d7e2bdULL, + 0xd28d7716adc8cfb9ULL, 0xa85507de9dfd46c0ULL, 0x273d9686cda3dd4bULL, 0x5de5e64efd965432ULL, + 0xb99d7ed15d9d8743ULL, 0xc3450e196da80e3aULL, 0x4c2d9f413df695b1ULL, 0x36f5ef890dc31cc8ULL, + 0x79a59ba2c5dc31ccULL, 0x037deb6af5e9b8b5ULL, 0x8c157a32a5b7233eULL, 0xf6cd0afa9582aa47ULL, + 0x4ad64994d625e4daULL, 0x300e395ce6106da3ULL, 0xbf66a804b64ef628ULL, 0xc5bed8cc867b7f51ULL, + 0x8aeeace74e645255ULL, 0xf036dc2f7e51db2cULL, 0x7f5e4d772e0f40a7ULL, 0x05863dbf1e3ac9deULL, + 0xe1fea520be311aafULL, 0x9b26d5e88e0493d6ULL, 0x144e44b0de5a085dULL, 0x6e963478ee6f8124ULL, + 0x21c640532670ac20ULL, 0x5b1e309b16452559ULL, 0xd476a1c3461bbed2ULL, 0xaeaed10b762e37abULL, + 0x37deb6af5e9b8b5bULL, 0x4d06c6676eae0222ULL, 0xc26e573f3ef099a9ULL, 0xb8b627f70ec510d0ULL, + 0xf7e653dcc6da3dd4ULL, 0x8d3e2314f6efb4adULL, 0x0256b24ca6b12f26ULL, 0x788ec2849684a65fULL, + 0x9cf65a1b368f752eULL, 0xe62e2ad306bafc57ULL, 0x6946bb8b56e467dcULL, 0x139ecb4366d1eea5ULL, + 0x5ccebf68aecec3a1ULL, 0x2616cfa09efb4ad8ULL, 0xa97e5ef8cea5d153ULL, 0xd3a62e30fe90582aULL, + 0xb0c7b7e3c7593bd8ULL, 0xca1fc72bf76cb2a1ULL, 0x45775673a732292aULL, 0x3faf26bb9707a053ULL, + 0x70ff52905f188d57ULL, 0x0a2722586f2d042eULL, 0x854fb3003f739fa5ULL, 0xff97c3c80f4616dcULL, + 0x1bef5b57af4dc5adULL, 0x61372b9f9f784cd4ULL, 0xee5fbac7cf26d75fULL, 0x9487ca0fff135e26ULL, + 0xdbd7be24370c7322ULL, 0xa10fceec0739fa5bULL, 0x2e675fb4576761d0ULL, 0x54bf2f7c6752e8a9ULL, + 0xcdcf48d84fe75459ULL, 0xb71738107fd2dd20ULL, 0x387fa9482f8c46abULL, 0x42a7d9801fb9cfd2ULL, + 0x0df7adabd7a6e2d6ULL, 0x772fdd63e7936bafULL, 0xf8474c3bb7cdf024ULL, 0x829f3cf387f8795dULL, + 0x66e7a46c27f3aa2cULL, 0x1c3fd4a417c62355ULL, 0x935745fc4798b8deULL, 0xe98f353477ad31a7ULL, + 0xa6df411fbfb21ca3ULL, 0xdc0731d78f8795daULL, 0x536fa08fdfd90e51ULL, 0x29b7d047efec8728ULL + }; + } + + void HashCRC64::Append(const UInt8* data, std::size_t len) + { + while (len--) + m_crc = crc64_table[(m_crc ^ *data++) & 0xFF] ^ (m_crc >> 8); + } + + void HashCRC64::Begin() + { + m_crc = 0; + } + + ByteArray HashCRC64::End() + { + #ifdef NAZARA_LITTLE_ENDIAN + SwapBytes(&m_crc, sizeof(UInt64)); + #endif + + return ByteArray(reinterpret_cast(&m_crc), 8); + } + + std::size_t HashCRC64::GetDigestLength() const + { + return 8; + } + + const char* HashCRC64::GetHashName() const + { + return "CRC64"; + } +} diff --git a/src/Nazara/Core/Hash/MD5.cpp b/src/Nazara/Core/Hash/MD5.cpp index 769ccb1a8..b0f25d684 100644 --- a/src/Nazara/Core/Hash/MD5.cpp +++ b/src/Nazara/Core/Hash/MD5.cpp @@ -101,7 +101,7 @@ namespace Nz { struct HashMD5_state { - UInt32 count[2]; /* message length in bits, lsw first */ + std::size_t count[2]; /* message length in bits, lsw first */ UInt32 abcd[4]; /* digest buffer */ UInt8 buf[64]; /* accumulate block */ }; @@ -280,9 +280,9 @@ namespace Nz void HashMD5::Append(const UInt8* data, std::size_t len) { const UInt8 *p = data; - int left = len; + std::size_t left = len; int offset = (m_state->count[0] >> 3) & 63; - UInt32 nbits = len << 3; + std::size_t nbits = len << 3; if (len <= 0) return; @@ -296,7 +296,7 @@ namespace Nz /* Process an initial partial block. */ if (offset) { - int copy = (offset + len > 64 ? 64 - offset : len); + std::size_t copy = (offset + len > 64 ? 64 - offset : len); std::memcpy(m_state->buf + offset, p, copy); if (offset + copy < 64) diff --git a/src/Nazara/Core/Hash/Whirlpool.cpp b/src/Nazara/Core/Hash/Whirlpool.cpp index 12b3e2a1b..e01fb4f4f 100644 --- a/src/Nazara/Core/Hash/Whirlpool.cpp +++ b/src/Nazara/Core/Hash/Whirlpool.cpp @@ -75,8 +75,8 @@ namespace Nz { struct HashWhirlpool_state { - int bufferBits; // current number of bits on the buffer */ - int bufferPos; // current (possibly incomplete) byte slot on the buffer */ + std::size_t bufferBits; // current number of bits on the buffer */ + std::size_t bufferPos; // current (possibly incomplete) byte slot on the buffer */ UInt8 bitLength[32]; // global number of hashed bits (256-bit counter) */ UInt8 buffer[64]; // buffer of data to hash */ UInt64 hash[8]; // the hashing state */ @@ -877,8 +877,8 @@ namespace Nz UInt32 b; UInt8* buffer = m_state->buffer; UInt8* bitLength = m_state->bitLength; - int bufferBits = m_state->bufferBits; - int bufferPos = m_state->bufferPos; + std::size_t bufferBits = m_state->bufferBits; + std::size_t bufferPos = m_state->bufferPos; // tally the length of the added data UInt64 value = len; @@ -968,8 +968,8 @@ namespace Nz UInt8 *buffer = m_state->buffer; UInt8 *bitLength = m_state->bitLength; - int bufferBits = m_state->bufferBits; - int bufferPos = m_state->bufferPos; + std::size_t bufferBits = m_state->bufferBits; + std::size_t bufferPos = m_state->bufferPos; UInt8 *digest = result; // append a '1'-bit diff --git a/src/Nazara/Core/MemoryManager.cpp b/src/Nazara/Core/MemoryManager.cpp index 2c4034623..aaf6bc520 100644 --- a/src/Nazara/Core/MemoryManager.cpp +++ b/src/Nazara/Core/MemoryManager.cpp @@ -413,9 +413,9 @@ namespace Nz while (ptr != &s_list) { if (ptr->file) - std::fprintf(log, "-0x%p -> %zu bytes allocated at %s:%u\n", reinterpret_cast(ptr) + sizeof(Block), ptr->size, ptr->file, ptr->line); + std::fprintf(log, "-0x%s -> %zu bytes allocated at %s:%u\n", reinterpret_cast(ptr) + sizeof(Block), ptr->size, ptr->file, ptr->line); else - std::fprintf(log, "-0x%p -> %zu bytes allocated at unknown position\n", reinterpret_cast(ptr) + sizeof(Block), ptr->size); + std::fprintf(log, "-0x%s -> %zu bytes allocated at unknown position\n", reinterpret_cast(ptr) + sizeof(Block), ptr->size); void* pointer = ptr; ptr = ptr->next; diff --git a/src/Nazara/Core/ParameterList.cpp b/src/Nazara/Core/ParameterList.cpp index 5206dd333..89fdb4591 100644 --- a/src/Nazara/Core/ParameterList.cpp +++ b/src/Nazara/Core/ParameterList.cpp @@ -95,7 +95,7 @@ namespace Nz } case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_None: case ParameterType_Pointer: case ParameterType_Userdata: @@ -137,9 +137,9 @@ namespace Nz return true; case ParameterType_Boolean: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_String: - case ParameterType_Float: case ParameterType_None: case ParameterType_Pointer: case ParameterType_Userdata: @@ -151,19 +151,19 @@ namespace Nz } /*! - * \brief Gets a parameter as a float - * \return true if the parameter could be represented as a float + * \brief Gets a parameter as a double + * \return true if the parameter could be represented as a double * * \param name Name of the parameter - * \param value Pointer to a float to hold the retrieved value + * \param value Pointer to a double to hold the retrieved value * * \remark value must be a valid pointer * \remark In case of failure, the variable pointed by value keep its value - * \remark If the parameter is not a float, a conversion will be performed, compatibles types are: - Integer: The integer value is converted to its float representation + * \remark If the parameter is not a double, a conversion will be performed, compatibles types are: + Integer: The integer value is converted to its double representation String: Conversion obeys the rule as described by String::ToDouble */ - bool ParameterList::GetFloatParameter(const String& name, float* value) const + bool ParameterList::GetDoubleParameter(const String& name, double* value) const { NazaraAssert(value, "Invalid pointer"); @@ -178,12 +178,12 @@ namespace Nz switch (it->second.type) { - case ParameterType_Float: - *value = it->second.value.floatVal; + case ParameterType_Double: + *value = it->second.value.doubleVal; return true; case ParameterType_Integer: - *value = static_cast(it->second.value.intVal); + *value = static_cast(it->second.value.intVal); return true; case ParameterType_String: @@ -191,7 +191,7 @@ namespace Nz double converted; if (it->second.value.stringVal.ToDouble(&converted)) { - *value = static_cast(converted); + *value = converted; return true; } @@ -206,7 +206,7 @@ namespace Nz break; } - NazaraError("Parameter value is not representable as a float"); + NazaraError("Parameter value is not representable as a double"); return false; } @@ -219,12 +219,12 @@ namespace Nz * * \remark value must be a valid pointer * \remark In case of failure, the variable pointed by value keep its value - * \remark If the parameter is not a float, a conversion will be performed, compatibles types are: + * \remark If the parameter is not an integer, a conversion will be performed, compatibles types are: Boolean: The boolean is represented as 1 if true and 0 if false - Float: The floating-point value is truncated and converted to a integer - String: Conversion obeys the rule as described by String::ToInteger but fails if the value could not be represented as a int + Double: The floating-point value is truncated and converted to a integer + String: Conversion obeys the rule as described by String::ToInteger */ - bool ParameterList::GetIntegerParameter(const String& name, int* value) const + bool ParameterList::GetIntegerParameter(const String& name, long long* value) const { NazaraAssert(value, "Invalid pointer"); @@ -243,8 +243,8 @@ namespace Nz *value = (it->second.value.boolVal) ? 1 : 0; return true; - case ParameterType_Float: - *value = static_cast(it->second.value.floatVal); + case ParameterType_Double: + *value = static_cast(it->second.value.doubleVal); return true; case ParameterType_Integer: @@ -256,11 +256,8 @@ namespace Nz long long converted; if (it->second.value.stringVal.ToInteger(&converted)) { - if (converted <= std::numeric_limits::max() && converted >= std::numeric_limits::min()) - { - *value = static_cast(converted); - return true; - } + *value = converted; + return true; } break; } @@ -335,7 +332,7 @@ namespace Nz case ParameterType_Boolean: case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_None: case ParameterType_String: @@ -358,7 +355,7 @@ namespace Nz * \remark If the parameter is not a string, a conversion will be performed, all types are compatibles: Boolean: Conversion obeys the rules of String::Boolean Color: Conversion obeys the rules of Color::ToString - Float: Conversion obeys the rules of String::Number + Double: Conversion obeys the rules of String::Number Integer: Conversion obeys the rules of String::Number None: An empty string is returned Pointer: Conversion obeys the rules of String::Pointer @@ -387,8 +384,8 @@ namespace Nz *value = it->second.value.colorVal.ToString(); return true; - case ParameterType_Float: - *value = String::Number(it->second.value.floatVal); + case ParameterType_Double: + *value = String::Number(it->second.value.doubleVal); return true; case ParameterType_Integer: @@ -560,18 +557,18 @@ namespace Nz } /*! - * \brief Sets a float parameter named `name` + * \brief Sets a double parameter named `name` * * If a parameter already exists with that name, it is destroyed and replaced by this call * * \param name Name of the parameter - * \param value The float value + * \param value The double value */ - void ParameterList::SetParameter(const String& name, float value) + void ParameterList::SetParameter(const String& name, double value) { Parameter& parameter = CreateValue(name); - parameter.type = ParameterType_Float; - parameter.value.floatVal = value; + parameter.type = ParameterType_Double; + parameter.value.doubleVal = value; } /*! @@ -582,7 +579,7 @@ namespace Nz * \param name Name of the parameter * \param value The integer value */ - void ParameterList::SetParameter(const String& name, int value) + void ParameterList::SetParameter(const String& name, long long value) { Parameter& parameter = CreateValue(name); parameter.type = ParameterType_Integer; @@ -627,8 +624,8 @@ namespace Nz case ParameterType_Color: ss << "Color(" << it->second.value.colorVal.ToString() << ")"; break; - case ParameterType_Float: - ss << "Float(" << it->second.value.floatVal << ")"; + case ParameterType_Double: + ss << "Double(" << it->second.value.doubleVal << ")"; break; case ParameterType_Integer: ss << "Integer(" << it->second.value.intVal << ")"; @@ -692,7 +689,7 @@ namespace Nz { case ParameterType_Boolean: case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_Pointer: std::memcpy(¶meter, &it->second, sizeof(Parameter)); @@ -764,7 +761,7 @@ namespace Nz case ParameterType_Boolean: case ParameterType_Color: - case ParameterType_Float: + case ParameterType_Double: case ParameterType_Integer: case ParameterType_None: case ParameterType_Pointer: diff --git a/src/Nazara/Core/Posix/FileImpl.cpp b/src/Nazara/Core/Posix/FileImpl.cpp index 5603ed79b..75b2275cc 100644 --- a/src/Nazara/Core/Posix/FileImpl.cpp +++ b/src/Nazara/Core/Posix/FileImpl.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace Nz @@ -72,11 +73,47 @@ namespace Nz if (mode & OpenMode_Truncate) flags |= O_TRUNC; - ///TODO: lock - //if ((mode & OpenMode_Lock) == 0) - // shareMode |= FILE_SHARE_WRITE; - m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions); + + static struct flock lock; + + auto initialize_flock = [](struct flock& fileLock) + { + fileLock.l_type = F_WRLCK; + fileLock.l_start = 0; + fileLock.l_whence = SEEK_SET; + fileLock.l_len = 0; + fileLock.l_pid = getpid(); + }; + + initialize_flock(lock); + + if (fcntl(m_fileDescriptor, F_GETLK, &lock) == -1) + { + Close(); + NazaraError("Unable to detect presence of lock on the file"); + return false; + } + + if (lock.l_type != F_UNLCK) + { + Close(); + NazaraError("A lock is present on the file"); + return false; + } + + if (mode & OpenMode_Lock) + { + initialize_flock(lock); + + if (fcntl(m_fileDescriptor, F_SETLK, &lock) == -1) + { + Close(); + NazaraError("Unable to place a lock on the file"); + return false; + } + } + return m_fileDescriptor != -1; } @@ -128,10 +165,7 @@ namespace Nz std::size_t FileImpl::Write(const void* buffer, std::size_t size) { - lockf64(m_fileDescriptor, F_LOCK, size); ssize_t written = write(m_fileDescriptor, buffer, size); - lockf64(m_fileDescriptor, F_ULOCK, size); - m_endOfFileUpdated = false; return written; diff --git a/src/Nazara/Core/Posix/ThreadImpl.cpp b/src/Nazara/Core/Posix/ThreadImpl.cpp index c16424328..aa0b87c5d 100644 --- a/src/Nazara/Core/Posix/ThreadImpl.cpp +++ b/src/Nazara/Core/Posix/ThreadImpl.cpp @@ -5,8 +5,9 @@ #include #include #include +#include +#include #include -#include #include namespace Nz @@ -28,6 +29,43 @@ namespace Nz pthread_join(m_handle, nullptr); } + void ThreadImpl::SetName(const Nz::String& name) + { +#ifdef __GNUC__ + pthread_setname_np(m_handle, name.GetConstBuffer()); +#else + NazaraWarning("Setting thread name is not supported on this platform"); +#endif + } + + void ThreadImpl::SetCurrentName(const Nz::String& name) + { +#ifdef __GNUC__ + pthread_setname_np(pthread_self(), name.GetConstBuffer()); +#else + NazaraWarning("Setting current thread name is not supported on this platform"); +#endif + } + + void ThreadImpl::Sleep(UInt32 time) + { + if (time == 0) + sched_yield(); + else + { + struct timespec ts; + ts.tv_sec = time / 1000; + ts.tv_nsec = (time - ts.tv_sec * 1000) * 1'000'000; + + int r; + do + { + r = nanosleep(&ts, &ts); + } + while (r == -1 && errno == EINTR); + } + } + void* ThreadImpl::ThreadProc(void* userdata) { Functor* func = static_cast(userdata); @@ -36,40 +74,4 @@ namespace Nz return nullptr; } - - void ThreadImpl::Sleep(UInt32 time) - { - // code from SFML2 Unix SleepImpl.cpp source https://github.com/LaurentGomila/SFML/blob/master/src/SFML/System/Unix/SleepImpl.cpp - - // usleep is not reliable enough (it might block the - // whole process instead of just the current thread) - // so we must use pthread_cond_timedwait instead - - // this implementation is inspired from Qt - - // get the current time - timeval tv; - gettimeofday(&tv, nullptr); - - // construct the time limit (current time + time to wait) - timespec ti; - ti.tv_nsec = (tv.tv_usec + (time % 1000)) * 1000; - ti.tv_sec = tv.tv_sec + (time / 1000) + (ti.tv_nsec / 1000000000); - ti.tv_nsec %= 1000000000; - - // create a mutex and thread condition - pthread_mutex_t mutex; - pthread_mutex_init(&mutex, nullptr); - pthread_cond_t condition; - pthread_cond_init(&condition, nullptr); - - // wait... - pthread_mutex_lock(&mutex); - pthread_cond_timedwait(&condition, &mutex, &ti); - pthread_mutex_unlock(&mutex); - - // destroy the mutex and condition - pthread_cond_destroy(&condition); - pthread_mutex_destroy(&mutex); - } } diff --git a/src/Nazara/Core/Posix/ThreadImpl.hpp b/src/Nazara/Core/Posix/ThreadImpl.hpp index 1ed6f3c8a..ba3d4ed84 100644 --- a/src/Nazara/Core/Posix/ThreadImpl.hpp +++ b/src/Nazara/Core/Posix/ThreadImpl.hpp @@ -8,6 +8,12 @@ #define NAZARA_THREADIMPL_HPP #include +#include + +#if defined(__GNUC__) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE +#endif + #include namespace Nz @@ -21,7 +27,9 @@ namespace Nz void Detach(); void Join(); + void SetName(const Nz::String& name); + static void SetCurrentName(const Nz::String& name); static void Sleep(UInt32 time); private: diff --git a/src/Nazara/Core/String.cpp b/src/Nazara/Core/String.cpp index 7ea8c7df2..98a8b882c 100644 --- a/src/Nazara/Core/String.cpp +++ b/src/Nazara/Core/String.cpp @@ -2115,7 +2115,7 @@ namespace Nz return ptr - m_sharedString->string.get(); } - catch (utf8::not_enough_room& e) + catch (utf8::not_enough_room& /*e*/) { // Returns npos } diff --git a/src/Nazara/Core/Thread.cpp b/src/Nazara/Core/Thread.cpp index c9532ec19..d8b0ebd42 100644 --- a/src/Nazara/Core/Thread.cpp +++ b/src/Nazara/Core/Thread.cpp @@ -117,6 +117,25 @@ namespace Nz m_impl = nullptr; } + /*! + * \brief Changes the debugging name associated to a thread + * + * Changes the debugging name associated with a particular thread, and may helps with debugging tools. + * + * \param name The new name of the thread + * + * \remark Due to system limitations, thread name cannot exceed 15 characters (excluding null-terminator) + * + * \see SetCurrentThreadName + */ + void Thread::SetName(const String& name) + { + NazaraAssert(m_impl, "Invalid thread"); + NazaraAssert(name.GetSize() < 16, "Thread name is too long"); + + m_impl->SetName(name); + } + /*! * \brief Moves the other thread into this * \return A reference to this @@ -145,18 +164,35 @@ namespace Nz * \brief Gets the number of simulatenous threads that can run on the same cpu * \return The number of simulatenous threads */ - unsigned int Thread::HardwareConcurrency() { return HardwareInfo::GetProcessorCount(); } + + /*! + * \brief Changes the debugging name associated to the calling thread + * + * Changes the debugging name associated with the calling thread, and may helps with debugging tools. + * + * \param name The new name associated with this thread + * + * \remark Due to system limitations, thread name cannot exceed 15 characters (excluding null-terminator) + * + * \see SetName + */ + void Thread::SetCurrentThreadName(const String& name) + { + NazaraAssert(name.GetSize() < 16, "Thread name is too long"); + + ThreadImpl::SetCurrentName(name); + } + /*! * \brief Makes sleep this thread * * \param milliseconds The number of milliseconds to sleep */ - void Thread::Sleep(UInt32 milliseconds) { ThreadImpl::Sleep(milliseconds); diff --git a/src/Nazara/Core/Win32/FileImpl.cpp b/src/Nazara/Core/Win32/FileImpl.cpp index b7c5d0f2d..4e5d75c6c 100644 --- a/src/Nazara/Core/Win32/FileImpl.cpp +++ b/src/Nazara/Core/Win32/FileImpl.cpp @@ -191,9 +191,7 @@ namespace Nz LARGE_INTEGER cursorPos; cursorPos.QuadPart = GetCursorPos(); - LockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, static_cast(size), 0); WriteFile(m_handle, buffer, static_cast(size), &written, nullptr); - UnlockFile(m_handle, cursorPos.LowPart, cursorPos.HighPart, static_cast(size), 0); m_endOfFileUpdated = false; diff --git a/src/Nazara/Core/Win32/ThreadImpl.cpp b/src/Nazara/Core/Win32/ThreadImpl.cpp index 5b44b94b6..cae997874 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.cpp +++ b/src/Nazara/Core/Win32/ThreadImpl.cpp @@ -6,15 +6,32 @@ #include #include #include +#include #include namespace Nz { + namespace + { +#pragma pack(push,8) + struct THREADNAME_INFO + { + DWORD dwType; + LPCSTR szName; + DWORD dwThreadID; + DWORD dwFlags; + }; +#pragma pack(pop) + } + ThreadImpl::ThreadImpl(Functor* functor) { - m_handle = reinterpret_cast(_beginthreadex(nullptr, 0, &ThreadImpl::ThreadProc, functor, 0, nullptr)); + unsigned int threadId; + m_handle = reinterpret_cast(_beginthreadex(nullptr, 0, &ThreadImpl::ThreadProc, functor, 0, &threadId)); if (!m_handle) NazaraInternalError("Failed to create thread: " + Error::GetLastSystemError()); + + m_threadId = threadId; } void ThreadImpl::Detach() @@ -29,6 +46,44 @@ namespace Nz CloseHandle(m_handle); } + void ThreadImpl::SetName(const Nz::String& name) + { + SetThreadName(m_threadId, name.GetConstBuffer()); + } + + void ThreadImpl::SetCurrentName(const Nz::String& name) + { + SetThreadName(::GetCurrentThreadId(), name.GetConstBuffer()); + } + + void ThreadImpl::Sleep(UInt32 time) + { + ::Sleep(time); + } + + void ThreadImpl::SetThreadName(DWORD threadId, const char* threadName) + { + // https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = threadId; + info.dwFlags = 0; + +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try + { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), reinterpret_cast(&info)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + } +#pragma warning(pop) + } + unsigned int __stdcall ThreadImpl::ThreadProc(void* userdata) { Functor* func = static_cast(userdata); @@ -42,9 +97,4 @@ namespace Nz return 0; } - - void ThreadImpl::Sleep(UInt32 time) - { - ::Sleep(time); - } } diff --git a/src/Nazara/Core/Win32/ThreadImpl.hpp b/src/Nazara/Core/Win32/ThreadImpl.hpp index 12e7f5c14..8070f7a22 100644 --- a/src/Nazara/Core/Win32/ThreadImpl.hpp +++ b/src/Nazara/Core/Win32/ThreadImpl.hpp @@ -10,6 +10,7 @@ #define NAZARA_THREADIMPL_HPP #include +#include #include namespace Nz @@ -23,12 +24,16 @@ namespace Nz void Detach(); void Join(); + void SetName(const Nz::String& name); + static void SetCurrentName(const Nz::String& name); static void Sleep(UInt32 time); private: + static void SetThreadName(DWORD threadId, const char* threadName); static unsigned int __stdcall ThreadProc(void* userdata); + DWORD m_threadId; HANDLE m_handle; }; } diff --git a/src/Nazara/Graphics/DeferredRenderQueue.cpp b/src/Nazara/Graphics/DeferredRenderQueue.cpp index 22ead6ec0..a0455fe11 100644 --- a/src/Nazara/Graphics/DeferredRenderQueue.cpp +++ b/src/Nazara/Graphics/DeferredRenderQueue.cpp @@ -191,8 +191,8 @@ namespace Nz void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) { - if (material->IsBlendingEnabled()) - // One transparent material ? I don't like it, go see if I'm in the forward queue + if (material->IsBlendingEnabled() || material->IsDepthSortingEnabled()) //< Fixme: Deferred Shading should be able to handle depth sorting + // Deferred Shading cannot handle blended objects, put them in the forward list m_forwardQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix); else { @@ -254,7 +254,7 @@ namespace Nz * \param overlay Texture of the sprites */ - void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) + void DeferredRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay) { m_forwardQueue->AddSprites(renderOrder, material, vertices, spriteCount, overlay); } diff --git a/src/Nazara/Graphics/DepthRenderQueue.cpp b/src/Nazara/Graphics/DepthRenderQueue.cpp index 46096e33f..a2acdf4bb 100644 --- a/src/Nazara/Graphics/DepthRenderQueue.cpp +++ b/src/Nazara/Graphics/DepthRenderQueue.cpp @@ -351,7 +351,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) + void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); diff --git a/src/Nazara/Graphics/DepthRenderTechnique.cpp b/src/Nazara/Graphics/DepthRenderTechnique.cpp index d58975d7f..4acbbc56d 100644 --- a/src/Nazara/Graphics/DepthRenderTechnique.cpp +++ b/src/Nazara/Graphics/DepthRenderTechnique.cpp @@ -68,7 +68,7 @@ namespace Nz * \param sceneData Data of the scene */ - void DepthRenderTechnique::Clear(const SceneData& sceneData) const + void DepthRenderTechnique::Clear(const SceneData& /*sceneData*/) const { Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthWrite, true); @@ -95,7 +95,7 @@ namespace Nz if (!layer.opaqueModels.empty()) DrawOpaqueModels(sceneData, layer); - if (!layer.basicSprites.empty()) + if (!layer.opaqueSprites.empty()) DrawBasicSprites(sceneData, layer); if (!layer.billboards.empty()) @@ -219,7 +219,7 @@ namespace Nz Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetVertexBuffer(&m_spriteBuffer); - for (auto& pipelinePair : layer.basicSprites) + for (auto& pipelinePair : layer.opaqueSprites) { const MaterialPipeline* pipeline = pipelinePair.first; auto& pipelineEntry = pipelinePair.second; diff --git a/src/Nazara/Graphics/ForwardRenderQueue.cpp b/src/Nazara/Graphics/ForwardRenderQueue.cpp index 8eb70fe7e..840875ea3 100644 --- a/src/Nazara/Graphics/ForwardRenderQueue.cpp +++ b/src/Nazara/Graphics/ForwardRenderQueue.cpp @@ -376,23 +376,23 @@ namespace Nz { NazaraAssert(material, "Invalid material"); - if (material->IsBlendingEnabled()) + if (material->IsDepthSortingEnabled()) { Layer& currentLayer = GetLayer(renderOrder); - auto& transparentModels = currentLayer.transparentModels; - auto& transparentModelData = currentLayer.transparentModelData; + auto& transparentMeshes = currentLayer.depthSortedMeshes; + auto& transparentData = currentLayer.depthSortedMeshData; - // The material is transparent, we must draw this mesh using another way (after the rendering of opages objects while sorting them) - std::size_t index = transparentModelData.size(); - transparentModelData.resize(index+1); + // The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them) + std::size_t index = transparentData.size(); + transparentData.resize(index+1); - TransparentModelData& data = transparentModelData.back(); + UnbatchedModelData& data = transparentData.back(); data.material = material; data.meshData = meshData; - data.squaredBoundingSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius()); + data.obbSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius()); data.transformMatrix = transformMatrix; - transparentModels.push_back(index); + transparentMeshes.push_back(index); } else { @@ -457,53 +457,74 @@ namespace Nz * * \remark Produces a NazaraAssert if material is invalid */ - void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, unsigned int spriteCount, const Texture* overlay) + void ForwardRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Texture* overlay) { NazaraAssert(material, "Invalid material"); Layer& currentLayer = GetLayer(renderOrder); - SpritePipelineBatches& basicSprites = currentLayer.basicSprites; - const MaterialPipeline* materialPipeline = material->GetPipeline(); - - auto pipelineIt = basicSprites.find(materialPipeline); - if (pipelineIt == basicSprites.end()) + if (material->IsDepthSortingEnabled()) { - BatchedSpritePipelineEntry materialEntry; - pipelineIt = basicSprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first; + auto& transparentSprites = currentLayer.depthSortedSprites; + auto& transparentData = currentLayer.depthSortedSpriteData; + + // The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them) + std::size_t index = transparentData.size(); + transparentData.resize(index + 1); + + UnbatchedSpriteData& data = transparentData.back(); + data.material = material; + data.overlay = overlay; + data.spriteCount = spriteCount; + data.vertices = vertices; + + transparentSprites.push_back(index); } - - BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second; - pipelineEntry.enabled = true; - - SpriteMaterialBatches& materialMap = pipelineEntry.materialMap; - - auto matIt = materialMap.find(material); - if (matIt == materialMap.end()) + else { - BatchedBasicSpriteEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); + SpritePipelineBatches& sprites = currentLayer.opaqueSprites; - matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first; + const MaterialPipeline* materialPipeline = material->GetPipeline(); + + auto pipelineIt = sprites.find(materialPipeline); + if (pipelineIt == sprites.end()) + { + BatchedSpritePipelineEntry materialEntry; + pipelineIt = sprites.insert(SpritePipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first; + } + + BatchedSpritePipelineEntry& pipelineEntry = pipelineIt->second; + pipelineEntry.enabled = true; + + SpriteMaterialBatches& materialMap = pipelineEntry.materialMap; + + auto matIt = materialMap.find(material); + if (matIt == materialMap.end()) + { + BatchedBasicSpriteEntry entry; + entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); + + matIt = materialMap.insert(SpriteMaterialBatches::value_type(material, std::move(entry))).first; + } + + BatchedBasicSpriteEntry& entry = matIt->second; + entry.enabled = true; + + auto& overlayMap = entry.overlayMap; + + auto overlayIt = overlayMap.find(overlay); + if (overlayIt == overlayMap.end()) + { + BatchedSpriteEntry overlayEntry; + if (overlay) + overlayEntry.textureReleaseSlot.Connect(overlay->OnTextureRelease, this, &ForwardRenderQueue::OnTextureInvalidation); + + overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first; + } + + auto& spriteVector = overlayIt->second.spriteChains; + spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount})); } - - BatchedBasicSpriteEntry& entry = matIt->second; - entry.enabled = true; - - auto& overlayMap = entry.overlayMap; - - auto overlayIt = overlayMap.find(overlay); - if (overlayIt == overlayMap.end()) - { - BatchedSpriteEntry overlayEntry; - if (overlay) - overlayEntry.textureReleaseSlot.Connect(overlay->OnTextureRelease, this, &ForwardRenderQueue::OnTextureInvalidation); - - overlayIt = overlayMap.insert(std::make_pair(overlay, std::move(overlayEntry))).first; - } - - auto& spriteVector = overlayIt->second.spriteChains; - spriteVector.push_back(SpriteChain_XYZ_Color_UV({vertices, spriteCount})); } /*! @@ -545,7 +566,7 @@ namespace Nz pipelineEntry.enabled = false; } - for (auto& pipelinePair : layer.basicSprites) + for (auto& pipelinePair : layer.opaqueSprites) { auto& pipelineEntry = pipelinePair.second; @@ -596,9 +617,11 @@ namespace Nz } } + layer.depthSortedMeshes.clear(); + layer.depthSortedMeshData.clear(); + layer.depthSortedSpriteData.clear(); + layer.depthSortedSprites.clear(); layer.otherDrawables.clear(); - layer.transparentModels.clear(); - layer.transparentModelData.clear(); ++it; } } @@ -613,44 +636,10 @@ namespace Nz void ForwardRenderQueue::Sort(const AbstractViewer* viewer) { - Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near); - Vector3f viewerPos = viewer->GetEyePosition(); - Vector3f viewerNormal = viewer->GetForward(); - - for (auto& pair : layers) - { - Layer& layer = pair.second; - - std::sort(layer.transparentModels.begin(), layer.transparentModels.end(), [&layer, &nearPlane, &viewerNormal] (std::size_t index1, std::size_t index2) - { - const Spheref& sphere1 = layer.transparentModelData[index1].squaredBoundingSphere; - const Spheref& sphere2 = layer.transparentModelData[index2].squaredBoundingSphere; - - Vector3f position1 = sphere1.GetNegativeVertex(viewerNormal); - Vector3f position2 = sphere2.GetNegativeVertex(viewerNormal); - - return nearPlane.Distance(position1) > nearPlane.Distance(position2); - }); - - for (auto& pipelinePair : layer.billboards) - { - for (auto& matPair : pipelinePair.second.materialMap) - { - const Material* mat = matPair.first; - - if (mat->IsDepthSortingEnabled()) - { - BatchedBillboardEntry& entry = matPair.second; - auto& billboardVector = entry.billboards; - - std::sort(billboardVector.begin(), billboardVector.end(), [&viewerPos] (const BillboardData& data1, const BillboardData& data2) - { - return viewerPos.SquaredDistance(data1.center) > viewerPos.SquaredDistance(data2.center); - }); - } - } - } - } + if (viewer->GetProjectionType() == ProjectionType_Orthogonal) + SortForOrthographic(viewer); + else + SortForPerspective(viewer); } /*! @@ -708,19 +697,97 @@ namespace Nz auto it = layers.find(i); if (it == layers.end()) it = layers.insert(std::make_pair(i, Layer())).first; - + Layer& layer = it->second; layer.clearCount = 0; 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); + + for (auto& pair : layers) + { + Layer& layer = pair.second; + + std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2) + { + const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere; + const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere; + + return nearPlane.Distance(sphere1.GetPosition()) < nearPlane.Distance(sphere2.GetPosition()); + }); + + std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &nearPlane] (std::size_t index1, std::size_t index2) + { + const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position; + const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position; + + return nearPlane.Distance(pos1) < nearPlane.Distance(pos2); + }); + + SortBillboards(layer, nearPlane); + } + } + + void ForwardRenderQueue::SortForPerspective(const AbstractViewer* viewer) + { + Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near); + Vector3f viewerPos = viewer->GetEyePosition(); + + for (auto& pair : layers) + { + Layer& layer = pair.second; + + std::sort(layer.depthSortedMeshes.begin(), layer.depthSortedMeshes.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2) + { + const Spheref& sphere1 = layer.depthSortedMeshData[index1].obbSphere; + const Spheref& sphere2 = layer.depthSortedMeshData[index2].obbSphere; + + return viewerPos.SquaredDistance(sphere1.GetPosition()) > viewerPos.SquaredDistance(sphere2.GetPosition()); + }); + + std::sort(layer.depthSortedSprites.begin(), layer.depthSortedSprites.end(), [&layer, &viewerPos] (std::size_t index1, std::size_t index2) + { + const Vector3f& pos1 = layer.depthSortedSpriteData[index1].vertices[0].position; + const Vector3f& pos2 = layer.depthSortedSpriteData[index2].vertices[0].position; + + return viewerPos.SquaredDistance(pos1) > viewerPos.SquaredDistance(pos2); + }); + + SortBillboards(layer, nearPlane); + } + } + /*! * \brief Handle the invalidation of an index buffer * * \param indexBuffer Index buffer being invalidated */ - void ForwardRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) { for (auto& pair : layers) @@ -757,7 +824,7 @@ namespace Nz { Layer& layer = pair.second; - for (auto& pipelineEntry : layer.basicSprites) + for (auto& pipelineEntry : layer.opaqueSprites) pipelineEntry.second.materialMap.erase(material); for (auto& pipelineEntry : layer.billboards) @@ -779,7 +846,7 @@ namespace Nz for (auto& pair : layers) { Layer& layer = pair.second; - for (auto& pipelineEntry : layer.basicSprites) + for (auto& pipelineEntry : layer.opaqueSprites) { for (auto& materialEntry : pipelineEntry.second.materialMap) materialEntry.second.overlayMap.erase(texture); diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index c0493e74b..1d202c837 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -33,8 +33,8 @@ namespace Nz Vector2f uv; }; - std::size_t s_maxQuads = std::numeric_limits::max() / 6; - std::size_t s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + UInt32 s_maxQuads = std::numeric_limits::max() / 6; + UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB } /*! @@ -101,12 +101,15 @@ namespace Nz if (!layer.opaqueModels.empty()) DrawOpaqueModels(sceneData, layer); - if (!layer.transparentModels.empty()) + if (!layer.depthSortedMeshes.empty()) DrawTransparentModels(sceneData, layer); - if (!layer.basicSprites.empty()) + if (!layer.opaqueSprites.empty()) DrawBasicSprites(sceneData, layer); + if (!layer.depthSortedSprites.empty()) + DrawOrderedSprites(sceneData, layer); + if (!layer.billboards.empty()) DrawBillboards(sceneData, layer); @@ -301,7 +304,10 @@ namespace Nz Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetVertexBuffer(&m_spriteBuffer); - for (auto& pipelinePair : layer.basicSprites) + const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); + const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); + + for (auto& pipelinePair : layer.opaqueSprites) { const MaterialPipeline* pipeline = pipelinePair.first; auto& pipelineEntry = pipelinePair.second; @@ -323,6 +329,9 @@ namespace Nz // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); + // Overlay texture unit + shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); + lastShader = shader; } @@ -335,10 +344,6 @@ namespace Nz { material->Apply(pipelineInstance); - unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); - - shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); - Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler()); auto& overlayMap = matEntry.overlayMap; @@ -362,7 +367,6 @@ namespace Nz VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); std::size_t spriteCount = 0; - std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); do { @@ -777,6 +781,142 @@ namespace Nz } } + void ForwardRenderTechnique::DrawOrderedSprites(const SceneData & sceneData, ForwardRenderQueue::Layer & layer) const + { + NazaraAssert(sceneData.viewer, "Invalid viewer"); + + Renderer::SetIndexBuffer(&s_quadIndexBuffer); + Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); + Renderer::SetVertexBuffer(&m_spriteBuffer); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const Texture* lastOverlay = nullptr; + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); + + bool updateVertexBuffer = true; + const std::size_t maxSpriteCount = std::min(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 vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); + VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); + + std::size_t availableSpriteSpace = maxSpriteCount; + bool split = false; + for (auto it2 = it; it2 != layer.depthSortedSprites.end(); ++it2) + { + const ForwardRenderQueue::UnbatchedSpriteData& spriteData = layer.depthSortedSpriteData[*it2]; + + std::size_t count = std::min(availableSpriteSpace, spriteData.spriteCount - spriteChainOffset); + + std::memcpy(vertices, spriteData.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += count * 4; + + availableSpriteSpace -= count; + + // Have we treated the entire chain ? + if (count != spriteData.spriteCount) + { + // Oops, not enough space to store current chain + spriteChainOffset += count; + splitChainIt = it2; + split = true; + break; + } + + // Switch to next sprite chain, if any + spriteChainOffset = 0; + } + + spriteIndex = 0; + updateVertexBuffer = false; + + if (!split) + splitChainIt = layer.depthSortedSprites.end(); + } + + std::size_t index = *it; + + const ForwardRenderQueue::UnbatchedSpriteData& spriteData = layer.depthSortedSpriteData[index]; + + const Material* material = spriteData.material; + if (material != lastMaterial) + { + const MaterialPipeline* pipeline = material->GetPipeline(); + if (pipeline != lastPipeline) + { + pipelineInstance = &pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + + // Uniforms are conserved in our program, there's no point to send them back until they change + if (shader != lastShader) + { + // Index of uniforms in the shader + const ShaderUniforms* shaderUniforms = GetShaderUniforms(shader); + + // Ambient color of the scene + shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + // Position of the camera + shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); + // Overlay texture unit + shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + material->Apply(*pipelineInstance); + + Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler()); + + lastMaterial = material; + } + + const Texture* overlay = (spriteData.overlay) ? spriteData.overlay : &m_whiteTexture; + if (overlay != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, overlay); + lastOverlay = overlay; + } + + std::size_t spriteCount; + if (it != splitChainIt) + { + spriteCount = spriteData.spriteCount - alreadyDrawnCount; + alreadyDrawnCount = 0; + + ++it; + } + else + { + spriteCount = spriteChainOffset; + + alreadyDrawnCount = spriteCount; + updateVertexBuffer = true; + + // Restart at current iterator next time + } + + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, spriteIndex * 6, spriteCount * 6); + spriteIndex += spriteCount; + } + } + /*! * \brief Draws transparent models * @@ -796,9 +936,9 @@ namespace Nz const ShaderUniforms* shaderUniforms = nullptr; unsigned int lightCount = 0; - for (unsigned int index : layer.transparentModels) + for (std::size_t index : layer.depthSortedMeshes) { - const ForwardRenderQueue::TransparentModelData& modelData = layer.transparentModelData[index]; + const ForwardRenderQueue::UnbatchedModelData& modelData = layer.depthSortedMeshData[index]; // Material const Material* material = modelData.material; @@ -865,8 +1005,8 @@ namespace Nz if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS) { // Compute the closest lights - Vector3f position = matrix.GetTranslation() + modelData.squaredBoundingSphere.GetPosition(); - float radius = modelData.squaredBoundingSphere.radius; + Vector3f position = matrix.GetTranslation() + modelData.obbSphere.GetPosition(); + float radius = modelData.obbSphere.radius; ChooseLights(Spheref(position, radius), false); for (std::size_t i = lightCount; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) @@ -990,7 +1130,6 @@ namespace Nz if (uniforms.locations.shadowMapping != -1) shader->SendBoolean(uniforms.locations.shadowMapping + uniformOffset, light.shadowMap != nullptr); - unsigned int textureUnit = Material::GetTextureUnit(static_cast(TextureMap_ShadowCube_1 + index)); if (light.shadowMap) { unsigned int textureUnitCube = Material::GetTextureUnit(static_cast(TextureMap_ShadowCube_1 + index)); @@ -1014,7 +1153,6 @@ namespace Nz if (uniforms.locations.shadowMapping != -1) shader->SendBoolean(uniforms.locations.shadowMapping + uniformOffset, light.shadowMap != nullptr); - unsigned int textureUnit = Material::GetTextureUnit(static_cast(TextureMap_Shadow2D_1 + index)); if (light.shadowMap) { unsigned int textureUnit2D = Material::GetTextureUnit(static_cast(TextureMap_Shadow2D_1 + index)); diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index e1b202716..5ae1d8554 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -173,7 +173,7 @@ namespace Nz } /*! - * \brief Uninitializes the Core module + * \brief Uninitializes the Graphics module * * \remark Produces a NazaraNotice */ diff --git a/src/Nazara/Graphics/Material.cpp b/src/Nazara/Graphics/Material.cpp index df871f9f2..0e865038a 100644 --- a/src/Nazara/Graphics/Material.cpp +++ b/src/Nazara/Graphics/Material.cpp @@ -114,14 +114,14 @@ namespace Nz { Color color; bool isEnabled; - float fValue; - int iValue; + double dValue; + long long iValue; String path; ErrorFlags errFlags(ErrorFlag_Silent | ErrorFlag_ThrowExceptionDisabled, true); - if (matData.GetFloatParameter(MaterialData::AlphaThreshold, &fValue)) - SetAlphaThreshold(fValue); + if (matData.GetDoubleParameter(MaterialData::AlphaThreshold, &dValue)) + SetAlphaThreshold(float(dValue)); if (matData.GetBooleanParameter(MaterialData::AlphaTest, &isEnabled)) EnableAlphaTest(isEnabled); @@ -147,17 +147,17 @@ namespace Nz if (matData.GetIntegerParameter(MaterialData::FaceFilling, &iValue)) SetFaceFilling(static_cast(iValue)); - if (matData.GetFloatParameter(MaterialData::LineWidth, &fValue)) - SetLineWidth(fValue); + if (matData.GetDoubleParameter(MaterialData::LineWidth, &dValue)) + SetLineWidth(float(dValue)); - if (matData.GetFloatParameter(MaterialData::PointSize, &fValue)) - SetPointSize(fValue); + if (matData.GetDoubleParameter(MaterialData::PointSize, &dValue)) + SetPointSize(float(dValue)); if (matData.GetColorParameter(MaterialData::SpecularColor, &color)) SetSpecularColor(color); - if (matData.GetFloatParameter(MaterialData::Shininess, &fValue)) - SetShininess(fValue); + if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue)) + SetShininess(float(dValue)); if (matData.GetIntegerParameter(MaterialData::SrcBlend, &iValue)) SetSrcBlend(static_cast(iValue)); @@ -277,17 +277,17 @@ namespace Nz matData->SetParameter(MaterialData::AlphaTest, IsAlphaTestEnabled()); matData->SetParameter(MaterialData::AlphaThreshold, GetAlphaThreshold()); matData->SetParameter(MaterialData::AmbientColor, GetAmbientColor()); - matData->SetParameter(MaterialData::CullingSide, int(GetFaceCulling())); - matData->SetParameter(MaterialData::DepthFunc, int(GetDepthFunc())); + matData->SetParameter(MaterialData::CullingSide, static_cast(GetFaceCulling())); + matData->SetParameter(MaterialData::DepthFunc, static_cast(GetDepthFunc())); matData->SetParameter(MaterialData::DepthSorting, IsDepthSortingEnabled()); matData->SetParameter(MaterialData::DiffuseColor, GetDiffuseColor()); - matData->SetParameter(MaterialData::DstBlend, int(GetDstBlend())); - matData->SetParameter(MaterialData::FaceFilling, int(GetFaceFilling())); + matData->SetParameter(MaterialData::DstBlend, static_cast(GetDstBlend())); + matData->SetParameter(MaterialData::FaceFilling, static_cast(GetFaceFilling())); matData->SetParameter(MaterialData::LineWidth, GetLineWidth()); matData->SetParameter(MaterialData::PointSize, GetPointSize()); matData->SetParameter(MaterialData::Shininess, GetShininess()); matData->SetParameter(MaterialData::SpecularColor, GetSpecularColor()); - matData->SetParameter(MaterialData::SrcBlend, int(GetSrcBlend())); + matData->SetParameter(MaterialData::SrcBlend, static_cast(GetSrcBlend())); // RendererParameter matData->SetParameter(MaterialData::Blending, IsBlendingEnabled()); @@ -299,29 +299,29 @@ namespace Nz matData->SetParameter(MaterialData::StencilTest, IsStencilTestEnabled()); // Samplers - matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, int(GetDiffuseSampler().GetAnisotropicLevel())); - matData->SetParameter(MaterialData::DiffuseFilter, int(GetDiffuseSampler().GetFilterMode())); - matData->SetParameter(MaterialData::DiffuseWrap, int(GetDiffuseSampler().GetWrapMode())); + matData->SetParameter(MaterialData::DiffuseAnisotropyLevel, static_cast(GetDiffuseSampler().GetAnisotropicLevel())); + matData->SetParameter(MaterialData::DiffuseFilter, static_cast(GetDiffuseSampler().GetFilterMode())); + matData->SetParameter(MaterialData::DiffuseWrap, static_cast(GetDiffuseSampler().GetWrapMode())); - matData->SetParameter(MaterialData::SpecularAnisotropyLevel, int(GetSpecularSampler().GetAnisotropicLevel())); - matData->SetParameter(MaterialData::SpecularFilter, int(GetSpecularSampler().GetFilterMode())); - matData->SetParameter(MaterialData::SpecularWrap, int(GetSpecularSampler().GetWrapMode())); + matData->SetParameter(MaterialData::SpecularAnisotropyLevel, static_cast(GetSpecularSampler().GetAnisotropicLevel())); + matData->SetParameter(MaterialData::SpecularFilter, static_cast(GetSpecularSampler().GetFilterMode())); + matData->SetParameter(MaterialData::SpecularWrap, static_cast(GetSpecularSampler().GetWrapMode())); // Stencil - matData->SetParameter(MaterialData::StencilCompare, int(GetPipelineInfo().stencilCompare.front)); - matData->SetParameter(MaterialData::StencilFail, int(GetPipelineInfo().stencilFail.front)); - matData->SetParameter(MaterialData::StencilPass, int(GetPipelineInfo().stencilPass.front)); - matData->SetParameter(MaterialData::StencilZFail, int(GetPipelineInfo().stencilDepthFail.front)); - matData->SetParameter(MaterialData::StencilMask, int(GetPipelineInfo().stencilWriteMask.front)); - matData->SetParameter(MaterialData::StencilReference, int(GetPipelineInfo().stencilReference.front)); + matData->SetParameter(MaterialData::StencilCompare, static_cast(GetPipelineInfo().stencilCompare.front)); + matData->SetParameter(MaterialData::StencilFail, static_cast(GetPipelineInfo().stencilFail.front)); + matData->SetParameter(MaterialData::StencilPass, static_cast(GetPipelineInfo().stencilPass.front)); + matData->SetParameter(MaterialData::StencilZFail, static_cast(GetPipelineInfo().stencilDepthFail.front)); + matData->SetParameter(MaterialData::StencilMask, static_cast(GetPipelineInfo().stencilWriteMask.front)); + matData->SetParameter(MaterialData::StencilReference, static_cast(GetPipelineInfo().stencilReference.front)); // Stencil (back) - matData->SetParameter(MaterialData::BackFaceStencilCompare, int(GetPipelineInfo().stencilCompare.back)); - matData->SetParameter(MaterialData::BackFaceStencilFail, int(GetPipelineInfo().stencilFail.back)); - matData->SetParameter(MaterialData::BackFaceStencilPass, int(GetPipelineInfo().stencilPass.back)); - matData->SetParameter(MaterialData::BackFaceStencilZFail, int(GetPipelineInfo().stencilDepthFail.back)); - matData->SetParameter(MaterialData::BackFaceStencilMask, int(GetPipelineInfo().stencilWriteMask.back)); - matData->SetParameter(MaterialData::BackFaceStencilReference, int(GetPipelineInfo().stencilReference.back)); + matData->SetParameter(MaterialData::BackFaceStencilCompare, static_cast(GetPipelineInfo().stencilCompare.back)); + matData->SetParameter(MaterialData::BackFaceStencilFail, static_cast(GetPipelineInfo().stencilFail.back)); + matData->SetParameter(MaterialData::BackFaceStencilPass, static_cast(GetPipelineInfo().stencilPass.back)); + matData->SetParameter(MaterialData::BackFaceStencilZFail, static_cast(GetPipelineInfo().stencilDepthFail.back)); + matData->SetParameter(MaterialData::BackFaceStencilMask, static_cast(GetPipelineInfo().stencilWriteMask.back)); + matData->SetParameter(MaterialData::BackFaceStencilReference, static_cast(GetPipelineInfo().stencilReference.back)); // Textures if (HasAlphaMap()) diff --git a/src/Nazara/Graphics/MaterialPipeline.cpp b/src/Nazara/Graphics/MaterialPipeline.cpp index 761bc500f..e9a100ad2 100644 --- a/src/Nazara/Graphics/MaterialPipeline.cpp +++ b/src/Nazara/Graphics/MaterialPipeline.cpp @@ -197,6 +197,7 @@ namespace Nz pipelineInfo.blending = true; pipelineInfo.depthWrite = false; pipelineInfo.faceCulling = false; + pipelineInfo.depthSorting = true; pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha; pipelineInfo.srcBlend = BlendFunc_SrcAlpha; @@ -207,6 +208,7 @@ namespace Nz pipelineInfo.depthBuffer = true; pipelineInfo.depthWrite = false; pipelineInfo.faceCulling = false; + pipelineInfo.depthSorting = true; pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha; pipelineInfo.srcBlend = BlendFunc_SrcAlpha; diff --git a/src/Nazara/Graphics/ParticleGroup.cpp b/src/Nazara/Graphics/ParticleGroup.cpp index 08743a58e..34a46089b 100644 --- a/src/Nazara/Graphics/ParticleGroup.cpp +++ b/src/Nazara/Graphics/ParticleGroup.cpp @@ -39,10 +39,10 @@ namespace Nz */ ParticleGroup::ParticleGroup(unsigned int maxParticleCount, ParticleDeclarationConstRef declaration) : - m_declaration(std::move(declaration)), - m_processing(false), m_maxParticleCount(maxParticleCount), - m_particleCount(0) + m_particleCount(0), + m_declaration(std::move(declaration)), + m_processing(false) { // In case of error, the constructor can only throw an exception ErrorFlags flags(ErrorFlag_ThrowException, true); @@ -60,14 +60,14 @@ namespace Nz ParticleGroup::ParticleGroup(const ParticleGroup& system) : Renderable(system), + m_maxParticleCount(system.m_maxParticleCount), + m_particleCount(system.m_particleCount), + m_particleSize(system.m_particleSize), m_controllers(system.m_controllers), m_generators(system.m_generators), m_declaration(system.m_declaration), m_renderer(system.m_renderer), - m_processing(false), - m_maxParticleCount(system.m_maxParticleCount), - m_particleCount(system.m_particleCount), - m_particleSize(system.m_particleSize) + m_processing(false) { ErrorFlags flags(ErrorFlag_ThrowException, true); diff --git a/src/Nazara/Lua/LuaCoroutine.cpp b/src/Nazara/Lua/LuaCoroutine.cpp new file mode 100644 index 000000000..197244134 --- /dev/null +++ b/src/Nazara/Lua/LuaCoroutine.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + LuaCoroutine::LuaCoroutine(lua_State* internalState, int refIndex) : + LuaState(internalState), + m_ref(refIndex) + { + } + + LuaCoroutine::~LuaCoroutine() + { + if (m_ref >= 0) + DestroyReference(m_ref); + } + + bool LuaCoroutine::CanResume() const + { + return lua_status(m_state) == LUA_YIELD; + } + + Ternary LuaCoroutine::Resume(unsigned int argCount) + { + LuaInstance& instance = GetInstance(m_state); + if (instance.m_level++ == 0) + instance.m_clock.Restart(); + + int status = lua_resume(m_state, nullptr, argCount); + instance.m_level--; + + if (status == LUA_OK) + return Ternary_True; + else if (status == LUA_YIELD) + return Ternary_Unknown; + else + { + m_lastError = ToString(-1); + Pop(); + return Ternary_False; + } + } + + bool LuaCoroutine::Run(int argCount, int /*resultCount*/) + { + return Resume(argCount) != Ternary_False; + } +} diff --git a/src/Nazara/Lua/LuaInstance.cpp b/src/Nazara/Lua/LuaInstance.cpp index 5e23d0a86..cd47ac5c7 100644 --- a/src/Nazara/Lua/LuaInstance.cpp +++ b/src/Nazara/Lua/LuaInstance.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,117 +22,16 @@ namespace Nz { namespace { - LuaType FromLuaType(int type) + int AtPanic(lua_State* internalState) { - switch (type) - { - case LUA_TBOOLEAN: - return LuaType_Boolean; - - case LUA_TFUNCTION: - return LuaType_Function; - - case LUA_TLIGHTUSERDATA: - return LuaType_LightUserdata; - - case LUA_TNIL: - return LuaType_Nil; - - case LUA_TNONE: - return LuaType_None; - - case LUA_TNUMBER: - return LuaType_Number; - - case LUA_TSTRING: - return LuaType_String; - - case LUA_TTABLE: - return LuaType_Table; - - case LUA_TTHREAD: - return LuaType_Thread; - - case LUA_TUSERDATA: - return LuaType_Userdata; - - default: - return LuaType_None; - } - } - - struct StreamData - { - Stream* stream; - char buffer[NAZARA_CORE_FILE_BUFFERSIZE]; - }; - - int AtPanic(lua_State* state) - { - String lastError(lua_tostring(state, -1)); + String lastError(lua_tostring(internalState, -1)); throw std::runtime_error("Lua panic: " + lastError); } - - const char* StreamReader(lua_State* state, void* data, std::size_t* size) - { - NazaraUnused(state); - - StreamData* streamData = static_cast(data); - - if (streamData->stream->EndOfStream()) - return nullptr; - else - { - *size = streamData->stream->Read(streamData->buffer, NAZARA_CORE_FILE_BUFFERSIZE); - return streamData->buffer; - } - } - - int s_comparisons[] = { - LUA_OPEQ, // LuaComparison_Equality - LUA_OPLT, // LuaComparison_Less - LUA_OPLE // LuaComparison_LessOrEqual - }; - - static_assert(sizeof(s_comparisons)/sizeof(int) == LuaComparison_Max+1, "Lua comparison array is incomplete"); - - int s_operations[] = { - LUA_OPADD, // LuaOperation_Addition - LUA_OPBAND, // LuaOperation_BitwiseAnd - LUA_OPSHL, // LuaOperation_BitwiseLeftShift - LUA_OPBNOT, // LuaOperation_BitwiseNot - LUA_OPBOR, // LuaOperation_BitwiseOr - LUA_OPSHR, // LuaOperation_BitwiseRightShift - LUA_OPBXOR, // LuaOperation_BitwiseXOr - LUA_OPDIV, // LuaOperation_Division - LUA_OPPOW, // LuaOperation_Exponentiation - LUA_OPIDIV, // LuaOperation_FloorDivision - LUA_OPMUL, // LuaOperation_Multiplication - LUA_OPMOD, // LuaOperation_Modulo - LUA_OPUNM, // LuaOperation_Negation - LUA_OPSUB // LuaOperation_Substraction - }; - - static_assert(sizeof(s_operations)/sizeof(int) == LuaOperation_Max+1, "Lua operation array is incomplete"); - - int s_types[] = { - LUA_TBOOLEAN, // LuaType_Boolean - LUA_TFUNCTION, // LuaType_Function - LUA_TLIGHTUSERDATA, // LuaType_LightUserdata - LUA_TNIL, // LuaType_Nil - LUA_TNUMBER, // LuaType_Number - LUA_TNONE, // LuaType_None - LUA_TSTRING, // LuaType_String - LUA_TTABLE, // LuaType_Table - LUA_TTHREAD, // LuaType_Thread - LUA_TUSERDATA // LuaType_Userdata - }; - - static_assert(sizeof(s_types)/sizeof(int) == LuaType_Max+1, "Lua type array is incomplete"); } LuaInstance::LuaInstance() : + LuaState(nullptr), m_memoryLimit(0), m_memoryUsage(0), m_timeLimit(1000), @@ -149,700 +49,22 @@ namespace Nz lua_close(m_state); } - void LuaInstance::ArgCheck(bool condition, unsigned int argNum, const char* error) const + inline void LuaInstance::SetMemoryUsage(std::size_t memoryUsage) { - luaL_argcheck(m_state, condition, argNum, error); - } - - void LuaInstance::ArgCheck(bool condition, unsigned int argNum, const String& error) const - { - luaL_argcheck(m_state, condition, argNum, error.GetConstBuffer()); - } - - int LuaInstance::ArgError(unsigned int argNum, const char* error) const - { - return luaL_argerror(m_state, argNum, error); - } - - int LuaInstance::ArgError(unsigned int argNum, const String& error) const - { - return luaL_argerror(m_state, argNum, error.GetConstBuffer()); - } - - bool LuaInstance::Call(unsigned int argCount) - { - return Run(argCount, LUA_MULTRET); - } - - bool LuaInstance::Call(unsigned int argCount, unsigned int resultCount) - { - return Run(argCount, resultCount); - } - - void LuaInstance::CheckAny(int index) const - { - luaL_checkany(m_state, index); - } - - bool LuaInstance::CheckBoolean(int index) const - { - if (lua_isnoneornil(m_state, index)) - { - const char* msg = lua_pushfstring(m_state, "%s expected, got %s", lua_typename(m_state, LUA_TBOOLEAN), luaL_typename(m_state, index)); - luaL_argerror(m_state, index, msg); // Lance une exception - return false; - } - - return lua_toboolean(m_state, index) != 0; - } - - bool LuaInstance::CheckBoolean(int index, bool defValue) const - { - if (lua_isnoneornil(m_state, index)) - return defValue; - - return lua_toboolean(m_state, index) != 0; - } - - long long LuaInstance::CheckInteger(int index) const - { - return luaL_checkinteger(m_state, index); - } - - long long LuaInstance::CheckInteger(int index, long long defValue) const - { - return luaL_optinteger(m_state, index, defValue); - } - - double LuaInstance::CheckNumber(int index) const - { - return luaL_checknumber(m_state, index); - } - - double LuaInstance::CheckNumber(int index, double defValue) const - { - return luaL_optnumber(m_state, index, defValue); - } - - void LuaInstance::CheckStack(int space, const char* error) const - { - luaL_checkstack(m_state, space, error); - } - - void LuaInstance::CheckStack(int space, const String& error) const - { - CheckStack(space, error.GetConstBuffer()); - } - - const char* LuaInstance::CheckString(int index, std::size_t* length) const - { - return luaL_checklstring(m_state, index, length); - } - - const char* LuaInstance::CheckString(int index, const char* defValue, std::size_t* length) const - { - return luaL_optlstring(m_state, index, defValue, length); - } - - void LuaInstance::CheckType(int index, LuaType type) const - { - #ifdef NAZARA_DEBUG - if (type > LuaType_Max) - { - NazaraError("Lua type out of enum"); - return; - } - #endif - - luaL_checktype(m_state, index, s_types[type]); - } - - void* LuaInstance::CheckUserdata(int index, const char* tname) const - { - return luaL_checkudata(m_state, index, tname); - } - - void* LuaInstance::CheckUserdata(int index, const String& tname) const - { - return luaL_checkudata(m_state, index, tname.GetConstBuffer()); - } - - bool LuaInstance::Compare(int index1, int index2, LuaComparison comparison) const - { - #ifdef NAZARA_DEBUG - if (comparison > LuaComparison_Max) - { - NazaraError("Lua comparison out of enum"); - return false; - } - #endif - - return (lua_compare(m_state, index1, index2, s_comparisons[comparison]) != 0); - } - - void LuaInstance::Compute(LuaOperation operation) const - { - #ifdef NAZARA_DEBUG - if (operation > LuaOperation_Max) - { - NazaraError("Lua operation out of enum"); - return; - } - #endif - - lua_arith(m_state, s_operations[operation]); - } - - void LuaInstance::Concatenate(int count) const - { - lua_concat(m_state, count); - } - - int LuaInstance::CreateReference() - { - return luaL_ref(m_state, LUA_REGISTRYINDEX); - } - - void LuaInstance::DestroyReference(int ref) - { - luaL_unref(m_state, LUA_REGISTRYINDEX, ref); - } - - String LuaInstance::DumpStack() const - { - StringStream stream; - unsigned int stackTop = GetStackTop(); - stream << stackTop << " entries\n"; - - for (unsigned int i = 1; i <= stackTop; ++i) - { - stream << i << ": "; - switch (GetType(i)) - { - case LuaType_Boolean: - stream << "Boolean(" << ToBoolean(i) << ')'; - break; - - case LuaType_Function: - stream << "Function(" << ToPointer(i) << ')'; - break; - - case LuaType_LightUserdata: - case LuaType_Userdata: - stream << "Userdata(" << ToUserdata(i) << ')'; - break; - - case LuaType_Nil: - stream << "Nil"; - break; - - case LuaType_None: - stream << "None"; - break; - - case LuaType_Number: - stream << "Number(" << ToNumber(i) << ')'; - break; - - case LuaType_String: - stream << "String(" << ToString(i) << ')'; - break; - - case LuaType_Table: - stream << "Table(" << ToPointer(i) << ')'; - break; - - case LuaType_Thread: - stream << "Thread(" << ToPointer(i) << ')'; - break; - - default: - stream << "Unknown(" << ToPointer(i) << ')'; - break; - } - - stream << '\n'; - } - - return stream.ToString(); - } - - void LuaInstance::Error(const char* message) const - { - luaL_error(m_state, message); - } - - void LuaInstance::Error(const String& message) const - { - luaL_error(m_state, message.GetConstBuffer()); - } - - bool LuaInstance::Execute(const String& code) - { - if (code.IsEmpty()) - return true; - - if (luaL_loadstring(m_state, code.GetConstBuffer()) != 0) - { - m_lastError = lua_tostring(m_state, -1); - lua_pop(m_state, 1); - - return false; - } - - return Run(0, 0); - } - - bool LuaInstance::ExecuteFromFile(const String& filePath) - { - File file(filePath); - if (!file.Open(OpenMode_ReadOnly | OpenMode_Text)) - { - NazaraError("Failed to open file"); - return false; - } - - std::size_t length = static_cast(file.GetSize()); - - String source(length, '\0'); - - if (file.Read(&source[0], length) != length) - { - NazaraError("Failed to read file"); - return false; - } - - file.Close(); - - return Execute(source); - } - - bool LuaInstance::ExecuteFromMemory(const void* data, std::size_t size) - { - MemoryView stream(data, size); - return ExecuteFromStream(stream); - } - - bool LuaInstance::ExecuteFromStream(Stream& stream) - { - StreamData data; - data.stream = &stream; - - if (lua_load(m_state, StreamReader, &data, "C++", nullptr) != 0) - { - m_lastError = lua_tostring(m_state, -1); - lua_pop(m_state, 1); - - return false; - } - - return Run(0, 0); - } - - int LuaInstance::GetAbsIndex(int index) const - { - return lua_absindex(m_state, index); - } - - LuaType LuaInstance::GetField(const char* fieldName, int tableIndex) const - { - return FromLuaType(lua_getfield(m_state, tableIndex, fieldName)); - } - - LuaType LuaInstance::GetField(const String& fieldName, int tableIndex) const - { - return FromLuaType(lua_getfield(m_state, tableIndex, fieldName.GetConstBuffer())); - } - - LuaType LuaInstance::GetGlobal(const char* name) const - { - return FromLuaType(lua_getglobal(m_state, name)); - } - - LuaType LuaInstance::GetGlobal(const String& name) const - { - return FromLuaType(lua_getglobal(m_state, name.GetConstBuffer())); - } - - LuaType LuaInstance::GetMetatable(const char* tname) const - { - return FromLuaType(luaL_getmetatable(m_state, tname)); - } - - LuaType LuaInstance::GetMetatable(const String& tname) const - { - return FromLuaType(luaL_getmetatable(m_state, tname.GetConstBuffer())); - } - - bool LuaInstance::GetMetatable(int index) const - { - return lua_getmetatable(m_state, index) != 0; - } - - unsigned int LuaInstance::GetStackTop() const - { - return static_cast(lua_gettop(m_state)); - } - - LuaType LuaInstance::GetTable(int index) const - { - return FromLuaType(lua_gettable(m_state, index)); - } - - LuaType LuaInstance::GetType(int index) const - { - return FromLuaType(lua_type(m_state, index)); - } - - const char* LuaInstance::GetTypeName(LuaType type) const - { - #ifdef NAZARA_DEBUG - if (type > LuaType_Max) - { - NazaraError("Lua type out of enum"); - return nullptr; - } - #endif - - return lua_typename(m_state, s_types[type]); - } - - void LuaInstance::Insert(int index) const - { - lua_insert(m_state, index); - } - - bool LuaInstance::IsOfType(int index, LuaType type) const - { - switch (type) - { - case LuaType_Boolean: - return lua_isboolean(m_state, index) != 0; - - case LuaType_Function: - return lua_isfunction(m_state, index) != 0; - - case LuaType_LightUserdata: - return lua_islightuserdata(m_state, index) != 0; - - case LuaType_Nil: - return lua_isnil(m_state, index) != 0; - - case LuaType_None: - return lua_isnone(m_state, index) != 0; - - case LuaType_Number: - return lua_isnumber(m_state, index) != 0; - - case LuaType_String: - return lua_isstring(m_state, index) != 0; - - case LuaType_Table: - return lua_istable(m_state, index) != 0; - - case LuaType_Thread: - return lua_isthread(m_state, index) != 0; - - case LuaType_Userdata: - return lua_isuserdata(m_state, index) != 0; - } - - NazaraError("Lua type not handled (0x" + String::Number(type, 16) + ')'); - return false; - } - - bool LuaInstance::IsOfType(int index, const char* tname) const - { - void* ud = luaL_testudata(m_state, index, tname); - return ud != nullptr; - } - - bool LuaInstance::IsOfType(int index, const String& tname) const - { - return IsOfType(index, tname.GetConstBuffer()); - } - - bool LuaInstance::IsValid(int index) const - { - return lua_isnoneornil(m_state, index) == 0; - } - - long long LuaInstance::Length(int index) const - { - return luaL_len(m_state, index); - } - - void LuaInstance::MoveTo(LuaInstance* instance, int n) const - { - lua_xmove(m_state, instance->m_state, n); - } - - bool LuaInstance::NewMetatable(const char* str) - { - return luaL_newmetatable(m_state, str) != 0; - } - - bool LuaInstance::NewMetatable(const String& str) - { - return luaL_newmetatable(m_state, str.GetConstBuffer()) != 0; - } - - bool LuaInstance::Next(int index) const - { - return lua_next(m_state, index) != 0; - } - - void LuaInstance::Pop(unsigned int n) const - { - lua_pop(m_state, static_cast(n)); - } - - void LuaInstance::PushBoolean(bool value) const - { - lua_pushboolean(m_state, (value) ? 1 : 0); - } - - void LuaInstance::PushCFunction(LuaCFunction func, unsigned int upvalueCount) const - { - lua_pushcclosure(m_state, func, upvalueCount); - } - - void LuaInstance::PushFunction(LuaFunction func) const - { - LuaFunction* luaFunc = static_cast(lua_newuserdata(m_state, sizeof(LuaFunction))); - PlacementNew(luaFunc, std::move(func)); - - lua_pushcclosure(m_state, ProxyFunc, 1); - } - - void LuaInstance::PushInteger(long long value) const - { - lua_pushinteger(m_state, value); - } - - void LuaInstance::PushLightUserdata(void* value) const - { - lua_pushlightuserdata(m_state, value); - } - - void LuaInstance::PushMetatable(const char* str) const - { - luaL_getmetatable(m_state, str); - } - - void LuaInstance::PushMetatable(const String& str) const - { - luaL_getmetatable(m_state, str.GetConstBuffer()); - } - - void LuaInstance::PushNil() const - { - lua_pushnil(m_state); - } - - void LuaInstance::PushNumber(double value) const - { - lua_pushnumber(m_state, value); - } - - void LuaInstance::PushReference(int ref) const - { - lua_rawgeti(m_state, LUA_REGISTRYINDEX, ref); - } - - void LuaInstance::PushString(const char* str) const - { - lua_pushstring(m_state, str); - } - - void LuaInstance::PushString(const char* str, std::size_t size) const - { - lua_pushlstring(m_state, str, size); - } - - void LuaInstance::PushString(const String& str) const - { - lua_pushlstring(m_state, str.GetConstBuffer(), str.GetSize()); - } - - void LuaInstance::PushTable(std::size_t sequenceElementCount, std::size_t arrayElementCount) const - { - constexpr std::size_t maxInt = std::numeric_limits::max(); - lua_createtable(m_state, static_cast(std::min(sequenceElementCount, maxInt)), static_cast(std::min(arrayElementCount, maxInt))); - } - - void* LuaInstance::PushUserdata(std::size_t size) const - { - return lua_newuserdata(m_state, size); - } - - void LuaInstance::PushValue(int index) const - { - lua_pushvalue(m_state, index); - } - - void LuaInstance::Remove(int index) const - { - lua_remove(m_state, index); - } - - void LuaInstance::Replace(int index) const - { - lua_replace(m_state, index); - } - - void LuaInstance::SetField(const char* name, int tableIndex) const - { - lua_setfield(m_state, tableIndex, name); - } - - void LuaInstance::SetField(const String& name, int tableIndex) const - { - lua_setfield(m_state, tableIndex, name.GetConstBuffer()); - } - - void LuaInstance::SetGlobal(const char* name) - { - lua_setglobal(m_state, name); - } - - void LuaInstance::SetGlobal(const String& name) - { - lua_setglobal(m_state, name.GetConstBuffer()); - } - - void LuaInstance::SetMetatable(const char* tname) const - { - luaL_setmetatable(m_state, tname); - } - - void LuaInstance::SetMetatable(const String& tname) const - { - luaL_setmetatable(m_state, tname.GetConstBuffer()); - } - - void LuaInstance::SetMetatable(int index) const - { - lua_setmetatable(m_state, index); - } - - void LuaInstance::SetMemoryLimit(std::size_t memoryLimit) - { - m_memoryLimit = memoryLimit; - } - - void LuaInstance::SetTable(int index) const - { - lua_settable(m_state, index); - } - - void LuaInstance::SetTimeLimit(UInt32 timeLimit) - { - if (m_timeLimit != timeLimit) - { - if (m_timeLimit == 0) - lua_sethook(m_state, TimeLimiter, LUA_MASKCOUNT, 1000); - else if (timeLimit == 0) - lua_sethook(m_state, TimeLimiter, 0, 1000); - - m_timeLimit = timeLimit; - } - } - - bool LuaInstance::ToBoolean(int index) const - { - return lua_toboolean(m_state, index) != 0; - } - - long long LuaInstance::ToInteger(int index, bool* succeeded) const - { - int success; - long long result = lua_tointegerx(m_state, index, &success); - - if (succeeded) - *succeeded = (success != 0); - - return result; - } - - double LuaInstance::ToNumber(int index, bool* succeeded) const - { - int success; - double result = lua_tonumberx(m_state, index, &success); - - if (succeeded) - *succeeded = (success != 0); - - return result; - } - - const void* LuaInstance::ToPointer(int index) const - { - return lua_topointer(m_state, index); - } - - const char* LuaInstance::ToString(int index, std::size_t* length) const - { - return lua_tolstring(m_state, index, length); - } - - void* LuaInstance::ToUserdata(int index) const - { - return lua_touserdata(m_state, index); - } - - void* LuaInstance::ToUserdata(int index, const char* tname) const - { - return luaL_testudata(m_state, index, tname); - } - - void* LuaInstance::ToUserdata(int index, const String& tname) const - { - return luaL_testudata(m_state, index, tname.GetConstBuffer()); - } - - int LuaInstance::GetIndexOfUpValue(int upValue) - { - return lua_upvalueindex(upValue); - } - - LuaInstance* LuaInstance::GetInstance(lua_State* state) - { - LuaInstance* instance; - lua_getallocf(state, reinterpret_cast(&instance)); - - return instance; - } - - bool LuaInstance::Run(int argCount, int resultCount) - { - if (m_level++ == 0) - m_clock.Restart(); - - int status = lua_pcall(m_state, argCount, resultCount, 0); - - m_level--; - - if (status != 0) - { - m_lastError = lua_tostring(m_state, -1); - lua_pop(m_state, 1); - - return false; - } - - return true; + m_memoryUsage = memoryUsage; } void* LuaInstance::MemoryAllocator(void* ud, void* ptr, std::size_t osize, std::size_t nsize) { LuaInstance* instance = static_cast(ud); - std::size_t& memoryLimit = instance->m_memoryLimit; - std::size_t& memoryUsage = instance->m_memoryUsage; + std::size_t memoryLimit = instance->GetMemoryLimit(); + std::size_t memoryUsage = instance->GetMemoryUsage(); if (nsize == 0) { - memoryUsage -= osize; + assert(memoryUsage >= osize); + + instance->SetMemoryUsage(memoryUsage - osize); std::free(ptr); return nullptr; @@ -859,24 +81,20 @@ namespace Nz return nullptr; } - memoryUsage = usage; + instance->SetMemoryUsage(usage); return std::realloc(ptr, nsize); } } - int LuaInstance::ProxyFunc(lua_State* state) - { - LuaFunction& func = *static_cast(lua_touserdata(state, lua_upvalueindex(1))); - return func(*GetInstance(state)); - } - - void LuaInstance::TimeLimiter(lua_State* state, lua_Debug* debug) + void LuaInstance::TimeLimiter(lua_State* internalState, lua_Debug* debug) { NazaraUnused(debug); - LuaInstance* instance = GetInstance(state); - if (instance->m_clock.GetMilliseconds() > instance->m_timeLimit) - luaL_error(state, "maximum execution time exceeded"); + LuaInstance* instance; + lua_getallocf(internalState, reinterpret_cast(&instance)); + + if (instance->m_clock.GetMilliseconds() > instance->GetTimeLimit()) + luaL_error(internalState, "maximum execution time exceeded"); } } diff --git a/src/Nazara/Lua/LuaState.cpp b/src/Nazara/Lua/LuaState.cpp new file mode 100644 index 000000000..4821b1d09 --- /dev/null +++ b/src/Nazara/Lua/LuaState.cpp @@ -0,0 +1,843 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Lua scripting module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + LuaType FromLuaType(int type) + { + switch (type) + { + case LUA_TBOOLEAN: + return LuaType_Boolean; + + case LUA_TFUNCTION: + return LuaType_Function; + + case LUA_TLIGHTUSERDATA: + return LuaType_LightUserdata; + + case LUA_TNIL: + return LuaType_Nil; + + case LUA_TNONE: + return LuaType_None; + + case LUA_TNUMBER: + return LuaType_Number; + + case LUA_TSTRING: + return LuaType_String; + + case LUA_TTABLE: + return LuaType_Table; + + case LUA_TTHREAD: + return LuaType_Thread; + + case LUA_TUSERDATA: + return LuaType_Userdata; + + default: + return LuaType_None; + } + } + + struct StreamData + { + Stream* stream; + char buffer[NAZARA_CORE_FILE_BUFFERSIZE]; + }; + + const char* StreamReader(lua_State* internalState, void* data, std::size_t* size) + { + NazaraUnused(internalState); + + StreamData* streamData = static_cast(data); + + if (streamData->stream->EndOfStream()) + return nullptr; + else + { + *size = streamData->stream->Read(streamData->buffer, NAZARA_CORE_FILE_BUFFERSIZE); + return streamData->buffer; + } + } + + int s_comparisons[] = { + LUA_OPEQ, // LuaComparison_Equality + LUA_OPLT, // LuaComparison_Less + LUA_OPLE // LuaComparison_LessOrEqual + }; + + static_assert(sizeof(s_comparisons)/sizeof(int) == LuaComparison_Max+1, "Lua comparison array is incomplete"); + + int s_operations[] = { + LUA_OPADD, // LuaOperation_Addition + LUA_OPBAND, // LuaOperation_BitwiseAnd + LUA_OPSHL, // LuaOperation_BitwiseLeftShift + LUA_OPBNOT, // LuaOperation_BitwiseNot + LUA_OPBOR, // LuaOperation_BitwiseOr + LUA_OPSHR, // LuaOperation_BitwiseRightShift + LUA_OPBXOR, // LuaOperation_BitwiseXOr + LUA_OPDIV, // LuaOperation_Division + LUA_OPPOW, // LuaOperation_Exponentiation + LUA_OPIDIV, // LuaOperation_FloorDivision + LUA_OPMUL, // LuaOperation_Multiplication + LUA_OPMOD, // LuaOperation_Modulo + LUA_OPUNM, // LuaOperation_Negation + LUA_OPSUB // LuaOperation_Substraction + }; + + static_assert(sizeof(s_operations)/sizeof(int) == LuaOperation_Max+1, "Lua operation array is incomplete"); + + int s_types[] = { + LUA_TBOOLEAN, // LuaType_Boolean + LUA_TFUNCTION, // LuaType_Function + LUA_TLIGHTUSERDATA, // LuaType_LightUserdata + LUA_TNIL, // LuaType_Nil + LUA_TNUMBER, // LuaType_Number + LUA_TNONE, // LuaType_None + LUA_TSTRING, // LuaType_String + LUA_TTABLE, // LuaType_Table + LUA_TTHREAD, // LuaType_Thread + LUA_TUSERDATA // LuaType_Userdata + }; + + static_assert(sizeof(s_types)/sizeof(int) == LuaType_Max+1, "Lua type array is incomplete"); + } + + LuaState::LuaState(LuaState&& state) noexcept : + m_lastError(state.m_lastError), + m_state(state.m_state) + { + } + + void LuaState::ArgCheck(bool condition, unsigned int argNum, const char* error) const + { + luaL_argcheck(m_state, condition, argNum, error); + } + + void LuaState::ArgCheck(bool condition, unsigned int argNum, const String& error) const + { + luaL_argcheck(m_state, condition, argNum, error.GetConstBuffer()); + } + + int LuaState::ArgError(unsigned int argNum, const char* error) const + { + return luaL_argerror(m_state, argNum, error); + } + + int LuaState::ArgError(unsigned int argNum, const String& error) const + { + return luaL_argerror(m_state, argNum, error.GetConstBuffer()); + } + + bool LuaState::Call(unsigned int argCount) + { + return Run(argCount, LUA_MULTRET); + } + + bool LuaState::Call(unsigned int argCount, unsigned int resultCount) + { + return Run(argCount, resultCount); + } + + void LuaState::CheckAny(int index) const + { + luaL_checkany(m_state, index); + } + + bool LuaState::CheckBoolean(int index) const + { + if (lua_isnoneornil(m_state, index)) + { + const char* msg = lua_pushfstring(m_state, "%s expected, got %s", lua_typename(m_state, LUA_TBOOLEAN), luaL_typename(m_state, index)); + luaL_argerror(m_state, index, msg); // Lance une exception + return false; + } + + return lua_toboolean(m_state, index) != 0; + } + + bool LuaState::CheckBoolean(int index, bool defValue) const + { + if (lua_isnoneornil(m_state, index)) + return defValue; + + return lua_toboolean(m_state, index) != 0; + } + + long long LuaState::CheckInteger(int index) const + { + return luaL_checkinteger(m_state, index); + } + + long long LuaState::CheckInteger(int index, long long defValue) const + { + return luaL_optinteger(m_state, index, defValue); + } + + double LuaState::CheckNumber(int index) const + { + return luaL_checknumber(m_state, index); + } + + double LuaState::CheckNumber(int index, double defValue) const + { + return luaL_optnumber(m_state, index, defValue); + } + + void LuaState::CheckStack(int space, const char* error) const + { + luaL_checkstack(m_state, space, error); + } + + void LuaState::CheckStack(int space, const String& error) const + { + CheckStack(space, error.GetConstBuffer()); + } + + const char* LuaState::CheckString(int index, std::size_t* length) const + { + return luaL_checklstring(m_state, index, length); + } + + const char* LuaState::CheckString(int index, const char* defValue, std::size_t* length) const + { + return luaL_optlstring(m_state, index, defValue, length); + } + + void LuaState::CheckType(int index, LuaType type) const + { + #ifdef NAZARA_DEBUG + if (type > LuaType_Max) + { + NazaraError("Lua type out of enum"); + return; + } + #endif + + luaL_checktype(m_state, index, s_types[type]); + } + + void* LuaState::CheckUserdata(int index, const char* tname) const + { + return luaL_checkudata(m_state, index, tname); + } + + void* LuaState::CheckUserdata(int index, const String& tname) const + { + return luaL_checkudata(m_state, index, tname.GetConstBuffer()); + } + + bool LuaState::Compare(int index1, int index2, LuaComparison comparison) const + { + #ifdef NAZARA_DEBUG + if (comparison > LuaComparison_Max) + { + NazaraError("Lua comparison out of enum"); + return false; + } + #endif + + return (lua_compare(m_state, index1, index2, s_comparisons[comparison]) != 0); + } + + void LuaState::Compute(LuaOperation operation) const + { + #ifdef NAZARA_DEBUG + if (operation > LuaOperation_Max) + { + NazaraError("Lua operation out of enum"); + return; + } + #endif + + lua_arith(m_state, s_operations[operation]); + } + + void LuaState::Concatenate(int count) const + { + lua_concat(m_state, count); + } + + int LuaState::CreateReference() + { + return luaL_ref(m_state, LUA_REGISTRYINDEX); + } + + void LuaState::DestroyReference(int ref) + { + luaL_unref(m_state, LUA_REGISTRYINDEX, ref); + } + + String LuaState::DumpStack() const + { + StringStream stream; + unsigned int stackTop = GetStackTop(); + stream << stackTop << " entries\n"; + + for (unsigned int i = 1; i <= stackTop; ++i) + { + stream << i << ": "; + switch (GetType(i)) + { + case LuaType_Boolean: + stream << "Boolean(" << ToBoolean(i) << ')'; + break; + + case LuaType_Function: + stream << "Function(" << ToPointer(i) << ')'; + break; + + case LuaType_LightUserdata: + case LuaType_Userdata: + stream << "Userdata(" << ToUserdata(i) << ')'; + break; + + case LuaType_Nil: + stream << "Nil"; + break; + + case LuaType_None: + stream << "None"; + break; + + case LuaType_Number: + stream << "Number(" << ToNumber(i) << ')'; + break; + + case LuaType_String: + stream << "String(" << ToString(i) << ')'; + break; + + case LuaType_Table: + stream << "Table(" << ToPointer(i) << ')'; + break; + + case LuaType_Thread: + stream << "Thread(" << ToPointer(i) << ')'; + break; + + default: + stream << "Unknown(" << ToPointer(i) << ')'; + break; + } + + stream << '\n'; + } + + return stream.ToString(); + } + + void LuaState::Error(const char* message) const + { + luaL_error(m_state, message); + } + + void LuaState::Error(const String& message) const + { + luaL_error(m_state, message.GetConstBuffer()); + } + + bool LuaState::Execute(const String& code) + { + if (code.IsEmpty()) + return true; + + if (luaL_loadstring(m_state, code.GetConstBuffer()) != 0) + { + m_lastError = lua_tostring(m_state, -1); + lua_pop(m_state, 1); + + return false; + } + + return Run(0, LUA_MULTRET); + } + + bool LuaState::ExecuteFromFile(const String& filePath) + { + File file(filePath); + if (!file.Open(OpenMode_ReadOnly | OpenMode_Text)) + { + NazaraError("Failed to open file"); + return false; + } + + std::size_t length = static_cast(file.GetSize()); + + String source(length, '\0'); + + if (file.Read(&source[0], length) != length) + { + NazaraError("Failed to read file"); + return false; + } + + file.Close(); + + return Execute(source); + } + + bool LuaState::ExecuteFromMemory(const void* data, std::size_t size) + { + MemoryView stream(data, size); + return ExecuteFromStream(stream); + } + + bool LuaState::ExecuteFromStream(Stream& stream) + { + StreamData data; + data.stream = &stream; + + if (lua_load(m_state, StreamReader, &data, "C++", nullptr) != 0) + { + m_lastError = lua_tostring(m_state, -1); + lua_pop(m_state, 1); + + return false; + } + + return Run(0, LUA_MULTRET); + } + + int LuaState::GetAbsIndex(int index) const + { + return lua_absindex(m_state, index); + } + + LuaType LuaState::GetField(const char* fieldName, int tableIndex) const + { + return FromLuaType(lua_getfield(m_state, tableIndex, fieldName)); + } + + LuaType LuaState::GetField(const String& fieldName, int tableIndex) const + { + return FromLuaType(lua_getfield(m_state, tableIndex, fieldName.GetConstBuffer())); + } + + LuaType LuaState::GetGlobal(const char* name) const + { + return FromLuaType(lua_getglobal(m_state, name)); + } + + LuaType LuaState::GetGlobal(const String& name) const + { + return FromLuaType(lua_getglobal(m_state, name.GetConstBuffer())); + } + + LuaType LuaState::GetMetatable(const char* tname) const + { + return FromLuaType(luaL_getmetatable(m_state, tname)); + } + + LuaType LuaState::GetMetatable(const String& tname) const + { + return FromLuaType(luaL_getmetatable(m_state, tname.GetConstBuffer())); + } + + bool LuaState::GetMetatable(int index) const + { + return lua_getmetatable(m_state, index) != 0; + } + + unsigned int LuaState::GetStackTop() const + { + return static_cast(lua_gettop(m_state)); + } + + LuaType LuaState::GetTable(int index) const + { + return FromLuaType(lua_gettable(m_state, index)); + } + + LuaType LuaState::GetTableRaw(int index) const + { + return FromLuaType(lua_rawget(m_state, index)); + } + + LuaType LuaState::GetType(int index) const + { + return FromLuaType(lua_type(m_state, index)); + } + + const char* LuaState::GetTypeName(LuaType type) const + { + #ifdef NAZARA_DEBUG + if (type > LuaType_Max) + { + NazaraError("Lua type out of enum"); + return nullptr; + } + #endif + + return lua_typename(m_state, s_types[type]); + } + + void LuaState::Insert(int index) const + { + lua_insert(m_state, index); + } + + bool LuaState::IsOfType(int index, LuaType type) const + { + switch (type) + { + case LuaType_Boolean: + return lua_isboolean(m_state, index) != 0; + + case LuaType_Function: + return lua_isfunction(m_state, index) != 0; + + case LuaType_LightUserdata: + return lua_islightuserdata(m_state, index) != 0; + + case LuaType_Nil: + return lua_isnil(m_state, index) != 0; + + case LuaType_None: + return lua_isnone(m_state, index) != 0; + + case LuaType_Number: + return lua_isnumber(m_state, index) != 0; + + case LuaType_String: + return lua_isstring(m_state, index) != 0; + + case LuaType_Table: + return lua_istable(m_state, index) != 0; + + case LuaType_Thread: + return lua_isthread(m_state, index) != 0; + + case LuaType_Userdata: + return lua_isuserdata(m_state, index) != 0; + } + + NazaraError("Lua type not handled (0x" + String::Number(type, 16) + ')'); + return false; + } + + bool LuaState::IsOfType(int index, const char* tname) const + { + void* ud = luaL_testudata(m_state, index, tname); + return ud != nullptr; + } + + bool LuaState::IsOfType(int index, const String& tname) const + { + return IsOfType(index, tname.GetConstBuffer()); + } + + bool LuaState::IsValid(int index) const + { + return lua_isnoneornil(m_state, index) == 0; + } + + long long LuaState::Length(int index) const + { + return luaL_len(m_state, index); + } + + std::size_t LuaState::LengthRaw(int index) const + { + return lua_rawlen(m_state, index); + } + + void LuaState::MoveTo(LuaState* instance, int n) const + { + lua_xmove(m_state, instance->m_state, n); + } + + LuaCoroutine LuaState::NewCoroutine() + { + lua_State* thread = lua_newthread(m_state); + int ref = luaL_ref(m_state, LUA_REGISTRYINDEX); + + return LuaCoroutine(thread, ref); + } + + bool LuaState::NewMetatable(const char* str) + { + return luaL_newmetatable(m_state, str) != 0; + } + + bool LuaState::NewMetatable(const String& str) + { + return luaL_newmetatable(m_state, str.GetConstBuffer()) != 0; + } + + bool LuaState::Next(int index) const + { + return lua_next(m_state, index) != 0; + } + + void LuaState::Pop(unsigned int n) const + { + lua_pop(m_state, static_cast(n)); + } + + void LuaState::PushBoolean(bool value) const + { + lua_pushboolean(m_state, (value) ? 1 : 0); + } + + void LuaState::PushCFunction(LuaCFunction func, unsigned int upvalueCount) const + { + lua_pushcclosure(m_state, func, upvalueCount); + } + + void LuaState::PushFunction(LuaFunction func) const + { + LuaFunction* luaFunc = static_cast(lua_newuserdata(m_state, sizeof(LuaFunction))); + PlacementNew(luaFunc, std::move(func)); + + lua_pushcclosure(m_state, ProxyFunc, 1); + } + + void LuaState::PushInteger(long long value) const + { + lua_pushinteger(m_state, value); + } + + void LuaState::PushLightUserdata(void* value) const + { + lua_pushlightuserdata(m_state, value); + } + + void LuaState::PushMetatable(const char* str) const + { + luaL_getmetatable(m_state, str); + } + + void LuaState::PushMetatable(const String& str) const + { + luaL_getmetatable(m_state, str.GetConstBuffer()); + } + + void LuaState::PushNil() const + { + lua_pushnil(m_state); + } + + void LuaState::PushNumber(double value) const + { + lua_pushnumber(m_state, value); + } + + void LuaState::PushReference(int ref) const + { + lua_rawgeti(m_state, LUA_REGISTRYINDEX, ref); + } + + void LuaState::PushString(const char* str) const + { + lua_pushstring(m_state, str); + } + + void LuaState::PushString(const char* str, std::size_t size) const + { + lua_pushlstring(m_state, str, size); + } + + void LuaState::PushString(const String& str) const + { + lua_pushlstring(m_state, str.GetConstBuffer(), str.GetSize()); + } + + void LuaState::PushTable(std::size_t sequenceElementCount, std::size_t arrayElementCount) const + { + constexpr std::size_t maxInt = std::numeric_limits::max(); + lua_createtable(m_state, static_cast(std::min(sequenceElementCount, maxInt)), static_cast(std::min(arrayElementCount, maxInt))); + } + + void* LuaState::PushUserdata(std::size_t size) const + { + return lua_newuserdata(m_state, size); + } + + void LuaState::PushValue(int index) const + { + lua_pushvalue(m_state, index); + } + + void LuaState::Remove(int index) const + { + lua_remove(m_state, index); + } + + void LuaState::Replace(int index) const + { + lua_replace(m_state, index); + } + + void LuaState::SetField(const char* name, int tableIndex) const + { + lua_setfield(m_state, tableIndex, name); + } + + void LuaState::SetField(const String& name, int tableIndex) const + { + lua_setfield(m_state, tableIndex, name.GetConstBuffer()); + } + + void LuaState::SetGlobal(const char* name) + { + lua_setglobal(m_state, name); + } + + void LuaState::SetGlobal(const String& name) + { + lua_setglobal(m_state, name.GetConstBuffer()); + } + + void LuaState::SetMetatable(const char* tname) const + { + luaL_setmetatable(m_state, tname); + } + + void LuaState::SetMetatable(const String& tname) const + { + luaL_setmetatable(m_state, tname.GetConstBuffer()); + } + + void LuaState::SetMetatable(int index) const + { + lua_setmetatable(m_state, index); + } + + void LuaState::SetTable(int index) const + { + lua_settable(m_state, index); + } + + void LuaState::SetTableRaw(int index) const + { + lua_rawset(m_state, index); + } + + bool LuaState::ToBoolean(int index) const + { + return lua_toboolean(m_state, index) != 0; + } + + long long LuaState::ToInteger(int index, bool* succeeded) const + { + int success; + long long result = lua_tointegerx(m_state, index, &success); + + if (succeeded) + *succeeded = (success != 0); + + return result; + } + + double LuaState::ToNumber(int index, bool* succeeded) const + { + int success; + double result = lua_tonumberx(m_state, index, &success); + + if (succeeded) + *succeeded = (success != 0); + + return result; + } + + const void* LuaState::ToPointer(int index) const + { + return lua_topointer(m_state, index); + } + + const char* LuaState::ToString(int index, std::size_t* length) const + { + return lua_tolstring(m_state, index, length); + } + + void* LuaState::ToUserdata(int index) const + { + return lua_touserdata(m_state, index); + } + + void* LuaState::ToUserdata(int index, const char* tname) const + { + return luaL_testudata(m_state, index, tname); + } + + void* LuaState::ToUserdata(int index, const String& tname) const + { + return luaL_testudata(m_state, index, tname.GetConstBuffer()); + } + + LuaState& LuaState::operator=(LuaState&& state) noexcept + { + m_lastError = std::move(state.m_lastError); + m_state = state.m_state; + + return *this; + } + + bool LuaState::Run(int argCount, int resultCount) + { + LuaInstance& instance = GetInstance(m_state); + + if (instance.m_level++ == 0) + instance.m_clock.Restart(); + + int status = lua_pcall(m_state, argCount, resultCount, 0); + + instance.m_level--; + + if (status != 0) + { + m_lastError = lua_tostring(m_state, -1); + lua_pop(m_state, 1); + + return false; + } + + return true; + } + + int LuaState::GetIndexOfUpValue(int upValue) + { + return lua_upvalueindex(upValue); + } + + LuaInstance& LuaState::GetInstance(lua_State* internalState) + { + LuaInstance* instance; + lua_getallocf(internalState, reinterpret_cast(&instance)); + + return *instance; + } + + int LuaState::ProxyFunc(lua_State* internalState) + { + LuaFunction& func = *static_cast(lua_touserdata(internalState, lua_upvalueindex(1))); + LuaState state = GetState(internalState); + + return func(state); + } + +} diff --git a/src/Nazara/Network/AlgorithmNetwork.cpp b/src/Nazara/Network/AlgorithmNetwork.cpp index 4538230f3..9a593db39 100644 --- a/src/Nazara/Network/AlgorithmNetwork.cpp +++ b/src/Nazara/Network/AlgorithmNetwork.cpp @@ -19,7 +19,6 @@ namespace Nz * \param number Optional argument to return the number parsed * \param endOfRead Optional argument to determine where parsing stopped */ - bool ParseDecimal(const char* str, unsigned int* number, const char** endOfRead) { const char* ptr = str; @@ -52,7 +51,6 @@ namespace Nz * \param number Optional argument to return the number parsed * \param endOfRead Optional argument to determine where parsing stopped */ - bool ParseHexadecimal(const char* str, unsigned int* number, const char** endOfRead) { const char* ptr = str; @@ -78,8 +76,113 @@ namespace Nz } } + /*! - * \ingroup network + * \ingroup network + * \brief Returns the text representation of an error + * \return Text representation of an error + * + * \param resolveError Error enumeration + */ + const char* ErrorToString(Nz::ResolveError resolveError) + { + switch (resolveError) + { + case Nz::ResolveError_NoError: + return "No error"; + + case Nz::ResolveError_Internal: + return "An internal error occurred"; + + case Nz::ResolveError_ResourceError: + return "The operating system lacks the resources to proceed"; + + case Nz::ResolveError_NonRecoverable: + return "A nonrecoverable error occurred"; + + case Nz::ResolveError_NotFound: + return "No such host is known"; + + case Nz::ResolveError_NotInitialized: + return "Nazara Network has not been initialized"; + + case Nz::ResolveError_ProtocolNotSupported: + return "A specified protocol is not supported by the server"; + + case Nz::ResolveError_TemporaryFailure: + return "A temporary failure occurred, try again"; + + case Nz::ResolveError_Unknown: + return "An unknown error occurred"; + + default: + return "Invalid error value"; + } + } + + /*! + * \ingroup network + * \brief Returns the text representation of an error + * \return Text representation of an error + * + * \param socketError Error enumeration + */ + const char* ErrorToString(Nz::SocketError socketError) + { + switch (socketError) + { + case Nz::SocketError_NoError: + return "No error"; + + case Nz::SocketError_AddressNotAvailable: + return "The address is already in use"; + + case Nz::SocketError_ConnectionClosed: + return "The connection has been closed"; + + case Nz::SocketError_ConnectionRefused: + return "The connection attempt was refused"; + + case Nz::SocketError_DatagramSize: + return "The datagram size is over the system limit"; + + case Nz::SocketError_Internal: + return "An internal error occurred"; + + case Nz::SocketError_Packet: + return "Packet encoding or decoding failed"; + + case Nz::SocketError_NetworkError: + return "Networking subsystem failed"; + + case Nz::SocketError_NotInitialized: + return "Network module has not been initialized"; + + case Nz::SocketError_NotSupported: + return "This operation is not supported"; + + case Nz::SocketError_ResolveError: + return "The hostname couldn't be resolved"; + + case Nz::SocketError_ResourceError: + return "The operating system lacks the resources to proceed"; + + case Nz::SocketError_TimedOut: + return "The operation timed out"; + + case Nz::SocketError_Unknown: + return "An unknown error occurred"; + + case Nz::SocketError_UnreachableHost: + return "The host is not reachable"; + + default: + return "Invalid error value"; + } + } + + /*! + * \ingroup network * \brief Parse a textual IPv4 or IPv6 address * \return true If successful * @@ -97,7 +200,6 @@ namespace Nz * \remark Produces a NazaraAssert if addressPtr is invalid * \remark Produces a NazaraAssert if result is invalid */ - bool ParseIPAddress(const char* addressPtr, UInt8 result[16], UInt16* port, bool* isIPv6, const char** endOfRead) { NazaraAssert(addressPtr, "Invalid address string"); diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp new file mode 100644 index 000000000..9fdfe284f --- /dev/null +++ b/src/Nazara/Network/ENetHost.cpp @@ -0,0 +1,1333 @@ +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + namespace + { + static std::size_t s_commandSizes[ENetProtocolCommand_Count] = + { + 0, + sizeof(ENetProtocolAcknowledge), + sizeof(ENetProtocolConnect), + sizeof(ENetProtocolVerifyConnect), + sizeof(ENetProtocolDisconnect), + sizeof(ENetProtocolPing), + sizeof(ENetProtocolSendReliable), + sizeof(ENetProtocolSendUnreliable), + sizeof(ENetProtocolSendFragment), + sizeof(ENetProtocolSendUnsequenced), + sizeof(ENetProtocolBandwidthLimit), + sizeof(ENetProtocolThrottleConfigure), + sizeof(ENetProtocolSendFragment) + }; + } + + + void ENetHost::Broadcast(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) + { + ENetPacketRef enetPacket = AllocatePacket(flags, std::move(packet)); + + for (ENetPeer& peer : m_peers) + { + if (peer.GetState() != ENetPeerState::Connected) + continue; + + peer.Send(channelId, enetPacket); + } + } + + bool ENetHost::CheckEvents(ENetEvent* event) + { + if (!event) + return false; + + event->type = ENetEventType::None; + event->peer = nullptr; + event->packet.Reset(); + + return DispatchIncomingCommands(event); + } + + ENetPeer* ENetHost::Connect(const IpAddress& remoteAddress, std::size_t channelCount, UInt32 data) + { + NazaraAssert(remoteAddress.IsValid(), "Invalid remote address"); + NazaraAssert(remoteAddress.GetPort() != 0, "Remote address has no port"); + + std::size_t peerId; + for (peerId = 0; peerId < m_peers.size(); ++peerId) + { + if (m_peers[peerId].GetState() == ENetPeerState::Disconnected) + break; + } + + if (peerId >= m_peers.size()) + { + NazaraError("Insufficient peers"); + return nullptr; + } + + m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); + + UInt32 windowSize; + if (m_outgoingBandwidth == 0) + windowSize = ENetProtocol_MaximumWindowSize; + else + windowSize = (m_outgoingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetProtocol_MinimumWindowSize; + + ENetPeer& peer = m_peers[peerId]; + peer.InitOutgoing(channelCount, remoteAddress, ++m_randomSeed, windowSize); + + ENetProtocol command(ENetProtocolCommand_Connect | ENetProtocolFlag_Acknowledge, 0xFF); + command.connect.channelCount = HostToNet(static_cast(channelCount)); + command.connect.connectID = peer.m_connectID; + command.connect.data = HostToNet(data); + command.connect.incomingBandwidth = HostToNet(m_incomingBandwidth); + command.connect.incomingSessionID = peer.m_incomingSessionID; + command.connect.mtu = HostToNet(peer.m_mtu); + command.connect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + command.connect.outgoingPeerID = HostToNet(peer.m_incomingPeerID); + command.connect.outgoingSessionID = peer.m_outgoingSessionID; + command.connect.packetThrottleAcceleration = HostToNet(peer.m_packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = HostToNet(peer.m_packetThrottleDeceleration); + command.connect.packetThrottleInterval = HostToNet(peer.m_packetThrottleInterval); + command.connect.windowSize = HostToNet(peer.m_windowSize); + peer.QueueOutgoingCommand(command); + + return &peer; + } + + ENetPeer* ENetHost::Connect(const String& hostName, NetProtocol protocol, const String& service, ResolveError* error, std::size_t channelCount, UInt32 data) + { + std::vector results = IpAddress::ResolveHostname(protocol, hostName, service, error); + if (results.empty()) + return nullptr; + + IpAddress hostnameAddress; + for (const HostnameInfo& result : results) + { + if (!result.address) + continue; + + hostnameAddress = result.address; + break; //< Take first valid address + } + + if (!hostnameAddress.IsValid()) + { + if (error) + *error = ResolveError_NotFound; + + return nullptr; + } + + return Connect(hostnameAddress, channelCount, data); + } + + bool ENetHost::Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount) + { + return Create(address, peerCount, channelCount, 0, 0); + } + + bool ENetHost::Create(const IpAddress& address, std::size_t peerCount, std::size_t channelCount, UInt32 incomingBandwidth, UInt32 outgoingBandwidth) + { + NazaraAssert(address.IsValid(), "Invalid listening address"); + + if (peerCount > ENetConstants::ENetProtocol_MaximumPeerId) + { + NazaraError("Peer count exceeds maximum peer count supported by protocol (" + String::Number(ENetConstants::ENetProtocol_MaximumPeerId) + ")"); + return false; + } + + if (!InitSocket(address)) + return false; + + m_address = address; + m_randomSeed = *reinterpret_cast(this); + m_randomSeed += s_randomGenerator(); + m_randomSeed = (m_randomSeed << 16) | (m_randomSeed >> 16); + m_channelLimit = Clamp(channelCount, ENetConstants::ENetProtocol_MinimumChannelCount, ENetConstants::ENetProtocol_MaximumChannelCount); + m_incomingBandwidth = incomingBandwidth; + m_outgoingBandwidth = outgoingBandwidth; + m_bandwidthThrottleEpoch = 0; + m_recalculateBandwidthLimits = false; + m_mtu = ENetConstants::ENetHost_DefaultMTU; + m_commandCount = 0; + m_bufferCount = 0; + m_peerCount = peerCount; + m_receivedAddress = IpAddress::AnyIpV4; + m_receivedData = nullptr; + m_receivedDataLength = 0; + + m_totalSentData = 0; + m_totalSentPackets = 0; + m_totalReceivedData = 0; + m_totalReceivedPackets = 0; + + m_bandwidthLimitedPeers = 0; + m_connectedPeers = 0; + m_duplicatePeers = ENetConstants::ENetProtocol_MaximumPeerId; + m_maximumPacketSize = ENetConstants::ENetHost_DefaultMaximumPacketSize; + m_maximumWaitingData = ENetConstants::ENetHost_DefaultMaximumWaitingData; + + m_peers.reserve(peerCount); + for (std::size_t i = 0; i < peerCount; ++i) + m_peers.emplace_back(this, UInt16(i)); + + return true; + } + + void ENetHost::Flush() + { + m_serviceTime = GetElapsedMilliseconds(); + + SendOutgoingCommands(nullptr, 0); + } + + int ENetHost::Service(ENetEvent* event, UInt32 timeout) + { + if (event) + { + event->type = ENetEventType::None; + event->peer = nullptr; + event->packet = nullptr; + + if (DispatchIncomingCommands(event)) + return 1; + } + + m_serviceTime = GetElapsedMilliseconds(); + timeout += m_serviceTime; + + do + { + if (ENetTimeDifference(m_serviceTime, m_bandwidthThrottleEpoch) >= ENetConstants::ENetHost_BandwidthThrottleInterval) + ThrottleBandwidth(); + + switch (SendOutgoingCommands(event, true)) + { + case 1: + return 1; + + case -1: + NazaraError("Error sending outgoing packets"); + return -1; + + default: + break; + } + + switch (ReceiveIncomingCommands(event)) + { + case 1: + return 1; + + case -1: + NazaraError("Error receiving incoming packets"); + return -1; + + default: + break; + } + + switch (SendOutgoingCommands(event, true)) + { + case 1: + return 1; + + case -1: + NazaraError("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + if (event) + { + if (DispatchIncomingCommands(event)) + return 1; + } + + if (ENetTimeGreaterEqual(m_serviceTime, timeout)) + return 0; + + for (;;) + { + m_serviceTime = GetElapsedMilliseconds(); + + if (ENetTimeGreaterEqual(m_serviceTime, timeout)) + return 0; + + if (m_poller.Wait(ENetTimeDifference(timeout, m_serviceTime))) + break; + } + + m_serviceTime = GetElapsedMilliseconds(); + } + while (m_poller.IsReadyToRead(m_socket)); + + return 0; + } + + void ENetHost::SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay) + { + NazaraAssert(maxDelay >= minDelay, "Maximum delay cannot be greater than minimum delay"); + + if (packetLossProbability <= 0.0 && minDelay == 0 && maxDelay == 0) + m_isSimulationEnabled = false; + else + { + m_isSimulationEnabled = true; + m_packetDelayDistribution = std::uniform_int_distribution(minDelay, maxDelay); + m_packetLossProbability = std::bernoulli_distribution(packetLossProbability); + } + } + + ENetPacketRef ENetHost::AllocatePacket(ENetPacketFlags flags) + { + ENetPacketRef enetPacket = m_packetPool.New(); + enetPacket->flags = flags; + enetPacket->owner = &m_packetPool; + + return enetPacket; + } + + bool ENetHost::InitSocket(const IpAddress& address) + { + if (!m_socket.Create(address.GetProtocol())) + return false; + + m_socket.EnableBlocking(false); + m_socket.EnableBroadcasting(true); + m_socket.SetReceiveBufferSize(ENetConstants::ENetHost_ReceiveBufferSize); + m_socket.SetSendBufferSize(ENetConstants::ENetHost_SendBufferSize); + + if (!address.IsLoopback()) + { + if (m_socket.Bind(address) != SocketState_Bound) + { + NazaraError("Failed to bind address " + address.ToString()); + return false; + } + } + + m_poller.RegisterSocket(m_socket, SocketPollEvent_Read); + + return true; + } + + void ENetHost::AddToDispatchQueue(ENetPeer* peer) + { + m_dispatchQueue.UnboundedSet(peer->GetPeerId()); + } + + void ENetHost::RemoveFromDispatchQueue(ENetPeer* peer) + { + m_dispatchQueue.UnboundedReset(peer->GetPeerId()); + } + + bool ENetHost::DispatchIncomingCommands(ENetEvent* event) + { + for (std::size_t bit = m_dispatchQueue.FindFirst(); bit != m_dispatchQueue.npos; bit = m_dispatchQueue.FindNext(bit)) + { + m_dispatchQueue.Reset(bit); + + ENetPeer& peer = m_peers[bit]; + switch (peer.GetState()) + { + case ENetPeerState::ConnectionPending: + peer.ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::IncomingConnect; + event->peer = &peer; + event->data = peer.m_eventData; + return true; + + case ENetPeerState::ConnectionSucceeded: + peer.ChangeState(ENetPeerState::Connected); + + event->type = ENetEventType::OutgoingConnect; + event->peer = &peer; + event->data = peer.m_eventData; + return true; + + case ENetPeerState::Zombie: + m_recalculateBandwidthLimits = true; + + event->type = ENetEventType::Disconnect; + event->peer = &peer; + event->data = peer.m_eventData; + + peer.Reset(); + return true; + + case ENetPeerState::Connected: + if (peer.m_dispatchedCommands.empty()) + continue; + + if (!peer.Receive(&event->packet, &event->channelId)) + continue; + + event->type = ENetEventType::Receive; + event->peer = &peer; + + if (!peer.m_dispatchedCommands.empty()) + AddToDispatchQueue(&peer); + + return true; + + default: + break; + } + } + + return false; + } + + ENetPeer* ENetHost::HandleConnect(ENetProtocolHeader* /*header*/, ENetProtocol* command) + { + UInt32 channelCount = NetToHost(command->connect.channelCount); + + if (channelCount < ENetProtocol_MinimumChannelCount || channelCount > ENetProtocol_MaximumChannelCount) + return nullptr; + + std::size_t duplicatePeers = 0; + ENetPeer* peer = nullptr; + for (ENetPeer& currentPeer : m_peers) + { + if (currentPeer.GetState() == ENetPeerState::Disconnected) + { + if (!peer) + peer = ¤tPeer; + } + else if (currentPeer.GetState() != ENetPeerState::Connecting) + { + // Compare users without comparing their port + IpAddress first(currentPeer.m_address); + first.SetPort(0); + + IpAddress second(m_receivedAddress); + second.SetPort(0); + + if (first == second) + { + if (currentPeer.m_address.GetPort() == m_receivedAddress.GetPort() && currentPeer.m_connectID == command->connect.connectID) + return nullptr; + + ++duplicatePeers; + } + } + } + + if (!peer || duplicatePeers >= m_duplicatePeers) + return nullptr; + + channelCount = std::min(channelCount, UInt32(m_channelLimit)); + + peer->InitIncoming(channelCount, m_receivedAddress, command->connect); + + UInt32 windowSize; + if (m_incomingBandwidth == 0) + windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + windowSize = (m_incomingBandwidth / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + windowSize = std::max(windowSize, NetToHost(command->connect.windowSize)); + windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + + ENetProtocol verifyCommand(ENetProtocolCommand_VerifyConnect | ENetProtocolFlag_Acknowledge, 0xFF); + verifyCommand.verifyConnect.connectID = peer->m_connectID; + verifyCommand.verifyConnect.incomingSessionID = peer->m_outgoingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = peer->m_incomingSessionID; + + verifyCommand.verifyConnect.channelCount = HostToNet(channelCount); + verifyCommand.verifyConnect.incomingBandwidth = HostToNet(m_incomingBandwidth); + verifyCommand.verifyConnect.mtu = HostToNet(peer->GetMtu()); + verifyCommand.verifyConnect.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + verifyCommand.verifyConnect.outgoingPeerID = HostToNet(peer->GetPeerId()); + verifyCommand.verifyConnect.packetThrottleAcceleration = HostToNet(peer->GetPacketThrottleAcceleration()); + verifyCommand.verifyConnect.packetThrottleDeceleration = HostToNet(peer->GetPacketThrottleDeceleration()); + verifyCommand.verifyConnect.packetThrottleInterval = HostToNet(peer->GetPacketThrottleInterval()); + verifyCommand.verifyConnect.windowSize = HostToNet(windowSize); + + peer->QueueOutgoingCommand(verifyCommand); + + return peer; + } + + bool ENetHost::HandleIncomingCommands(ENetEvent* event) + { + if (m_receivedDataLength < NazaraOffsetOf(ENetProtocolHeader, sentTime)) + return false; + + ENetProtocolHeader* header = reinterpret_cast(m_receivedData); + + UInt16 peerID = NetToHost(header->peerID); + UInt8 sessionID = (peerID & ENetProtocolHeaderSessionMask) >> ENetProtocolHeaderSessionShift; + UInt16 flags = peerID & ENetProtocolHeaderFlag_Mask; + peerID &= ~(ENetProtocolHeaderFlag_Mask | ENetProtocolHeaderSessionMask); + + std::size_t headerSize = (flags & ENetProtocolHeaderFlag_SentTime) ? sizeof(ENetProtocolHeader) : NazaraOffsetOf(ENetProtocolHeader, sentTime); + + ENetPeer* peer; + if (peerID == ENetConstants::ENetProtocol_MaximumPeerId) + peer = nullptr; + else + { + if (peerID >= m_peers.size()) + return false; + else + { + peer = &m_peers[peerID]; + + if (peer->GetState() == ENetPeerState::Disconnected || peer->GetState() == ENetPeerState::Zombie) + return false; + + if (m_receivedAddress != peer->GetAddress() && peer->GetAddress() != IpAddress::BroadcastIpV4) + return false; + + if (peer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId && sessionID != peer->m_incomingSessionID) + return false; + } + } + + // Compression handling + + // Checksum + + if (peer) + { + peer->m_address = m_receivedAddress; + peer->m_incomingDataTotal += UInt32(m_receivedDataLength); + } + + auto commandError = [&]() -> bool + { + if (event && event->type != ENetEventType::None) + return true; + + return false; + }; + + UInt8* currentData = m_receivedData + headerSize; + + while (currentData < &m_receivedData[m_receivedDataLength]) + { + ENetProtocol* command = reinterpret_cast(currentData); + + if (currentData + sizeof(ENetProtocolCommandHeader) > &m_receivedData[m_receivedDataLength]) + break; + + UInt8 commandNumber = command->header.command & ENetProtocolCommand_Mask; + if (commandNumber >= ENetProtocolCommand_Count) + break; + + std::size_t commandSize = s_commandSizes[commandNumber]; + if (commandSize == 0 || currentData + commandSize > &m_receivedData[m_receivedDataLength]) + break; + + currentData += commandSize; + + if (!peer && commandNumber != ENetProtocolCommand_Connect) + break; + + command->header.reliableSequenceNumber = NetToHost(command->header.reliableSequenceNumber); + + switch (commandNumber) + { + case ENetProtocolCommand_Acknowledge: + if (!peer->HandleAcknowledge(command, event)) + return commandError(); + + break; + + case ENetProtocolCommand_Connect: + if (peer) + return commandError(); + + peer = HandleConnect(header, command); + if (!peer) + return commandError(); + + break; + + case ENetProtocolCommand_VerifyConnect: + if (!peer->HandleVerifyConnect(command, event)) + return commandError(); + + break; + + case ENetProtocolCommand_Disconnect: + if (!peer->HandleDisconnect(command)) + return commandError(); + + break; + + case ENetProtocolCommand_Ping: + if (!peer->HandlePing(command)) + return commandError(); + + break; + + case ENetProtocolCommand_SendReliable: + if (!peer->HandleSendReliable(command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnreliable: + if (!peer->HandleSendUnreliable(command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnsequenced: + if (!peer->HandleSendUnsequenced(command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_SendFragment: + if (!peer->HandleSendFragment(command, ¤tData)) + return commandError(); + + break; + + case ENetProtocolCommand_BandwidthLimit: + if (!peer->HandleBandwidthLimit(command)) + return commandError(); + + break; + + case ENetProtocolCommand_ThrottleConfigure: + if (!peer->HandleThrottleConfigure(command)) + return commandError(); + + break; + + case ENetProtocolCommand_SendUnreliableFragment: + if (!peer->HandleSendUnreliableFragment(command, ¤tData)) + return commandError(); + + break; + + default: + return commandError(); + } + + if (peer && (command->header.command & ENetProtocolFlag_Acknowledge) != 0) + { + UInt16 sentTime; + + if (!(flags & ENetProtocolHeaderFlag_SentTime)) + break; + + sentTime = NetToHost(header->sentTime); + + switch (peer->GetState()) + { + case ENetPeerState::Disconnecting: + case ENetPeerState::AcknowledgingConnect: + case ENetPeerState::Disconnected: + case ENetPeerState::Zombie: + break; + + case ENetPeerState::AcknowledgingDisconnect: + if ((command->header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) + peer->QueueAcknowledgement(command, sentTime); + break; + + default: + peer->QueueAcknowledgement(command, sentTime); + break; + } + } + } + + return commandError(); + } + + int ENetHost::ReceiveIncomingCommands(ENetEvent* event) + { + for (unsigned int i = 0; i < 256; ++i) + { + bool shouldReceive = true; + std::size_t receivedLength; + + if (m_isSimulationEnabled) + { + for (auto it = m_pendingIncomingPackets.begin(); it != m_pendingIncomingPackets.end(); ++it) + { + if (m_serviceTime >= it->deliveryTime) + { + shouldReceive = false; + + m_receivedAddress = it->from; + receivedLength = it->data.GetDataSize(); + std::memcpy(m_packetData[0].data(), it->data.GetConstData() + NetPacket::HeaderSize, receivedLength); + + m_pendingIncomingPackets.erase(it); + break; + } + } + } + + if (shouldReceive) + { + if (!m_socket.Receive(m_packetData[0].data(), m_packetData[0].size(), &m_receivedAddress, &receivedLength)) + return -1; //< Error + + if (receivedLength == 0) + return 0; + + if (m_isSimulationEnabled) + { + if (m_packetLossProbability(s_randomGenerator)) + continue; + + UInt16 delay = m_packetDelayDistribution(s_randomGenerator); + if (delay > 0) + { + PendingIncomingPacket pendingPacket; + pendingPacket.deliveryTime = m_serviceTime + delay; + pendingPacket.from = m_receivedAddress; + pendingPacket.data.Reset(0, m_packetData[0].data(), receivedLength); + + auto it = std::upper_bound(m_pendingIncomingPackets.begin(), m_pendingIncomingPackets.end(), pendingPacket, [] (const PendingIncomingPacket& first, const PendingIncomingPacket& second) + { + return first.deliveryTime < second.deliveryTime; + }); + + m_pendingIncomingPackets.emplace(it, std::move(pendingPacket)); + continue; + } + } + } + + m_receivedData = m_packetData[0].data(); + m_receivedDataLength = receivedLength; + + m_totalReceivedData += receivedLength; + m_totalReceivedPackets++; + + // Intercept + + if (HandleIncomingCommands(event)) + return 1; + } + + return -1; + } + + void ENetHost::NotifyConnect(ENetPeer* peer, ENetEvent* event, bool incoming) + { + m_recalculateBandwidthLimits = true; + + if (event) + { + peer->ChangeState(ENetPeerState::Connected); + + event->type = (incoming) ? ENetEventType::IncomingConnect : ENetEventType::OutgoingConnect; + event->peer = peer; + event->data = peer->m_eventData; + } + else + peer->DispatchState((peer->GetState() == ENetPeerState::Connecting) ? ENetPeerState::ConnectionSucceeded : ENetPeerState::ConnectionPending); + } + + void ENetHost::NotifyDisconnect(ENetPeer* peer, ENetEvent* event) + { + if (peer->GetState() >= ENetPeerState::ConnectionPending) + m_recalculateBandwidthLimits = true; + + if (peer->GetState() != ENetPeerState::Connecting && (peer->GetState() < ENetPeerState::ConnectionSucceeded)) + peer->Reset(); + else if (event) + { + event->type = ENetEventType::Disconnect; + event->peer = peer; + event->data = peer->m_eventData; + + peer->Reset(); + } + else + { + peer->m_eventData = 0; + + peer->DispatchState(ENetPeerState::Zombie); + } + } + + void ENetHost::SendAcknowledgements(ENetPeer* peer) + { + auto it = peer->m_acknowledgements.begin(); + for (; it != peer->m_acknowledgements.end(); ++it) + { + if (m_commandCount >= m_commands.size() || m_bufferCount >= m_buffers.size() || peer->GetMtu() - m_packetSize < sizeof(ENetProtocolAcknowledge)) + { + m_continueSending = true; + break; + } + + ENetPeer::Acknowledgement& acknowledgement = *it; + + ENetProtocol& command = m_commands[m_commandCount]; + NetBuffer& buffer = m_buffers[m_bufferCount]; + + buffer.data = &command; + buffer.dataLength = sizeof(ENetProtocolAcknowledge); + + m_packetSize += buffer.dataLength; + + UInt16 reliableSequenceNumber = HostToNet(acknowledgement.command.header.reliableSequenceNumber); + + command.header.command = ENetProtocolCommand_Acknowledge; + command.header.channelID = acknowledgement.command.header.channelID; + command.header.reliableSequenceNumber = reliableSequenceNumber; + command.acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; + command.acknowledge.receivedSentTime = HostToNet(acknowledgement.sentTime); + + if ((acknowledgement.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_Disconnect) + peer->DispatchState(ENetPeerState::Zombie); + + ++m_bufferCount; + ++m_commandCount; + } + + peer->m_acknowledgements.erase(peer->m_acknowledgements.begin(), it); + } + + bool ENetHost::SendReliableOutgoingCommands(ENetPeer* peer) + { + bool canPing = true; + bool windowExceeded = false; + bool windowWrap = false; + + auto currentCommand = peer->m_outgoingReliableCommands.begin(); + while (currentCommand != peer->m_outgoingReliableCommands.end()) + { + auto outgoingCommand = currentCommand; + + UInt16 reliableWindow = outgoingCommand->reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + ENetPeer::Channel* channel = (outgoingCommand->command.header.channelID < peer->m_channels.size()) ? &peer->m_channels[outgoingCommand->command.header.channelID] : nullptr; + if (channel) + { + if (!windowWrap && outgoingCommand->sendAttempts < 1 && !(outgoingCommand->reliableSequenceNumber % ENetPeer_ReliableWindowSize) && + ((channel->reliableWindows[(reliableWindow + ENetPeer_ReliableWindows - 1) % ENetPeer_ReliableWindows] >= ENetPeer_ReliableWindowSize) || + channel->usedReliableWindows & ((((1 << ENetPeer_ReliableWindows) - 1) << reliableWindow) | + (((1 << ENetPeer_FreeReliableWindows) - 1) >> (ENetPeer_ReliableWindows - reliableWindow))))) + windowWrap = true; + + if (windowWrap) + { + ++currentCommand; + continue; + } + } + + if (outgoingCommand->packet) + { + if (!windowExceeded) + { + UInt32 windowSize = (peer->m_packetThrottle * peer->m_windowSize) / ENetPeer_PacketThrottleScale; + + if (peer->m_reliableDataInTransit + outgoingCommand->fragmentLength > std::max(windowSize, peer->GetMtu())) + windowExceeded = true; + } + + if (windowExceeded) + { + ++currentCommand; + continue; + } + } + + canPing = false; + + std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask]; + if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->GetMtu() - m_packetSize < commandSize || + (outgoingCommand->packet && UInt16(peer->GetMtu() - m_packetSize) < UInt16(commandSize + outgoingCommand->fragmentLength))) + { + m_continueSending = true; + break; + } + + ++currentCommand; + + if (channel && outgoingCommand->sendAttempts < 1) + { + channel->usedReliableWindows |= 1 << reliableWindow; + ++channel->reliableWindows[reliableWindow]; + } + + ++outgoingCommand->sendAttempts; + + if (outgoingCommand->roundTripTimeout == 0) + { + outgoingCommand->roundTripTimeout = peer->m_roundTripTime + 4 * peer->m_roundTripTimeVariance; + outgoingCommand->roundTripTimeoutLimit = peer->m_timeoutLimit * outgoingCommand->roundTripTimeout; + } + + if (peer->m_sentReliableCommands.empty()) + peer->m_nextTimeout = m_serviceTime + outgoingCommand->roundTripTimeout; + + peer->m_sentReliableCommands.emplace_back(std::move(*outgoingCommand)); + peer->m_outgoingReliableCommands.erase(outgoingCommand); + + outgoingCommand = peer->m_sentReliableCommands.end(); + --outgoingCommand; + + outgoingCommand->sentTime = m_serviceTime; + + ENetProtocol& command = m_commands[m_commandCount]; + NetBuffer& buffer = m_buffers[m_bufferCount]; + + buffer.data = &command; + buffer.dataLength = commandSize; + + m_packetSize += buffer.dataLength; + m_headerFlags |= ENetProtocolHeaderFlag_SentTime; + + command = outgoingCommand->command; + + if (outgoingCommand->packet) + { + ++m_bufferCount; + + NetBuffer& packetBuffer = m_buffers[m_bufferCount]; + packetBuffer.data = outgoingCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + outgoingCommand->fragmentOffset; + packetBuffer.dataLength = outgoingCommand->fragmentLength; + + m_packetSize += packetBuffer.dataLength; + + peer->m_reliableDataInTransit += outgoingCommand->fragmentLength; + } + + ++peer->m_packetsSent; + ++peer->m_totalPacketSent; + ++m_bufferCount; + ++m_commandCount; + } + + return canPing; + } + + int ENetHost::SendOutgoingCommands(ENetEvent* event, bool checkForTimeouts) + { + std::array headerData; + ENetProtocolHeader* header = reinterpret_cast(headerData.data()); + + m_continueSending = true; + + while (m_continueSending) + { + m_continueSending = false; + + for (std::size_t peer = 0; peer < m_peerCount; ++peer) + { + ENetPeer* currentPeer = &m_peers[peer]; + if (currentPeer->GetState() == ENetPeerState::Disconnected || currentPeer->GetState() == ENetPeerState::Zombie) + continue; + + m_headerFlags = 0; + m_commandCount = 0; + m_bufferCount = 1; + m_packetSize = sizeof(ENetProtocolHeader); + + if (!currentPeer->m_acknowledgements.empty()) + SendAcknowledgements(currentPeer); + + if (checkForTimeouts && !currentPeer->m_sentReliableCommands.empty() && ENetTimeGreaterEqual(m_serviceTime, currentPeer->m_nextTimeout) && currentPeer->CheckTimeouts(event)) + { + if (event && event->type != ENetEventType::None) + return 1; + else + continue; + } + + if ((currentPeer->m_outgoingReliableCommands.empty() || SendReliableOutgoingCommands(currentPeer)) && currentPeer->m_sentReliableCommands.empty() && + ENetTimeDifference(m_serviceTime, currentPeer->m_lastReceiveTime) >= currentPeer->m_pingInterval && currentPeer->m_mtu - m_packetSize >= sizeof(ENetProtocolPing)) + { + currentPeer->Ping(); + SendReliableOutgoingCommands(currentPeer); + } + + if (!currentPeer->m_outgoingUnreliableCommands.empty()) + SendUnreliableOutgoingCommands(currentPeer); + + if (m_commandCount == 0) + continue; + + if (currentPeer->m_packetLossEpoch == 0) + currentPeer->m_packetLossEpoch = m_serviceTime; + else if (ENetTimeDifference(m_serviceTime, currentPeer->m_packetLossEpoch) >= ENetPeer_PacketLossInterval && currentPeer->m_packetsSent > 0) + { + UInt32 packetLoss = currentPeer->m_packetsLost * ENetPeer_PacketLossScale / currentPeer->m_packetsSent; + + #ifdef ENET_DEBUG + printf("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer->incomingPeerID, currentPeer->packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->roundTripTime, currentPeer->roundTripTimeVariance, currentPeer->packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size(¤tPeer->outgoingReliableCommands), enet_list_size(¤tPeer->outgoingUnreliableCommands), currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingReliableCommands) : 0, currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingUnreliableCommands) : 0); + #endif + + currentPeer->m_packetLossVariance -= currentPeer->m_packetLossVariance / 4; + + if (packetLoss >= currentPeer->m_packetLoss) + { + currentPeer->m_packetLoss += (packetLoss - currentPeer->m_packetLoss) / 8; + currentPeer->m_packetLossVariance += (packetLoss - currentPeer->m_packetLoss) / 4; + } + else + { + currentPeer->m_packetLoss -= (currentPeer->m_packetLoss - packetLoss) / 8; + currentPeer->m_packetLossVariance += (currentPeer->m_packetLoss - packetLoss) / 4; + } + + currentPeer->m_packetLossEpoch = m_serviceTime; + currentPeer->m_packetsSent = 0; + currentPeer->m_packetsLost = 0; + } + + + m_buffers[0].data = headerData.data(); + if (m_headerFlags & ENetProtocolHeaderFlag_SentTime) + { + header->sentTime = HostToNet(static_cast(m_serviceTime)); + + m_buffers[0].dataLength = sizeof(ENetProtocolHeader); + } + else + m_buffers[0].dataLength = NazaraOffsetOf(ENetProtocolHeader, sentTime); + + if (currentPeer->m_outgoingPeerID < ENetConstants::ENetProtocol_MaximumPeerId) + m_headerFlags |= currentPeer->m_outgoingSessionID << ENetProtocolHeaderSessionShift; + + header->peerID = HostToNet(static_cast(currentPeer->m_outgoingPeerID | m_headerFlags)); + + currentPeer->m_lastSendTime = m_serviceTime; + + // Simulate network by adding delay to packet sending and losing some packets + bool sendNow = true; + if (currentPeer->IsSimulationEnabled()) + { + sendNow = false; + if (!currentPeer->m_packetLossProbability(s_randomGenerator)) + { + Nz::UInt16 delay = currentPeer->m_packetDelayDistribution(s_randomGenerator); + if (delay == 0) + sendNow = true; + else + { + PendingOutgoingPacket outgoingPacket; + outgoingPacket.deliveryTime = m_serviceTime + delay; + outgoingPacket.to = currentPeer->GetAddress(); + + // Accumulate every temporary buffer into a datagram + for (std::size_t i = 0; i < m_bufferCount; ++i) + { + NetBuffer& buffer = m_buffers[i]; + outgoingPacket.data.Write(buffer.data, buffer.dataLength); + } + + m_totalSentData += outgoingPacket.data.GetDataSize(); + + // Add it to the right place + auto it = std::upper_bound(m_pendingOutgoingPackets.begin(), m_pendingOutgoingPackets.end(), outgoingPacket, [](const PendingOutgoingPacket& first, const PendingOutgoingPacket& second) + { + return first.deliveryTime < second.deliveryTime; + }); + + m_pendingOutgoingPackets.emplace(it, std::move(outgoingPacket)); + } + } + } + + if (sendNow) + { + std::size_t sentLength = 0; + + if (!m_socket.SendMultiple(currentPeer->GetAddress(), m_buffers.data(), m_bufferCount, &sentLength)) + return -1; + + m_totalSentData += sentLength; + } + + currentPeer->RemoveSentUnreliableCommands(); + m_totalSentPackets++; + } + } + + if (!m_pendingOutgoingPackets.empty()) + { + auto it = m_pendingOutgoingPackets.begin(); + for (; it != m_pendingOutgoingPackets.end(); ++it) + { + if (m_serviceTime < it->deliveryTime) + break; + + if (!m_socket.Send(it->to, it->data.GetConstData() + NetPacket::HeaderSize, it->data.GetDataSize(), nullptr)) + return -1; + } + + m_pendingOutgoingPackets.erase(m_pendingOutgoingPackets.begin(), it); + } + + return 0; + } + + void ENetHost::SendUnreliableOutgoingCommands(ENetPeer* peer) + { + auto currentCommand = peer->m_outgoingUnreliableCommands.begin(); + while (currentCommand != peer->m_outgoingUnreliableCommands.end()) + { + auto outgoingCommand = currentCommand; + + std::size_t commandSize = s_commandSizes[outgoingCommand->command.header.command & ENetProtocolCommand_Mask]; + + if (m_commandCount >= m_commands.size() || m_bufferCount + 1 >= m_buffers.size() || peer->m_mtu - m_packetSize < commandSize || + (outgoingCommand->packet && peer->m_mtu - m_packetSize < commandSize + outgoingCommand->fragmentLength)) + { + m_continueSending = true; + break; + } + + ++currentCommand; + + if (outgoingCommand->packet && outgoingCommand->fragmentOffset == 0) + { + peer->m_packetThrottleCounter += ENetConstants::ENetPeer_PacketThrottleCounter; + peer->m_packetThrottleCounter %= ENetConstants::ENetPeer_PacketThrottleScale; + + if (peer->m_packetThrottleCounter > peer->m_packetThrottle) + { + UInt16 reliableSequenceNumber = outgoingCommand->reliableSequenceNumber; + UInt16 unreliableSequenceNumber = outgoingCommand->unreliableSequenceNumber; + + for (;;) + { + peer->m_outgoingUnreliableCommands.erase(outgoingCommand); + + if (currentCommand == peer->m_outgoingUnreliableCommands.end()) + break; + + outgoingCommand = currentCommand; + if (outgoingCommand->reliableSequenceNumber != reliableSequenceNumber || outgoingCommand->unreliableSequenceNumber != unreliableSequenceNumber) + break; + + ++currentCommand; + } + + continue; + } + } + + ENetProtocol& command = m_commands[m_commandCount]; + NetBuffer& buffer = m_buffers[m_bufferCount]; + + buffer.data = &command; + buffer.dataLength = commandSize; + + command = outgoingCommand->command; + + if (outgoingCommand->packet) + { + ++m_bufferCount; + + NetBuffer& packetBuffer = m_buffers[m_bufferCount]; + packetBuffer.data = outgoingCommand->packet->data.GetData() + Nz::NetPacket::HeaderSize + outgoingCommand->fragmentOffset; + packetBuffer.dataLength = outgoingCommand->fragmentLength; + + m_packetSize += packetBuffer.dataLength; + + // In order to keep the packet buffer alive until we send it, place it into a temporary queue + peer->m_sentUnreliableCommands.emplace_back(std::move(*outgoingCommand)); + } + + peer->m_outgoingUnreliableCommands.erase(outgoingCommand); + + ++m_bufferCount; + ++m_commandCount; + } + + if (peer->GetState() == ENetPeerState::DisconnectLater && !peer->HasPendingCommands()) + peer->Disconnect(peer->m_eventData); + } + + void ENetHost::ThrottleBandwidth() + { + UInt32 currentTime = GetElapsedMilliseconds(); + UInt32 elapsedTime = currentTime - m_bandwidthThrottleEpoch; + + if (elapsedTime < ENetConstants::ENetHost_BandwidthThrottleInterval) + return; + + m_bandwidthThrottleEpoch = currentTime; + + if (m_connectedPeers == 0) + return; + + UInt32 dataTotal = ~0; + UInt32 bandwidth = ~0; + + if (m_outgoingBandwidth != 0) + { + bandwidth = (m_outgoingBandwidth * elapsedTime) / 1000; + + dataTotal = 0; + for (ENetPeer& peer : m_peers) + { + if (peer.IsConnected()) + continue; + + dataTotal += peer.m_outgoingDataTotal; + } + } + + UInt32 peersRemaining = m_connectedPeers; + UInt32 bandwidthLimit = ~0; + UInt32 throttle = ~0; + bool needsAdjustment = m_bandwidthLimitedPeers > 0; + + while (peersRemaining > 0 && needsAdjustment) + { + needsAdjustment = false; + + if (dataTotal <= bandwidth) + throttle = ENetConstants::ENetPeer_PacketThrottleScale; + else + throttle = (bandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / dataTotal; + + for (ENetPeer& peer : m_peers) + { + if (!peer.IsConnected() || peer.m_incomingBandwidth == 0 || peer.m_outgoingBandwidthThrottleEpoch == currentTime) + continue; + + UInt32 peerBandwidth = (peer.m_incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer.m_outgoingDataTotal) / ENetConstants::ENetPeer_PacketThrottleScale <= peerBandwidth) + continue; + + peer.m_packetThrottleLimit = Clamp((peerBandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / peer.m_outgoingDataTotal, 0, peer.m_packetThrottleLimit); + peer.m_outgoingBandwidthThrottleEpoch = currentTime; + + peer.m_incomingDataTotal = 0; + peer.m_outgoingDataTotal = 0; + + needsAdjustment = true; + --peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + { + if (dataTotal <= bandwidth) + throttle = ENetConstants::ENetPeer_PacketThrottleScale; + else + throttle = (bandwidth * ENetConstants::ENetPeer_PacketThrottleScale) / dataTotal; + + for (ENetPeer& peer : m_peers) + { + if (!peer.IsConnected() || peer.m_outgoingBandwidthThrottleEpoch == currentTime) + continue; + + peer.m_packetThrottleLimit = throttle; + peer.m_packetThrottle = std::min(peer.m_packetThrottle, peer.m_packetThrottleLimit); + + peer.m_incomingDataTotal = 0; + peer.m_outgoingDataTotal = 0; + } + } + + if (m_recalculateBandwidthLimits) + { + m_recalculateBandwidthLimits = false; + + peersRemaining = m_connectedPeers; + bandwidth = m_incomingBandwidth; + needsAdjustment = true; + + if (bandwidth == 0) + bandwidthLimit = 0; + else + { + while (peersRemaining > 0 && needsAdjustment) + { + needsAdjustment = false; + bandwidthLimit = bandwidth / peersRemaining; + + for (ENetPeer& peer : m_peers) + { + if (!peer.IsConnected() || peer.m_incomingBandwidthThrottleEpoch == currentTime) + continue; + + if (peer.m_outgoingBandwidth > 0 && peer.m_outgoingBandwidth >= bandwidthLimit) + continue; + + peer.m_incomingBandwidthThrottleEpoch = currentTime; + + needsAdjustment = true; + --peersRemaining; + bandwidth -= peer.m_outgoingBandwidth; + } + } + } + + for (ENetPeer& peer : m_peers) + { + if (!peer.IsConnected()) + continue; + + ENetProtocol command(ENetProtocolCommand_BandwidthLimit | ENetProtocolFlag_Acknowledge, 0xFF); + command.bandwidthLimit.outgoingBandwidth = HostToNet(m_outgoingBandwidth); + + if (peer.m_incomingBandwidthThrottleEpoch == currentTime) + command.bandwidthLimit.incomingBandwidth = HostToNet(peer.m_outgoingBandwidth); + else + command.bandwidthLimit.incomingBandwidth = HostToNet(bandwidthLimit); + + peer.QueueOutgoingCommand(command); + } + } + } + + std::size_t ENetHost::GetCommandSize(UInt8 commandNumber) + { + return s_commandSizes[commandNumber & ENetProtocolCommand_Mask]; + } + + bool ENetHost::Initialize() + { + std::random_device device; + s_randomGenerator.seed(device()); + s_randomGenerator64.seed(device()); + + return true; + } + + void ENetHost::Uninitialize() + { + } + + std::mt19937 ENetHost::s_randomGenerator; + std::mt19937_64 ENetHost::s_randomGenerator64; +} diff --git a/src/Nazara/Network/ENetPacket.cpp b/src/Nazara/Network/ENetPacket.cpp new file mode 100644 index 000000000..4b4157ac4 --- /dev/null +++ b/src/Nazara/Network/ENetPacket.cpp @@ -0,0 +1,24 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + /// Temporary + void ENetPacketRef::Reset(ENetPacket* packet) + { + if (m_packet) + { + if (--m_packet->referenceCount == 0) + m_packet->owner->Delete(m_packet); + } + + m_packet = packet; + if (m_packet) + m_packet->referenceCount++; + } +} diff --git a/src/Nazara/Network/ENetPeer.cpp b/src/Nazara/Network/ENetPeer.cpp new file mode 100644 index 000000000..80e46a36b --- /dev/null +++ b/src/Nazara/Network/ENetPeer.cpp @@ -0,0 +1,1349 @@ +/* + Copyright(c) 2002 - 2016 Lee Salzman + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : + + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Network module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +namespace Nz +{ + void ENetPeer::Disconnect(UInt32 data) + { + if (m_state == ENetPeerState::Disconnecting || + m_state == ENetPeerState::Disconnected || + m_state == ENetPeerState::AcknowledgingDisconnect || + m_state == ENetPeerState::Zombie) + return; + + ResetQueues(); + + ENetProtocol command(ENetProtocolCommand_Disconnect, 0xFF); + command.disconnect.data = HostToNet(data); + + if (IsConnected()) + command.header.command |= ENetProtocolFlag_Acknowledge; + else + command.header.command |= ENetProtocolFlag_Unsequenced; + + QueueOutgoingCommand(command); + + if (IsConnected()) + { + OnDisconnect(); + + m_state = ENetPeerState::Disconnecting; + } + else + { + m_host->Flush(); + + Reset(); + } + } + + void ENetPeer::DisconnectLater(UInt32 data) + { + if (IsConnected() && HasPendingCommands()) + { + m_state = ENetPeerState::DisconnectLater; + m_eventData = data; + } + else + Disconnect(data); + } + + void ENetPeer::DisconnectNow(UInt32 data) + { + if (m_state == ENetPeerState::Disconnected) + return; + + if (m_state != ENetPeerState::Zombie && m_state != ENetPeerState::Disconnecting) + { + ResetQueues(); + + ENetProtocol command(ENetProtocolCommand_Disconnect | ENetProtocolFlag_Unsequenced, 0xFF); + command.disconnect.data = HostToNet(data); + QueueOutgoingCommand(command); + + m_host->Flush(); + } + + Reset(); + } + + void ENetPeer::Ping() + { + if (m_state != ENetPeerState::Connected) + return; + + ENetProtocol command; + command.header.command = ENetProtocolCommand_Ping | ENetProtocolFlag_Acknowledge; + command.header.channelID = 0xFF; + QueueOutgoingCommand(command); + } + + bool ENetPeer::Receive(ENetPacketRef* packet, UInt8* channelId) + { + if (m_dispatchedCommands.empty()) + return false; + + IncomingCommmand& incomingCommand = m_dispatchedCommands.front(); + + m_totalWaitingData -= incomingCommand.packet->data.GetDataSize(); + + if (packet) + *packet = std::move(incomingCommand.packet); + + if (channelId) + *channelId = incomingCommand.command.header.channelID; + + m_dispatchedCommands.pop_front(); + + return true; + } + + void ENetPeer::Reset() + { + OnDisconnect(); + + m_outgoingPeerID = ENetConstants::ENetProtocol_MaximumPeerId; + m_connectID = 0; + + m_state = ENetPeerState::Disconnected; + + m_incomingBandwidth = 0; + m_outgoingBandwidth = 0; + m_incomingBandwidthThrottleEpoch = 0; + m_outgoingBandwidthThrottleEpoch = 0; + m_incomingDataTotal = 0; + m_outgoingDataTotal = 0; + m_lastSendTime = 0; + m_lastReceiveTime = 0; + m_nextTimeout = 0; + m_earliestTimeout = 0; + m_packetLossEpoch = 0; + m_packetsSent = 0; + m_packetsLost = 0; + m_packetLoss = 0; + m_packetLossVariance = 0; + m_packetThrottle = ENetConstants::ENetPeer_DefaultPacketThrottle; + m_packetThrottleLimit = ENetConstants::ENetPeer_PacketThrottleScale; + m_packetThrottleCounter = 0; + m_packetThrottleEpoch = 0; + m_packetThrottleAcceleration = ENetConstants::ENetPeer_PacketThrottleAcceleration; + m_packetThrottleDeceleration = ENetConstants::ENetPeer_PacketThrottleDeceleration; + m_packetThrottleInterval = ENetConstants::ENetPeer_PacketThrottleInterval; + m_pingInterval = ENetConstants::ENetPeer_PingInterval; + m_timeoutLimit = ENetConstants::ENetPeer_TimeoutLimit; + m_timeoutMinimum = ENetConstants::ENetPeer_TimeoutMinimum; + m_timeoutMaximum = ENetConstants::ENetPeer_TimeoutMaximum; + m_lastRoundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_lowestRoundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_lastRoundTripTimeVariance = 0; + m_highestRoundTripTimeVariance = 0; + m_roundTripTime = ENetConstants::ENetPeer_DefaultRoundTripTime; + m_roundTripTimeVariance = 0; + m_mtu = m_host->m_mtu; + m_reliableDataInTransit = 0; + m_outgoingReliableSequenceNumber = 0; + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + m_incomingUnsequencedGroup = 0; + m_outgoingUnsequencedGroup = 0; + m_eventData = 0; + m_totalPacketLost = 0; + m_totalPacketSent = 0; + m_totalWaitingData = 0; + + m_unsequencedWindow.fill(0); + + ResetQueues(); + } + + bool ENetPeer::Send(UInt8 channelId, ENetPacketFlags flags, NetPacket&& packet) + { + return Send(channelId, m_host->AllocatePacket(flags, std::move(packet))); + } + + void ENetPeer::SimulateNetwork(double packetLossProbability, UInt16 minDelay, UInt16 maxDelay) + { + NazaraAssert(maxDelay >= minDelay, "Maximum delay cannot be greater than minimum delay"); + + if (packetLossProbability <= 0.0 && minDelay == 0 && maxDelay == 0) + m_isSimulationEnabled = false; + else + { + m_isSimulationEnabled = true; + m_packetDelayDistribution = std::uniform_int_distribution(minDelay, maxDelay); + m_packetLossProbability = std::bernoulli_distribution(packetLossProbability); + } + } + + bool ENetPeer::Send(UInt8 channelId, ENetPacketRef packetRef) + { + if (m_state != ENetPeerState::Connected || channelId >= m_channels.size() || packetRef->data.GetDataSize() > m_host->m_maximumPacketSize) + return false; + + Channel& channel = m_channels[channelId]; + + UInt16 fragmentLength = static_cast(m_mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment)); + + UInt32 packetSize = static_cast(packetRef->data.GetDataSize()); + if (packetSize > fragmentLength) + { + UInt32 fragmentCount = (packetSize + fragmentLength - 1) / fragmentLength; + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount) + return false; + + UInt8 commandNumber; + UInt16 startSequenceNumber; + if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_UnreliableFragment)) == ENetPacketFlag_UnreliableFragment && + channel.outgoingUnreliableSequenceNumber < 0xFFFF) + { + commandNumber = ENetProtocolCommand_SendUnreliable; + startSequenceNumber = HostToNet(channel.outgoingUnreliableSequenceNumber + 1); + } + else + { + commandNumber = ENetProtocolCommand_SendFragment | ENetProtocolFlag_Acknowledge; + startSequenceNumber = HostToNet(channel.outgoingReliableSequenceNumber + 1); + } + + for (UInt32 fragmentNumber = 0, fragmentOffset = 0; fragmentOffset < packetSize; ++fragmentNumber, fragmentOffset += fragmentLength) + { + if (packetSize - fragmentOffset < fragmentLength) + fragmentLength = UInt16(packetSize - fragmentOffset); + + OutgoingCommand outgoingCommand; + outgoingCommand.fragmentOffset = fragmentOffset; + outgoingCommand.fragmentLength = fragmentLength; + outgoingCommand.packet = packetRef; + outgoingCommand.command.header.command = commandNumber; + outgoingCommand.command.header.channelID = channelId; + outgoingCommand.command.sendFragment.startSequenceNumber = startSequenceNumber; + outgoingCommand.command.sendFragment.dataLength = HostToNet(fragmentLength); + outgoingCommand.command.sendFragment.fragmentCount = HostToNet(fragmentCount); + outgoingCommand.command.sendFragment.fragmentNumber = HostToNet(fragmentNumber); + outgoingCommand.command.sendFragment.totalLength = HostToNet(packetSize); + outgoingCommand.command.sendFragment.fragmentOffset = HostToNet(fragmentOffset); + + SetupOutgoingCommand(outgoingCommand); + } + + return true; + } + + ENetProtocol command; + command.header.channelID = channelId; + + if ((packetRef->flags & (ENetPacketFlag_Reliable | ENetPacketFlag_Unsequenced)) == ENetPacketFlag_Unsequenced) + { + command.header.command = ENetProtocolCommand_SendUnsequenced | ENetProtocolFlag_Unsequenced; + command.sendUnsequenced.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } + else if (packetRef->flags & ENetPacketFlag_Reliable || channel.outgoingUnreliableSequenceNumber >= 0xFFFF) + { + command.header.command = ENetProtocolCommand_SendReliable | ENetProtocolFlag_Acknowledge; + command.sendReliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } + else + { + command.header.command = ENetProtocolCommand_SendUnreliable; + command.sendUnreliable.dataLength = HostToNet(UInt16(packetRef->data.GetDataSize())); + } + + QueueOutgoingCommand(command, packetRef, 0, packetSize); + + return true; + } + + void ENetPeer::ThrottleConfigure(UInt32 interval, UInt32 acceleration, UInt32 deceleration) + { + m_packetThrottleInterval = interval; + m_packetThrottleAcceleration = acceleration; + m_packetThrottleDeceleration = deceleration; + + ENetProtocol command(ENetProtocolCommand_ThrottleConfigure | ENetProtocolFlag_Acknowledge, 0xFF); + command.throttleConfigure.packetThrottleInterval = HostToNet(interval); + command.throttleConfigure.packetThrottleAcceleration = HostToNet(acceleration); + command.throttleConfigure.packetThrottleDeceleration = HostToNet(deceleration); + QueueOutgoingCommand(command); + } + + bool ENetPeer::CheckTimeouts(ENetEvent* event) + { + UInt32 serviceTime = m_host->GetServiceTime(); + + auto it = m_sentReliableCommands.begin(); + for (; it != m_sentReliableCommands.end();) + { + OutgoingCommand& command = *it; + + if (ENetTimeDifference(serviceTime, command.sentTime) < command.roundTripTimeout) + { + ++it; + continue; + } + + if (m_earliestTimeout == 0 || ENetTimeLess(command.sentTime, m_earliestTimeout)) + m_earliestTimeout = command.sentTime; + + if (m_earliestTimeout != 0 && (ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMaximum || + (command.roundTripTimeout >= command.roundTripTimeoutLimit && ENetTimeDifference(serviceTime, m_earliestTimeout) >= m_timeoutMinimum))) + { + m_host->NotifyDisconnect(this, event); + return true; + } + + if (command.packet) + m_reliableDataInTransit -= command.fragmentLength; + + ++m_packetsLost; + ++m_totalPacketLost; + + // http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html + command.roundTripTimeout = m_roundTripTime + 4 * m_roundTripTimeVariance; + command.roundTripTimeoutLimit = m_timeoutLimit * command.roundTripTimeout; + + m_outgoingReliableCommands.emplace_front(std::move(command)); + it = m_sentReliableCommands.erase(it); + + // Okay this should just never procs, I don't see how it would be possible + /*if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && + !enet_list_empty(&peer->sentReliableCommands)) + { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; + }*/ + } + + return false; + } + + void ENetPeer::DispatchState(ENetPeerState state) + { + ChangeState(state); + + m_host->AddToDispatchQueue(this); + } + + void ENetPeer::DispatchIncomingReliableCommands(Channel& channel) + { + auto currentCommand = channel.incomingReliableCommands.begin(); + for (; currentCommand != channel.incomingReliableCommands.end(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if (incomingCommand.fragmentsRemaining > 0 || incomingCommand.reliableSequenceNumber != (channel.incomingReliableSequenceNumber + 1)) + break; + + channel.incomingReliableSequenceNumber = incomingCommand.reliableSequenceNumber; + + if (incomingCommand.fragments.GetSize() > 0) + channel.incomingReliableSequenceNumber += incomingCommand.fragments.GetSize() - 1; + } + + if (currentCommand == channel.incomingReliableCommands.begin()) + return; + + channel.incomingUnreliableSequenceNumber = 0; + + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingReliableCommands, channel.incomingReliableCommands.begin(), currentCommand); + + m_host->AddToDispatchQueue(this); + + if (!channel.incomingUnreliableCommands.empty()) + DispatchIncomingUnreliableCommands(channel); + } + + void ENetPeer::DispatchIncomingUnreliableCommands(Channel& channel) + { + std::list::iterator currentCommand; + std::list::iterator droppedCommand; + std::list::iterator startCommand; + + for (droppedCommand = startCommand = currentCommand = channel.incomingUnreliableCommands.begin(); + currentCommand != channel.incomingUnreliableCommands.end(); + ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_SendUnsequenced) + continue; + + if (incomingCommand.reliableSequenceNumber == channel.incomingReliableSequenceNumber) + { + if (incomingCommand.fragmentsRemaining <= 0) + { + channel.incomingUnreliableSequenceNumber = incomingCommand.unreliableSequenceNumber; + continue; + } + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + + droppedCommand = currentCommand; + } + else if (droppedCommand != currentCommand) + { + droppedCommand = currentCommand; + --droppedCommand; + } + } + else + { + UInt16 reliableWindow = incomingCommand.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENetConstants::ENetPeer_ReliableWindowSize - 1) + break; + + droppedCommand = currentCommand; + ++droppedCommand; + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + } + } + + startCommand = currentCommand; + ++startCommand; + } + + if (startCommand != currentCommand) + { + m_dispatchedCommands.splice(m_dispatchedCommands.end(), channel.incomingUnreliableCommands, startCommand, currentCommand); + + m_host->AddToDispatchQueue(this); + + droppedCommand = currentCommand; + } + + channel.incomingUnreliableCommands.erase(channel.incomingUnreliableCommands.begin(), droppedCommand); + } + + bool ENetPeer::HandleAcknowledge(const ENetProtocol* command, ENetEvent* event) + { + if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie) + return true; + + UInt32 serviceTime = m_host->GetServiceTime(); + + UInt32 receivedSentTime = NetToHost(command->acknowledge.receivedSentTime); + receivedSentTime |= serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENetTimeLess(serviceTime, receivedSentTime)) + return true; + + m_lastReceiveTime = serviceTime; + m_earliestTimeout = 0; + + UInt32 roundTripTime = ENetTimeDifference(serviceTime, receivedSentTime); + + Throttle(roundTripTime); + + m_roundTripTimeVariance -= m_roundTripTimeVariance / 4; + + if (roundTripTime >= m_roundTripTime) + { + m_roundTripTime += (roundTripTime - m_roundTripTime) / 8; + m_roundTripTimeVariance += (roundTripTime - m_roundTripTime) / 4; + } + else + { + m_roundTripTime -= (m_roundTripTime - roundTripTime) / 8; + m_roundTripTimeVariance += (m_roundTripTime - roundTripTime) / 4; + } + + m_lowestRoundTripTime = std::min(m_lowestRoundTripTime, m_roundTripTime); + m_highestRoundTripTimeVariance = std::max(m_highestRoundTripTimeVariance, m_roundTripTimeVariance); + + if (m_packetThrottleEpoch == 0 || ENetTimeDifference(serviceTime, m_packetThrottleEpoch) >= m_packetThrottleInterval) + { + m_lastRoundTripTime = m_lowestRoundTripTime; + m_lastRoundTripTimeVariance = m_highestRoundTripTimeVariance; + m_lowestRoundTripTime = m_roundTripTime; + m_highestRoundTripTimeVariance = m_roundTripTimeVariance; + m_packetThrottleEpoch = serviceTime; + } + + UInt16 receivedReliableSequenceNumber = NetToHost(command->acknowledge.receivedReliableSequenceNumber); + + ENetProtocolCommand commandNumber = RemoveSentReliableCommand(receivedReliableSequenceNumber, command->header.channelID); + + switch (m_state) + { + case ENetPeerState::AcknowledgingConnect: + if (commandNumber != ENetProtocolCommand_VerifyConnect) + return false; + + m_host->NotifyConnect(this, event, true); + break; + + case ENetPeerState::Disconnecting: + if (commandNumber != ENetProtocolCommand_Disconnect) + return false; + + m_host->NotifyDisconnect(this, event); + break; + + case ENetPeerState::DisconnectLater: + if (!HasPendingCommands()) + Disconnect(m_eventData); + + break; + + default: + break; + } + + return true; + } + + bool ENetPeer::HandleBandwidthLimit(const ENetProtocol* command) + { + if (!IsConnected()) + return false; + + if (m_incomingBandwidth != 0) + --m_host->m_bandwidthLimitedPeers; + + m_incomingBandwidth = NetToHost(command->bandwidthLimit.incomingBandwidth); + m_outgoingBandwidth = NetToHost(command->bandwidthLimit.outgoingBandwidth); + + if (m_incomingBandwidth != 0) + ++m_host->m_bandwidthLimitedPeers; + + if (m_incomingBandwidth == 0 && m_host->m_outgoingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else + { + if (m_incomingBandwidth == 0 || m_host->m_outgoingBandwidth == 0) + m_windowSize = (std::max(m_incomingBandwidth, m_host->m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_incomingBandwidth, m_host->m_outgoingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + return true; + } + + bool ENetPeer::HandleDisconnect(const ENetProtocol* command) + { + if (m_state == ENetPeerState::Disconnected || m_state == ENetPeerState::Zombie || m_state == ENetPeerState::AcknowledgingDisconnect) + return true; + + ResetQueues(); + + if (m_state == ENetPeerState::ConnectionSucceeded || m_state == ENetPeerState::Disconnecting || m_state == ENetPeerState::Connecting) + DispatchState(ENetPeerState::Zombie); + else + { + if (!IsConnected()) + { + if (m_state == ENetPeerState::ConnectionPending) + m_host->m_recalculateBandwidthLimits = true; + + Reset(); + } + else + { + if (command->header.command & ENetProtocolFlag_Acknowledge) + ChangeState(ENetPeerState::AcknowledgingDisconnect); + else + DispatchState(ENetPeerState::Zombie); + } + } + + if (m_state != ENetPeerState::Disconnected) + m_eventData = NetToHost(command->disconnect.data); + + return true; + } + + bool ENetPeer::HandlePing(const ENetProtocol* /*command*/) + { + if (!IsConnected()) + return false; + + return true; + } + + bool ENetPeer::HandleSendFragment(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *data += fragmentLength; + if (fragmentLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = m_channels[command->header.channelID]; + UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); + UInt16 startWindow = startSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (startSequenceNumber < channel.incomingReliableSequenceNumber) + startWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return true; + + UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); + UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); + UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); + UInt32 totalLength = NetToHost(command->sendFragment.totalLength); + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_host->m_maximumPacketSize || + fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) + return false; + + ENetPeer::IncomingCommmand* startCommand = nullptr; + for (auto currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) + { + ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; + + if (startSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendFragment || + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (!startCommand) + { + ENetProtocol hostCommand = *command; + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + + startCommand = QueueIncomingCommand(hostCommand, nullptr, totalLength, ENetPacketFlag_Reliable, fragmentCount); + if (!startCommand) + return false; + } + + if (!startCommand->fragments.Test(fragmentNumber)) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments.Set(fragmentNumber, true); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = static_cast(startCommand->packet->data.GetDataSize() - fragmentOffset); + + std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + DispatchIncomingReliableCommands(channel); + } + + return true; + } + + bool ENetPeer::HandleSendReliable(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 dataLength = NetToHost(command->sendReliable.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendReliable), dataLength, ENetPacketFlag_Reliable, 0)) + return false; + + return true; + } + + bool ENetPeer::HandleSendUnreliable(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 dataLength = NetToHost(command->sendUnreliable.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0)) + return false; + + return true; + } + + bool ENetPeer::HandleSendUnreliableFragment(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + UInt16 fragmentLength = NetToHost(command->sendFragment.dataLength); + *data += fragmentLength; + if (fragmentLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + ENetPeer::Channel& channel = m_channels[command->header.channelID]; + UInt32 reliableSequenceNumber = command->header.reliableSequenceNumber; + UInt32 startSequenceNumber = NetToHost(command->sendFragment.startSequenceNumber); + + UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (startSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return true; + + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && startSequenceNumber <= channel.incomingUnreliableSequenceNumber) + return true; + + UInt32 fragmentNumber = NetToHost(command->sendFragment.fragmentNumber); + UInt32 fragmentCount = NetToHost(command->sendFragment.fragmentCount); + UInt32 fragmentOffset = NetToHost(command->sendFragment.fragmentOffset); + UInt32 totalLength = NetToHost(command->sendFragment.totalLength); + + if (fragmentCount > ENetConstants::ENetProtocol_MaximumFragmentCount || fragmentNumber >= fragmentCount || totalLength > m_host->m_maximumPacketSize || + fragmentOffset >= totalLength || fragmentLength > totalLength - fragmentOffset) + return false; + + ENetPeer::IncomingCommmand* startCommand = nullptr; + for (auto currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) + { + ENetPeer::IncomingCommmand& incomingCommand = *currentCommand; + + if (startSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand.unreliableSequenceNumber <= startSequenceNumber) + { + if (incomingCommand.unreliableSequenceNumber < startSequenceNumber) + break; + + if ((incomingCommand.command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnreliableFragment || + totalLength != incomingCommand.packet->data.GetDataSize() || fragmentCount != incomingCommand.fragments.GetSize()) + return false; + + startCommand = &incomingCommand; + break; + } + } + + if (startCommand) + { + if (!QueueIncomingCommand(*command, nullptr, totalLength, ENetPacketFlag_UnreliableFragment, fragmentCount)) + return false; + } + + if (!startCommand->fragments.Test(fragmentNumber)) + { + --startCommand->fragmentsRemaining; + + startCommand->fragments.Set(fragmentNumber, true); + + if (fragmentOffset + fragmentLength > startCommand->packet->data.GetDataSize()) + fragmentLength = static_cast(startCommand->packet->data.GetDataSize() - fragmentOffset); + + std::memcpy(startCommand->packet->data.GetData() + NetPacket::HeaderSize + fragmentOffset, reinterpret_cast(command) + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) + DispatchIncomingUnreliableCommands(channel); + } + + return true; + } + + bool ENetPeer::HandleSendUnsequenced(const ENetProtocol* command, UInt8** data) + { + if (command->header.channelID >= m_channels.size() || !IsConnected()) + return false; + + std::size_t dataLength = NetToHost(command->sendUnsequenced.dataLength); + *data += dataLength; + if (dataLength >= m_host->m_maximumPacketSize || *data < m_host->m_receivedData || *data > &m_host->m_receivedData[m_host->m_receivedDataLength]) + return false; + + UInt32 unsequencedGroup = NetToHost(command->sendUnsequenced.unsequencedGroup); + UInt32 index = unsequencedGroup % ENetConstants::ENetPeer_UnsequencedWindowSize; + + if (unsequencedGroup < m_incomingUnsequencedGroup) + unsequencedGroup += 0x10000; + + if (unsequencedGroup >= static_cast(m_incomingUnsequencedGroup) + ENetConstants::ENetPeer_UnsequencedWindows * ENetConstants::ENetPeer_UnsequencedWindowSize) + return true; + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != m_incomingUnsequencedGroup) + { + m_incomingUnsequencedGroup = unsequencedGroup - index; + + m_unsequencedWindow.fill(0); + } + else if (m_unsequencedWindow[index / 32] & (1 << (index % 32))) + return true; + + if (!QueueIncomingCommand(*command, reinterpret_cast(command) + sizeof(ENetProtocolSendUnsequenced), dataLength, ENetPacketFlag_Unsequenced, 0)) + return false; + + m_unsequencedWindow[index / 32] |= 1 << (index % 32); + + return true; + } + + bool ENetPeer::HandleThrottleConfigure(const ENetProtocol* command) + { + if (!IsConnected()) + return false; + + m_packetThrottleInterval = NetToHost(command->throttleConfigure.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(command->throttleConfigure.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(command->throttleConfigure.packetThrottleDeceleration); + + return true; + } + + bool ENetPeer::HandleVerifyConnect(const ENetProtocol* command, ENetEvent* event) + { + if (m_state != ENetPeerState::Connecting) + return true; + + UInt32 channelCount = NetToHost(command->verifyConnect.channelCount); + + if (channelCount < ENetConstants::ENetProtocol_MinimumChannelCount || channelCount > ENetConstants::ENetProtocol_MaximumChannelCount || + NetToHost(command->verifyConnect.packetThrottleInterval) != m_packetThrottleInterval || + NetToHost(command->verifyConnect.packetThrottleAcceleration) != m_packetThrottleAcceleration || + NetToHost(command->verifyConnect.packetThrottleDeceleration) != m_packetThrottleDeceleration || + command->verifyConnect.connectID != m_connectID) + { + m_eventData = 0; + + DispatchState(ENetPeerState::Zombie); + + return false; + } + + RemoveSentReliableCommand(1, 0xFF); + + if (channelCount < m_channels.size()) + m_channels.resize(channelCount); + + m_outgoingPeerID = NetToHost(command->verifyConnect.outgoingPeerID); + m_incomingSessionID = command->verifyConnect.incomingSessionID; + m_outgoingSessionID = command->verifyConnect.outgoingSessionID; + + UInt32 mtu = Clamp(NetToHost(command->verifyConnect.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + m_mtu = std::min(m_mtu, mtu); + + UInt32 windowSize = Clamp(NetToHost(command->verifyConnect.windowSize), ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + m_windowSize = std::min(m_windowSize, windowSize); + + m_incomingBandwidth = NetToHost(command->verifyConnect.incomingBandwidth); + m_outgoingBandwidth = NetToHost(command->verifyConnect.outgoingBandwidth); + + m_host->NotifyConnect(this, event, false); + return true; + } + + void ENetPeer::InitIncoming(std::size_t channelCount, const IpAddress& address, ENetProtocolConnect& incomingCommand) + { + m_channels.resize(channelCount); + m_address = address; + + m_connectID = incomingCommand.connectID; + m_eventData = NetToHost(incomingCommand.data); + m_incomingBandwidth = NetToHost(incomingCommand.incomingBandwidth); + m_outgoingBandwidth = NetToHost(incomingCommand.outgoingBandwidth); + m_packetThrottleInterval = NetToHost(incomingCommand.packetThrottleInterval); + m_packetThrottleAcceleration = NetToHost(incomingCommand.packetThrottleAcceleration); + m_packetThrottleDeceleration = NetToHost(incomingCommand.packetThrottleDeceleration); + m_outgoingPeerID = NetToHost(incomingCommand.outgoingPeerID); + m_state = ENetPeerState::AcknowledgingConnect; + + UInt8 incomingSessionId, outgoingSessionId; + + incomingSessionId = incomingCommand.incomingSessionID == 0xFF ? m_outgoingSessionID : incomingCommand.incomingSessionID; + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (incomingSessionId == m_outgoingSessionID) + incomingSessionId = (incomingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_outgoingSessionID = incomingSessionId; + + outgoingSessionId = incomingCommand.outgoingSessionID == 0xFF ? m_incomingSessionID : incomingCommand.outgoingSessionID; + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + if (outgoingSessionId == m_incomingSessionID) + outgoingSessionId = (outgoingSessionId + 1) & (ENetProtocolHeaderSessionMask >> ENetProtocolHeaderSessionShift); + m_incomingSessionID = outgoingSessionId; + + m_mtu = Clamp(NetToHost(incomingCommand.mtu), ENetConstants::ENetProtocol_MinimumMTU, ENetConstants::ENetProtocol_MaximumMTU); + + if (m_host->m_outgoingBandwidth == 0 && m_incomingBandwidth == 0) + m_windowSize = ENetConstants::ENetProtocol_MaximumWindowSize; + else if (m_host->m_outgoingBandwidth == 0 || m_incomingBandwidth == 0) + m_windowSize = (std::max(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + else + m_windowSize = (std::min(m_host->m_outgoingBandwidth, m_incomingBandwidth) / ENetConstants::ENetPeer_WindowSizeScale) * ENetConstants::ENetProtocol_MinimumWindowSize; + + m_windowSize = Clamp(m_windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::InitOutgoing(std::size_t channelCount, const IpAddress& address, UInt32 connectId, UInt32 windowSize) + { + m_channels.resize(channelCount); + + m_address = address; + m_connectID = connectId; + m_state = ENetPeerState::Connecting; + m_windowSize = Clamp(windowSize, ENetConstants::ENetProtocol_MinimumWindowSize, ENetConstants::ENetProtocol_MaximumWindowSize); + } + + void ENetPeer::OnConnect() + { + if (!IsConnected()) + { + if (m_incomingBandwidth != 0) + ++m_host->m_bandwidthLimitedPeers; + + ++m_host->m_connectedPeers; + } + } + + void ENetPeer::OnDisconnect() + { + if (IsConnected()) + { + if (m_incomingBandwidth != 0) + --m_host->m_bandwidthLimitedPeers; + + --m_host->m_connectedPeers; + } + } + + ENetProtocolCommand ENetPeer::RemoveSentReliableCommand(UInt16 reliableSequenceNumber, UInt8 channelId) + { + std::list* commandList = nullptr; + + bool found = false; + auto currentCommand = m_sentReliableCommands.begin(); + commandList = &m_sentReliableCommands; + for (; currentCommand != m_sentReliableCommands.end(); ++currentCommand) + { + found = true; + + if (currentCommand->reliableSequenceNumber == reliableSequenceNumber && + currentCommand->command.header.channelID == channelId) + break; + } + + bool wasSent = true; + if (currentCommand == m_sentReliableCommands.end()) + { + currentCommand = m_outgoingReliableCommands.begin(); + commandList = &m_outgoingReliableCommands; + for (; currentCommand != m_outgoingReliableCommands.end(); ++currentCommand) + { + found = true; + + if (currentCommand->sendAttempts < 1) + return ENetProtocolCommand_None; + + if (currentCommand->reliableSequenceNumber == reliableSequenceNumber && + currentCommand->command.header.channelID == channelId) + break; + } + + if (currentCommand == m_outgoingReliableCommands.end()) + return ENetProtocolCommand_None; + + wasSent = false; + } + + if (!found) //< Really useful? + return ENetProtocolCommand_None; + + if (channelId < m_channels.size()) + { + Channel& channel = m_channels[channelId]; + + UInt16 reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + if (channel.reliableWindows[reliableWindow] > 0) + { + --channel.reliableWindows[reliableWindow]; + if (!channel.reliableWindows[reliableWindow]) + channel.usedReliableWindows &= ~(1 << reliableWindow); + } + } + + ENetProtocolCommand commandNumber = static_cast(currentCommand->command.header.command & ENetProtocolCommand_Mask); + + if (currentCommand->packet && wasSent) + m_reliableDataInTransit -= currentCommand->fragmentLength; + + commandList->erase(currentCommand); + + if (m_sentReliableCommands.empty()) + return commandNumber; + + currentCommand = m_sentReliableCommands.begin(); + m_nextTimeout = currentCommand->sentTime + currentCommand->roundTripTimeout; + + return commandNumber; + } + + void ENetPeer::RemoveSentUnreliableCommands() + { + m_sentUnreliableCommands.clear(); + } + + void ENetPeer::ResetQueues() + { + m_host->RemoveFromDispatchQueue(this); + + m_acknowledgements.clear(); + m_dispatchedCommands.clear(); + m_outgoingReliableCommands.clear(); + m_outgoingUnreliableCommands.clear(); + m_sentReliableCommands.clear(); + m_sentUnreliableCommands.clear(); + + m_channels.clear(); + } + + bool ENetPeer::QueueAcknowledgement(ENetProtocol*command, UInt16 sentTime) + { + if (command->header.channelID < m_channels.size()) + { + Channel& channel = m_channels[command->header.channelID]; + + UInt16 reliableWindow = command->header.reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + UInt16 currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (command->header.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1 && reliableWindow <= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows) + return false; + } + + Acknowledgement acknowledgment; + acknowledgment.command = *command; + acknowledgment.sentTime = sentTime; + + m_outgoingDataTotal += sizeof(Acknowledgement); + + m_acknowledgements.emplace_back(acknowledgment); + + return true; + } + + ENetPeer::IncomingCommmand* ENetPeer::QueueIncomingCommand(const ENetProtocol& command, const void* data, std::size_t dataLength, UInt32 flags, UInt32 fragmentCount) + { + static IncomingCommmand dummyCommand; + + UInt32 reliableSequenceNumber = 0; + UInt32 unreliableSequenceNumber = 0; + UInt16 reliableWindow; + UInt16 currentWindow; + + auto discardCommand = [&]() -> IncomingCommmand* + { + if (fragmentCount > 0) + return nullptr; //< Error + + return &dummyCommand; + }; + + if (m_state == ENetPeerState::DisconnectLater) + return discardCommand(); + + Channel& channel = m_channels[command.header.channelID]; + + if ((command.header.command & ENetProtocolCommand_Mask) != ENetProtocolCommand_SendUnsequenced) + { + reliableSequenceNumber = command.header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + currentWindow = channel.incomingReliableSequenceNumber / ENetConstants::ENetPeer_ReliableWindowSize; + + if (reliableSequenceNumber < channel.incomingReliableSequenceNumber) + reliableWindow += ENetConstants::ENetPeer_ReliableWindows; + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENetConstants::ENetPeer_FreeReliableWindows - 1) + return discardCommand(); + } + + std::list* commandList = nullptr; + std::list::reverse_iterator currentCommand; + + switch (command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendFragment: + case ENetProtocolCommand_SendReliable: + { + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber) + return discardCommand(); + + commandList = &channel.incomingReliableCommands; + + for (currentCommand = channel.incomingReliableCommands.rbegin(); currentCommand != channel.incomingReliableCommands.rend(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if (reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + return discardCommand(); + } + } + break; + } + + case ENetProtocolCommand_SendUnreliable: + case ENetProtocolCommand_SendUnreliableFragment: + { + unreliableSequenceNumber = NetToHost(command.sendUnreliable.unreliableSequenceNumber); + + if (reliableSequenceNumber == channel.incomingReliableSequenceNumber && unreliableSequenceNumber <= channel.incomingUnreliableSequenceNumber) + return discardCommand(); + + commandList = &channel.incomingUnreliableCommands; + + for (currentCommand = channel.incomingUnreliableCommands.rbegin(); currentCommand != channel.incomingUnreliableCommands.rend(); ++currentCommand) + { + IncomingCommmand& incomingCommand = *currentCommand; + + if ((command.header.command & ENetProtocolCommand_Mask) == ENetProtocolCommand_SendUnsequenced) //< wtf + continue; + + if (reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + { + if (incomingCommand.reliableSequenceNumber < channel.incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand.reliableSequenceNumber >= channel.incomingReliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber < reliableSequenceNumber) + break; + + if (incomingCommand.reliableSequenceNumber > reliableSequenceNumber) + continue; + + if (incomingCommand.unreliableSequenceNumber <= unreliableSequenceNumber) + { + if (incomingCommand.unreliableSequenceNumber < unreliableSequenceNumber) + break; + + return discardCommand(); + } + } + break; + } + + case ENetProtocolCommand_SendUnsequenced: + { + commandList = &channel.incomingUnreliableCommands; + + currentCommand = channel.incomingUnreliableCommands.rend(); + break; + } + + default: + return discardCommand(); + } + + if (m_totalWaitingData >= m_host->m_maximumWaitingData) + return nullptr; + + ENetPacketRef packet = m_host->AllocatePacket(flags); + packet->data.Reset(0, data, dataLength); + + IncomingCommmand incomingCommand; + incomingCommand.reliableSequenceNumber = command.header.reliableSequenceNumber; + incomingCommand.unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand.command = command; + incomingCommand.packet = packet; + incomingCommand.fragments.Resize(fragmentCount); + incomingCommand.fragmentsRemaining = fragmentCount; + + if (packet) + m_totalWaitingData += packet->data.GetDataSize(); + + auto it = commandList->insert(currentCommand.base(), incomingCommand); + + switch (command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendFragment: + case ENetProtocolCommand_SendReliable: + DispatchIncomingReliableCommands(channel); + break; + + default: + DispatchIncomingUnreliableCommands(channel); + break; + } + + return &(*it); + } + + void ENetPeer::QueueOutgoingCommand(ENetProtocol& command, ENetPacketRef packet, UInt32 offset, UInt16 length) + { + OutgoingCommand outgoingCommand; + outgoingCommand.command = command; + outgoingCommand.fragmentLength = length; + outgoingCommand.fragmentOffset = offset; + outgoingCommand.packet = packet; + + SetupOutgoingCommand(outgoingCommand); + } + + void ENetPeer::SetupOutgoingCommand(OutgoingCommand& outgoingCommand) + { + m_outgoingDataTotal += static_cast(ENetHost::GetCommandSize(outgoingCommand.command.header.command) + outgoingCommand.fragmentLength); + + if (outgoingCommand.command.header.channelID == 0xFF) + { + ++m_outgoingReliableSequenceNumber; + + outgoingCommand.reliableSequenceNumber = m_outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = 0; + } + else + { + Channel* channel = &m_channels[outgoingCommand.command.header.channelID]; + if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge) + { + ++channel->outgoingReliableSequenceNumber; + channel->outgoingUnreliableSequenceNumber = 0; + + outgoingCommand.reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = 0; + } + else if (outgoingCommand.command.header.command & ENetProtocolFlag_Unsequenced) + { + ++m_outgoingUnsequencedGroup; + + outgoingCommand.reliableSequenceNumber = 0; + outgoingCommand.unreliableSequenceNumber = 0; + } + else + { + if (outgoingCommand.fragmentOffset == 0) + ++channel->outgoingUnreliableSequenceNumber; + + outgoingCommand.reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand.unreliableSequenceNumber = channel->outgoingUnreliableSequenceNumber; + } + } + + outgoingCommand.sendAttempts = 0; + outgoingCommand.sentTime = 0; + outgoingCommand.roundTripTimeout = 0; + outgoingCommand.roundTripTimeoutLimit = 0; + outgoingCommand.command.header.reliableSequenceNumber = HostToNet(outgoingCommand.reliableSequenceNumber); + + switch (outgoingCommand.command.header.command & ENetProtocolCommand_Mask) + { + case ENetProtocolCommand_SendUnreliable: + outgoingCommand.command.sendUnreliable.unreliableSequenceNumber = HostToNet(outgoingCommand.unreliableSequenceNumber); + break; + + case ENetProtocolCommand_SendUnsequenced: + outgoingCommand.command.sendUnsequenced.unsequencedGroup = HostToNet(m_outgoingUnsequencedGroup); + break; + + default: + break; + } + + if (outgoingCommand.command.header.command & ENetProtocolFlag_Acknowledge) + m_outgoingReliableCommands.emplace_back(outgoingCommand); + else + m_outgoingUnreliableCommands.emplace_back(outgoingCommand); + } + + int ENetPeer::Throttle(UInt32 rtt) + { + if (m_lastRoundTripTime <= m_lastRoundTripTimeVariance) + m_packetThrottle = m_packetThrottleLimit; + else + { + if (rtt < m_lastRoundTripTime) + { + m_packetThrottle = std::min(m_packetThrottle + m_packetThrottleAcceleration, m_packetThrottleLimit); + return 1; + } + else if (rtt > m_lastRoundTripTime + 2 * m_lastRoundTripTimeVariance) + { + if (m_packetThrottle > m_packetThrottleDeceleration) + m_packetThrottle -= m_packetThrottleDeceleration; + else + m_packetThrottle = 0; + + return -1; + } + } + + return 0; + } +} diff --git a/src/Nazara/Network/Linux/SocketPollerImpl.cpp b/src/Nazara/Network/Linux/SocketPollerImpl.cpp index c839d7352..6e902a587 100644 --- a/src/Nazara/Network/Linux/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Linux/SocketPollerImpl.cpp @@ -23,13 +23,19 @@ namespace Nz void SocketPollerImpl::Clear() { - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); m_sockets.clear(); } - bool SocketPollerImpl::IsReady(SocketHandle socket) const + bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const { - return m_activeSockets.count(socket) != 0; + return m_readyToReadSockets.count(socket) != 0; + } + + bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const + { + return m_readyToWriteSockets.count(socket) != 0; } bool SocketPollerImpl::IsRegistered(SocketHandle socket) const @@ -37,15 +43,21 @@ namespace Nz return m_sockets.count(socket) != 0; } - bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "Socket is already registered"); - epoll_event event; - event.events = EPOLLIN; - event.data.fd = socket; + epoll_event entry; + entry.events = 0; + entry.data.fd = socket; - if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &event) != 0) + if (eventFlags & SocketPollEvent_Read) + entry.events |= EPOLLIN; + + if (eventFlags & SocketPollEvent_Write) + entry.events |= EPOLLOUT; + + if (epoll_ctl(m_handle, EPOLL_CTL_ADD, socket, &entry) != 0) { NazaraError("Failed to add socket to epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')'); return false; @@ -60,14 +72,15 @@ namespace Nz { NazaraAssert(IsRegistered(socket), "Socket is not registered"); - m_activeSockets.erase(socket); + m_readyToReadSockets.erase(socket); + m_readyToWriteSockets.erase(socket); m_sockets.erase(socket); if (epoll_ctl(m_handle, EPOLL_CTL_DEL, socket, nullptr) != 0) NazaraWarning("An error occured while removing socket from epoll structure (errno " + String::Number(errno) + ": " + Error::GetLastSystemError() + ')'); } - int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error) + int SocketPollerImpl::Wait(int msTimeout, SocketError* error) { int activeSockets; @@ -84,21 +97,27 @@ namespace Nz return 0; } - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); if (activeSockets > 0) { int socketCount = activeSockets; for (int i = 0; i < socketCount; ++i) { - if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) + if (m_events[i].events & (EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR)) { - m_activeSockets.insert(m_events[i].data.fd); + if (m_events[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR)) + m_readyToReadSockets.insert(m_events[i].data.fd); + + if (m_events[i].events & (EPOLLOUT | EPOLLERR)) + m_readyToWriteSockets.insert(m_events[i].data.fd); + if (m_events[i].events & EPOLLERR) NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll with EPOLLERR status"); } else { - NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN (events: 0x" + String::Number(m_events[i].events, 16) + ')'); + NazaraWarning("Descriptor " + String::Number(m_events[i].data.fd) + " was returned by epoll without EPOLLIN nor EPOLLOUT flags (events: 0x" + String::Number(m_events[i].events, 16) + ')'); activeSockets--; } } diff --git a/src/Nazara/Network/Linux/SocketPollerImpl.hpp b/src/Nazara/Network/Linux/SocketPollerImpl.hpp index 1c54471fc..882141d38 100644 --- a/src/Nazara/Network/Linux/SocketPollerImpl.hpp +++ b/src/Nazara/Network/Linux/SocketPollerImpl.hpp @@ -23,16 +23,18 @@ namespace Nz void Clear(); - bool IsReady(SocketHandle socket) const; + bool IsReadyToRead(SocketHandle socket) const; + bool IsReadyToWrite(SocketHandle socket) const; bool IsRegistered(SocketHandle socket) const; - bool RegisterSocket(SocketHandle socket); + bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags); void UnregisterSocket(SocketHandle socket); - int Wait(UInt64 msTimeout, SocketError* error); + int Wait(int msTimeout, SocketError* error); private: - std::unordered_set m_activeSockets; + std::unordered_set m_readyToReadSockets; + std::unordered_set m_readyToWriteSockets; std::unordered_set m_sockets; std::vector m_events; int m_handle; diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp index be6f84581..7ca69ae29 100644 --- a/src/Nazara/Network/Posix/SocketImpl.cpp +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -509,12 +509,12 @@ namespace Nz NazaraAssert(buffer && length > 0, "Invalid buffer"); IpAddressImpl::SockAddrBuffer nameBuffer; - socklen_t bufferLength = sizeof(sockaddr_in); + socklen_t bufferLength = static_cast(nameBuffer.size()); IpAddress senderIp; int byteRead = recvfrom(handle, buffer, length, 0, reinterpret_cast(&nameBuffer), &bufferLength); - if (byteRead == SOCKET_ERROR) + if (byteRead == -1) { int errorCode = GetLastErrorCode(); if (errorCode == EAGAIN) @@ -549,6 +549,92 @@ namespace Nz else // else we received something senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); + if (from) + *from = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); + + if (read) + *read = byteRead; + + if (error) + *error = SocketError_NoError; + + return true; + } + + bool SocketImpl::ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(buffers && bufferCount > 0, "Invalid buffers"); + + StackAllocation memory = NazaraStackAllocation(bufferCount * sizeof(iovec)); + struct iovec* sysBuffers = static_cast(memory.GetPtr()); + for (std::size_t i = 0; i < bufferCount; ++i) + { + sysBuffers[i].iov_base = buffers[i].data; + sysBuffers[i].iov_len = buffers[i].dataLength; + } + + struct msghdr msgHdr; + std::memset(&msgHdr, 0, sizeof(msgHdr)); + + msgHdr.msg_iov = sysBuffers; + msgHdr.msg_iovlen = static_cast(bufferCount); + + IpAddressImpl::SockAddrBuffer nameBuffer; + if (from) + { + msgHdr.msg_name = nameBuffer.data(); + msgHdr.msg_namelen = static_cast(nameBuffer.size()); + } + + IpAddress senderIp; + + int byteRead = recvmsg(handle, &msgHdr, MSG_NOSIGNAL); + if (byteRead == -1) + { + int errorCode = GetLastErrorCode(); + if (errorCode == EAGAIN) + errorCode = EWOULDBLOCK; + + switch (errorCode) + { + case EWOULDBLOCK: + { + // If we have no data and are not blocking, return true with 0 byte read + byteRead = 0; + senderIp = IpAddress::Invalid; + break; + } + + default: + { + if (error) + *error = TranslateErrnoToResolveError(errorCode); + + return false; //< Error + } + } + } + else if (byteRead == 0) + { + if (error) + *error = SocketError_ConnectionClosed; + + return false; //< Connection closed + } + else // else we received something + senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast(nameBuffer.data())); + +#ifdef HAS_MSGHDR_FLAGS + if (msgHdr.msg_flags & MSG_TRUNC) + { + if (error) + *error = SocketError_DatagramSize; + + return false; + } +#endif + if (from) *from = senderIp; diff --git a/src/Nazara/Network/Posix/SocketImpl.hpp b/src/Nazara/Network/Posix/SocketImpl.hpp index 7ee2e24f6..abba97e4f 100644 --- a/src/Nazara/Network/Posix/SocketImpl.hpp +++ b/src/Nazara/Network/Posix/SocketImpl.hpp @@ -63,6 +63,7 @@ namespace Nz static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error); static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error); + static bool ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error); static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error); static bool SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error); diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.cpp b/src/Nazara/Network/Posix/SocketPollerImpl.cpp index 5d2a6c317..ed391c6f3 100644 --- a/src/Nazara/Network/Posix/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Posix/SocketPollerImpl.cpp @@ -10,14 +10,20 @@ namespace Nz { void SocketPollerImpl::Clear() { - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); m_allSockets.clear(); m_sockets.clear(); } - bool SocketPollerImpl::IsReady(SocketHandle socket) const + bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const { - return m_activeSockets.count(socket) != 0; + return m_readyToReadSockets.count(socket) != 0; + } + + bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const + { + return m_readyToWriteSockets.count(socket) != 0; } bool SocketPollerImpl::IsRegistered(SocketHandle socket) const @@ -25,16 +31,22 @@ namespace Nz return m_allSockets.count(socket) != 0; } - bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "Socket is already registered"); PollSocket entry = { socket, - POLLRDNORM, + 0, 0 }; + if (eventFlags & SocketPollEvent_Read) + entry.events |= POLLRDNORM; + + if (eventFlags & SocketPollEvent_Write) + entry.events |= POLLWRNORM; + m_allSockets[socket] = m_sockets.size(); m_sockets.emplace_back(entry); @@ -57,31 +69,37 @@ namespace Nz // Now move it properly (lastElement is invalid after the following line) and pop it m_sockets[entry] = std::move(m_sockets.back()); } - m_sockets.pop_back(); - m_activeSockets.erase(socket); + m_allSockets.erase(socket); + m_readyToReadSockets.erase(socket); + m_readyToWriteSockets.erase(socket); } - int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error) + int SocketPollerImpl::Wait(int msTimeout, SocketError* error) { int activeSockets; // Reset status of sockets - for (PollSocket& entry : m_sockets) - entry.revents = 0; - activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); - m_activeSockets.clear(); - if (activeSockets > 0) + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); + if (activeSockets > 0U) { int socketRemaining = activeSockets; for (PollSocket& entry : m_sockets) { - if (entry.revents & POLLRDNORM) + if (entry.revents != 0) { - m_activeSockets.insert(entry.fd); + if (entry.revents & POLLRDNORM) + m_readyToReadSockets.insert(entry.fd); + + if (entry.revents & POLLWRNORM) + m_readyToWriteSockets.insert(entry.fd); + + entry.revents = 0; + if (--socketRemaining == 0) break; } diff --git a/src/Nazara/Network/Posix/SocketPollerImpl.hpp b/src/Nazara/Network/Posix/SocketPollerImpl.hpp index 3472c3265..1ded2dabc 100644 --- a/src/Nazara/Network/Posix/SocketPollerImpl.hpp +++ b/src/Nazara/Network/Posix/SocketPollerImpl.hpp @@ -27,13 +27,14 @@ namespace Nz bool IsReady(SocketHandle socket) const; bool IsRegistered(SocketHandle socket) const; - bool RegisterSocket(SocketHandle socket); + bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags); void UnregisterSocket(SocketHandle socket); - int Wait(UInt64 msTimeout, SocketError* error); + int Wait(int msTimeout, SocketError* error); private: - std::unordered_set m_activeSockets; + std::unordered_set m_readyToReadSockets; + std::unordered_set m_readyToWriteSockets; std::unordered_map m_allSockets; std::vector m_sockets; }; diff --git a/src/Nazara/Network/RUdpConnection.cpp b/src/Nazara/Network/RUdpConnection.cpp index f704b9568..3667eb113 100644 --- a/src/Nazara/Network/RUdpConnection.cpp +++ b/src/Nazara/Network/RUdpConnection.cpp @@ -527,7 +527,7 @@ namespace Nz } else { - NazaraNotice("Received wrong token (" + String::Number(token) + " instead of " + String::Number(~peer.stateData1) + ") from client " + peer.address); + NazaraNotice("Received wrong token (" + String::Number(token) + " instead of " + String::Number(~peer.stateData1) + ") from client " + peer.address.ToString()); return; //< Ignore } diff --git a/src/Nazara/Network/SocketPoller.cpp b/src/Nazara/Network/SocketPoller.cpp index fa5aa837e..50eeb5cdf 100644 --- a/src/Nazara/Network/SocketPoller.cpp +++ b/src/Nazara/Network/SocketPoller.cpp @@ -57,12 +57,13 @@ namespace Nz /*! * \brief Checks if a specific socket is ready to read data * - * This function allows you to read the results of the last Wait operation and if a specific socket is ready. + * This function allows you to read the results of the last Wait operation and if a specific socket is ready to read (has incoming data). * - * A socket in the ready state (with the exception of TcpServer) has incoming data and can be read without blocking. + * A socket in the ready to read state (with the exception of TcpServer) has incoming data and can be read without blocking. * - * \remark When used on a TcpServer socket, this function returns true if the server is ready to accept a new client. - * \remark You must call Wait before using this function in order to refresh the state. + * \remark You must call Wait before using this function in order to refresh the read state. + * \remark A socket must be registered with SocketPollerEvent_Read event flag for its read state to be watched + * \remark A TcpServer socket becomes ready to read when it is ready to accept a new client. * * \param socket Reference to the socket to check * @@ -70,11 +71,32 @@ namespace Nz * * \see Wait */ - bool SocketPoller::IsReady(const AbstractSocket& socket) const + bool SocketPoller::IsReadyToRead(const AbstractSocket& socket) const { NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller"); - return m_impl->IsReady(socket.GetNativeHandle()); + return m_impl->IsReadyToRead(socket.GetNativeHandle()); + } + + /*! + * \brief Checks if a specific socket is ready to write data + * + * This function allows you to read the results of the last Wait operation and if a specific socket is ready to write (can be written to without blocking). + * + * \remark You must call Wait before using this function in order to refresh the read state. + * \remark A socket must be registered with SocketPollerEvent_Write event flag for its read state to be watched + * + * \param socket Reference to the socket to check + * + * \return True if the socket is available for writing without blocking, false otherwise + * + * \see Wait + */ + bool SocketPoller::IsReadyToWrite(const AbstractSocket& socket) const + { + NazaraAssert(IsRegistered(socket), "Socket is not registered in the poller"); + + return m_impl->IsReadyToWrite(socket.GetNativeHandle()); } /*! @@ -97,7 +119,7 @@ namespace Nz /*! * \brief Register a socket in the SocketPoller * - * A registered socket is part of the SocketPoller and will be checked by the next Wait operations. + * A registered socket is part of the SocketPoller and will be checked by the next Wait operations according to the event flags passed when registered. * * The SocketPoller keeps a reference to the internal handle of registered socket, which should not be freed while it is registered in the SocketPooler. * @@ -107,17 +129,18 @@ namespace Nz * \remark The socket should not be freed while it is registered in the SocketPooler. * * \param socket Reference to the socket to register + * \param eventFlags Socket events to watch * * \return True if the socket is registered, false otherwise * * \see IsRegistered * \see UnregisterSocket */ - bool SocketPoller::RegisterSocket(AbstractSocket& socket) + bool SocketPoller::RegisterSocket(AbstractSocket& socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "This socket is already registered in this SocketPoller"); - return m_impl->RegisterSocket(socket.GetNativeHandle()); + return m_impl->RegisterSocket(socket.GetNativeHandle(), eventFlags); } /*! @@ -142,19 +165,21 @@ namespace Nz } /*! - * \brief Wait until any registered socket switches to a ready state + * \brief Wait until any registered socket switches to a ready state. * * Waits a specific/undetermined amount of time until at least one socket part of the SocketPoller becomes ready. - * To query the ready state of the registered socket, use the IsReady function. + * To query the ready state of the registered socket, use the IsReadyToRead or IsReadyToWrite functions. * - * \param msTimeout Maximum time to wait in milliseconds, 0 for infinity + * \param msTimeout Maximum time to wait in milliseconds, 0 will returns immediately and -1 will block indefinitely + * + * \return True if at least one socket registered to the poller is ready. * * \remark It is an error to try to unregister a non-registered socket from a SocketPoller. * * \see IsReady * \see RegisterSocket */ - bool SocketPoller::Wait(UInt64 msTimeout) + bool SocketPoller::Wait(int msTimeout) { SocketError error; diff --git a/src/Nazara/Network/TcpClient.cpp b/src/Nazara/Network/TcpClient.cpp index 54144e8fd..9e2eb7e0c 100644 --- a/src/Nazara/Network/TcpClient.cpp +++ b/src/Nazara/Network/TcpClient.cpp @@ -326,7 +326,7 @@ namespace Nz }); } - while (totalByteSent < size) + while (totalByteSent < size || !IsBlockingEnabled()) { int sendSize = static_cast(std::min(size - totalByteSent, std::numeric_limits::max())); //< Handle very large send int sentSize; diff --git a/src/Nazara/Network/UdpSocket.cpp b/src/Nazara/Network/UdpSocket.cpp index bc86f8401..c0a88eb88 100644 --- a/src/Nazara/Network/UdpSocket.cpp +++ b/src/Nazara/Network/UdpSocket.cpp @@ -118,6 +118,42 @@ namespace Nz return true; } + /*! + * \brief Receive multiple datagram from one peer + * \return true If data were sent + * + * \param to Destination IpAddress (must match socket protocol) + * \param buffers A pointer to an array of NetBuffer containing buffers and size data + * \param bufferCount Number of buffers available + * \param from IpAddress of the peer + * \param received Optional argument to get the number of bytes received + */ + bool UdpSocket::ReceiveMultiple(NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, std::size_t* received) + { + NazaraAssert(m_handle != SocketImpl::InvalidHandle, "Socket hasn't been created"); + NazaraAssert(buffers && bufferCount > 0, "Invalid buffer"); + + int read; + if (!SocketImpl::ReceiveMultiple(m_handle, buffers, bufferCount, from, &read, &m_lastError)) + { + switch (m_lastError) + { + case SocketError_ConnectionClosed: + m_lastError = SocketError_NoError; + read = 0; + break; + + default: + return false; + } + } + + if (received) + *received = read; + + return true; + } + /*! * \brief Receives the packet available * \return true If packet received diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index 32404f53a..6c82f0505 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -586,6 +586,72 @@ namespace Nz return true; } + bool SocketImpl::ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + NazaraAssert(buffers && bufferCount > 0, "Invalid buffers"); + + IpAddressImpl::SockAddrBuffer nameBuffer; + int bufferLength = static_cast(nameBuffer.size()); + + IpAddress senderIp; + + StackAllocation memory = NazaraStackAllocation(bufferCount * sizeof(WSABUF)); + WSABUF* winBuffers = static_cast(memory.GetPtr()); + for (std::size_t i = 0; i < bufferCount; ++i) + { + winBuffers[i].buf = static_cast(buffers[i].data); + winBuffers[i].len = static_cast(buffers[i].dataLength); + } + + DWORD flags = 0; + DWORD byteRead; + if (WSARecvFrom(handle, winBuffers, static_cast(bufferCount), &byteRead, &flags, reinterpret_cast(nameBuffer.data()), &bufferLength, nullptr, nullptr) == SOCKET_ERROR) + { + int errorCode = WSAGetLastError(); + switch (errorCode) + { + case WSAECONNRESET: + case WSAEWOULDBLOCK: + { + // If we have no data and are not blocking, return true with 0 byte read + byteRead = 0; + senderIp = IpAddress::Invalid; + break; + } + + default: + { + if (error) + *error = TranslateWSAErrorToSocketError(errorCode); + + return false; //< Error + } + } + } + else + senderIp = IpAddressImpl::FromSockAddr(reinterpret_cast(&nameBuffer)); + + if (flags & MSG_PARTIAL) + { + if (error) + *error = SocketError_DatagramSize; + + return false; + } + + if (from) + *from = senderIp; + + if (read) + *read = byteRead; + + if (error) + *error = SocketError_NoError; + + return true; + } + bool SocketImpl::Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error) { NazaraAssert(handle != InvalidHandle, "Invalid handle"); diff --git a/src/Nazara/Network/Win32/SocketImpl.hpp b/src/Nazara/Network/Win32/SocketImpl.hpp index edcc7ce09..864e629dd 100644 --- a/src/Nazara/Network/Win32/SocketImpl.hpp +++ b/src/Nazara/Network/Win32/SocketImpl.hpp @@ -64,6 +64,7 @@ namespace Nz static bool Receive(SocketHandle handle, void* buffer, int length, int* read, SocketError* error); static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error); + static bool ReceiveMultiple(SocketHandle handle, NetBuffer* buffers, std::size_t bufferCount, IpAddress* from, int* read, SocketError* error); static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error); static bool SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error); diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.cpp b/src/Nazara/Network/Win32/SocketPollerImpl.cpp index 292e8dfa5..6789f35f4 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.cpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.cpp @@ -10,29 +10,43 @@ namespace Nz SocketPollerImpl::SocketPollerImpl() { #if !NAZARA_NETWORK_POLL_SUPPORT - FD_ZERO(&m_activeSockets); - FD_ZERO(&m_sockets); + FD_ZERO(&m_readSockets); + FD_ZERO(&m_readyToReadSockets); + FD_ZERO(&m_readyToWriteSockets); + FD_ZERO(&m_writeSockets); #endif } void SocketPollerImpl::Clear() { #if NAZARA_NETWORK_POLL_SUPPORT - m_activeSockets.clear(); m_allSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); m_sockets.clear(); #else - FD_ZERO(&m_activeSockets); - FD_ZERO(&m_sockets); + FD_ZERO(&m_readSockets); + FD_ZERO(&m_readyToReadSockets); + FD_ZERO(&m_readyToWriteSockets); + FD_ZERO(&m_writeSockets); #endif } - bool SocketPollerImpl::IsReady(SocketHandle socket) const + bool SocketPollerImpl::IsReadyToRead(SocketHandle socket) const { #if NAZARA_NETWORK_POLL_SUPPORT - return m_activeSockets.count(socket) != 0; + return m_readyToReadSockets.count(socket) != 0; #else - return FD_ISSET(socket, &m_activeSockets) != 0; + return FD_ISSET(socket, &m_readyToReadSockets) != 0; + #endif + } + + bool SocketPollerImpl::IsReadyToWrite(SocketHandle socket) const + { + #if NAZARA_NETWORK_POLL_SUPPORT + return m_readyToWriteSockets.count(socket) != 0; + #else + return FD_ISSET(socket, &m_readyToWriteSockets) != 0; #endif } @@ -41,31 +55,45 @@ namespace Nz #if NAZARA_NETWORK_POLL_SUPPORT return m_allSockets.count(socket) != 0; #else - return FD_ISSET(socket, &m_sockets) != 0; + return FD_ISSET(socket, &m_readSockets) != 0 || + FD_ISSET(socket, &m_writeSockets) != 0; #endif } - bool SocketPollerImpl::RegisterSocket(SocketHandle socket) + bool SocketPollerImpl::RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags) { NazaraAssert(!IsRegistered(socket), "Socket is already registered"); #if NAZARA_NETWORK_POLL_SUPPORT PollSocket entry = { socket, - POLLRDNORM, + 0, 0 }; + if (eventFlags & SocketPollEvent_Read) + entry.events |= POLLRDNORM; + + if (eventFlags & SocketPollEvent_Write) + entry.events |= POLLWRNORM; + m_allSockets[socket] = m_sockets.size(); m_sockets.emplace_back(entry); #else - if (m_sockets.fd_count > FD_SETSIZE) + for (std::size_t i = 0; i < 2; ++i) { - NazaraError("Socket count exceeding FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")"); - return false; - } + if ((eventFlags & ((i == 0) ? SocketPollEvent_Read : SocketPollEvent_Write)) == 0) + continue; - FD_SET(socket, &m_sockets); + fd_set& targetSet = (i == 0) ? m_readSockets : m_writeSockets; + if (targetSet.fd_count > FD_SETSIZE) + { + NazaraError("Socket count exceeding hard-coded FD_SETSIZE (" + String::Number(FD_SETSIZE) + ")"); + return false; + } + + FD_SET(socket, &targetSet); + } #endif return true; @@ -88,50 +116,70 @@ namespace Nz // Now move it properly (lastElement is invalid after the following line) and pop it m_sockets[entry] = std::move(m_sockets.back()); } - m_sockets.pop_back(); - m_activeSockets.erase(socket); + m_allSockets.erase(socket); + m_readyToReadSockets.erase(socket); + m_readyToWriteSockets.erase(socket); #else - FD_CLR(socket, &m_activeSockets); - FD_CLR(socket, &m_sockets); + FD_CLR(socket, &m_readSockets); + FD_CLR(socket, &m_readyToReadSockets); + FD_CLR(socket, &m_readyToWriteSockets); + FD_CLR(socket, &m_writeSockets); #endif } - int SocketPollerImpl::Wait(UInt64 msTimeout, SocketError* error) + int SocketPollerImpl::Wait(int msTimeout, SocketError* error) { int activeSockets; #if NAZARA_NETWORK_POLL_SUPPORT - // Reset status of sockets - for (PollSocket& entry : m_sockets) - entry.revents = 0; - activeSockets = SocketImpl::Poll(m_sockets.data(), m_sockets.size(), static_cast(msTimeout), error); - m_activeSockets.clear(); + m_readyToReadSockets.clear(); + m_readyToWriteSockets.clear(); if (activeSockets > 0U) { int socketRemaining = activeSockets; for (PollSocket& entry : m_sockets) { - if (entry.revents & POLLRDNORM) + if (entry.revents != 0) { - m_activeSockets.insert(entry.fd); + if (entry.revents & POLLRDNORM) + m_readyToReadSockets.insert(entry.fd); + + if (entry.revents & POLLWRNORM) + m_readyToWriteSockets.insert(entry.fd); + + entry.revents = 0; + if (--socketRemaining == 0) break; } } } - #else - m_activeSockets = m_sockets; + #else + fd_set* readSet = nullptr; + fd_set* writeSet = nullptr; + + if (m_readSockets.fd_count > 0) + { + m_readyToReadSockets = m_readSockets; + readSet = &m_readyToReadSockets; + } + + if (m_writeSockets.fd_count > 0) + { + m_readyToWriteSockets = m_writeSockets; + readSet = &m_readyToWriteSockets; + } timeval tv; tv.tv_sec = static_cast(msTimeout / 1000ULL); tv.tv_usec = static_cast((msTimeout % 1000ULL) * 1000ULL); - activeSockets = ::select(0xDEADBEEF, &m_activeSockets, nullptr, nullptr, (msTimeout > 0) ? &tv : nullptr); //< The first argument is ignored on Windows + activeSockets = ::select(0xDEADBEEF, readSet, writeSet, nullptr, (msTimeout >= 0) ? &tv : nullptr); //< The first argument is ignored on Windows if (activeSockets == SOCKET_ERROR) { if (error) diff --git a/src/Nazara/Network/Win32/SocketPollerImpl.hpp b/src/Nazara/Network/Win32/SocketPollerImpl.hpp index 0a745878d..2dfb32070 100644 --- a/src/Nazara/Network/Win32/SocketPollerImpl.hpp +++ b/src/Nazara/Network/Win32/SocketPollerImpl.hpp @@ -25,24 +25,28 @@ namespace Nz void Clear(); - bool IsReady(SocketHandle socket) const; + bool IsReadyToRead(SocketHandle socket) const; + bool IsReadyToWrite(SocketHandle socket) const; bool IsRegistered(SocketHandle socket) const; - bool RegisterSocket(SocketHandle socket); + bool RegisterSocket(SocketHandle socket, SocketPollEventFlags eventFlags); void UnregisterSocket(SocketHandle socket); - int Wait(UInt64 msTimeout, SocketError* error); + int Wait(int msTimeout, SocketError* error); private: #if NAZARA_NETWORK_POLL_SUPPORT - std::unordered_set m_activeSockets; + std::unordered_set m_readyToReadSockets; + std::unordered_set m_readyToWriteSockets; std::unordered_map m_allSockets; std::vector m_sockets; #else - fd_set m_sockets; - fd_set m_activeSockets; + fd_set m_readSockets; + fd_set m_readyToReadSockets; + fd_set m_readyToWriteSockets; + fd_set m_writeSockets; #endif }; } -#endif // NAZARA_SOCKETPOLLERIMPL_HPP \ No newline at end of file +#endif // NAZARA_SOCKETPOLLERIMPL_HPP diff --git a/src/Nazara/Physics2D/Collider2D.cpp b/src/Nazara/Physics2D/Collider2D.cpp index 928ea3974..f92c405db 100644 --- a/src/Nazara/Physics2D/Collider2D.cpp +++ b/src/Nazara/Physics2D/Collider2D.cpp @@ -11,10 +11,27 @@ namespace Nz { Collider2D::~Collider2D() = default; + std::vector Collider2D::GenerateShapes(RigidBody2D* body) const + { + cpShapeFilter filter = cpShapeFilterNew(m_collisionGroup, m_categoryMask, m_collisionMask); + + std::vector shapes; + CreateShapes(body, shapes); + + for (cpShape* shape : shapes) + { + cpShapeSetFilter(shape, filter); + cpShapeSetCollisionType(shape, m_collisionId); + cpShapeSetSensor(shape, (m_trigger) ? cpTrue : cpFalse); + } + + return shapes; + } + /******************************** BoxCollider2D *********************************/ BoxCollider2D::BoxCollider2D(const Vector2f& size, float radius) : - BoxCollider2D(Rectf(-size.x / 2.f, -size.y / 2.f, size.x / 2.f, size.y / 2.f), radius) + BoxCollider2D(Rectf(-size.x / 2.f, -size.y / 2.f, size.x, size.y), radius) { } @@ -24,9 +41,9 @@ namespace Nz { } - float BoxCollider2D::ComputeInertialMatrix(float mass) const + float BoxCollider2D::ComputeMomentOfInertia(float mass) const { - return static_cast(cpMomentForBox2(mass, cpBBNew(m_rect.x, m_rect.y + m_rect.height, m_rect.x + m_rect.width, m_rect.y))); + return static_cast(cpMomentForBox2(mass, cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height))); } ColliderType2D BoxCollider2D::GetType() const @@ -34,12 +51,9 @@ namespace Nz return ColliderType2D_Box; } - std::vector BoxCollider2D::CreateShapes(RigidBody2D* body) const + void BoxCollider2D::CreateShapes(RigidBody2D* body, std::vector& shapes) const { - std::vector shapes; - shapes.push_back(cpBoxShapeNew2(body->GetHandle(), cpBBNew(m_rect.x, m_rect.y + m_rect.height, m_rect.x + m_rect.width, m_rect.y), m_radius)); - - return shapes; + shapes.push_back(cpBoxShapeNew2(body->GetHandle(), cpBBNew(m_rect.x, m_rect.y, m_rect.x + m_rect.width, m_rect.y + m_rect.height), m_radius)); } /******************************** CircleCollider2D *********************************/ @@ -50,7 +64,7 @@ namespace Nz { } - float CircleCollider2D::ComputeInertialMatrix(float mass) const + float CircleCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForCircle(mass, 0.f, m_radius, cpv(m_offset.x, m_offset.y))); } @@ -60,12 +74,66 @@ namespace Nz return ColliderType2D_Circle; } - std::vector CircleCollider2D::CreateShapes(RigidBody2D* body) const + void CircleCollider2D::CreateShapes(RigidBody2D* body, std::vector& shapes) const { - std::vector shapes; shapes.push_back(cpCircleShapeNew(body->GetHandle(), m_radius, cpv(m_offset.x, m_offset.y))); + } - return shapes; + /******************************** CompoundCollider2D *********************************/ + + CompoundCollider2D::CompoundCollider2D(std::vector geoms) : + m_geoms(std::move(geoms)) + { + } + + float CompoundCollider2D::ComputeMomentOfInertia(float mass) const + { + ///TODO: Correctly compute moment using parallel axis theorem: + /// https://chipmunk-physics.net/forum/viewtopic.php?t=1056 + float momentOfInertia = 0.f; + for (const auto& geom : m_geoms) + momentOfInertia += geom->ComputeMomentOfInertia(mass); //< Eeeer + + return momentOfInertia; + } + + ColliderType2D CompoundCollider2D::GetType() const + { + return ColliderType2D_Compound; + } + + void CompoundCollider2D::CreateShapes(RigidBody2D* body, std::vector& shapes) const + { + // Since C++ does not allow protected call from other objects, we have to be a friend of Collider2D, yay + for (const auto& geom : m_geoms) + geom->CreateShapes(body, shapes); + } + + /******************************** ConvexCollider2D *********************************/ + + ConvexCollider2D::ConvexCollider2D(SparsePtr vertices, std::size_t vertexCount, float radius) : + m_radius(radius) + { + m_vertices.resize(vertexCount); + for (std::size_t i = 0; i < vertexCount; ++i) + m_vertices[i].Set(*vertices++); + } + + float ConvexCollider2D::ComputeMomentOfInertia(float mass) const + { + static_assert(sizeof(cpVect) == sizeof(Vector2d), "Chipmunk vector is not equivalent to Vector2d"); + + return static_cast(cpMomentForPoly(mass, int(m_vertices.size()), reinterpret_cast(m_vertices.data()), cpv(0.0, 0.0), m_radius)); + } + + ColliderType2D ConvexCollider2D::GetType() const + { + return ColliderType2D_Convex; + } + + void ConvexCollider2D::CreateShapes(RigidBody2D* body, std::vector& shapes) const + { + shapes.push_back(cpPolyShapeNew(body->GetHandle(), int(m_vertices.size()), reinterpret_cast(m_vertices.data()), cpTransformIdentity, m_radius)); } /********************************* NullCollider2D **********************************/ @@ -75,19 +143,18 @@ namespace Nz return ColliderType2D_Null; } - float NullCollider2D::ComputeInertialMatrix(float /*mass*/) const + float NullCollider2D::ComputeMomentOfInertia(float /*mass*/) const { return 0.f; } - std::vector NullCollider2D::CreateShapes(RigidBody2D* /*body*/) const + void NullCollider2D::CreateShapes(RigidBody2D* /*body*/, std::vector& /*shapes*/) const { - return std::vector(); } /******************************** SegmentCollider2D *********************************/ - float SegmentCollider2D::ComputeInertialMatrix(float mass) const + float SegmentCollider2D::ComputeMomentOfInertia(float mass) const { return static_cast(cpMomentForSegment(mass, cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness)); } @@ -97,12 +164,8 @@ namespace Nz return ColliderType2D_Segment; } - std::vector SegmentCollider2D::CreateShapes(RigidBody2D* body) const + void SegmentCollider2D::CreateShapes(RigidBody2D* body, std::vector& shapes) const { - std::vector shapes; shapes.push_back(cpSegmentShapeNew(body->GetHandle(), cpv(m_first.x, m_first.y), cpv(m_second.x, m_second.y), m_thickness)); - - return shapes; } - } diff --git a/src/Nazara/Physics2D/PhysWorld2D.cpp b/src/Nazara/Physics2D/PhysWorld2D.cpp index 62d194e9b..997b53468 100644 --- a/src/Nazara/Physics2D/PhysWorld2D.cpp +++ b/src/Nazara/Physics2D/PhysWorld2D.cpp @@ -37,6 +37,128 @@ namespace Nz return m_stepSize; } + bool PhysWorld2D::NearestBodyQuery(const Vector2f & from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RigidBody2D** nearestBody) + { + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + + if (cpShape* shape = cpSpacePointQueryNearest(m_handle, {from.x, from.y}, maxDistance, filter, nullptr)) + { + if (nearestBody) + *nearestBody = static_cast(cpShapeGetUserData(shape)); + + return true; + } + else + return false; + } + + bool PhysWorld2D::NearestBodyQuery(const Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result) + { + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + + if (result) + { + cpPointQueryInfo queryInfo; + + if (cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, &queryInfo)) + { + result->closestPoint.Set(Nz::Vector2(queryInfo.point.x, queryInfo.point.y)); + result->distance = float(queryInfo.distance); + result->fraction.Set(Nz::Vector2(queryInfo.gradient.x, queryInfo.gradient.y)); + result->nearestBody = static_cast(cpShapeGetUserData(queryInfo.shape)); + + return true; + } + else + return false; + } + else + { + if (cpSpacePointQueryNearest(m_handle, { from.x, from.y }, maxDistance, filter, nullptr)) + return true; + else + return false; + } + } + + bool PhysWorld2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* hitInfos) + { + using ResultType = decltype(hitInfos); + + auto callback = [](cpShape* shape, cpVect point, cpVect normal, cpFloat alpha, void* data) + { + ResultType results = static_cast(data); + + RaycastHit hitInfo; + hitInfo.fraction = float(alpha); + hitInfo.hitNormal.Set(Nz::Vector2(normal.x, normal.y)); + hitInfo.hitPos.Set(Nz::Vector2(point.x, point.y)); + hitInfo.nearestBody = static_cast(cpShapeGetUserData(shape)); + + results->emplace_back(std::move(hitInfo)); + }; + + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + + std::size_t previousSize = hitInfos->size(); + cpSpaceSegmentQuery(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, callback, hitInfos); + + return hitInfos->size() != previousSize; + } + + bool PhysWorld2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo) + { + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + + if (hitInfo) + { + cpSegmentQueryInfo queryInfo; + + if (cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, &queryInfo)) + { + hitInfo->fraction = float(queryInfo.alpha); + hitInfo->hitNormal.Set(Nz::Vector2(queryInfo.normal.x, queryInfo.normal.y)); + hitInfo->hitPos.Set(Nz::Vector2(queryInfo.point.x, queryInfo.point.y)); + hitInfo->nearestBody = static_cast(cpShapeGetUserData(queryInfo.shape)); + + return true; + } + else + return false; + } + else + { + if (cpSpaceSegmentQueryFirst(m_handle, { from.x, from.y }, { to.x, to.y }, radius, filter, nullptr)) + return true; + else + return false; + } + } + + void PhysWorld2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector* bodies) + { + using ResultType = decltype(bodies); + + auto callback = [] (cpShape* shape, void* data) + { + ResultType results = static_cast(data); + results->push_back(static_cast(cpShapeGetUserData(shape))); + }; + + cpShapeFilter filter = cpShapeFilterNew(collisionGroup, categoryMask, collisionMask); + cpSpaceBBQuery(m_handle, cpBBNew(boundingBox.x, boundingBox.y, boundingBox.x + boundingBox.width, boundingBox.y + boundingBox.height), filter, callback, bodies); + } + + void PhysWorld2D::RegisterCallbacks(unsigned int collisionId, const Callback& callbacks) + { + InitCallbacks(cpSpaceAddWildcardHandler(m_handle, collisionId), callbacks); + } + + void PhysWorld2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, const Callback& callbacks) + { + InitCallbacks(cpSpaceAddCollisionHandler(m_handle, collisionIdA, collisionIdB), callbacks); + } + void PhysWorld2D::SetGravity(const Vector2f& gravity) { cpSpaceSetGravity(m_handle, cpv(gravity.x, gravity.y)); @@ -53,8 +175,155 @@ namespace Nz while (m_timestepAccumulator >= m_stepSize) { + OnPhysWorld2DPreStep(this); + cpSpaceStep(m_handle, m_stepSize); + + OnPhysWorld2DPostStep(this); + if (!m_rigidPostSteps.empty()) + { + for (const auto& pair : m_rigidPostSteps) + { + for (const auto& step : pair.second.funcs) + step(pair.first); + } + + m_rigidPostSteps.clear(); + } + m_timestepAccumulator -= m_stepSize; } } + + void PhysWorld2D::InitCallbacks(cpCollisionHandler* handler, const Callback& callbacks) + { + auto it = m_callbacks.emplace(handler, std::make_unique(callbacks)).first; + + handler->userData = it->second.get(); + + if (callbacks.startCallback) + { + handler->beginFunc = [](cpArbiter* arb, cpSpace* space, void *data) -> cpBool + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + if (customCallbacks->startCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata)) + { + cpBool retA = cpArbiterCallWildcardBeginA(arb, space); + cpBool retB = cpArbiterCallWildcardBeginB(arb, space); + return retA && retB; + } + else + return cpFalse; + }; + } + + if (callbacks.endCallback) + { + handler->separateFunc = [](cpArbiter* arb, cpSpace* space, void *data) + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + customCallbacks->endCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata); + + cpArbiterCallWildcardSeparateA(arb, space); + cpArbiterCallWildcardSeparateB(arb, space); + }; + } + + if (callbacks.preSolveCallback) + { + handler->preSolveFunc = [](cpArbiter* arb, cpSpace* space, void *data) -> cpBool + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + if (customCallbacks->preSolveCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata)) + { + cpBool retA = cpArbiterCallWildcardPreSolveA(arb, space); + cpBool retB = cpArbiterCallWildcardPreSolveB(arb, space); + return retA && retB; + } + else + return cpFalse; + }; + } + + if (callbacks.postSolveCallback) + { + handler->postSolveFunc = [](cpArbiter* arb, cpSpace* space, void *data) + { + cpBody* firstBody; + cpBody* secondBody; + cpArbiterGetBodies(arb, &firstBody, &secondBody); + + PhysWorld2D* world = static_cast(cpSpaceGetUserData(space)); + RigidBody2D* firstRigidBody = static_cast(cpBodyGetUserData(firstBody)); + RigidBody2D* secondRigidBody = static_cast(cpBodyGetUserData(secondBody)); + + const Callback* customCallbacks = static_cast(data); + customCallbacks->postSolveCallback(*world, *firstRigidBody, *secondRigidBody, customCallbacks->userdata); + + cpArbiterCallWildcardPostSolveA(arb, space); + cpArbiterCallWildcardPostSolveB(arb, space); + }; + } + } + + void PhysWorld2D::OnRigidBodyMoved(RigidBody2D* oldPointer, RigidBody2D* newPointer) + { + auto it = m_rigidPostSteps.find(oldPointer); + if (it == m_rigidPostSteps.end()) + return; //< Shouldn't happen + + m_rigidPostSteps.emplace(std::make_pair(newPointer, std::move(it->second))); + m_rigidPostSteps.erase(oldPointer); + } + + void PhysWorld2D::OnRigidBodyRelease(RigidBody2D* rigidBody) + { + m_rigidPostSteps.erase(rigidBody); + } + + void PhysWorld2D::RegisterPostStep(RigidBody2D* rigidBody, PostStep&& func) + { + // If space isn't locked, no need to wait + if (!cpSpaceIsLocked(m_handle)) + { + func(rigidBody); + return; + } + + auto it = m_rigidPostSteps.find(rigidBody); + if (it == m_rigidPostSteps.end()) + { + PostStepContainer postStep; + postStep.onMovedSlot.Connect(rigidBody->OnRigidBody2DMove, this, &PhysWorld2D::OnRigidBodyMoved); + postStep.onReleaseSlot.Connect(rigidBody->OnRigidBody2DRelease, this, &PhysWorld2D::OnRigidBodyRelease); + + it = m_rigidPostSteps.insert(std::make_pair(rigidBody, std::move(postStep))).first; + } + + it->second.funcs.emplace_back(std::move(func)); + } } diff --git a/src/Nazara/Physics2D/RigidBody2D.cpp b/src/Nazara/Physics2D/RigidBody2D.cpp index 9078749b3..292d9ee14 100644 --- a/src/Nazara/Physics2D/RigidBody2D.cpp +++ b/src/Nazara/Physics2D/RigidBody2D.cpp @@ -20,6 +20,7 @@ namespace Nz RigidBody2D::RigidBody2D(PhysWorld2D* world, float mass, Collider2DRef geom) : m_geom(), + m_userData(nullptr), m_world(world), m_gravityFactor(1.f), m_mass(1.f) @@ -34,6 +35,7 @@ namespace Nz RigidBody2D::RigidBody2D(const RigidBody2D& object) : m_geom(object.m_geom), + m_userData(object.m_userData), m_world(object.m_world), m_gravityFactor(object.m_gravityFactor), m_mass(0.f) @@ -43,23 +45,54 @@ namespace Nz Create(); + cpBodySetMass(m_handle, cpBodyGetMass(object.GetHandle())); + cpBodySetMoment(m_handle, cpBodyGetMoment(object.GetHandle())); + SetGeom(object.GetGeom()); SetMass(object.GetMass()); + + cpBodySetForce(m_handle, cpBodyGetForce(object.GetHandle())); + cpBodySetTorque(m_handle, cpBodyGetTorque(object.GetHandle())); + + cpBodySetAngle(m_handle, cpBodyGetAngle(object.GetHandle())); + cpBodySetAngularVelocity(m_handle, cpBodyGetAngularVelocity(object.GetHandle())); + cpBodySetCenterOfGravity(m_handle, cpBodyGetCenterOfGravity(object.GetHandle())); + cpBodySetPosition(m_handle, cpBodyGetPosition(object.GetHandle())); + cpBodySetVelocity(m_handle, cpBodyGetVelocity(object.GetHandle())); + + for (int i = 0; i != m_shapes.size(); ++i) + m_shapes[i]->bb = cpShapeCacheBB(object.m_shapes[i]); + + cpBodySetMass(m_handle, cpBodyGetMass(object.GetHandle())); + cpBodySetMoment(m_handle, cpBodyGetMoment(object.GetHandle())); + + m_handle->m = object.GetHandle()->m; } RigidBody2D::RigidBody2D(RigidBody2D&& object) : + OnRigidBody2DMove(std::move(object.OnRigidBody2DMove)), + OnRigidBody2DRelease(std::move(object.OnRigidBody2DRelease)), m_shapes(std::move(object.m_shapes)), m_geom(std::move(object.m_geom)), + m_userData(object.m_userData), m_handle(object.m_handle), m_world(object.m_world), m_gravityFactor(object.m_gravityFactor), m_mass(object.m_mass) { + cpBodySetUserData(m_handle, this); + for (cpShape* shape : m_shapes) + cpShapeSetUserData(shape, this); + object.m_handle = nullptr; + + OnRigidBody2DMove(&object, this); } RigidBody2D::~RigidBody2D() { + OnRigidBody2DRelease(this); + Destroy(); } @@ -80,25 +113,48 @@ namespace Nz cpBodyApplyForceAtLocalPoint(m_handle, cpv(force.x, force.y), cpv(point.x, point.y)); break; } +} + + void RigidBody2D::AddImpulse(const Vector2f& impulse, CoordSys coordSys) + { + return AddImpulse(impulse, GetCenterOfGravity(coordSys), coordSys); + } + + void RigidBody2D::AddImpulse(const Vector2f& impulse, const Vector2f& point, CoordSys coordSys) + { + switch (coordSys) + { + case CoordSys_Global: + cpBodyApplyImpulseAtWorldPoint(m_handle, cpv(impulse.x, impulse.y), cpv(point.x, point.y)); + break; + + case CoordSys_Local: + cpBodyApplyImpulseAtLocalPoint(m_handle, cpv(impulse.x, impulse.y), cpv(point.x, point.y)); + break; + } } void RigidBody2D::AddTorque(float torque) { - cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + torque); + cpBodySetTorque(m_handle, cpBodyGetTorque(m_handle) + ToRadians(torque)); } Rectf RigidBody2D::GetAABB() const { - cpBB bb = cpBBNew(0.f, 0.f, 0.f, 0.f); - for (cpShape* shape : m_shapes) - bb = cpBBMerge(bb, cpShapeGetBB(shape)); + if (m_shapes.empty()) + return Rectf::Zero(); - return Rectf(Rect(bb.l, bb.t, bb.r - bb.l, bb.b - bb.t)); + auto it = m_shapes.begin(); + cpBB bb = cpShapeGetBB(*it++); + for (; it != m_shapes.end(); ++it) + bb = cpBBMerge(bb, cpShapeGetBB(*it)); + + return Rectf(Rect(bb.l, bb.b, bb.r - bb.l, bb.t - bb.b)); } float RigidBody2D::GetAngularVelocity() const { - return static_cast(cpBodyGetAngularVelocity(m_handle)); + return FromRadians(static_cast(cpBodyGetAngularVelocity(m_handle))); } const Collider2DRef& RigidBody2D::GetGeom() const @@ -141,7 +197,12 @@ namespace Nz float RigidBody2D::GetRotation() const { - return static_cast(cpBodyGetAngle(m_handle)); + return FromRadians(static_cast(cpBodyGetAngle(m_handle))); + } + + void* RigidBody2D::GetUserdata() const + { + return m_userData; } Vector2f RigidBody2D::GetVelocity() const @@ -150,6 +211,11 @@ namespace Nz return Vector2f(static_cast(vel.x), static_cast(vel.y)); } + PhysWorld2D* RigidBody2D::GetWorld() const + { + return m_world; + } + bool RigidBody2D::IsMoveable() const { return m_mass > 0.f; @@ -162,7 +228,7 @@ namespace Nz void RigidBody2D::SetAngularVelocity(float angularVelocity) { - cpBodySetAngularVelocity(m_handle, angularVelocity); + cpBodySetAngularVelocity(m_handle, ToRadians(angularVelocity)); } void RigidBody2D::SetGeom(Collider2DRef geom) @@ -171,18 +237,11 @@ namespace Nz // So let's save some attributes of the body, destroy it and rebuild it if (m_geom) { - cpVect pos = cpBodyGetPosition(m_handle); cpFloat mass = cpBodyGetMass(m_handle); cpFloat moment = cpBodyGetMoment(m_handle); - cpFloat rot = cpBodyGetAngle(m_handle); - cpVect vel = cpBodyGetVelocity(m_handle); Destroy(); - Create(mass, moment); - - cpBodySetAngle(m_handle, rot); - cpBodySetPosition(m_handle, pos); - cpBodySetVelocity(m_handle, vel); + Create(static_cast(mass), static_cast(moment)); } if (geom) @@ -190,13 +249,16 @@ namespace Nz else m_geom = NullCollider2D::New(); - m_shapes = m_geom->CreateShapes(this); + m_shapes = m_geom->GenerateShapes(this); cpSpace* space = m_world->GetHandle(); for (cpShape* shape : m_shapes) + { + cpShapeSetUserData(shape, this); cpSpaceAddShape(space, shape); + } - cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass)); + cpBodySetMoment(m_handle, m_geom->ComputeMomentOfInertia(m_mass)); } void RigidBody2D::SetMass(float mass) @@ -205,20 +267,26 @@ namespace Nz { if (mass > 0.f) { - cpBodySetMass(m_handle, mass); - cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass)); + m_world->RegisterPostStep(this, [mass](Nz::RigidBody2D* body) + { + cpBodySetMass(body->GetHandle(), mass); + cpBodySetMoment(body->GetHandle(), body->GetGeom()->ComputeMomentOfInertia(mass)); + }); } else - cpBodySetType(m_handle, CP_BODY_TYPE_STATIC); + m_world->RegisterPostStep(this, [](Nz::RigidBody2D* body) { cpBodySetType(body->GetHandle(), CP_BODY_TYPE_STATIC); } ); } else if (mass > 0.f) { - if (cpBodyGetType(m_handle) == CP_BODY_TYPE_STATIC) + m_world->RegisterPostStep(this, [mass](Nz::RigidBody2D* body) { - cpBodySetType(m_handle, CP_BODY_TYPE_DYNAMIC); - cpBodySetMass(m_handle, mass); - cpBodySetMoment(m_handle, m_geom->ComputeInertialMatrix(m_mass)); - } + if (cpBodyGetType(body->GetHandle()) == CP_BODY_TYPE_STATIC) + { + cpBodySetType(body->GetHandle(), CP_BODY_TYPE_DYNAMIC); + cpBodySetMass(body->GetHandle(), mass); + cpBodySetMoment(body->GetHandle(), body->GetGeom()->ComputeMomentOfInertia(mass)); + } + }); } m_mass = mass; @@ -230,6 +298,14 @@ namespace Nz cpBodySetCenterOfGravity(m_handle, cpv(center.x, center.y)); } + void RigidBody2D::SetMomentOfInertia(float moment) + { + m_world->RegisterPostStep(this, [moment] (Nz::RigidBody2D* body) + { + cpBodySetMoment(body->GetHandle(), moment); + }); + } + void RigidBody2D::SetPosition(const Vector2f& position) { cpBodySetPosition(m_handle, cpv(position.x, position.y)); @@ -239,7 +315,12 @@ namespace Nz void RigidBody2D::SetRotation(float rotation) { - cpBodySetAngle(m_handle, rotation); + cpBodySetAngle(m_handle, ToRadians(rotation)); + } + + void RigidBody2D::SetUserdata(void* ud) + { + m_userData = ud; } void RigidBody2D::SetVelocity(const Vector2f& velocity) @@ -257,15 +338,25 @@ namespace Nz { Destroy(); + OnRigidBody2DMove = std::move(object.OnRigidBody2DMove); + OnRigidBody2DRelease = std::move(object.OnRigidBody2DRelease); + m_handle = object.m_handle; m_geom = std::move(object.m_geom); m_gravityFactor = object.m_gravityFactor; m_mass = object.m_mass; m_shapes = std::move(object.m_shapes); + m_userData = object.m_userData; m_world = object.m_world; + cpBodySetUserData(m_handle, this); + for (cpShape* shape : m_shapes) + cpShapeSetUserData(shape, this); + object.m_handle = nullptr; + OnRigidBody2DMove(&object, this); + return *this; } @@ -273,6 +364,7 @@ namespace Nz { m_handle = cpBodyNew(mass, moment); cpBodySetUserData(m_handle, this); + cpSpaceAddBody(m_world->GetHandle(), m_handle); } @@ -290,5 +382,6 @@ namespace Nz cpSpaceRemoveBody(space, m_handle); cpBodyFree(m_handle); } + m_shapes.clear(); } } diff --git a/src/Nazara/Physics3D/Collider3D.cpp b/src/Nazara/Physics3D/Collider3D.cpp index d71f4caa8..857ec4ba8 100644 --- a/src/Nazara/Physics3D/Collider3D.cpp +++ b/src/Nazara/Physics3D/Collider3D.cpp @@ -128,12 +128,12 @@ namespace Nz std::size_t primitiveCount = list.GetSize(); if (primitiveCount > 1) { - std::vector geoms(primitiveCount); + std::vector geoms(primitiveCount); for (unsigned int i = 0; i < primitiveCount; ++i) geoms[i] = CreateGeomFromPrimitive(list.GetPrimitive(i)); - return CompoundCollider3D::New(&geoms[0], primitiveCount); + return CompoundCollider3D::New(std::move(geoms)); } else if (primitiveCount > 0) return CreateGeomFromPrimitive(list.GetPrimitive(0)); @@ -239,11 +239,9 @@ namespace Nz /******************************* CompoundCollider3D ********************************/ - CompoundCollider3D::CompoundCollider3D(Collider3D** geoms, std::size_t geomCount) + CompoundCollider3D::CompoundCollider3D(std::vector geoms) : + m_geoms(std::move(geoms)) { - m_geoms.reserve(geomCount); - for (std::size_t i = 0; i < geomCount; ++i) - m_geoms.emplace_back(geoms[i]); } const std::vector& CompoundCollider3D::GetGeoms() const diff --git a/src/Nazara/Physics3D/RigidBody3D.cpp b/src/Nazara/Physics3D/RigidBody3D.cpp index 9a909f98f..3d697aa8c 100644 --- a/src/Nazara/Physics3D/RigidBody3D.cpp +++ b/src/Nazara/Physics3D/RigidBody3D.cpp @@ -204,6 +204,11 @@ namespace Nz return velocity; } + PhysWorld3D* RigidBody3D::GetWorld() const + { + return m_world; + } + bool RigidBody3D::IsAutoSleepEnabled() const { return NewtonBodyGetAutoSleep(m_body) != 0; @@ -314,7 +319,7 @@ namespace Nz NazaraUnused(userData); NewtonBodySetSleepState(body, 0); return 1; - }, + }, nullptr); } } diff --git a/src/Nazara/Utility/Cursor.cpp b/src/Nazara/Platform/Cursor.cpp similarity index 86% rename from src/Nazara/Utility/Cursor.cpp rename to src/Nazara/Platform/Cursor.cpp index e8b3e0b21..7d68a460b 100644 --- a/src/Nazara/Utility/Cursor.cpp +++ b/src/Nazara/Platform/Cursor.cpp @@ -1,18 +1,18 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_X11) - #include + #include #else #error Lack of implementation: Cursor #endif -#include +#include namespace Nz { diff --git a/src/Nazara/Platform/Debug/NewOverload.cpp b/src/Nazara/Platform/Debug/NewOverload.cpp new file mode 100644 index 000000000..c5522beb8 --- /dev/null +++ b/src/Nazara/Platform/Debug/NewOverload.cpp @@ -0,0 +1,31 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#if NAZARA_PLATFORM_MANAGE_MEMORY + +#include +#include // Needed ? + +void* operator new(std::size_t size) +{ + return Nz::MemoryManager::Allocate(size, false); +} + +void* operator new[](std::size_t size) +{ + return Nz::MemoryManager::Allocate(size, true); +} + +void operator delete(void* pointer) noexcept +{ + Nz::MemoryManager::Free(pointer, false); +} + +void operator delete[](void* pointer) noexcept +{ + Nz::MemoryManager::Free(pointer, true); +} + +#endif // NAZARA_PLATFORM_MANAGE_MEMORY diff --git a/src/Nazara/Utility/Icon.cpp b/src/Nazara/Platform/Icon.cpp similarity index 73% rename from src/Nazara/Utility/Icon.cpp rename to src/Nazara/Platform/Icon.cpp index 843e64456..010e9dfc2 100644 --- a/src/Nazara/Utility/Icon.cpp +++ b/src/Nazara/Platform/Icon.cpp @@ -1,18 +1,18 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_X11) - #include + #include #else #error Lack of implementation: Icon #endif -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Keyboard.cpp b/src/Nazara/Platform/Keyboard.cpp similarity index 64% rename from src/Nazara/Utility/Keyboard.cpp rename to src/Nazara/Platform/Keyboard.cpp index 08f4b05a7..be1341eb6 100644 --- a/src/Nazara/Utility/Keyboard.cpp +++ b/src/Nazara/Platform/Keyboard.cpp @@ -1,18 +1,18 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_X11) - #include + #include #else #error Lack of implementation: Keyboard #endif -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Mouse.cpp b/src/Nazara/Platform/Mouse.cpp similarity index 82% rename from src/Nazara/Utility/Mouse.cpp rename to src/Nazara/Platform/Mouse.cpp index b25ce2506..6d589697e 100644 --- a/src/Nazara/Utility/Mouse.cpp +++ b/src/Nazara/Platform/Mouse.cpp @@ -1,19 +1,19 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include -#include +#include +#include #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_X11) - #include + #include #else #error Lack of implementation: Mouse #endif -#include +#include namespace Nz { diff --git a/src/Nazara/Platform/Platform.cpp b/src/Nazara/Platform/Platform.cpp new file mode 100644 index 000000000..5151ed123 --- /dev/null +++ b/src/Nazara/Platform/Platform.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Platform module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \ingroup system + * \class Nz::Platform + * \brief Platform class that represents the module initializer of Platform + */ + + /*! + * \brief Initializes the Platform module + * \return true if initialization is successful + * + * \remark Produces a NazaraNotice + * \remark Produces a NazaraError if one submodule failed + */ + + bool Platform::Initialize() + { + if (s_moduleReferenceCounter > 0) + { + s_moduleReferenceCounter++; + return true; // Already initialized + } + + // Initialize module dependencies + if (!Utility::Initialize()) + { + NazaraError("Failed to initialize utility module"); + return false; + } + + s_moduleReferenceCounter++; + + // Initialisation of the module + CallOnExit onExit(Platform::Uninitialize); + + if (!Window::Initialize()) + { + NazaraError("Failed to initialize window's system"); + return false; + } + + // Must be initialized after Window + if (!Cursor::Initialize()) + { + NazaraError("Failed to initialize cursors"); + return false; + } + + onExit.Reset(); + + NazaraNotice("Initialized: Platform module"); + return true; + } + + /*! + * \brief Checks whether the module is initialized + * \return true if module is initialized + */ + + bool Platform::IsInitialized() + { + return s_moduleReferenceCounter != 0; + } + + /*! + * \brief Uninitializes the Platform module + * + * \remark Produces a NazaraNotice + */ + + void Platform::Uninitialize() + { + if (s_moduleReferenceCounter != 1) + { + // The module is still in use, or can not be uninitialized + if (s_moduleReferenceCounter > 1) + s_moduleReferenceCounter--; + + return; + } + + // Free of module + s_moduleReferenceCounter = 0; + + Cursor::Uninitialize(); //< Must be done before Window + Window::Uninitialize(); + + NazaraNotice("Uninitialized: Platform module"); + + // Free of dependances + Utility::Uninitialize(); + } + + unsigned int Platform::s_moduleReferenceCounter = 0; +} diff --git a/src/Nazara/Utility/VideoMode.cpp b/src/Nazara/Platform/VideoMode.cpp similarity index 90% rename from src/Nazara/Utility/VideoMode.cpp rename to src/Nazara/Platform/VideoMode.cpp index 7d1f3beec..5cc78d981 100644 --- a/src/Nazara/Utility/VideoMode.cpp +++ b/src/Nazara/Platform/VideoMode.cpp @@ -1,20 +1,20 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_X11) - #include + #include #else #error Lack of implementation: Window #endif -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/VideoModeImpl.hpp b/src/Nazara/Platform/VideoModeImpl.hpp similarity index 86% rename from src/Nazara/Utility/VideoModeImpl.hpp rename to src/Nazara/Platform/VideoModeImpl.hpp index e5c5c0118..b5be4b3b1 100644 --- a/src/Nazara/Utility/VideoModeImpl.hpp +++ b/src/Nazara/Platform/VideoModeImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once diff --git a/src/Nazara/Utility/Win32/CursorImpl.cpp b/src/Nazara/Platform/Win32/CursorImpl.cpp similarity index 94% rename from src/Nazara/Utility/Win32/CursorImpl.cpp rename to src/Nazara/Platform/Win32/CursorImpl.cpp index c2fff0a40..399320c59 100644 --- a/src/Nazara/Utility/Win32/CursorImpl.cpp +++ b/src/Nazara/Platform/Win32/CursorImpl.cpp @@ -1,12 +1,12 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Win32/CursorImpl.hpp b/src/Nazara/Platform/Win32/CursorImpl.hpp similarity index 88% rename from src/Nazara/Utility/Win32/CursorImpl.hpp rename to src/Nazara/Platform/Win32/CursorImpl.hpp index a8f82377c..ad0324d79 100644 --- a/src/Nazara/Utility/Win32/CursorImpl.hpp +++ b/src/Nazara/Platform/Win32/CursorImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,7 +8,7 @@ #define NAZARA_CURSORIMPL_HPP #include -#include +#include #include #include diff --git a/src/Nazara/Utility/Win32/IconImpl.cpp b/src/Nazara/Platform/Win32/IconImpl.cpp similarity index 89% rename from src/Nazara/Utility/Win32/IconImpl.cpp rename to src/Nazara/Platform/Win32/IconImpl.cpp index 19e7fffb0..14a67cfba 100644 --- a/src/Nazara/Utility/Win32/IconImpl.cpp +++ b/src/Nazara/Platform/Win32/IconImpl.cpp @@ -1,11 +1,11 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Win32/IconImpl.hpp b/src/Nazara/Platform/Win32/IconImpl.hpp similarity index 88% rename from src/Nazara/Utility/Win32/IconImpl.hpp rename to src/Nazara/Platform/Win32/IconImpl.hpp index 7ba9acc7a..48644198c 100644 --- a/src/Nazara/Utility/Win32/IconImpl.hpp +++ b/src/Nazara/Platform/Win32/IconImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once diff --git a/src/Nazara/Utility/Win32/InputImpl.cpp b/src/Nazara/Platform/Win32/InputImpl.cpp similarity index 97% rename from src/Nazara/Utility/Win32/InputImpl.cpp rename to src/Nazara/Platform/Win32/InputImpl.cpp index e250ae8be..f44594fa4 100644 --- a/src/Nazara/Utility/Win32/InputImpl.cpp +++ b/src/Nazara/Platform/Win32/InputImpl.cpp @@ -1,12 +1,12 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include +#include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Win32/InputImpl.hpp b/src/Nazara/Platform/Win32/InputImpl.hpp similarity index 83% rename from src/Nazara/Utility/Win32/InputImpl.hpp rename to src/Nazara/Platform/Win32/InputImpl.hpp index e91bfd889..fc5e226a5 100644 --- a/src/Nazara/Utility/Win32/InputImpl.hpp +++ b/src/Nazara/Platform/Win32/InputImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -9,8 +9,8 @@ #include #include -#include -#include +#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Win32/VideoModeImpl.cpp b/src/Nazara/Platform/Win32/VideoModeImpl.cpp similarity index 83% rename from src/Nazara/Utility/Win32/VideoModeImpl.cpp rename to src/Nazara/Platform/Win32/VideoModeImpl.cpp index 95a964790..6102a568e 100644 --- a/src/Nazara/Utility/Win32/VideoModeImpl.cpp +++ b/src/Nazara/Platform/Win32/VideoModeImpl.cpp @@ -1,12 +1,12 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include -#include +#include +#include #include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Win32/VideoModeImpl.hpp b/src/Nazara/Platform/Win32/VideoModeImpl.hpp similarity index 79% rename from src/Nazara/Utility/Win32/VideoModeImpl.hpp rename to src/Nazara/Platform/Win32/VideoModeImpl.hpp index 460cec364..39579b9a2 100644 --- a/src/Nazara/Utility/Win32/VideoModeImpl.hpp +++ b/src/Nazara/Platform/Win32/VideoModeImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -7,7 +7,7 @@ #ifndef NAZARA_VIDEOMODEIMPL_HPP #define NAZARA_VIDEOMODEIMPL_HPP -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Platform/Win32/WindowImpl.cpp similarity index 98% rename from src/Nazara/Utility/Win32/WindowImpl.cpp rename to src/Nazara/Platform/Win32/WindowImpl.cpp index c9e94876e..e2278bebb 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Platform/Win32/WindowImpl.cpp @@ -1,24 +1,24 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp // Un grand merci à Laurent Gomila pour la SFML qui m'aura bien aidé à réaliser cette implémentation -#include +#include #include #include #include #include -#include -#include +#include +#include +#include +#include +#include #include -#include -#include -#include #include #include #include -#include +#include #ifdef _WIN64 #define GCL_HCURSOR GCLP_HCURSOR @@ -907,7 +907,7 @@ namespace Nz } } - #if NAZARA_UTILITY_WINDOWS_DISABLE_MENU_KEYS + #if NAZARA_PLATFORM_WINDOWS_DISABLE_MENU_KEYS // http://msdn.microsoft.com/en-us/library/windows/desktop/ms646360(v=vs.85).aspx if (message == WM_SYSCOMMAND && wParam == SC_KEYMENU) return true; diff --git a/src/Nazara/Utility/Win32/WindowImpl.hpp b/src/Nazara/Platform/Win32/WindowImpl.hpp similarity index 92% rename from src/Nazara/Utility/Win32/WindowImpl.hpp rename to src/Nazara/Platform/Win32/WindowImpl.hpp index 83056f825..1cdaff70e 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.hpp +++ b/src/Nazara/Platform/Win32/WindowImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp // Interface inspirée de la SFML par Laurent Gomila @@ -14,11 +14,11 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include namespace Nz diff --git a/src/Nazara/Utility/Window.cpp b/src/Nazara/Platform/Window.cpp similarity index 88% rename from src/Nazara/Utility/Window.cpp rename to src/Nazara/Platform/Window.cpp index 3130c6641..126149105 100644 --- a/src/Nazara/Utility/Window.cpp +++ b/src/Nazara/Platform/Window.cpp @@ -1,26 +1,26 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include #include -#include +#include +#include #include -#include #include #if defined(NAZARA_PLATFORM_WINDOWS) - #include + #include #elif defined(NAZARA_PLATFORM_X11) - #include + #include #else #error Lack of implementation: Window #endif -#include +#include namespace Nz { @@ -50,7 +50,7 @@ namespace Nz bool Window::Create(VideoMode mode, const String& title, WindowStyleFlags style) { - // Si la fenêtre est déjà ouverte, nous conservons sa position + // If the window is already open, we keep its position bool opened = IsOpen(); Vector2i position; if (opened) @@ -58,7 +58,7 @@ namespace Nz Destroy(); - // Inspiré du code de la SFML par Laurent Gomila + // Inspired by the code of the SFML by Laurent Gomila (and its team) if (style & WindowStyle_Fullscreen) { if (fullscreenWindow) @@ -101,7 +101,7 @@ namespace Nz return false; } - // Paramètres par défaut + // Default parameters m_impl->EnableKeyRepeat(true); m_impl->EnableSmoothScrolling(false); m_impl->SetMaximumSize(-1, -1); @@ -169,7 +169,7 @@ namespace Nz void Window::EnableKeyRepeat(bool enable) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -182,7 +182,7 @@ namespace Nz void Window::EnableSmoothScrolling(bool enable) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -195,7 +195,7 @@ namespace Nz WindowHandle Window::GetHandle() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -208,7 +208,7 @@ namespace Nz unsigned int Window::GetHeight() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -221,7 +221,7 @@ namespace Nz Vector2i Window::GetPosition() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -234,7 +234,7 @@ namespace Nz Vector2ui Window::GetSize() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -247,7 +247,7 @@ namespace Nz WindowStyleFlags Window::GetStyle() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -260,7 +260,7 @@ namespace Nz String Window::GetTitle() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -273,7 +273,7 @@ namespace Nz unsigned int Window::GetWidth() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -286,7 +286,7 @@ namespace Nz bool Window::HasFocus() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -299,7 +299,7 @@ namespace Nz bool Window::IsMinimized() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -312,7 +312,7 @@ namespace Nz bool Window::IsVisible() const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -325,7 +325,7 @@ namespace Nz bool Window::PollEvent(WindowEvent* event) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -378,7 +378,7 @@ namespace Nz void Window::SetEventListener(bool listener) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -397,7 +397,7 @@ namespace Nz void Window::SetFocus() { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -419,7 +419,7 @@ namespace Nz void Window::SetMaximumSize(const Vector2i& maxSize) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -432,7 +432,7 @@ namespace Nz void Window::SetMaximumSize(int width, int height) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -445,7 +445,7 @@ namespace Nz void Window::SetMinimumSize(const Vector2i& minSize) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -458,7 +458,7 @@ namespace Nz void Window::SetMinimumSize(int width, int height) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -471,7 +471,7 @@ namespace Nz void Window::SetPosition(const Vector2i& position) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -484,7 +484,7 @@ namespace Nz void Window::SetPosition(int x, int y) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -497,7 +497,7 @@ namespace Nz void Window::SetSize(const Vector2i& size) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -510,7 +510,7 @@ namespace Nz void Window::SetSize(unsigned int width, unsigned int height) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -523,7 +523,7 @@ namespace Nz void Window::SetStayOnTop(bool stayOnTop) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -536,7 +536,7 @@ namespace Nz void Window::SetTitle(const String& title) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -549,7 +549,7 @@ namespace Nz void Window::SetVisible(bool visible) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -562,7 +562,7 @@ namespace Nz bool Window::WaitEvent(WindowEvent* event) { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); @@ -626,7 +626,7 @@ namespace Nz void Window::IgnoreNextMouseEvent(int mouseX, int mouseY) const { - #if NAZARA_UTILITY_SAFE + #if NAZARA_PLATFORM_SAFE if (!m_impl) { NazaraError("Window not created"); diff --git a/src/Nazara/Utility/X11/CursorImpl.cpp b/src/Nazara/Platform/X11/CursorImpl.cpp similarity index 77% rename from src/Nazara/Utility/X11/CursorImpl.cpp rename to src/Nazara/Platform/X11/CursorImpl.cpp index 2925b2b6d..148be7b6b 100644 --- a/src/Nazara/Utility/X11/CursorImpl.cpp +++ b/src/Nazara/Platform/X11/CursorImpl.cpp @@ -1,13 +1,13 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include #include -#include +#include #include // Some older versions of xcb/util-renderutil (notably the one available on Travis CI) use `template` as an argument name @@ -20,7 +20,7 @@ extern "C" } #undef template -#include +#include namespace Nz { @@ -164,8 +164,19 @@ namespace Nz ScopedXCBConnection connection; xcb_screen_t* screen = X11::XCBDefaultScreen(connection); - if (xcb_cursor_context_new(connection, screen, &m_cursorContext) >= 0) - m_cursor = xcb_cursor_load_cursor(m_cursorContext, s_systemCursorIds[cursor]); + const char* cursorName = s_systemCursorIds[cursor]; + if (cursorName) + { + if (xcb_cursor_context_new(connection, screen, &m_cursorContext) >= 0) + m_cursor = xcb_cursor_load_cursor(m_cursorContext, cursorName); + else + { + NazaraError("Failed to create cursor context"); + return false; + } + } + else + m_cursor = s_hiddenCursor; return true; } @@ -232,25 +243,27 @@ namespace Nz std::array CursorImpl::s_systemCursorIds = { - // http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6 - "crosshair", // SystemCursor_Crosshair - "left_ptr", // SystemCursor_Default - "hand", // SystemCursor_Hand - "help", // SystemCursor_Help - "fleur", // SystemCursor_Move - nullptr, // SystemCursor_None - "hand", // SystemCursor_Pointer - "watch", // SystemCursor_Progress - "right_side", // SystemCursor_ResizeE - "top_side", // SystemCursor_ResizeN - "top_right_corner", // SystemCursor_ResizeNE - "top_left_corner", // SystemCursor_ResizeNW - "bottom_side", // SystemCursor_ResizeS - "bottom_right_corner", // SystemCursor_ResizeSE - "bottom_left_corner", // SystemCursor_ResizeSW - "left_side", // SystemCursor_ResizeW - "xterm", // SystemCursor_Text - "watch" // SystemCursor_Wait + { + // http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6 + "crosshair", // SystemCursor_Crosshair + "left_ptr", // SystemCursor_Default + "hand", // SystemCursor_Hand + "help", // SystemCursor_Help + "fleur", // SystemCursor_Move + nullptr, // SystemCursor_None + "hand", // SystemCursor_Pointer + "watch", // SystemCursor_Progress + "right_side", // SystemCursor_ResizeE + "top_side", // SystemCursor_ResizeN + "top_right_corner", // SystemCursor_ResizeNE + "top_left_corner", // SystemCursor_ResizeNW + "bottom_side", // SystemCursor_ResizeS + "bottom_right_corner", // SystemCursor_ResizeSE + "bottom_left_corner", // SystemCursor_ResizeSW + "left_side", // SystemCursor_ResizeW + "xterm", // SystemCursor_Text + "watch" // SystemCursor_Wait + } }; static_assert(SystemCursor_Max + 1 == 18, "System cursor array is incomplete"); diff --git a/src/Nazara/Utility/X11/CursorImpl.hpp b/src/Nazara/Platform/X11/CursorImpl.hpp similarity index 89% rename from src/Nazara/Utility/X11/CursorImpl.hpp rename to src/Nazara/Platform/X11/CursorImpl.hpp index 4041b81ed..85b0bf4ef 100644 --- a/src/Nazara/Utility/X11/CursorImpl.hpp +++ b/src/Nazara/Platform/X11/CursorImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,7 +8,7 @@ #define NAZARA_CURSORIMPL_HPP #include -#include +#include #include #include diff --git a/src/Nazara/Utility/X11/Display.cpp b/src/Nazara/Platform/X11/Display.cpp similarity index 96% rename from src/Nazara/Utility/X11/Display.cpp rename to src/Nazara/Platform/X11/Display.cpp index 8a9ff719c..9a3390512 100644 --- a/src/Nazara/Utility/X11/Display.cpp +++ b/src/Nazara/Platform/X11/Display.cpp @@ -1,14 +1,14 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include #include #include -#include +#include namespace Nz { @@ -229,14 +229,14 @@ namespace Nz return screen_nbr; } - xcb_screen_t* X11::XCBScreenOfDisplay(xcb_connection_t* connection, int screen_nbr) + xcb_screen_t* X11::XCBScreenOfDisplay(xcb_connection_t* connection, int screenIndex) { NazaraAssert(connection == sharedConnection, "The model is meant for one connection to X11 server"); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); - for (; iter.rem; --screen_nbr, xcb_screen_next (&iter)) + for (; iter.rem; --screenIndex, xcb_screen_next (&iter)) { - if (screen_nbr == 0) + if (screenIndex == 0) return iter.data; } diff --git a/src/Nazara/Utility/X11/Display.hpp b/src/Nazara/Platform/X11/Display.hpp similarity index 88% rename from src/Nazara/Utility/X11/Display.hpp rename to src/Nazara/Platform/X11/Display.hpp index 88f80f2ee..bb7037a62 100644 --- a/src/Nazara/Utility/X11/Display.hpp +++ b/src/Nazara/Platform/X11/Display.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,8 +8,8 @@ #define NAZARA_X11DISPLAY_HPP #include -#include -#include +#include +#include typedef struct _XCBKeySymbols xcb_key_symbols_t; @@ -17,7 +17,7 @@ namespace Nz { class String; - class NAZARA_UTILITY_API X11 + class NAZARA_PLATFORM_API X11 { public: X11() = delete; diff --git a/src/Nazara/Utility/X11/IconImpl.cpp b/src/Nazara/Platform/X11/IconImpl.cpp similarity index 93% rename from src/Nazara/Utility/X11/IconImpl.cpp rename to src/Nazara/Platform/X11/IconImpl.cpp index 030cbdf8b..d36a5b8f8 100644 --- a/src/Nazara/Utility/X11/IconImpl.cpp +++ b/src/Nazara/Platform/X11/IconImpl.cpp @@ -1,14 +1,14 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include #include #include #include -#include -#include +#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/IconImpl.hpp b/src/Nazara/Platform/X11/IconImpl.hpp similarity index 82% rename from src/Nazara/Utility/X11/IconImpl.hpp rename to src/Nazara/Platform/X11/IconImpl.hpp index 1e8b301bc..e72faa26a 100644 --- a/src/Nazara/Utility/X11/IconImpl.hpp +++ b/src/Nazara/Platform/X11/IconImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,7 +8,7 @@ #define NAZARA_ICONIMPL_HPP #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/InputImpl.cpp b/src/Nazara/Platform/X11/InputImpl.cpp similarity index 98% rename from src/Nazara/Utility/X11/InputImpl.cpp rename to src/Nazara/Platform/X11/InputImpl.cpp index 7083100db..1b07754bc 100644 --- a/src/Nazara/Utility/X11/InputImpl.cpp +++ b/src/Nazara/Platform/X11/InputImpl.cpp @@ -1,16 +1,16 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include -#include +#include +#include #include #include #include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/InputImpl.hpp b/src/Nazara/Platform/X11/InputImpl.hpp similarity index 84% rename from src/Nazara/Utility/X11/InputImpl.hpp rename to src/Nazara/Platform/X11/InputImpl.hpp index 608585b1e..b6c30df0a 100644 --- a/src/Nazara/Utility/X11/InputImpl.hpp +++ b/src/Nazara/Platform/X11/InputImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -10,8 +10,8 @@ #include #include #include -#include -#include +#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/ScopedXCB.cpp b/src/Nazara/Platform/X11/ScopedXCB.cpp similarity index 95% rename from src/Nazara/Utility/X11/ScopedXCB.cpp rename to src/Nazara/Platform/X11/ScopedXCB.cpp index 49bd76b26..9911fa760 100644 --- a/src/Nazara/Utility/X11/ScopedXCB.cpp +++ b/src/Nazara/Platform/X11/ScopedXCB.cpp @@ -1,12 +1,12 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include +#include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/ScopedXCB.hpp b/src/Nazara/Platform/X11/ScopedXCB.hpp similarity index 94% rename from src/Nazara/Utility/X11/ScopedXCB.hpp rename to src/Nazara/Platform/X11/ScopedXCB.hpp index 452379bc4..1881ac1be 100644 --- a/src/Nazara/Utility/X11/ScopedXCB.hpp +++ b/src/Nazara/Platform/X11/ScopedXCB.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -95,6 +95,6 @@ namespace Nz }; } -#include +#include #endif // NAZARA_SCOPEDXCB_HPP diff --git a/src/Nazara/Utility/X11/ScopedXCB.inl b/src/Nazara/Platform/X11/ScopedXCB.inl similarity index 83% rename from src/Nazara/Utility/X11/ScopedXCB.inl rename to src/Nazara/Platform/X11/ScopedXCB.inl index d9881b9af..22f099970 100644 --- a/src/Nazara/Utility/X11/ScopedXCB.inl +++ b/src/Nazara/Platform/X11/ScopedXCB.inl @@ -1,9 +1,9 @@ // Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #include -#include +#include namespace Nz { @@ -44,4 +44,4 @@ namespace Nz } } -#include +#include diff --git a/src/Nazara/Utility/X11/VideoModeImpl.cpp b/src/Nazara/Platform/X11/VideoModeImpl.cpp similarity index 95% rename from src/Nazara/Utility/X11/VideoModeImpl.cpp rename to src/Nazara/Platform/X11/VideoModeImpl.cpp index e0b9a5ce7..1fa2ffd10 100644 --- a/src/Nazara/Utility/X11/VideoModeImpl.cpp +++ b/src/Nazara/Platform/X11/VideoModeImpl.cpp @@ -1,14 +1,14 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include #include -#include -#include +#include +#include #include #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/VideoModeImpl.hpp b/src/Nazara/Platform/X11/VideoModeImpl.hpp similarity index 80% rename from src/Nazara/Utility/X11/VideoModeImpl.hpp rename to src/Nazara/Platform/X11/VideoModeImpl.hpp index 2e63e8a09..fd502b828 100644 --- a/src/Nazara/Utility/X11/VideoModeImpl.hpp +++ b/src/Nazara/Platform/X11/VideoModeImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once @@ -8,7 +8,7 @@ #define NAZARA_VIDEOMODEIMPL_HPP #include -#include +#include namespace Nz { diff --git a/src/Nazara/Utility/X11/WindowImpl.cpp b/src/Nazara/Platform/X11/WindowImpl.cpp similarity index 98% rename from src/Nazara/Utility/X11/WindowImpl.cpp rename to src/Nazara/Platform/X11/WindowImpl.cpp index d0cf3da59..432bb9da0 100644 --- a/src/Nazara/Utility/X11/WindowImpl.cpp +++ b/src/Nazara/Platform/X11/WindowImpl.cpp @@ -1,26 +1,26 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp // Un grand merci à Laurent Gomila pour la SFML qui m'aura bien aidé à réaliser cette implémentation -#include +#include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include -#include +#include /* Things to do left: @@ -58,7 +58,6 @@ namespace Nz m_style(0), m_parent(parent), m_smoothScrolling(false), - m_scrolling(0), m_mousePos(0, 0), m_keyRepeat(true) { @@ -1134,7 +1133,6 @@ namespace Nz // if (std::isprint(codePoint)) Is not working ? + handle combining ? { - WindowEvent event; event.type = Nz::WindowEventType_TextEntered; event.text.character = codePoint; event.text.repeated = false; @@ -1396,7 +1394,7 @@ namespace Nz hints.functions |= MWM_FUNC_CLOSE; } - ScopedXCB error(xcb_request_check( + ScopedXCB propertyError(xcb_request_check( connection, xcb_change_property_checked( connection, @@ -1410,7 +1408,7 @@ namespace Nz ) )); - if (error) + if (propertyError) NazaraError("xcb_change_property failed, could not set window hints"); } else diff --git a/src/Nazara/Utility/X11/WindowImpl.hpp b/src/Nazara/Platform/X11/WindowImpl.hpp similarity index 93% rename from src/Nazara/Utility/X11/WindowImpl.hpp rename to src/Nazara/Platform/X11/WindowImpl.hpp index 8ce44f178..7330b21af 100644 --- a/src/Nazara/Utility/X11/WindowImpl.hpp +++ b/src/Nazara/Platform/X11/WindowImpl.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2015 Jérôme Leclercq -// This file is part of the "Nazara Engine - Utility module" +// This file is part of the "Nazara Engine - Platform module" // For conditions of distribution and use, see copyright notice in Config.hpp // Interface inspirée de la SFML par Laurent Gomila @@ -12,9 +12,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -111,7 +111,6 @@ namespace Nz bool m_ownsWindow; bool m_smoothScrolling; bool m_threadActive; - short m_scrolling; Vector2i m_mousePos; bool m_keyRepeat; diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index acc57006e..7fbad6002 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -121,9 +121,7 @@ namespace Nz break; default: - // Peut être rajouté par une extension - ss << "Unknown"; - break; + return; //< Block NVidia buffer usage hint for now } ss << '\n'; diff --git a/src/Nazara/Renderer/ContextParameters.cpp b/src/Nazara/Renderer/ContextParameters.cpp index cdb087561..1af405b2e 100644 --- a/src/Nazara/Renderer/ContextParameters.cpp +++ b/src/Nazara/Renderer/ContextParameters.cpp @@ -8,28 +8,28 @@ namespace Nz { - // Version majeure d'OpenGL, initialisé par OpenGL::Initialize() + // Major version of OpenGL, initialised by OpenGL::Initialize() UInt8 ContextParameters::defaultMajorVersion; - // Version majeure d'OpenGL, initialisé par OpenGL::Initialize() + // Minor version of OpenGL, initialised by OpenGL::Initialize() UInt8 ContextParameters::defaultMinorVersion; - // Contexte de partage par défaut, initialisé par OpenGL::Initialize() + // Context of default sharing, initialised by OpenGL::Initialize() const Context* ContextParameters::defaultShareContext = nullptr; - // Si possible, garder la compatibilité avec les fonctionnalités dépréciées + // If it's possible, keep the compatibility with deprecated functionalities bool ContextParameters::defaultCompatibilityProfile = false; - // Mode debug d'OpenGL par défaut + // Default debug mode of OpenGL #if NAZARA_RENDERER_OPENGL_DEBUG || defined(NAZARA_DEBUG) bool ContextParameters::defaultDebugMode = true; #else bool ContextParameters::defaultDebugMode = false; #endif - // Active le double-buffering sur les contextes + // Enables double-buffering on contexts Active le double-buffering sur les contextes bool ContextParameters::defaultDoubleBuffered = false; - // Active le partage des ressources entre contextes (Via le defaultShareContext) + // Enables ressource sharing on contexts (via defaultShareContext) bool ContextParameters::defaultShared = true; } diff --git a/src/Nazara/Renderer/HardwareBuffer.cpp b/src/Nazara/Renderer/HardwareBuffer.cpp index 52bc339c2..f8378abf3 100644 --- a/src/Nazara/Renderer/HardwareBuffer.cpp +++ b/src/Nazara/Renderer/HardwareBuffer.cpp @@ -50,7 +50,8 @@ namespace Nz UInt32 totalSize = m_parent->GetSize(); - bool forceDiscard = (size == totalSize); + //bool forceDiscard = (size == totalSize); + bool forceDiscard = true; OpenGL::BindBuffer(m_type, m_buffer); diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index 455247952..dad2e0de9 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -10,7 +10,7 @@ #include #include #if defined(NAZARA_PLATFORM_GLX) -#include +#include #endif // NAZARA_PLATFORM_GLX #include #include diff --git a/src/Nazara/Renderer/RenderTexture.cpp b/src/Nazara/Renderer/RenderTexture.cpp index aa32dd447..8ae1a4bb1 100644 --- a/src/Nazara/Renderer/RenderTexture.cpp +++ b/src/Nazara/Renderer/RenderTexture.cpp @@ -36,7 +36,7 @@ namespace Nz unsigned int width; }; - unsigned int attachmentIndex[AttachmentPoint_Max+1] = + unsigned int s_attachmentIndex[AttachmentPoint_Max+1] = { 3, // AttachmentPoint_Color 0, // AttachmentPoint_Depth @@ -117,7 +117,7 @@ namespace Nz return false; } - unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil]; + unsigned int depthStencilIndex = s_attachmentIndex[AttachmentPoint_DepthStencil]; if (m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed) { if (attachmentPoint == AttachmentPoint_Depth) @@ -154,7 +154,7 @@ namespace Nz Unlock(); - unsigned int attachIndex = attachmentIndex[attachmentPoint] + index; + unsigned int attachIndex = s_attachmentIndex[attachmentPoint] + index; if (attachIndex >= m_impl->attachments.size()) m_impl->attachments.resize(attachIndex+1); @@ -223,7 +223,7 @@ namespace Nz return false; } - unsigned int depthStencilIndex = attachmentIndex[AttachmentPoint_DepthStencil]; + unsigned int depthStencilIndex = s_attachmentIndex[AttachmentPoint_DepthStencil]; if (attachmentPoint == AttachmentPoint_Depth && m_impl->attachments.size() > depthStencilIndex && m_impl->attachments[depthStencilIndex].isUsed) { @@ -288,7 +288,7 @@ namespace Nz Unlock(); - unsigned int attachIndex = attachmentIndex[attachmentPoint] + index; + unsigned int attachIndex = s_attachmentIndex[attachmentPoint] + index; if (attachIndex >= m_impl->attachments.size()) m_impl->attachments.resize(attachIndex+1); @@ -394,7 +394,7 @@ namespace Nz } #endif - unsigned int attachIndex = attachmentIndex[attachmentPoint] + index; + unsigned int attachIndex = s_attachmentIndex[attachmentPoint] + index; if (attachIndex >= m_impl->attachments.size()) return; @@ -575,7 +575,7 @@ namespace Nz #if NAZARA_RENDERER_SAFE for (unsigned int i = 0; i < targetCount; ++i) { - unsigned int index = attachmentIndex[AttachmentPoint_Color] + targets[i]; + unsigned int index = s_attachmentIndex[AttachmentPoint_Color] + targets[i]; if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed) { NazaraError("Target " + String::Number(targets[i]) + " not attached"); @@ -598,7 +598,7 @@ namespace Nz #if NAZARA_RENDERER_SAFE for (UInt8 target : targets) { - unsigned int index = attachmentIndex[AttachmentPoint_Color] + target; + unsigned int index = s_attachmentIndex[AttachmentPoint_Color] + target; if (index >= m_impl->attachments.size() || !m_impl->attachments[index].isUsed) { NazaraError("Target " + String::Number(target) + " not attached"); @@ -752,7 +752,7 @@ namespace Nz for (UInt8 index : m_impl->colorTargets) { - Attachment& attachment = m_impl->attachments[attachmentIndex[AttachmentPoint_Color] + index]; + Attachment& attachment = m_impl->attachments[s_attachmentIndex[AttachmentPoint_Color] + index]; if (!attachment.isBuffer) attachment.texture->InvalidateMipmaps(); } @@ -833,7 +833,7 @@ namespace Nz m_impl->colorTargets.clear(); unsigned int colorIndex = 0; - for (unsigned int index = attachmentIndex[AttachmentPoint_Color]; index < m_impl->attachments.size(); ++index) + for (unsigned int index = s_attachmentIndex[AttachmentPoint_Color]; index < m_impl->attachments.size(); ++index) m_impl->colorTargets.push_back(colorIndex++); } diff --git a/src/Nazara/Renderer/Renderer.cpp b/src/Nazara/Renderer/Renderer.cpp index 72bbfdaaa..13c6f2f69 100644 --- a/src/Nazara/Renderer/Renderer.cpp +++ b/src/Nazara/Renderer/Renderer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -573,9 +574,9 @@ namespace Nz } // Initialisation des dépendances - if (!Utility::Initialize()) + if (!Platform::Initialize()) { - NazaraError("Failed to initialize Utility module"); + NazaraError("Failed to initialize Platform module"); return false; } @@ -1374,7 +1375,7 @@ namespace Nz NazaraNotice("Uninitialized: Renderer module"); // Libération des dépendances - Utility::Uninitialize(); + Platform::Uninitialize(); } void Renderer::EnableInstancing(bool instancing) diff --git a/src/Nazara/Renderer/TextureSampler.cpp b/src/Nazara/Renderer/TextureSampler.cpp index ec3b25dd7..4f1f9233f 100644 --- a/src/Nazara/Renderer/TextureSampler.cpp +++ b/src/Nazara/Renderer/TextureSampler.cpp @@ -129,7 +129,7 @@ namespace Nz if (s_useAnisotropicFilter) { - for (const std::pair& pair : s_samplers) + for (const std::pair& pair : s_samplers) { if (((pair.first >> 5) & 0xFF) == 0) glSamplerParameterf(pair.second, GL_TEXTURE_MAX_ANISOTROPY_EXT, static_cast(anisotropyLevel)); @@ -149,7 +149,7 @@ namespace Nz s_defaultFilterMode = filterMode; - for (const std::pair& pair : s_samplers) + for (const std::pair& pair : s_samplers) { if (((pair.first >> 1) & 0x3) == SamplerFilter_Default) { @@ -204,7 +204,7 @@ namespace Nz s_defaultWrapMode = wrapMode; GLenum wrapEnum = OpenGL::SamplerWrapMode[wrapMode]; - for (const std::pair& pair : s_samplers) + for (const std::pair& pair : s_samplers) { if (((pair.first >> 3) & 0x3) == SamplerWrap_Default) { @@ -380,7 +380,7 @@ namespace Nz if (!s_samplers.empty()) { Context::EnsureContext(); - for (const std::pair& pair : s_samplers) + for (const std::pair& pair : s_samplers) OpenGL::DeleteSampler(pair.second); s_samplers.clear(); diff --git a/src/Nazara/Renderer/UberShaderPreprocessor.cpp b/src/Nazara/Renderer/UberShaderPreprocessor.cpp index 6f838d6cf..b6d524645 100644 --- a/src/Nazara/Renderer/UberShaderPreprocessor.cpp +++ b/src/Nazara/Renderer/UberShaderPreprocessor.cpp @@ -93,7 +93,7 @@ namespace Nz } catch (const std::exception&) { - ErrorFlags errFlags(ErrorFlag_ThrowExceptionDisabled); + ErrorFlags errFlags2(ErrorFlag_ThrowExceptionDisabled); NazaraError("Shader code failed to compile (" + stage.GetLog() + ")\n" + code.ToString()); throw; diff --git a/src/Nazara/Utility/Formats/MD2Loader.cpp b/src/Nazara/Utility/Formats/MD2Loader.cpp index 76ee1c1ea..9008a22ad 100644 --- a/src/Nazara/Utility/Formats/MD2Loader.cpp +++ b/src/Nazara/Utility/Formats/MD2Loader.cpp @@ -219,13 +219,16 @@ namespace Nz Nz::Matrix4f matrix = Matrix4f::Transform(translate, rotationQuat, scale); matrix *= parameters.matrix; + Nz::Matrix4f normalMatrix = Matrix4f::Rotate(rotationQuat); + normalMatrix *= parameters.matrix; + for (unsigned int v = 0; v < header.num_vertices; ++v) { const MD2_Vertex& vert = vertices[v]; Vector3f position = matrix * Vector3f(vert.x, vert.y, vert.z); vertex->position = position; - vertex->normal = rotationQuat * md2Normals[vert.n]; + vertex->normal = normalMatrix.Transform(md2Normals[vert.n], 0.f); vertex++; } diff --git a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp index 0168e4ffe..5284d1d2c 100644 --- a/src/Nazara/Utility/Formats/MD5MeshLoader.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshLoader.cpp @@ -91,8 +91,8 @@ namespace Nz bool largeIndices = (vertexCount > std::numeric_limits::max()); - IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.storage, 0); + IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, 0); + VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent_Skinning), UInt32(vertexCount), parameters.storage, 0); // Index buffer IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); @@ -236,7 +236,7 @@ namespace Nz // Index buffer bool largeIndices = (vertexCount > std::numeric_limits::max()); - IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, indexCount, parameters.storage, 0); + IndexBufferRef indexBuffer = IndexBuffer::New(largeIndices, UInt32(indexCount), parameters.storage, 0); IndexMapper indexMapper(indexBuffer, BufferAccess_DiscardAndWrite); IndexIterator index = indexMapper.begin(); @@ -251,7 +251,7 @@ namespace Nz indexMapper.Unmap(); // Vertex buffer - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0); + VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, 0); BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); MeshVertex* vertices = static_cast(vertexMapper.GetPointer()); diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index 951892085..b9573b5d5 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -124,8 +124,8 @@ namespace Nz // Some default settings data.SetParameter(MaterialData::Blending, true); data.SetParameter(MaterialData::DepthWrite, true); - data.SetParameter(MaterialData::DstBlend, static_cast(BlendFunc_InvSrcAlpha)); - data.SetParameter(MaterialData::SrcBlend, static_cast(BlendFunc_SrcAlpha)); + data.SetParameter(MaterialData::DstBlend, static_cast(BlendFunc_InvSrcAlpha)); + data.SetParameter(MaterialData::SrcBlend, static_cast(BlendFunc_SrcAlpha)); } it = materialCache.emplace(matName, std::move(data)).first; @@ -139,7 +139,7 @@ namespace Nz bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) { - int reservedVertexCount; + long long reservedVertexCount; if (!parameters.custom.GetIntegerParameter("NativeOBJLoader_VertexCount", &reservedVertexCount)) reservedVertexCount = 100; @@ -233,8 +233,8 @@ namespace Nz } // Création des buffers - IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), indices.size(), parameters.storage, 0); - VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), vertexCount, parameters.storage, 0); + IndexBufferRef indexBuffer = IndexBuffer::New(vertexCount > std::numeric_limits::max(), UInt32(indices.size()), parameters.storage, 0); + VertexBufferRef vertexBuffer = VertexBuffer::New(VertexDeclaration::Get(VertexLayout_XYZ_Normal_UV_Tangent), UInt32(vertexCount), parameters.storage, 0); // Remplissage des indices IndexMapper indexMapper(indexBuffer, BufferAccess_WriteOnly); @@ -244,6 +244,12 @@ namespace Nz indexMapper.Unmap(); // Pour laisser les autres tâches affecter l'index buffer // Remplissage des vertices + + // Make sure the normal matrix won't rescale our normals + Nz::Matrix4f normalMatrix = parameters.matrix; + if (normalMatrix.HasScale()) + normalMatrix.ApplyScale(1.f / normalMatrix.GetScale()); + bool hasNormals = true; bool hasTexCoords = true; BufferMapper vertexMapper(vertexBuffer, BufferAccess_WriteOnly); @@ -259,7 +265,7 @@ namespace Nz vertex.position = Vector3f(parameters.matrix * vec); if (vertexIndices.normal > 0) - vertex.normal = normals[vertexIndices.normal-1]; + vertex.normal = normalMatrix.Transform(normals[vertexIndices.normal - 1], 0.f); else hasNormals = false; diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index ab1cbdbfb..f85251f57 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -228,7 +228,7 @@ namespace Nz if (p < 0) { - p += m_positions.size() - 1; + p += static_cast(m_positions.size() - 1); if (p < 0) { Error("Vertex index out of range (" + String::Number(p) + " < 0"); @@ -239,7 +239,7 @@ namespace Nz if (n < 0) { - n += m_normals.size() - 1; + n += static_cast(m_normals.size() - 1); if (n < 0) { Error("Normal index out of range (" + String::Number(n) + " < 0"); @@ -250,7 +250,7 @@ namespace Nz if (t < 0) { - t += m_texCoords.size() - 1; + t += static_cast(m_texCoords.size() - 1); if (t < 0) { Error("Texture coordinates index out of range (" + String::Number(t) + " < 0"); diff --git a/src/Nazara/Utility/Formats/OBJSaver.cpp b/src/Nazara/Utility/Formats/OBJSaver.cpp index 513f28ff7..7b3507730 100644 --- a/src/Nazara/Utility/Formats/OBJSaver.cpp +++ b/src/Nazara/Utility/Formats/OBJSaver.cpp @@ -128,7 +128,7 @@ namespace Nz else { Color colorVal; - float fValue; + double dValue; if (matData.GetColorParameter(MaterialData::AmbientColor, &colorVal)) material->ambient = colorVal; @@ -139,8 +139,8 @@ namespace Nz if (matData.GetColorParameter(MaterialData::SpecularColor, &colorVal)) material->specular = colorVal; - if (matData.GetFloatParameter(MaterialData::Shininess, &fValue)) - material->shininess = fValue; + if (matData.GetDoubleParameter(MaterialData::Shininess, &dValue)) + material->shininess = float(dValue); if (matData.GetStringParameter(MaterialData::AlphaTexturePath, &strVal)) material->alphaMap = strVal; @@ -176,7 +176,7 @@ namespace Nz UInt32 faceIndex = 0; TriangleIterator triangle(staticMesh); - do + do { OBJParser::Face& face = meshes[i].faces[faceIndex]; face.firstVertex = faceIndex * 3; diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index bdfe57007..15d9133fe 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -835,7 +835,6 @@ namespace Nz if (!PixelFormat::IsCompressed(m_sharedImage->format)) { const PixelFormatInfo& info = PixelFormat::GetInfo(m_sharedImage->format); - const UInt8* pixel = GetConstPixels(); Bitset<> workingBitset; std::size_t pixelCount = m_sharedImage->width * m_sharedImage->height * ((m_sharedImage->type == ImageType_Cubemap) ? 6 : m_sharedImage->depth); diff --git a/src/Nazara/Utility/IndexBuffer.cpp b/src/Nazara/Utility/IndexBuffer.cpp index ed49535cd..306fffb7f 100644 --- a/src/Nazara/Utility/IndexBuffer.cpp +++ b/src/Nazara/Utility/IndexBuffer.cpp @@ -35,10 +35,10 @@ namespace Nz IndexBuffer::IndexBuffer(const IndexBuffer& indexBuffer) : RefCounted(), m_buffer(indexBuffer.m_buffer), - m_largeIndices(indexBuffer.m_largeIndices), m_endOffset(indexBuffer.m_endOffset), m_indexCount(indexBuffer.m_indexCount), - m_startOffset(indexBuffer.m_startOffset) + m_startOffset(indexBuffer.m_startOffset), + m_largeIndices(indexBuffer.m_largeIndices) { } diff --git a/src/Nazara/Utility/IndexMapper.cpp b/src/Nazara/Utility/IndexMapper.cpp index 7ddcd9a08..78fdd36a0 100644 --- a/src/Nazara/Utility/IndexMapper.cpp +++ b/src/Nazara/Utility/IndexMapper.cpp @@ -12,38 +12,38 @@ namespace Nz { namespace { - UInt32 GetterSequential(const void* buffer, unsigned int i) + UInt32 GetterSequential(const void* buffer, std::size_t i) { NazaraUnused(buffer); - return i; + return static_cast(i); } - UInt32 Getter16(const void* buffer, unsigned int i) + UInt32 Getter16(const void* buffer, std::size_t i) { const UInt16* ptr = static_cast(buffer); return ptr[i]; } - UInt32 Getter32(const void* buffer, unsigned int i) + UInt32 Getter32(const void* buffer, std::size_t i) { const UInt32* ptr = static_cast(buffer); return ptr[i]; } - void Setter16(void* buffer, unsigned int i, UInt32 value) + void Setter16(void* buffer, std::size_t i, UInt32 value) { UInt16* ptr = static_cast(buffer); ptr[i] = static_cast(value); } - void Setter32(void* buffer, unsigned int i, UInt32 value) + void Setter32(void* buffer, std::size_t i, UInt32 value) { UInt32* ptr = static_cast(buffer); ptr[i] = value; } - void SetterError(void*, unsigned int, UInt32) + void SetterError(void*, std::size_t, UInt32) { NazaraError("Index buffer opened with read-only access"); } @@ -113,15 +113,9 @@ namespace Nz { } - UInt32 IndexMapper::Get(unsigned int i) const + UInt32 IndexMapper::Get(std::size_t i) const { - #if NAZARA_UTILITY_SAFE - if (i >= m_indexCount) - { - NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')'); - return 0; - } - #endif + NazaraAssert(i < m_indexCount, "Index out of range"); return m_getter(m_mapper.GetPointer(), i); } @@ -131,20 +125,14 @@ namespace Nz return m_mapper.GetBuffer(); } - unsigned int IndexMapper::GetIndexCount() const + std::size_t IndexMapper::GetIndexCount() const { return m_indexCount; } - void IndexMapper::Set(unsigned int i, UInt32 value) + void IndexMapper::Set(std::size_t i, UInt32 value) { - #if NAZARA_UTILITY_SAFE - if (i >= m_indexCount) - { - NazaraError("Index out of range (" + String::Number(i) + " >= " + String::Number(m_indexCount) + ')'); - return; - } - #endif + NazaraAssert(i < m_indexCount, "Index out of range"); m_setter(m_mapper.GetPointer(), i, value); } diff --git a/src/Nazara/Utility/Mesh.cpp b/src/Nazara/Utility/Mesh.cpp index 27c1bd186..b6985714e 100644 --- a/src/Nazara/Utility/Mesh.cpp +++ b/src/Nazara/Utility/Mesh.cpp @@ -79,7 +79,7 @@ namespace Nz NazaraAssert(subMesh, "Invalid submesh"); NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type"); - m_impl->subMeshes.push_back(subMesh); + m_impl->subMeshes.emplace_back(subMesh); InvalidateAABB(); } @@ -92,10 +92,10 @@ namespace Nz NazaraAssert(subMesh, "Invalid submesh"); NazaraAssert(subMesh->GetAnimationType() == m_impl->animationType, "Submesh animation type doesn't match mesh animation type"); - UInt32 index = m_impl->subMeshes.size(); + std::size_t index = m_impl->subMeshes.size(); - m_impl->subMeshes.push_back(subMesh); - m_impl->subMeshMap[identifier] = index; + m_impl->subMeshes.emplace_back(subMesh); + m_impl->subMeshMap[identifier] = static_cast(index); InvalidateAABB(); } @@ -349,11 +349,11 @@ namespace Nz if (!m_impl->aabbUpdated) { - UInt32 subMeshCount = m_impl->subMeshes.size(); + std::size_t subMeshCount = m_impl->subMeshes.size(); if (subMeshCount > 0) { m_impl->aabb.Set(m_impl->subMeshes[0]->GetAABB()); - for (UInt32 i = 1; i < subMeshCount; ++i) + for (std::size_t i = 1; i < subMeshCount; ++i) m_impl->aabb.ExtendTo(m_impl->subMeshes[i]->GetAABB()); } else @@ -407,7 +407,7 @@ namespace Nz { NazaraAssert(m_impl, "Mesh should be created first"); - return m_impl->materialData.size(); + return static_cast(m_impl->materialData.size()); } Skeleton* Mesh::GetSkeleton() @@ -466,7 +466,7 @@ namespace Nz { NazaraAssert(m_impl, "Mesh should be created first"); - return m_impl->subMeshes.size(); + return static_cast(m_impl->subMeshes.size()); } UInt32 Mesh::GetSubMeshIndex(const String& identifier) const diff --git a/src/Nazara/Utility/PixelFormat.cpp b/src/Nazara/Utility/PixelFormat.cpp index 8bfe461e3..f27f6bd00 100644 --- a/src/Nazara/Utility/PixelFormat.cpp +++ b/src/Nazara/Utility/PixelFormat.cpp @@ -1268,6 +1268,102 @@ namespace Nz } } + bool PixelFormat::Flip(PixelFlipping flipping, PixelFormatType format, unsigned int width, unsigned int height, unsigned int depth, const void* src, void* dst) + { + #if NAZARA_UTILITY_SAFE + if (!IsValid(format)) + { + NazaraError("Invalid pixel format"); + return false; + } + #endif + + auto it = s_flipFunctions[flipping].find(format); + if (it != s_flipFunctions[flipping].end()) + it->second(width, height, depth, reinterpret_cast(src), reinterpret_cast(dst)); + else + { + // Flipping générique + + #if NAZARA_UTILITY_SAFE + if (IsCompressed(format)) + { + NazaraError("No function to flip compressed format"); + return false; + } + #endif + + UInt8 bpp = GetBytesPerPixel(format); + unsigned int lineStride = width*bpp; + switch (flipping) + { + case PixelFlipping_Horizontally: + { + if (src == dst) + { + for (unsigned int z = 0; z < depth; ++z) + { + UInt8* ptr = reinterpret_cast(dst) + width*height*z; + for (unsigned int y = 0; y < height / 2; ++y) + std::swap_ranges(&ptr[y*lineStride], &ptr[(y + 1)*lineStride - 1], &ptr[(height - y - 1)*lineStride]); + } + } + else + { + for (unsigned int z = 0; z < depth; ++z) + { + const UInt8* srcPtr = reinterpret_cast(src); + UInt8* dstPtr = reinterpret_cast(dst) + (width - 1)*height*depth*bpp; + for (unsigned int y = 0; y < height; ++y) + { + std::memcpy(dstPtr, srcPtr, lineStride); + + srcPtr += lineStride; + dstPtr -= lineStride; + } + } + } + break; + } + + case PixelFlipping_Vertically: + { + if (src == dst) + { + for (unsigned int z = 0; z < depth; ++z) + { + UInt8* ptr = reinterpret_cast(dst) + width*height*z; + for (unsigned int y = 0; y < height; ++y) + { + for (unsigned int x = 0; x < width / 2; ++x) + std::swap_ranges(&ptr[x*bpp], &ptr[(x + 1)*bpp], &ptr[(width - x)*bpp]); + + ptr += lineStride; + } + } + } + else + { + for (unsigned int z = 0; z < depth; ++z) + { + UInt8* ptr = reinterpret_cast(dst) + width*height*z; + for (unsigned int y = 0; y < height; ++y) + { + for (unsigned int x = 0; x < width; ++x) + std::memcpy(&ptr[x*bpp], &ptr[(width - x)*bpp], bpp); + + ptr += lineStride; + } + } + } + break; + } + } + } + + return true; + } + PixelFormatType PixelFormat::IdentifyFormat(const PixelFormatInfo& info) { for (unsigned int i = 0; i <= PixelFormatType_Max; ++i) diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 1b8c41653..739af792e 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -105,11 +105,10 @@ namespace Nz const AbstractTextDrawer::Line& SimpleTextDrawer::GetLine(std::size_t index) const { - NazaraAssert(index < m_lines.size(), "Line index out of range"); - if (!m_glyphUpdated) UpdateGlyphs(); + NazaraAssert(index < m_lines.size(), "Line index out of range"); return m_lines[index]; } @@ -243,7 +242,7 @@ namespace Nz m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly) if (m_font) - m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, m_font->GetSizeInfo(m_characterSize).lineHeight), 0}); + m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, float(m_font->GetSizeInfo(m_characterSize).lineHeight)), 0}); else m_lines.emplace_back(Line{Rectf::Zero(), 0}); } @@ -319,6 +318,10 @@ namespace Nz glyph.color = m_color; glyph.flipped = fontGlyph.flipped; + glyph.bounds.Set(fontGlyph.aabb); + glyph.bounds.x += m_drawPos.x; + glyph.bounds.y += m_drawPos.y; + if (fontGlyph.requireFauxBold) { // Let's simulate bold by enlarging the glyph (not a neat idea, but should work) @@ -330,16 +333,13 @@ namespace Nz // Replace it at the correct height Vector2f offset(glyph.bounds.GetCenter() - center); + glyph.bounds.x -= offset.x; glyph.bounds.y -= offset.y; // Adjust advance (+10%) advance += advance / 10; } - glyph.bounds.Set(fontGlyph.aabb); - glyph.bounds.x += m_drawPos.x; - glyph.bounds.y += m_drawPos.y; - // We "lean" the glyph to simulate italics style float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f; float italicTop = italic * glyph.bounds.y; @@ -354,7 +354,7 @@ namespace Nz { glyph.atlas = nullptr; - glyph.bounds.Set(m_drawPos.x, m_drawPos.y, float(advance), sizeInfo.lineHeight); + glyph.bounds.Set(float(m_drawPos.x), float(m_drawPos.y), float(advance), float(sizeInfo.lineHeight)); glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop)); glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop)); @@ -365,17 +365,19 @@ namespace Nz { case '\n': { + // Extend the line bounding rect to the last glyph it contains, thus extending upon all glyphs of the line if (!m_glyphs.empty()) { - Glyph& glyph = m_glyphs.back(); - m_lines.back().bounds.ExtendTo(glyph.bounds); + Glyph& lastGlyph = m_glyphs.back(); + m_lines.back().bounds.ExtendTo(lastGlyph.bounds); } + // Reset cursor advance = 0; m_drawPos.x = 0; m_drawPos.y += sizeInfo.lineHeight; - m_lines.emplace_back(Line{Rectf(0.f, sizeInfo.lineHeight * m_lines.size(), 0.f, sizeInfo.lineHeight), m_glyphs.size() + 1}); + m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1}); break; } } diff --git a/src/Nazara/Utility/Skeleton.cpp b/src/Nazara/Utility/Skeleton.cpp index 7d33ad9bd..480522b4e 100644 --- a/src/Nazara/Utility/Skeleton.cpp +++ b/src/Nazara/Utility/Skeleton.cpp @@ -72,12 +72,12 @@ namespace Nz if (!m_impl->aabbUpdated) { - UInt32 jointCount = m_impl->joints.size(); + std::size_t jointCount = m_impl->joints.size(); if (jointCount > 0) { Vector3f pos = m_impl->joints[0].GetPosition(); m_impl->aabb.Set(pos.x, pos.y, pos.z, 0.f, 0.f, 0.f); - for (UInt32 i = 1; i < jointCount; ++i) + for (std::size_t i = 1; i < jointCount; ++i) m_impl->aabb.ExtendTo(m_impl->joints[i].GetPosition()); } else @@ -219,7 +219,7 @@ namespace Nz } #endif - return m_impl->joints.size(); + return static_cast(m_impl->joints.size()); } int Skeleton::GetJointIndex(const String& jointName) const @@ -411,16 +411,9 @@ namespace Nz String name = m_impl->joints[i].GetName(); if (!name.IsEmpty()) { - #if NAZARA_UTILITY_SAFE - auto it = m_impl->jointMap.find(name); - if (it != m_impl->jointMap.end()) - { - NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + String::Number(it->second)); - continue; - } - #endif + NazaraAssert(m_impl->jointMap.find(name) == m_impl->jointMap.end(), "Joint name \"" + name + "\" is already present in joint map"); - m_impl->jointMap[name] = i; + m_impl->jointMap[name] = static_cast(i); } } diff --git a/src/Nazara/Utility/TriangleIterator.cpp b/src/Nazara/Utility/TriangleIterator.cpp index 68f65c0db..ad6dfb2c6 100644 --- a/src/Nazara/Utility/TriangleIterator.cpp +++ b/src/Nazara/Utility/TriangleIterator.cpp @@ -66,18 +66,9 @@ namespace Nz return true; } - UInt32 TriangleIterator::operator[](unsigned int i) const + UInt32 TriangleIterator::operator[](std::size_t i) const { - #if NAZARA_UTILITY_SAFE - if (i >= 3) - { - StringStream ss; - ss << "Index out of range: (" << i << " >= 3)"; - - NazaraError(ss); - throw std::domain_error(ss.ToString()); - } - #endif + NazaraAssert(i < 3, "Index out of range"); return m_triangleIndices[i]; } diff --git a/src/Nazara/Utility/Utility.cpp b/src/Nazara/Utility/Utility.cpp index c6e87e0bb..4c8f1809e 100644 --- a/src/Nazara/Utility/Utility.cpp +++ b/src/Nazara/Utility/Utility.cpp @@ -6,21 +6,15 @@ #include #include #include -#include -#include -#include -#include #include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -35,15 +29,29 @@ namespace Nz { + /*! + * \ingroup utility + * \class Nz::Utility + * \brief Utility class that represents the module initializer of Utility + */ + + /*! + * \brief Initializes the Utility module + * \return true if initialization is successful + * + * \remark Produces a NazaraNotice + * \remark Produces a NazaraError if one submodule failed + */ + bool Utility::Initialize() { if (s_moduleReferenceCounter > 0) { s_moduleReferenceCounter++; - return true; // Déjà initialisé + return true; // Already initialized } - // Initialisation des dépendances + // Initialisation of dependencies if (!Core::Initialize()) { NazaraError("Failed to initialize core module"); @@ -103,23 +111,6 @@ namespace Nz return false; } - bool bParam; - if (!s_initializationParameters.GetBooleanParameter("NoWindowSystem", &bParam) || !bParam) - { - if (!Window::Initialize()) - { - NazaraError("Failed to initialize window's system"); - return false; - } - - // Must be initialized after Window - if (!Cursor::Initialize()) - { - NazaraError("Failed to initialize cursors"); - return false; - } - } - // On enregistre les loaders pour les extensions // Il s'agit ici d'une liste LIFO, le dernier loader enregistré possède la priorité @@ -159,11 +150,6 @@ namespace Nz return s_moduleReferenceCounter != 0; } - void Utility::SetParameters(const ParameterList& parameters) - { - s_initializationParameters = parameters; - } - void Utility::Uninitialize() { if (s_moduleReferenceCounter != 1) @@ -188,9 +174,6 @@ namespace Nz Loaders::UnregisterSTBLoader(); Loaders::UnregisterSTBSaver(); - Cursor::Uninitialize(); //< Must be done before Window - Window::Uninitialize(); - VertexDeclaration::Uninitialize(); Skeleton::Uninitialize(); PixelFormat::Uninitialize(); @@ -246,6 +229,5 @@ namespace Nz static_assert(ComponentType_Max+1 == 14, "Component stride array is incomplete"); - ParameterList Utility::s_initializationParameters; unsigned int Utility::s_moduleReferenceCounter = 0; } diff --git a/src/Nazara/Utility/VertexBuffer.cpp b/src/Nazara/Utility/VertexBuffer.cpp index 371ba2efa..f06d46ed0 100644 --- a/src/Nazara/Utility/VertexBuffer.cpp +++ b/src/Nazara/Utility/VertexBuffer.cpp @@ -31,10 +31,10 @@ namespace Nz VertexBuffer::VertexBuffer(const VertexBuffer& vertexBuffer) : RefCounted(), m_buffer(vertexBuffer.m_buffer), - m_vertexDeclaration(vertexBuffer.m_vertexDeclaration), m_endOffset(vertexBuffer.m_endOffset), m_startOffset(vertexBuffer.m_startOffset), - m_vertexCount(vertexBuffer.m_vertexCount) + m_vertexCount(vertexBuffer.m_vertexCount), + m_vertexDeclaration(vertexBuffer.m_vertexDeclaration) { } diff --git a/tests/Engine/Core/ParameterList.cpp b/tests/Engine/Core/ParameterList.cpp index ef2729833..5d998f5b8 100644 --- a/tests/Engine/Core/ParameterList.cpp +++ b/tests/Engine/Core/ParameterList.cpp @@ -24,13 +24,13 @@ SCENARIO("ParameterList", "[CORE][PARAMETERLIST]") WHEN("We add Float '3.f'") { - float fl = 3.f; - parameterList.SetParameter("float", fl); + double fl = 3.f; + parameterList.SetParameter("double", fl); THEN("We can get it back") { - float newFl; - REQUIRE(parameterList.GetFloatParameter("float", &newFl)); + double newFl; + REQUIRE(parameterList.GetDoubleParameter("double", &newFl)); REQUIRE(newFl == fl); } } diff --git a/tests/Engine/Math/AlgorithmMath.cpp b/tests/Engine/Math/AlgorithmMath.cpp index 01413d902..e6dc2218b 100644 --- a/tests/Engine/Math/AlgorithmMath.cpp +++ b/tests/Engine/Math/AlgorithmMath.cpp @@ -1,5 +1,6 @@ #include #include +#include TEST_CASE("Approach", "[MATH][ALGORITHM]") { @@ -48,6 +49,11 @@ TEST_CASE("CountBits", "[MATH][ALGORITHM]") { REQUIRE(Nz::CountBits(0) == 0); } + + SECTION("Number 0xFFFFFFFF has 32 bit set to 1") + { + REQUIRE(Nz::CountBits(0xFFFFFFFF) == 32); + } } TEST_CASE("DegreeToRadian", "[MATH][ALGORITHM]") @@ -205,9 +211,19 @@ TEST_CASE("NumberEquals", "[MATH][ALGORITHM]") CHECK(Nz::NumberEquals(2.35, 2.35, 0.01)); } - SECTION("3 and 4 unsigned should be the same at 1") + SECTION("0 and 4 unsigned should be the same at 1") { - CHECK(Nz::NumberEquals(3U, 4U, 1U)); + CHECK(Nz::NumberEquals(0U, 4U, 4U)); + } + + SECTION("Maximum integer and -1 should not be equal") + { + CHECK_FALSE(Nz::NumberEquals(std::numeric_limits::max(), -1)); + } + + SECTION("Maximum integer and minimum integer should not be equal") + { + CHECK_FALSE(Nz::NumberEquals(std::numeric_limits::max(), std::numeric_limits::min())); } } diff --git a/tests/Engine/Math/Quaternion.cpp b/tests/Engine/Math/Quaternion.cpp index 7ebf6ede5..46a0c5f89 100644 --- a/tests/Engine/Math/Quaternion.cpp +++ b/tests/Engine/Math/Quaternion.cpp @@ -173,15 +173,52 @@ SCENARIO("Quaternion", "[MATH][QUATERNION]") WHEN("We get the rotation between two vectors") { - /*TODO - * Nz::Quaternionf rotationBetweenXY = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitY()); + Nz::Quaternionf rotationBetweenXY = Nz::Quaternionf::RotationBetween(Nz::Vector3f::UnitX(), Nz::Vector3f::UnitY()); - THEN("The rotation in left-handed is 270 degree on z") + THEN("The rotation in right-handed is 90 degree on z") { - Nz::Quaternionf rotation270Z(Nz::FromDegrees(270.f), Nz::Vector3f::UnitZ()); Nz::Quaternionf rotation90Z(Nz::FromDegrees(90.f), Nz::Vector3f::UnitZ()); REQUIRE(rotation90Z == rotationBetweenXY); - }*/ + } + } + } + + GIVEN("Different angles") + { + Nz::Quaternionf rotation90X(0.707f, 0.707f, 0.f, 0.f); + Nz::Quaternionf rotation90Y(0.707f, 0.f, 0.707f, 0.f); + Nz::Quaternionf rotation90Z(0.707f, 0.f, 0.f, 0.707f); + + Nz::Quaternionf rotation180X(0.f, 1.f, 0.f, 0.f); + Nz::Quaternionf rotation180Y(0.f, 0.f, 1.f, 0.f); + Nz::Quaternionf rotation180Z(0.f, 0.f, 0.f, 1.f); + + Nz::Quaternionf rotation270X(-0.707f, 0.707f, 0.f, 0.f); + Nz::Quaternionf rotation270Y(-0.707f, 0.f, 0.707f, 0.f); + Nz::Quaternionf rotation270Z(-0.707f, 0.f, 0.f, 0.707f); + + Nz::Quaternionf special(0.707f, 0.006f, 0.006f, 0.707f); + + WHEN("We convert them to euler angles") + { + THEN("Those are equal to") + { + CHECK(Nz::NumberEquals(rotation90X.ToEulerAngles().pitch, Nz::FromDegrees(90.f), 0.1f)); + CHECK(Nz::NumberEquals(rotation90Y.ToEulerAngles().yaw, Nz::FromDegrees(90.f), 0.1f)); + CHECK(Nz::NumberEquals(rotation90Z.ToEulerAngles().roll, Nz::FromDegrees(90.f), 0.1f)); + + CHECK(rotation180X == Nz::EulerAnglesf(180.f, 0.f, 0.f)); + CHECK(rotation180Y == Nz::EulerAnglesf(0.f, 180.f, 0.f)); + CHECK(rotation180Z == Nz::EulerAnglesf(0.f, 0.f, 180.f)); + + CHECK(Nz::NumberEquals(rotation270X.ToEulerAngles().pitch, Nz::FromDegrees(-90.f), 0.1f)); + CHECK(Nz::NumberEquals(rotation270Y.ToEulerAngles().yaw, Nz::FromDegrees(-90.f), 0.1f)); + CHECK(Nz::NumberEquals(rotation270Z.ToEulerAngles().roll, Nz::FromDegrees(-90.f), 0.1f)); + + CHECK(Nz::NumberEquals(special.ToEulerAngles().pitch, Nz::FromDegrees(0.f), 0.1f)); + CHECK(Nz::NumberEquals(special.ToEulerAngles().yaw, Nz::FromDegrees(1.f), 0.1f)); + CHECK(Nz::NumberEquals(special.ToEulerAngles().roll, Nz::FromDegrees(90.f), 0.1f)); + } } } } diff --git a/tests/Engine/Network/SocketPoller.cpp b/tests/Engine/Network/SocketPoller.cpp index 7081c1b30..2e880cf5c 100644 --- a/tests/Engine/Network/SocketPoller.cpp +++ b/tests/Engine/Network/SocketPoller.cpp @@ -27,7 +27,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") WHEN("We register the server socket to the poller") { - REQUIRE(serverPoller.RegisterSocket(server)); + REQUIRE(serverPoller.RegisterSocket(server, Nz::SocketPollEvent_Read)); THEN("The poller should have registered our socket") { @@ -48,7 +48,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") WHEN("We register the client socket to the poller") { - REQUIRE(serverPoller.RegisterSocket(serverToClient)); + REQUIRE(serverPoller.RegisterSocket(serverToClient, Nz::SocketPollEvent_Read)); THEN("The poller should have registered our socket") { @@ -65,7 +65,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") REQUIRE(serverPoller.Wait(1000)); - CHECK(serverPoller.IsReady(serverToClient)); + CHECK(serverPoller.IsReadyToRead(serverToClient)); CHECK(serverToClient.Read(buffer.data(), buffer.size()) == sent); @@ -73,7 +73,7 @@ SCENARIO("SocketPoller", "[NETWORK][SOCKETPOLLER]") { REQUIRE_FALSE(serverPoller.Wait(100)); - REQUIRE_FALSE(serverPoller.IsReady(serverToClient)); + REQUIRE_FALSE(serverPoller.IsReadyToRead(serverToClient)); } } } diff --git a/tests/Engine/Physics2D/Collider2D.cpp b/tests/Engine/Physics2D/Collider2D.cpp new file mode 100644 index 000000000..dee2b85c8 --- /dev/null +++ b/tests/Engine/Physics2D/Collider2D.cpp @@ -0,0 +1,133 @@ +#include +#include + +SCENARIO("Collider2D", "[PHYSICS2D][COLLIDER2D]") +{ + GIVEN("No particular elements") + { + WHEN("We construct a box with Rect") + { + Nz::Rectf aabb(5.f, 3.f, 10.f, 6.f); + Nz::BoxCollider2D box(aabb); + + THEN("We expect those to be true") + { + CHECK(box.GetRect() == aabb); + CHECK(box.GetSize() == aabb.GetLengths()); + CHECK(box.GetType() == Nz::ColliderType2D_Box); + } + } + + WHEN("We construct a box with Vector2D") + { + Nz::Vector2f vec(5.f, 3.f); + Nz::Rectf aabb(-2.5f, -1.5f, 5.f, 3.f); + Nz::BoxCollider2D box(vec); + + THEN("We expect those to be true") + { + CHECK(box.GetRect() == aabb); + CHECK(box.GetSize() == vec); + CHECK(box.GetType() == Nz::ColliderType2D_Box); + } + } + + WHEN("We construct a circle") + { + Nz::Vector2f position(5.f, 3.f); + float radius = 7.f; + Nz::CircleCollider2D circle(radius, position); + + THEN("We expect those to be true") + { + CHECK(circle.GetRadius() == Approx(radius)); + CHECK(circle.GetType() == Nz::ColliderType2D_Circle); + } + } + + WHEN("We construct a compound") + { + Nz::Rectf aabb(0.f, 0.f, 1.f, 1.f); + Nz::BoxCollider2DRef box1 = Nz::BoxCollider2D::New(aabb); + aabb.Translate(Nz::Vector2f::Unit()); + Nz::BoxCollider2DRef box2 = Nz::BoxCollider2D::New(aabb); + + std::vector colliders; + colliders.push_back(box1); + colliders.push_back(box2); + Nz::CompoundCollider2D compound(colliders); + + THEN("We expect those to be true") + { + CHECK(compound.GetType() == Nz::ColliderType2D_Compound); + } + } + + WHEN("We construct a convex") + { + std::vector vertices; + vertices.push_back(Nz::Vector2f(0.f, 0.f)); + vertices.push_back(Nz::Vector2f(0.f, 1.f)); + vertices.push_back(Nz::Vector2f(1.f, 1.f)); + vertices.push_back(Nz::Vector2f(1.f, 0.f)); + + Nz::ConvexCollider2D convex(Nz::SparsePtr(vertices.data()), vertices.size()); + + THEN("We expect those to be true") + { + CHECK(convex.GetType() == Nz::ColliderType2D_Convex); + } + } + + WHEN("We construct a null") + { + Nz::NullCollider2D null; + + THEN("We expect those to be true") + { + CHECK(null.GetType() == Nz::ColliderType2D_Null); + } + } + + WHEN("We construct a segment") + { + Nz::Vector2f firstPoint(2.f, 1.f); + Nz::Vector2f secondPoint(-4.f, -3.f); + Nz::SegmentCollider2D segment(firstPoint, secondPoint); + + THEN("We expect those to be true") + { + CHECK(segment.GetFirstPoint() == firstPoint); + CHECK(segment.GetLength() == firstPoint.Distance(secondPoint)); + CHECK(segment.GetSecondPoint() == secondPoint); + CHECK(segment.GetType() == Nz::ColliderType2D_Segment); + } + } + + WHEN("We verify general purpose methods") + { + Nz::Rectf aabb(5.f, 3.f, 10.f, 6.f); + Nz::BoxCollider2D box(aabb); + + Nz::UInt32 categoryMask = 1; + Nz::UInt32 groupId = 2; + Nz::UInt32 typeId = 3; + Nz::UInt32 mask = 4; + bool trigger = true; + box.SetCategoryMask(categoryMask); + box.SetCollisionGroup(groupId); + box.SetCollisionId(typeId); + box.SetCollisionMask(mask); + box.SetTrigger(trigger); + + THEN("We expect those to be true") + { + CHECK(box.GetCategoryMask() == categoryMask); + CHECK(box.GetCollisionGroup() == groupId); + CHECK(box.GetCollisionId() == typeId); + CHECK(box.GetCollisionMask() == mask); + CHECK(box.IsTrigger() == trigger); + } + } + } +} diff --git a/tests/Engine/Physics2D/PhysWorld2D.cpp b/tests/Engine/Physics2D/PhysWorld2D.cpp new file mode 100644 index 000000000..539932f71 --- /dev/null +++ b/tests/Engine/Physics2D/PhysWorld2D.cpp @@ -0,0 +1,114 @@ +#include +#include + +Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world, const Nz::Vector2f& position, bool isMoving = true, const Nz::Vector2f& lengths = Nz::Vector2f::Unit()); + +Nz::UInt32 collisionGroup = 1; +Nz::UInt32 categoryMask = 2; +Nz::UInt32 collisionMask = 3; + +SCENARIO("PhysWorld2D", "[PHYSICS2D][PHYSWORLD2D]") +{ + GIVEN("A physic world and a bunch of entities on a grid") + { + Nz::PhysWorld2D world; + + std::vector bodies; + const int numberOfBodiesPerLign = 3; + for (int i = 0; i != numberOfBodiesPerLign; ++i) + { + for (int j = 0; j != numberOfBodiesPerLign; ++j) + { + bodies.push_back(CreateBody(world, Nz::Vector2f(10.f * i, 10.f * j))); + } + } + + world.Step(1.f); + + WHEN("We ask for the nearest body") + { + Nz::PhysWorld2D::NearestQueryResult result; + REQUIRE(world.NearestBodyQuery(-Nz::Vector2f::UnitY() * 1.f, 2.f, collisionGroup, categoryMask, collisionMask, &result)); + + THEN("It should be the one on the origin") + { + CHECK(result.nearestBody == &bodies[0]); + CHECK(result.closestPoint == Nz::Vector2f::Zero()); + CHECK(result.fraction == -Nz::Vector2f::UnitY()); + CHECK(result.distance == Approx(1.f)); + } + + REQUIRE(world.NearestBodyQuery(Nz::Vector2f::UnitY() * 2.f, 2.f, collisionGroup, categoryMask, collisionMask, &result)); + + THEN("It should be the one on the origin") + { + CHECK(result.nearestBody == &bodies[0]); + CHECK(result.closestPoint == Nz::Vector2f::UnitY()); + CHECK(result.fraction == Nz::Vector2f::UnitY()); + CHECK(result.distance == Approx(1.f)); + } + } + + WHEN("We ask for the first ray collision") + { + Nz::Vector2f origin = -Nz::Vector2f::UnitY() * 2.f; + Nz::Vector2f end = (numberOfBodiesPerLign + 1) * 10.f * Nz::Vector2f::UnitY(); + Nz::PhysWorld2D::RaycastHit result; + REQUIRE(world.RaycastQueryFirst(origin, end, 1.f, collisionGroup, categoryMask, collisionMask, &result)); + + THEN("It should be the one on the origin") + { + CHECK(result.nearestBody == &bodies[0]); + CHECK(result.fraction == Approx(1.f / 42.f)); + CHECK(result.hitPos == Nz::Vector2f::Zero()); + CHECK(result.hitNormal == -Nz::Vector2f::UnitY()); + } + } + + WHEN("We ask for the ray collisions") + { + Nz::Vector2f origin = -Nz::Vector2f::UnitY() * 2.f; + Nz::Vector2f end = (numberOfBodiesPerLign + 1) * 10.f * Nz::Vector2f::UnitY(); + std::vector results; + REQUIRE(world.RaycastQuery(origin, end, 1.f, collisionGroup, categoryMask, collisionMask, &results)); + + THEN("It should be the first lign") + { + REQUIRE(results.size() == numberOfBodiesPerLign); + + for (int i = 0; i != numberOfBodiesPerLign; ++i) + { + const Nz::PhysWorld2D::RaycastHit& result = results[i]; + CHECK(result.nearestBody == &bodies[i]); + CHECK(result.fraction == Approx(i / 4.f).epsilon(0.1f)); + CHECK(result.hitPos == Nz::Vector2f(0.f, i * 10.f)); + CHECK(result.hitNormal == -Nz::Vector2f::UnitY()); + } + } + } + + WHEN("We ask for a region") + { + std::vector results; + world.RegionQuery(Nz::Rectf(-5.f, -5.f, 5.f, 5.f), collisionGroup, categoryMask, collisionMask, &results); + + THEN("It should be the one on the origin") + { + REQUIRE(results.size() == 1); + CHECK(results[0] == &bodies[0]); + } + } + } +} + +Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world, const Nz::Vector2f& position, bool isMoving, const Nz::Vector2f& lengths) +{ + Nz::Rectf aabb(0.f, 0.f, lengths.x, lengths.y); + Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + box->SetCategoryMask(categoryMask); + box->SetCollisionMask(collisionMask); + float mass = isMoving ? 1.f : 0.f; + Nz::RigidBody2D rigidBody(&world, mass, box); + rigidBody.SetPosition(position); + return rigidBody; +} diff --git a/tests/Engine/Physics2D/RigidBody2D.cpp b/tests/Engine/Physics2D/RigidBody2D.cpp new file mode 100644 index 000000000..f45e727b1 --- /dev/null +++ b/tests/Engine/Physics2D/RigidBody2D.cpp @@ -0,0 +1,318 @@ +#include +#include +#include + +Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world); +void EQUALITY(const Nz::RigidBody2D& left, const Nz::RigidBody2D& right); + +SCENARIO("RigidBody2D", "[PHYSICS2D][RIGIDBODY2D]") +{ + GIVEN("A physic world and a rigid body") + { + Nz::PhysWorld2D world; + + Nz::Vector2f positionAABB(3.f, 4.f); + Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); + Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + float mass = 1.f; + Nz::RigidBody2D body(&world, mass, box); + float angularVelocity = 0.2f; + body.SetAngularVelocity(angularVelocity); + Nz::Vector2f massCenter(5.f, 7.f); + body.SetMassCenter(massCenter); + Nz::Vector2f position(9.f, 1.f); + body.SetPosition(position); + float rotation = 0.1f; + body.SetRotation(rotation); + Nz::Vector2f velocity(-4.f, -2.f); + body.SetVelocity(velocity); + bool userdata = false; + body.SetUserdata(&userdata); + + world.Step(1.f); + + WHEN("We copy construct the body") + { + body.AddForce(Nz::Vector2f(3.f, 5.f)); + Nz::RigidBody2D copiedBody(body); + EQUALITY(copiedBody, body); + world.Step(1.f); + EQUALITY(copiedBody, body); + } + + WHEN("We move construct the body") + { + Nz::RigidBody2D copiedBody(body); + Nz::RigidBody2D movedBody(std::move(body)); + EQUALITY(movedBody, copiedBody); + } + + WHEN("We copy assign the body") + { + Nz::RigidBody2D copiedBody(&world, 0.f); + copiedBody = body; + EQUALITY(copiedBody, body); + } + + WHEN("We move assign the body") + { + Nz::RigidBody2D copiedBody(body); + Nz::RigidBody2D movedBody(&world, 0.f); + movedBody = std::move(body); + EQUALITY(movedBody, copiedBody); + } + + WHEN("We set a new geometry") + { + float radius = 5.f; + Nz::Vector2f positionCircle(0.f, 0.f); + Nz::Collider2DRef circle = Nz::CircleCollider2D::New(radius, position); + body.SetGeom(circle); + + world.Step(1.f); + + THEN("The aabb should be updated") + { + Nz::Rectf circleAABB(position.x - radius, position.y - radius, 2.f * radius, 2.f* radius); + REQUIRE(body.GetAABB() == circleAABB); + } + } + } + + GIVEN("A physic world") + { + Nz::PhysWorld2D world; + Nz::Rectf aabb(3.f, 4.f, 1.f, 2.f); + + WHEN("We get a rigid body from a function") + { + std::vector tmp; + tmp.push_back(CreateBody(world)); + tmp.push_back(CreateBody(world)); + world.Step(1.f); + + THEN("They should be valid") + { + CHECK(tmp[0].GetAABB() == aabb); + CHECK(tmp[1].GetAABB() == aabb); + } + } + } + + GIVEN("A physic world and a rigid body") + { + Nz::PhysWorld2D world; + Nz::Vector2f positionAABB(3.f, 4.f); + Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); + Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + float mass = 1.f; + Nz::RigidBody2D body(&world, mass, box); + bool userData = false; + body.SetUserdata(&userData); + + Nz::Vector2f position = Nz::Vector2f::Zero(); + + world.Step(1.f); + + WHEN("We retrieve standard information") + { + THEN("We expect those to be true") + { + CHECK(body.GetAABB() == aabb); + CHECK(body.GetAngularVelocity() == Approx(0.f)); + CHECK(body.GetCenterOfGravity() == Nz::Vector2f::Zero()); + CHECK(body.GetGeom() == box); + CHECK(body.GetMass() == Approx(mass)); + CHECK(body.GetPosition() == position); + CHECK(body.GetRotation() == Approx(0.f)); + CHECK(body.GetUserdata() == &userData); + CHECK(body.GetVelocity() == Nz::Vector2f::Zero()); + + CHECK(body.IsMoveable() == true); + CHECK(body.IsSleeping() == false); + } + } + + WHEN("We set a velocity") + { + Nz::Vector2f velocity(Nz::Vector2f::Unit()); + body.SetVelocity(velocity); + position += velocity; + world.Step(1.f); + + THEN("We expect those to be true") + { + aabb.Translate(velocity); + CHECK(body.GetAABB() == aabb); + CHECK(body.GetCenterOfGravity() == Nz::Vector2f::Zero()); + CHECK(body.GetPosition() == position); + CHECK(body.GetVelocity() == velocity); + } + + AND_THEN("We apply an impulse in the opposite direction") + { + body.AddImpulse(-velocity); + world.Step(1.f); + + REQUIRE(body.GetVelocity() == Nz::Vector2f::Zero()); + } + } + + WHEN("We set an angular velocity") + { + float angularSpeed = Nz::FromDegrees(90.f); + body.SetAngularVelocity(angularSpeed); + world.Step(1.f); + + THEN("We expect those to be true") + { + CHECK(body.GetAngularVelocity() == Approx(angularSpeed)); + CHECK(body.GetRotation() == Approx(angularSpeed)); + CHECK(body.GetAABB() == Nz::Rectf(-6.f, 3.f, 2.f, 1.f)); + + world.Step(1.f); + CHECK(body.GetRotation() == Approx(2.f * angularSpeed)); + CHECK(body.GetAABB() == Nz::Rectf(-4.f, -6.f, 1.f, 2.f)); + + world.Step(1.f); + CHECK(body.GetRotation() == Approx(3.f * angularSpeed)); + CHECK(body.GetAABB() == Nz::Rectf(4.f, -4.f, 2.f, 1.f)); + + world.Step(1.f); + CHECK(body.GetRotation() == Approx(4.f * angularSpeed)); + } + } + + WHEN("We apply a torque") + { + float angularSpeed = Nz::DegreeToRadian(90.f); + body.AddTorque(angularSpeed); + world.Step(1.f); + + THEN("It is also counter-clockwise") + { + CHECK(body.GetAngularVelocity() >= 0.f); + CHECK(body.GetRotation() >= 0.f); + } + } + } + + GIVEN("A physic world and a rigid body of circle") + { + Nz::PhysWorld2D world; + + Nz::Vector2f position(3.f, 4.f); + float radius = 5.f; + Nz::Collider2DRef circle = Nz::CircleCollider2D::New(radius, position); + float mass = 1.f; + Nz::RigidBody2D body(&world, mass, circle); + world.Step(1.f); + + WHEN("We ask for the aabb of the circle") + { + THEN("We expect this to be true") + { + Nz::Rectf circleAABB(position.x - radius, position.y - radius, 2.f * radius, 2.f* radius); + REQUIRE(body.GetAABB() == circleAABB); + } + } + } + + GIVEN("A physic world and a rigid body of compound") + { + Nz::PhysWorld2D world; + + Nz::Rectf aabb(0.f, 0.f, 1.f, 1.f); + Nz::BoxCollider2DRef box1 = Nz::BoxCollider2D::New(aabb); + aabb.Translate(Nz::Vector2f::Unit()); + Nz::BoxCollider2DRef box2 = Nz::BoxCollider2D::New(aabb); + + std::vector colliders; + colliders.push_back(box1); + colliders.push_back(box2); + Nz::CompoundCollider2DRef compound = Nz::CompoundCollider2D::New(colliders); + + float mass = 1.f; + Nz::RigidBody2D body(&world, mass, compound); + world.Step(1.f); + + WHEN("We ask for the aabb of the compound") + { + THEN("We expect this to be true") + { + Nz::Rectf compoundAABB(0.f, 0.f, 2.f, 2.f); + REQUIRE(body.GetAABB() == compoundAABB); + } + } + } + + GIVEN("A physic world and a rigid body of circle") + { + Nz::PhysWorld2D world; + + std::vector vertices; + vertices.push_back(Nz::Vector2f(0.f, 0.f)); + vertices.push_back(Nz::Vector2f(0.f, 1.f)); + vertices.push_back(Nz::Vector2f(1.f, 1.f)); + vertices.push_back(Nz::Vector2f(1.f, 0.f)); + + Nz::SparsePtr sparsePtr(vertices.data()); + Nz::ConvexCollider2DRef convex = Nz::ConvexCollider2D::New(sparsePtr, vertices.size()); + float mass = 1.f; + Nz::RigidBody2D body(&world, mass, convex); + world.Step(1.f); + + WHEN("We ask for the aabb of the convex") + { + THEN("We expect this to be true") + { + Nz::Rectf convexAABB(0.f, 0.f, 1.f, 1.f); + REQUIRE(body.GetAABB() == convexAABB); + } + } + } + + GIVEN("A physic world and a rigid body of segment") + { + Nz::PhysWorld2D world; + + Nz::Vector2f positionA(3.f, 4.f); + Nz::Vector2f positionB(1.f, -4.f); + Nz::Collider2DRef segment = Nz::SegmentCollider2D::New(positionA, positionB, 0.f); + float mass = 1.f; + Nz::RigidBody2D body(&world, mass, segment); + world.Step(1.f); + + WHEN("We ask for the aabb of the segment") + { + THEN("We expect this to be true") + { + Nz::Rectf segmentAABB(positionA, positionB); + REQUIRE(body.GetAABB() == segmentAABB); + } + } + } +} + +Nz::RigidBody2D CreateBody(Nz::PhysWorld2D& world) +{ + Nz::Vector2f positionAABB(3.f, 4.f); + Nz::Rectf aabb(positionAABB.x, positionAABB.y, 1.f, 2.f); + Nz::Collider2DRef box = Nz::BoxCollider2D::New(aabb); + float mass = 1.f; + return Nz::RigidBody2D(&world, mass, box); +} + +void EQUALITY(const Nz::RigidBody2D& left, const Nz::RigidBody2D& right) +{ + CHECK(left.GetAABB() == right.GetAABB()); + CHECK(left.GetAngularVelocity() == right.GetAngularVelocity()); + CHECK(left.GetCenterOfGravity() == right.GetCenterOfGravity()); + CHECK(left.GetGeom() == right.GetGeom()); + CHECK(left.GetHandle() != right.GetHandle()); + CHECK(left.GetMass() == right.GetMass()); + CHECK(left.GetPosition() == right.GetPosition()); + CHECK(left.GetRotation() == right.GetRotation()); + CHECK(left.GetUserdata() == right.GetUserdata()); + CHECK(left.GetVelocity() == right.GetVelocity()); +} \ No newline at end of file diff --git a/tests/Engine/Utility/EventHandler.cpp b/tests/Engine/Platform/EventHandler.cpp similarity index 97% rename from tests/Engine/Utility/EventHandler.cpp rename to tests/Engine/Platform/EventHandler.cpp index dedf3fc31..b143b949a 100644 --- a/tests/Engine/Utility/EventHandler.cpp +++ b/tests/Engine/Platform/EventHandler.cpp @@ -25,7 +25,7 @@ Ndk::EntityHandle AddCamera(Ndk::World& world, Nz::RenderWindow& window); - Text entered is never repeated */ -SCENARIO("EventHandler", "[UTILITY][EVENTHANDLER][INTERACTIVE][.]") +SCENARIO("EventHandler", "[PLATFORM][EVENTHANDLER][INTERACTIVE][.]") { GIVEN("An application") { diff --git a/tests/Engine/Platform/EventHandler/BaseState.cpp b/tests/Engine/Platform/EventHandler/BaseState.cpp new file mode 100644 index 000000000..ed1f19655 --- /dev/null +++ b/tests/Engine/Platform/EventHandler/BaseState.cpp @@ -0,0 +1,39 @@ +#include "BaseState.hpp" + +#include "StateContext.hpp" +#include "StateFactory.hpp" + +#include +#include + +BaseState::BaseState(StateContext& context) : +State(), +m_context(context), +m_text(context) +{ +} + +BaseState::~BaseState() +{ +} + +void BaseState::Enter(Ndk::StateMachine& fsm) +{ + m_text.SetVisible(true); + DrawMenu(); +} + +void BaseState::Leave(Ndk::StateMachine& /*fsm*/) +{ + m_text.SetVisible(false); +} + +bool BaseState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) +{ + return true; +} + +void BaseState::DrawMenu() +{ + m_text.SetContent("This shouldn't be visible\nM for Menu"); +} \ No newline at end of file diff --git a/tests/Engine/Platform/EventHandler/BaseState.hpp b/tests/Engine/Platform/EventHandler/BaseState.hpp new file mode 100644 index 000000000..2356e39cd --- /dev/null +++ b/tests/Engine/Platform/EventHandler/BaseState.hpp @@ -0,0 +1,31 @@ +#ifndef BASESTATE_HPP +#define BASESTATE_HPP + +#include "Text.hpp" + +#include + +#include + +class StateContext; + +class BaseState : public Ndk::State +{ + public: + BaseState(StateContext& stateContext); + virtual ~BaseState(); + + virtual void Enter(Ndk::StateMachine& fsm) override; + + virtual void Leave(Ndk::StateMachine& fsm) override; + + virtual bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; + + protected: + virtual void DrawMenu(); + + StateContext& m_context; + Text m_text; +}; + +#endif // BASESTATE_HPP \ No newline at end of file diff --git a/tests/Engine/Utility/EventHandler/EventState.cpp b/tests/Engine/Platform/EventHandler/EventState.cpp similarity index 88% rename from tests/Engine/Utility/EventHandler/EventState.cpp rename to tests/Engine/Platform/EventHandler/EventState.cpp index 4f74e3000..1d6a6784a 100644 --- a/tests/Engine/Utility/EventHandler/EventState.cpp +++ b/tests/Engine/Platform/EventHandler/EventState.cpp @@ -7,17 +7,14 @@ #include EventState::EventState(StateContext& context) : -State(), -m_context(context), -m_text(context), +BaseState(context), m_count(0) { } void EventState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -35,16 +32,6 @@ void EventState::Enter(Ndk::StateMachine& fsm) }); } -void EventState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool EventState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void EventState::AddEvent(const Nz::WindowEvent& event) { if (m_events.size() > 9) @@ -53,9 +40,9 @@ void EventState::AddEvent(const Nz::WindowEvent& event) m_events.push_back(Nz::String::Number(m_count) + " - " + ToString(event)); Nz::String content; - for (auto&& event : m_events) + for (auto&& currentEvent : m_events) { - content += event + "\n"; + content += currentEvent + "\n"; } content += "\nM for Menu"; m_text.SetContent(content, 36); diff --git a/tests/Engine/Utility/EventHandler/EventState.hpp b/tests/Engine/Platform/EventHandler/EventState.hpp similarity index 59% rename from tests/Engine/Utility/EventHandler/EventState.hpp rename to tests/Engine/Platform/EventHandler/EventState.hpp index 7b1cc63d7..d22ebd4c4 100644 --- a/tests/Engine/Utility/EventHandler/EventState.hpp +++ b/tests/Engine/Platform/EventHandler/EventState.hpp @@ -1,32 +1,26 @@ #ifndef __EVENTSTATE_HPP__ #define __EVENTSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" #include class StateContext; -class EventState : public Ndk::State +class EventState : public BaseState { public: EventState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: void AddEvent(const Nz::WindowEvent& event); - void DrawMenu(); + + void DrawMenu() override; + Nz::String ToString(const Nz::WindowEvent& event) const; - StateContext& m_context; - Text m_text; std::deque m_events; int m_count; NazaraSlot(Nz::EventHandler, OnEvent, m_eventSlot); diff --git a/tests/Engine/Utility/EventHandler/FocusState.cpp b/tests/Engine/Platform/EventHandler/FocusState.cpp similarity index 78% rename from tests/Engine/Utility/EventHandler/FocusState.cpp rename to tests/Engine/Platform/EventHandler/FocusState.cpp index bc9c77ab5..ee5fd5f7e 100644 --- a/tests/Engine/Utility/EventHandler/FocusState.cpp +++ b/tests/Engine/Platform/EventHandler/FocusState.cpp @@ -7,16 +7,13 @@ #include FocusState::FocusState(StateContext& context) : -State(), -m_context(context), -m_text(context) +BaseState(context) { } void FocusState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -38,16 +35,6 @@ void FocusState::Enter(Ndk::StateMachine& fsm) }); } -void FocusState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool FocusState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void FocusState::DrawMenu() { m_text.SetContent("Click outside the windows, this text should change !\nM for Menu"); diff --git a/tests/Engine/Utility/EventHandler/FocusState.hpp b/tests/Engine/Platform/EventHandler/FocusState.hpp similarity index 53% rename from tests/Engine/Utility/EventHandler/FocusState.hpp rename to tests/Engine/Platform/EventHandler/FocusState.hpp index 9287722ab..359dceaa1 100644 --- a/tests/Engine/Utility/EventHandler/FocusState.hpp +++ b/tests/Engine/Platform/EventHandler/FocusState.hpp @@ -1,28 +1,20 @@ #ifndef __FOCUSSTATE_HPP__ #define __FOCUSSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; -class FocusState : public Ndk::State +class FocusState : public BaseState { public: FocusState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: - void DrawMenu(); + void DrawMenu() override; - StateContext& m_context; - Text m_text; NazaraSlot(Nz::EventHandler, OnGainedFocus, m_gainedFocusSlot); NazaraSlot(Nz::EventHandler, OnLostFocus, m_lostFocusSlot); NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); diff --git a/tests/Engine/Utility/EventHandler/KeyState.cpp b/tests/Engine/Platform/EventHandler/KeyState.cpp similarity index 82% rename from tests/Engine/Utility/EventHandler/KeyState.cpp rename to tests/Engine/Platform/EventHandler/KeyState.cpp index 043dc5837..40bd785f1 100644 --- a/tests/Engine/Utility/EventHandler/KeyState.cpp +++ b/tests/Engine/Platform/EventHandler/KeyState.cpp @@ -7,17 +7,14 @@ #include KeyState::KeyState(StateContext& context) : -State(), -m_context(context), -m_text(context), +BaseState(context), m_keyStatus(KeyStatus::Pressed) { } void KeyState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -31,22 +28,12 @@ void KeyState::Enter(Ndk::StateMachine& fsm) }); } -void KeyState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool KeyState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void KeyState::DrawMenu() { m_text.SetContent("Clic on a key, this text should change !\nN for alternating event\nM for Menu"); } -void KeyState::ManageInput(KeyStatus isKeyPressed, const Nz::WindowEvent::KeyEvent& key, Ndk::StateMachine& fsm) +void KeyState::ManageInput(KeyStatus /*isKeyPressed*/, const Nz::WindowEvent::KeyEvent& key, Ndk::StateMachine& fsm) { if (key.code == Nz::Keyboard::Key::M && key.shift) fsm.ChangeState(StateFactory::Get(EventStatus::Menu)); diff --git a/tests/Engine/Utility/EventHandler/KeyState.hpp b/tests/Engine/Platform/EventHandler/KeyState.hpp similarity index 60% rename from tests/Engine/Utility/EventHandler/KeyState.hpp rename to tests/Engine/Platform/EventHandler/KeyState.hpp index 9b0fb1fcd..8e16c85f2 100644 --- a/tests/Engine/Utility/EventHandler/KeyState.hpp +++ b/tests/Engine/Platform/EventHandler/KeyState.hpp @@ -1,11 +1,7 @@ #ifndef __KEYSTATE_HPP__ #define __KEYSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; @@ -15,21 +11,18 @@ enum class KeyStatus Released }; -class KeyState : public Ndk::State +class KeyState : public BaseState { public: KeyState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: - void DrawMenu(); + void DrawMenu() override; + void ManageInput(KeyStatus isKeyPressed, const Nz::WindowEvent::KeyEvent& key, Ndk::StateMachine& fsm); - StateContext& m_context; - Text m_text; KeyStatus m_keyStatus; NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); NazaraSlot(Nz::EventHandler, OnKeyReleased, m_keyReleasedSlot); diff --git a/tests/Engine/Utility/EventHandler/MenuState.cpp b/tests/Engine/Platform/EventHandler/MenuState.cpp similarity index 82% rename from tests/Engine/Utility/EventHandler/MenuState.cpp rename to tests/Engine/Platform/EventHandler/MenuState.cpp index b659f51b2..d1a244369 100644 --- a/tests/Engine/Utility/EventHandler/MenuState.cpp +++ b/tests/Engine/Platform/EventHandler/MenuState.cpp @@ -7,17 +7,14 @@ #include MenuState::MenuState(StateContext& context) : -State(), -m_context(context), -m_text(context), +BaseState(context), m_selectedNextState(-1) { } -void MenuState::Enter(Ndk::StateMachine& /*fsm*/) +void MenuState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [this] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -29,9 +26,9 @@ void MenuState::Enter(Ndk::StateMachine& /*fsm*/) }); } -void MenuState::Leave(Ndk::StateMachine& /*fsm*/) +void MenuState::Leave(Ndk::StateMachine& fsm) { - m_text.SetVisible(false); + BaseState::Leave(fsm); m_selectedNextState = -1; } diff --git a/tests/Engine/Utility/EventHandler/MenuState.hpp b/tests/Engine/Platform/EventHandler/MenuState.hpp similarity index 72% rename from tests/Engine/Utility/EventHandler/MenuState.hpp rename to tests/Engine/Platform/EventHandler/MenuState.hpp index 356a12a72..7ce82001e 100644 --- a/tests/Engine/Utility/EventHandler/MenuState.hpp +++ b/tests/Engine/Platform/EventHandler/MenuState.hpp @@ -1,28 +1,24 @@ #ifndef __MENUSTATE_HPP__ #define __MENUSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; -class MenuState : public Ndk::State +class MenuState : public BaseState { public: MenuState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; + void Leave(Ndk::StateMachine& fsm) override; + bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: void DrawMenu(); - StateContext& m_context; - Text m_text; NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); int m_selectedNextState; }; diff --git a/tests/Engine/Utility/EventHandler/MouseClickState.cpp b/tests/Engine/Platform/EventHandler/MouseClickState.cpp similarity index 85% rename from tests/Engine/Utility/EventHandler/MouseClickState.cpp rename to tests/Engine/Platform/EventHandler/MouseClickState.cpp index 1de923bd4..74cb8ef79 100644 --- a/tests/Engine/Utility/EventHandler/MouseClickState.cpp +++ b/tests/Engine/Platform/EventHandler/MouseClickState.cpp @@ -7,16 +7,13 @@ #include MouseClickState::MouseClickState(StateContext& context) : -State(), -m_context(context), -m_text(context) +BaseState(context) { } void MouseClickState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -43,22 +40,12 @@ void MouseClickState::Enter(Ndk::StateMachine& fsm) }); } -void MouseClickState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool MouseClickState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void MouseClickState::DrawMenu() { m_text.SetContent("Click in the windows, this text should change !\nM for Menu"); } -void MouseClickState::ManageInput(MouseStatus mouseStatus, const Nz::WindowEvent::MouseButtonEvent& mouse, Ndk::StateMachine& fsm) +void MouseClickState::ManageInput(MouseStatus mouseStatus, const Nz::WindowEvent::MouseButtonEvent& mouse, Ndk::StateMachine& /*fsm*/) { Nz::String content; if (mouseStatus == MouseStatus::Pressed) diff --git a/tests/Engine/Utility/EventHandler/MouseClickState.hpp b/tests/Engine/Platform/EventHandler/MouseClickState.hpp similarity index 67% rename from tests/Engine/Utility/EventHandler/MouseClickState.hpp rename to tests/Engine/Platform/EventHandler/MouseClickState.hpp index 28c4203a9..9a0e38077 100644 --- a/tests/Engine/Utility/EventHandler/MouseClickState.hpp +++ b/tests/Engine/Platform/EventHandler/MouseClickState.hpp @@ -1,11 +1,7 @@ #ifndef __MOUSECLICKSTATE_HPP__ #define __MOUSECLICKSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; @@ -16,21 +12,18 @@ enum class MouseStatus Released }; -class MouseClickState : public Ndk::State +class MouseClickState : public BaseState { public: MouseClickState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: - void DrawMenu(); + void DrawMenu() override; + void ManageInput(MouseStatus mouseStatus, const Nz::WindowEvent::MouseButtonEvent& mouse, Ndk::StateMachine& fsm); - StateContext& m_context; - Text m_text; NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); NazaraSlot(Nz::EventHandler, OnMouseButtonDoubleClicked, m_mouseButtonDoubleClickedSlot); NazaraSlot(Nz::EventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot); diff --git a/tests/Engine/Utility/EventHandler/MouseEnterState.cpp b/tests/Engine/Platform/EventHandler/MouseEnterState.cpp similarity index 78% rename from tests/Engine/Utility/EventHandler/MouseEnterState.cpp rename to tests/Engine/Platform/EventHandler/MouseEnterState.cpp index 2a13f1c1e..1eb2ca9e2 100644 --- a/tests/Engine/Utility/EventHandler/MouseEnterState.cpp +++ b/tests/Engine/Platform/EventHandler/MouseEnterState.cpp @@ -7,16 +7,13 @@ #include MouseEnterState::MouseEnterState(StateContext& context) : -State(), -m_context(context), -m_text(context) +BaseState(context) { } void MouseEnterState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -38,16 +35,6 @@ void MouseEnterState::Enter(Ndk::StateMachine& fsm) }); } -void MouseEnterState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool MouseEnterState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void MouseEnterState::DrawMenu() { m_text.SetContent("Move your mouse outside the windows, this text should change !\nM for Menu"); diff --git a/tests/Engine/Utility/EventHandler/MouseEnterState.hpp b/tests/Engine/Platform/EventHandler/MouseEnterState.hpp similarity index 54% rename from tests/Engine/Utility/EventHandler/MouseEnterState.hpp rename to tests/Engine/Platform/EventHandler/MouseEnterState.hpp index b5c7a72be..2328149ea 100644 --- a/tests/Engine/Utility/EventHandler/MouseEnterState.hpp +++ b/tests/Engine/Platform/EventHandler/MouseEnterState.hpp @@ -1,28 +1,20 @@ #ifndef __MOUSEENTERSTATE_HPP__ #define __MOUSEENTERSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; -class MouseEnterState : public Ndk::State +class MouseEnterState : public BaseState { public: MouseEnterState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: - void DrawMenu(); + void DrawMenu() override; - StateContext& m_context; - Text m_text; NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); NazaraSlot(Nz::EventHandler, OnMouseEntered, m_mouseEnteredSlot); NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot); diff --git a/tests/Engine/Utility/EventHandler/MouseMoveState.cpp b/tests/Engine/Platform/EventHandler/MouseMoveState.cpp similarity index 82% rename from tests/Engine/Utility/EventHandler/MouseMoveState.cpp rename to tests/Engine/Platform/EventHandler/MouseMoveState.cpp index 6a2cbd947..f0fcb3659 100644 --- a/tests/Engine/Utility/EventHandler/MouseMoveState.cpp +++ b/tests/Engine/Platform/EventHandler/MouseMoveState.cpp @@ -7,16 +7,13 @@ #include MouseMoveState::MouseMoveState(StateContext& context) : -State(), -m_context(context), -m_text(context) +BaseState(context) { } void MouseMoveState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -38,16 +35,6 @@ void MouseMoveState::Enter(Ndk::StateMachine& fsm) }); } -void MouseMoveState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool MouseMoveState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void MouseMoveState::DrawMenu() { m_text.SetContent("Move your mouse or your wheel, this text should change !\nM for Menu"); diff --git a/tests/Engine/Utility/EventHandler/MouseMoveState.hpp b/tests/Engine/Platform/EventHandler/MouseMoveState.hpp similarity index 54% rename from tests/Engine/Utility/EventHandler/MouseMoveState.hpp rename to tests/Engine/Platform/EventHandler/MouseMoveState.hpp index f94dc0998..9aade79f8 100644 --- a/tests/Engine/Utility/EventHandler/MouseMoveState.hpp +++ b/tests/Engine/Platform/EventHandler/MouseMoveState.hpp @@ -1,28 +1,20 @@ #ifndef __MOUSEMOVESTATE_HPP__ #define __MOUSEMOVESTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; -class MouseMoveState : public Ndk::State +class MouseMoveState : public BaseState { public: MouseMoveState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: - void DrawMenu(); + void DrawMenu() override; - StateContext& m_context; - Text m_text; NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); NazaraSlot(Nz::EventHandler, OnMouseMoved, m_mouseMovedSlot); NazaraSlot(Nz::EventHandler, OnMouseWheelMoved, m_mouseWheelMovedSlot); diff --git a/tests/Engine/Utility/EventHandler/StateContext.cpp b/tests/Engine/Platform/EventHandler/StateContext.cpp similarity index 100% rename from tests/Engine/Utility/EventHandler/StateContext.cpp rename to tests/Engine/Platform/EventHandler/StateContext.cpp diff --git a/tests/Engine/Utility/EventHandler/StateContext.hpp b/tests/Engine/Platform/EventHandler/StateContext.hpp similarity index 100% rename from tests/Engine/Utility/EventHandler/StateContext.hpp rename to tests/Engine/Platform/EventHandler/StateContext.hpp diff --git a/tests/Engine/Utility/EventHandler/StateFactory.cpp b/tests/Engine/Platform/EventHandler/StateFactory.cpp similarity index 100% rename from tests/Engine/Utility/EventHandler/StateFactory.cpp rename to tests/Engine/Platform/EventHandler/StateFactory.cpp diff --git a/tests/Engine/Utility/EventHandler/StateFactory.hpp b/tests/Engine/Platform/EventHandler/StateFactory.hpp similarity index 100% rename from tests/Engine/Utility/EventHandler/StateFactory.hpp rename to tests/Engine/Platform/EventHandler/StateFactory.hpp diff --git a/tests/Engine/Utility/EventHandler/Text.cpp b/tests/Engine/Platform/EventHandler/Text.cpp similarity index 90% rename from tests/Engine/Utility/EventHandler/Text.cpp rename to tests/Engine/Platform/EventHandler/Text.cpp index 75cece5b9..98637b276 100644 --- a/tests/Engine/Utility/EventHandler/Text.cpp +++ b/tests/Engine/Platform/EventHandler/Text.cpp @@ -11,7 +11,7 @@ Text::Text(StateContext& stateContext) : m_context(stateContext) { m_text = m_context.world.CreateEntity(); - Ndk::NodeComponent& nodeComponent = m_text->AddComponent(); + m_text->AddComponent(); Ndk::GraphicsComponent& graphicsComponent = m_text->AddComponent(); m_textSprite = Nz::TextSprite::New(); diff --git a/tests/Engine/Utility/EventHandler/Text.hpp b/tests/Engine/Platform/EventHandler/Text.hpp similarity index 100% rename from tests/Engine/Utility/EventHandler/Text.hpp rename to tests/Engine/Platform/EventHandler/Text.hpp diff --git a/tests/Engine/Utility/EventHandler/TextEnterState.cpp b/tests/Engine/Platform/EventHandler/TextEnterState.cpp similarity index 79% rename from tests/Engine/Utility/EventHandler/TextEnterState.cpp rename to tests/Engine/Platform/EventHandler/TextEnterState.cpp index 1a0516f29..2aa58da69 100644 --- a/tests/Engine/Utility/EventHandler/TextEnterState.cpp +++ b/tests/Engine/Platform/EventHandler/TextEnterState.cpp @@ -7,16 +7,13 @@ #include TextEnterState::TextEnterState(StateContext& context) : -State(), -m_context(context), -m_text(context) +BaseState(context) { } void TextEnterState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -36,16 +33,6 @@ void TextEnterState::Enter(Ndk::StateMachine& fsm) }); } -void TextEnterState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool TextEnterState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void TextEnterState::DrawMenu() { m_text.SetContent("Enter some text, this text should change !\nM for Menu"); diff --git a/tests/Engine/Platform/EventHandler/TextEnterState.hpp b/tests/Engine/Platform/EventHandler/TextEnterState.hpp new file mode 100644 index 000000000..ed193d204 --- /dev/null +++ b/tests/Engine/Platform/EventHandler/TextEnterState.hpp @@ -0,0 +1,22 @@ +#ifndef __TEXTENTERSTATE_HPP__ +#define __TEXTENTERSTATE_HPP__ + +#include "BaseState.hpp" + +class StateContext; + +class TextEnterState : public BaseState +{ + public: + TextEnterState(StateContext& stateContext); + + void Enter(Ndk::StateMachine& fsm) override; + + private: + void DrawMenu() override; + + NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); + NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot); +}; + +#endif // __TEXTENTERSTATE_HPP__ \ No newline at end of file diff --git a/tests/Engine/Utility/EventHandler/WindowModificationState.cpp b/tests/Engine/Platform/EventHandler/WindowModificationState.cpp similarity index 81% rename from tests/Engine/Utility/EventHandler/WindowModificationState.cpp rename to tests/Engine/Platform/EventHandler/WindowModificationState.cpp index e50d94f51..027185fe6 100644 --- a/tests/Engine/Utility/EventHandler/WindowModificationState.cpp +++ b/tests/Engine/Platform/EventHandler/WindowModificationState.cpp @@ -7,16 +7,13 @@ #include WindowModificationState::WindowModificationState(StateContext& context) : -State(), -m_context(context), -m_text(context) +BaseState(context) { } void WindowModificationState::Enter(Ndk::StateMachine& fsm) { - m_text.SetVisible(true); - DrawMenu(); + BaseState::Enter(fsm); Nz::EventHandler& eventHandler = m_context.window.GetEventHandler(); m_keyPressedSlot.Connect(eventHandler.OnKeyPressed, [&] (const Nz::EventHandler*, const Nz::WindowEvent::KeyEvent& key) @@ -38,16 +35,6 @@ void WindowModificationState::Enter(Ndk::StateMachine& fsm) }); } -void WindowModificationState::Leave(Ndk::StateMachine& /*fsm*/) -{ - m_text.SetVisible(false); -} - -bool WindowModificationState::Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) -{ - return true; -} - void WindowModificationState::DrawMenu() { m_text.SetContent("Move the window or resize it, this text should change !\nM for Menu"); diff --git a/tests/Engine/Utility/EventHandler/WindowModificationState.hpp b/tests/Engine/Platform/EventHandler/WindowModificationState.hpp similarity index 53% rename from tests/Engine/Utility/EventHandler/WindowModificationState.hpp rename to tests/Engine/Platform/EventHandler/WindowModificationState.hpp index 4fb84188d..fce207039 100644 --- a/tests/Engine/Utility/EventHandler/WindowModificationState.hpp +++ b/tests/Engine/Platform/EventHandler/WindowModificationState.hpp @@ -1,28 +1,20 @@ #ifndef __WINDOWMODIFICATIONSTATE_HPP__ #define __WINDOWMODIFICATIONSTATE_HPP__ -#include "Text.hpp" - -#include - -#include +#include "BaseState.hpp" class StateContext; -class WindowModificationState : public Ndk::State +class WindowModificationState : public BaseState { public: WindowModificationState(StateContext& stateContext); void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; private: - void DrawMenu(); + void DrawMenu() override; - StateContext& m_context; - Text m_text; NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); NazaraSlot(Nz::EventHandler, OnMoved, m_movedSlot); NazaraSlot(Nz::EventHandler, OnResized, m_resizedSlot); diff --git a/tests/Engine/Utility/EventHandler/TextEnterState.hpp b/tests/Engine/Utility/EventHandler/TextEnterState.hpp deleted file mode 100644 index c9137c51d..000000000 --- a/tests/Engine/Utility/EventHandler/TextEnterState.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __TEXTENTERSTATE_HPP__ -#define __TEXTENTERSTATE_HPP__ - -#include "Text.hpp" - -#include - -#include - -class StateContext; - -class TextEnterState : public Ndk::State -{ - public: - TextEnterState(StateContext& stateContext); - - void Enter(Ndk::StateMachine& fsm) override; - void Leave(Ndk::StateMachine& fsm) override; - bool Update(Ndk::StateMachine& fsm, float elapsedTime) override; - - private: - void DrawMenu(); - - StateContext& m_context; - Text m_text; - NazaraSlot(Nz::EventHandler, OnKeyPressed, m_keyPressedSlot); - NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot); -}; - -#endif // __TEXTENTERSTATE_HPP__ \ No newline at end of file diff --git a/tests/SDK/NDK/BaseSystem.cpp b/tests/SDK/NDK/BaseSystem.cpp index a202c1f70..3bb0fa9e4 100644 --- a/tests/SDK/NDK/BaseSystem.cpp +++ b/tests/SDK/NDK/BaseSystem.cpp @@ -38,7 +38,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]") WHEN("We add an entity") { - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); entity->AddComponent(); THEN("System should have it") @@ -50,7 +50,7 @@ SCENARIO("BaseSystem", "[NDK][BASESYSTEM]") WHEN("We add an entity with excluded component") { - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); entity->AddComponent(); entity->AddComponent(); diff --git a/tests/SDK/NDK/Entity.cpp b/tests/SDK/NDK/Entity.cpp index cf02370ec..dd3216fb0 100644 --- a/tests/SDK/NDK/Entity.cpp +++ b/tests/SDK/NDK/Entity.cpp @@ -57,18 +57,18 @@ SCENARIO("Entity", "[NDK][ENTITY]") { Ndk::World world; Ndk::BaseSystem& system = world.AddSystem(); - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); WHEN("We add our UpdateComponent") { UpdatableComponent& updatableComponent = entity->AddComponent(); - REQUIRE(!updatableComponent.IsUpdated()); + CHECK(!updatableComponent.IsUpdated()); THEN("Update the world should update the entity's component") { world.Update(1.f); UpdatableComponent& updatableComponentGet = entity->GetComponent(); - REQUIRE(updatableComponentGet.IsUpdated()); + CHECK(updatableComponentGet.IsUpdated()); } THEN("Update the world should not update the entity's component if it's disabled") @@ -76,14 +76,14 @@ SCENARIO("Entity", "[NDK][ENTITY]") entity->Enable(false); world.Update(1.f); UpdatableComponent& updatableComponentGet = entity->GetComponent(); - REQUIRE(!updatableComponentGet.IsUpdated()); + CHECK(!updatableComponentGet.IsUpdated()); } THEN("We can remove its component") { entity->RemoveComponent(Ndk::GetComponentIndex()); world.Update(1.f); - REQUIRE(!entity->HasComponent()); + CHECK(!entity->HasComponent()); } } @@ -94,7 +94,7 @@ SCENARIO("Entity", "[NDK][ENTITY]") THEN("It's no more valid") { - REQUIRE(!world.IsEntityValid(entity)); + CHECK(!world.IsEntityValid(entity)); } } } diff --git a/tests/SDK/NDK/EntityList.cpp b/tests/SDK/NDK/EntityList.cpp index 4b76766d5..30a57573d 100644 --- a/tests/SDK/NDK/EntityList.cpp +++ b/tests/SDK/NDK/EntityList.cpp @@ -16,8 +16,8 @@ SCENARIO("EntityList", "[NDK][ENTITYLIST]") THEN("These results are expected") { REQUIRE(entityList.Has(entity->GetId())); - const Ndk::EntityHandle& entity = world.CreateEntity(); - REQUIRE(!entityList.Has(entity->GetId())); + const Ndk::EntityHandle& newEntity = world.CreateEntity(); + REQUIRE(!entityList.Has(newEntity->GetId())); } } diff --git a/tests/SDK/NDK/EntityOwner.cpp b/tests/SDK/NDK/EntityOwner.cpp index eb9a29edf..f2fd76d58 100644 --- a/tests/SDK/NDK/EntityOwner.cpp +++ b/tests/SDK/NDK/EntityOwner.cpp @@ -7,7 +7,7 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]") GIVEN("A world & an entity") { Ndk::World world; - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); WHEN("We set the ownership of the entity to our owner") { @@ -15,13 +15,21 @@ SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]") THEN("Entity is still valid") { - REQUIRE(entity.IsValid()); + CHECK(entity.IsValid()); } THEN("Resetting or getting out of scope is no more valid") { entityOwner.Reset(); world.Update(1.f); + CHECK(!entity.IsValid()); + } + + THEN("Moving an entity owner works") + { + Ndk::EntityOwner entityOwner2(std::move(entityOwner)); + entityOwner2.Reset(); + world.Update(1.f); REQUIRE(!entity.IsValid()); } } diff --git a/tests/SDK/NDK/StateMachine.cpp b/tests/SDK/NDK/StateMachine.cpp index 1c14b1e76..066a150d7 100644 --- a/tests/SDK/NDK/StateMachine.cpp +++ b/tests/SDK/NDK/StateMachine.cpp @@ -28,21 +28,79 @@ class TestState : public Ndk::State bool m_isUpdated; }; +class SecondTestState : public Ndk::State +{ + public: + void Enter(Ndk::StateMachine& /*fsm*/) override + { + m_isUpdated = false; + } + + bool IsUpdated() const + { + return m_isUpdated; + } + + void Leave(Ndk::StateMachine& /*fsm*/) override + { + } + + bool Update(Ndk::StateMachine& fsm, float /*elapsedTime*/) override + { + if (fsm.IsTopState(this)) + m_isUpdated = true; + return true; + } + + private: + bool m_isUpdated; +}; + SCENARIO("State & StateMachine", "[NDK][STATE]") { - GIVEN("A statemachine with our TestState") + GIVEN("A statemachine with our test states") { std::shared_ptr testState = std::make_shared(); - Ndk::StateMachine stateMachine(testState); + std::shared_ptr secondTestState = std::make_shared(); + Ndk::StateMachine stateMachine(secondTestState); + stateMachine.PushState(testState); REQUIRE(!testState->IsUpdated()); + REQUIRE(!secondTestState->IsUpdated()); WHEN("We update our machine") { stateMachine.Update(1.f); - THEN("Our state has been updated") + THEN("Our state on the top has been updated but not the bottom one") { + REQUIRE(stateMachine.IsTopState(testState.get())); + REQUIRE(!stateMachine.IsTopState(secondTestState.get())); + REQUIRE(testState->IsUpdated()); + REQUIRE(!secondTestState->IsUpdated()); + } + } + + WHEN("We exchange the states' positions while emptying the stack") + { + REQUIRE(stateMachine.PopStatesUntil(secondTestState)); + REQUIRE(stateMachine.IsTopState(secondTestState.get())); + + std::shared_ptr 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()); } } } diff --git a/tests/SDK/NDK/Systems/ListenerSystem.cpp b/tests/SDK/NDK/Systems/ListenerSystem.cpp index 2792dbc25..b83b24cd1 100644 --- a/tests/SDK/NDK/Systems/ListenerSystem.cpp +++ b/tests/SDK/NDK/Systems/ListenerSystem.cpp @@ -11,7 +11,7 @@ SCENARIO("ListenerSystem", "[NDK][LISTENERSYSTEM]") GIVEN("A world and an entity with listener & node components") { Ndk::World world; - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); Ndk::ListenerComponent& listenerComponent = entity->AddComponent(); Ndk::NodeComponent& nodeComponent = entity->AddComponent(); diff --git a/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp new file mode 100644 index 000000000..0dc944130 --- /dev/null +++ b/tests/SDK/NDK/Systems/PhysicsSystem2D.cpp @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include + +Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf AABB); + +SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]") +{ + GIVEN("A world and an entity") + { + Ndk::World world; + + Nz::Vector2f position(2.f, 3.f); + Nz::Rectf movingAABB(0.f, 0.f, 16.f, 18.f); + Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB); + Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent(); + Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent(); + + WHEN("We update the world") + { + world.Update(1.f); + + THEN("Entity should have correct bounding box") + { + REQUIRE(nodeComponent.GetPosition() == position); + movingAABB.Translate(position); + REQUIRE(physicsComponent2D.GetAABB() == movingAABB); + } + } + + WHEN("We make it collide with a wall") + { + int rawDistance = 3; + Nz::Vector2f distance(rawDistance, 0.f); + Nz::Vector2f wallPosition = position + Nz::Vector2f(movingAABB.width, 0.f) + distance; + Nz::Rectf wallAABB(0.f, 0.f, 100.f, 100.f); + Ndk::EntityHandle wallEntity = CreateBaseEntity(world, wallPosition, wallAABB); + + world.Update(1.f); + + THEN("It should moved freely") + { + REQUIRE(nodeComponent.GetPosition() == position); + movingAABB.Translate(position); + REQUIRE(physicsComponent2D.GetAABB() == movingAABB); + + physicsComponent2D.SetVelocity(Nz::Vector2f::UnitX()); + + for (int i = 0; i < rawDistance; ++i) + { + world.Update(1.f); + position += Nz::Vector2f::UnitX(); + REQUIRE(nodeComponent.GetPosition() == position); + movingAABB.Translate(Nz::Vector2f::UnitX()); + REQUIRE(physicsComponent2D.GetAABB() == movingAABB); + } + } + + AND_THEN("It should be stopped by it") + { + world.Update(1.f); + REQUIRE(nodeComponent.GetPosition().SquaredDistance(position) < 0.1f); + } + } + } + + GIVEN("A world and a simple entity") + { + Ndk::World world; + + Nz::Vector2f position(0.f, 0.f); + Nz::Rectf movingAABB(0.f, 0.f, 1.f, 2.f); + Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB); + Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent(); + Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent(); + + WHEN("We make rotate our entity") + { + float angularSpeed = Nz::FromDegrees(45.f); + physicsComponent2D.SetAngularVelocity(angularSpeed); + world.Update(2.f); + + THEN("It should have been rotated") + { + CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(-2.f, 0.f, 2.f, 1.f)); + CHECK(physicsComponent2D.GetRotation() == Approx(Nz::FromDegrees(90.f))); + CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(90.f))); + } + } + + WHEN("We put a force on it") + { + float stepSize = world.GetSystem().GetWorld().GetStepSize(); + Nz::Vector2f velocity = Nz::Vector2f::UnitX(); + physicsComponent2D.AddForce(velocity / stepSize); + world.Update(1.f); + + THEN("Velocity should be the one targetted") + { + REQUIRE(physicsComponent2D.GetVelocity() == velocity); + world.Update(99.f); + REQUIRE(physicsComponent2D.GetPosition().Distance(Nz::Vector2f::UnitX() * 100.f) < 1.f); + REQUIRE(nodeComponent.GetPosition().Distance(Nz::Vector2f::UnitX() * 100.f) < 1.f); + } + } + } + + GIVEN("A world and a simple entity not at the origin") + { + Ndk::World world; + + Nz::Vector2f position(3.f, 4.f); + Nz::Rectf movingAABB(0.f, 0.f, 1.f, 2.f); + Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB); + Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent(); + Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent(); + + WHEN("We make rotate our entity") + { + float angularSpeed = Nz::FromDegrees(45.f); + physicsComponent2D.SetAngularVelocity(angularSpeed); + world.Update(2.f); + + THEN("It should have been rotated") + { + CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(1.f, 4.f, 2.f, 1.f)); + CHECK(physicsComponent2D.GetRotation() == Approx(Nz::FromDegrees(90.f))); + CHECK(nodeComponent.GetPosition() == position); + CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(90.f))); + } + } + } +} + +Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf AABB) +{ + Ndk::EntityHandle entity = world.CreateEntity(); + Ndk::NodeComponent& nodeComponent = entity->AddComponent(); + nodeComponent.SetPosition(position); + Nz::BoxCollider2DRef collisionBox = Nz::BoxCollider2D::New(AABB); + entity->AddComponent(collisionBox); + return entity; +} diff --git a/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp b/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp index 3cb0d6bdb..b66aa89b7 100644 --- a/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp +++ b/tests/SDK/NDK/Systems/PhysicsSystem3D.cpp @@ -5,7 +5,7 @@ #include #include -SCENARIO("PhysicsSystem", "[NDK][PHYSICSSYSTEM]") +SCENARIO("PhysicsSystem3D", "[NDK][PHYSICSSYSTEM3D]") { GIVEN("A world and a static entity & a dynamic entity") { diff --git a/tests/SDK/NDK/Systems/RenderSystem.cpp b/tests/SDK/NDK/Systems/RenderSystem.cpp index f106b3aae..ed0244806 100644 --- a/tests/SDK/NDK/Systems/RenderSystem.cpp +++ b/tests/SDK/NDK/Systems/RenderSystem.cpp @@ -1,13 +1,11 @@ #include #include -#include -#include -#include -#include -#include +#include #include #include +void CompareAABB(const Nz::Rectf& aabb, const Nz::BoundingVolumef& boundingVolume); + SCENARIO("RenderSystem", "[NDK][RenderSystem]") { GIVEN("A world with a camera, a drawable, a light and some particles") @@ -41,4 +39,79 @@ SCENARIO("RenderSystem", "[NDK][RenderSystem]") } } } + + GIVEN("A world with 2D coordinates (upper-left) and an entity with graphics and physics") + { + Ndk::World world; + world.GetSystem().SetGlobalUp(Nz::Vector3f::Down()); + const Ndk::EntityHandle& entity = world.CreateEntity(); + + Nz::Vector2f position(3.f, 4.f); + Ndk::NodeComponent& nodeComponent = entity->AddComponent(); + nodeComponent.SetPosition(position); + + Nz::Vector2f dimensions(1.f, 2.f); + Ndk::GraphicsComponent& graphicsComponent = entity->AddComponent(); + Nz::SpriteRef sprite = Nz::Sprite::New(); + sprite->SetSize(dimensions); + graphicsComponent.Attach(sprite); + + Nz::Rectf aabb(Nz::Vector2f::Zero(), dimensions); + Nz::BoxCollider2DRef boxCollider2D = Nz::BoxCollider2D::New(aabb); + entity->AddComponent(boxCollider2D); + Ndk::PhysicsComponent2D& physicsComponent2D = entity->AddComponent(); + + world.Update(1.f); + + WHEN("We move it") + { + Nz::Vector2f velocity = Nz::Vector2f::UnitY(); + physicsComponent2D.SetVelocity(velocity); + world.Update(1.f); + + THEN("Graphics and physics should be synchronised") + { + CHECK(nodeComponent.GetPosition() == position + velocity); + CHECK(physicsComponent2D.GetAABB() == aabb.Translate(position + velocity)); + CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume()); + } + } + + WHEN("We set an angular velocity") + { + float angularSpeed = Nz::FromDegrees(90.f); + physicsComponent2D.SetAngularVelocity(angularSpeed); + world.Update(1.f); + + THEN("We expect those to be true") + { + CHECK(physicsComponent2D.GetAngularVelocity() == Approx(angularSpeed)); + CHECK(physicsComponent2D.GetRotation() == Approx(angularSpeed)); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(1.f, 4.f, 2.f, 1.f)); + CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume()); + + world.Update(1.f); + CHECK(physicsComponent2D.GetRotation() == Approx(2.f * angularSpeed)); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(2.f, 2.f, 1.f, 2.f)); + CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume()); + + world.Update(1.f); + CHECK(physicsComponent2D.GetRotation() == Approx(3.f * angularSpeed)); + CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(3.f, 3.f, 2.f, 1.f)); + CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume()); + + world.Update(1.f); + CHECK(physicsComponent2D.GetRotation() == Approx(4.f * angularSpeed)); + } + } + } +} + +void CompareAABB(const Nz::Rectf& aabb, const Nz::BoundingVolumef& boundingVolume) +{ + Nz::Boxf box = boundingVolume.aabb; + CHECK(aabb.x == Approx(box.x)); + CHECK(aabb.y == Approx(box.y)); + CHECK(aabb.width == Approx(box.width)); + CHECK(aabb.height == Approx(box.height)); } \ No newline at end of file diff --git a/tests/SDK/NDK/World.cpp b/tests/SDK/NDK/World.cpp index 85ee241b4..d46b6621b 100644 --- a/tests/SDK/NDK/World.cpp +++ b/tests/SDK/NDK/World.cpp @@ -79,7 +79,7 @@ SCENARIO("World", "[NDK][WORLD]") AND_WHEN("We update our world with our entity") { REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem()); - const Ndk::EntityHandle& entity = world.CreateEntity(); + Ndk::EntityHandle entity = world.CreateEntity(); UpdatableComponent& component = entity->AddComponent(); THEN("Our entity component must be updated")