diff --git a/ChangeLog.md b/ChangeLog.md index c87390157..d85eb5164 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -15,6 +15,7 @@ Miscellaneous: - Fix compilation with some MinGW distributions - Add Lua unit tests - NDEBUG is now defined in Release +- Replaced typedefs keywords with modern using keywords Nazara Engine: - VertexMapper:GetComponentPtr no longer throw an error if component is disabled or incompatible with template type, instead a null pointer is returned. @@ -66,6 +67,33 @@ Nazara Engine: - Add PhysWorld2D::[Get|Set]IterationCount to control how many iterations chipmunk will perform per step. - Add PhysWorld2D::UseSpatialHash to use spatial hashing instead of bounding box trees, which may speedup simulation in some cases. - Add PhysWorld[2D|3D] max step count per Step call (default: 50), to avoid spirals of death when the physics engine simulation time is over step size. +- Fix Window triggering KeyPressed event after triggering a resize/movement event on Windows +- (WIP) Add support for materials and callbacks to Physics3D module. +- PhysWorld3D class is now movable +- ⚠️ Removed array/pointer constructor from Vector classes +- Fixed Platform module not being classified as client-only +- ⚠️ Renamed Bitset::Read to Bitset::Write +- Fixed ENetCompressor class destructor not being virtual +- ⚠️ Added a type tag parameter to Serialize and Unserialize functions, to prevent implicit conversions with overloads +- Added Collider3D::ForEachPolygon method, allowing construction of a debug mesh based on the physics collider +- Fixed ConvexCollider3D::GetType returning Compound instead of ConvexHull. +- Dual-stack sockets are now supported (by using NetProtocol_Any at creation/opening) +- Fixed IPv6 addresses not being correctly encoded/decoded from the socket API. +- Fix copy and move semantic on HandledObject and ObjectHandle +- Add support for emissive and normal maps in .mtl loader using custom keywords ([map_]emissive and [map_]normal) +- Music, Sound and SoundEmitter are now movable +- Fixed Sound copy which was not copying looping state +- Fixed Billboard bounding volume +- Fixed Directory::GetResultSize and Directory::IsResultDirectory on Posix systems +- Fixed Quaternion::Inverse which was not correctly normalizing quaternions +- Graphics module now register "White2D" and "WhiteCubemap" textures to the TextureLibrary (respectively a 1x1 texture 2D and a 1x1 texture cubemap) +- Added AbstractTextDrawer::GetLineGlyphCount, which returns the number of glyph part of the line +- Fixed Font handling of whitespace glyphs (which were triggering an error) +- ⚠️ Translucent2D pipeline no longer has depth sorting +- Fixed SimpleTextDrawer line bounds +- ⚠️ Stream::ReadLine will now returns empty lines if present in the file +- Fixed cubemaps seams with OpenGL +- HandledObject movement constructor/assignement operator are now marked noexcept Nazara Development Kit: - Added ImageWidget (#139) @@ -101,6 +129,19 @@ Nazara Development Kit: - ⚠️ Renamed World::Update() to World::Refresh() for more clarity and to differentiate it from World::Update(elapsedTime) - World entity ids are now reused from lowest to highest (they were previously reused in reverse order of death) - World now has an internal profiler, allowing to measure the refresh and system update time +- CollisionComponent[2D|3D] and PhysicsComponent[2D|3D] now configures their internal RigidBody userdata to the entity ID they belong to (useful for callbacks). +- Fixed EntityList copy/movement assignment operator which was not properly unregistering contained entities. +- ListenerSystem now handles velocity in a generic way (no longer require a VelocityComponent and is compatible with physics) +- World now has const getters for systems +- Add World::ForEachSystem method, allowing iteration on every active system on a specific world +- Fix GraphicsComponent bounding volume not taking local matrix in account +- ⚠️ Rewrote all render queue system, which should be more efficient, take scissor box into account +- ⚠️ All widgets are now bound to a scissor box when rendering +- Add DebugComponent (a component able to show aabb/obb/collision mesh) +- ⚠️ TextAreaWidget now support text selection (WIP) +- ⚠️ TextAreaWidget::GetHoveredGlyph now returns a two-dimensional position instead of a single glyph position +- Fixed Entity::OnEntityDestruction signal not being properly moved and thus not being called. +- Fixed EntityOwner move assignment which was losing entity ownership # 0.4: diff --git a/SDK/include/NDK/BaseWidget.hpp b/SDK/include/NDK/BaseWidget.hpp index 0804a5191..a8c3e5cd4 100644 --- a/SDK/include/NDK/BaseWidget.hpp +++ b/SDK/include/NDK/BaseWidget.hpp @@ -83,9 +83,10 @@ namespace Ndk }; protected: - const EntityHandle& CreateEntity(); + const EntityHandle& CreateEntity(bool isContentEntity); void DestroyEntity(Entity* entity); virtual void Layout(); + void InvalidateNode() override; virtual bool IsFocusable() const; @@ -111,11 +112,18 @@ namespace Ndk void RegisterToCanvas(); inline void UpdateCanvasIndex(std::size_t index); void UnregisterFromCanvas(); + void UpdatePositionAndSize(); + + struct WidgetEntity + { + EntityOwner handle; + bool isContent; + }; static constexpr std::size_t InvalidCanvasIndex = std::numeric_limits::max(); std::size_t m_canvasIndex; - std::vector m_entities; + std::vector m_entities; std::vector> m_children; Canvas* m_canvas; EntityOwner m_backgroundEntity; diff --git a/SDK/include/NDK/Canvas.inl b/SDK/include/NDK/Canvas.inl index 251a09fbc..7ac84a45d 100644 --- a/SDK/include/NDK/Canvas.inl +++ b/SDK/include/NDK/Canvas.inl @@ -62,7 +62,7 @@ namespace Ndk WidgetEntry& entry = m_widgetEntries[index]; Nz::Vector3f pos = entry.widget->GetPosition(); - Nz::Vector2f size = entry.widget->GetContentSize(); + Nz::Vector2f size = entry.widget->GetSize(); entry.box.Set(pos.x, pos.y, pos.z, size.x, size.y, 1.f); } diff --git a/SDK/include/NDK/Components.hpp b/SDK/include/NDK/Components.hpp index e099b641b..97c15fc7c 100644 --- a/SDK/include/NDK/Components.hpp +++ b/SDK/include/NDK/Components.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -17,6 +19,5 @@ #include #include #include -#include #endif // NDK_COMPONENTS_GLOBAL_HPP diff --git a/SDK/include/NDK/Components/DebugComponent.hpp b/SDK/include/NDK/Components/DebugComponent.hpp new file mode 100644 index 000000000..85e868b5a --- /dev/null +++ b/SDK/include/NDK/Components/DebugComponent.hpp @@ -0,0 +1,80 @@ +// 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 Prerequisites.hpp + +#pragma once + +#ifndef NDK_SERVER +#ifndef NDK_COMPONENTS_DEBUGCOMPONENT_HPP +#define NDK_COMPONENTS_DEBUGCOMPONENT_HPP + +#include +#include +#include + +namespace Ndk +{ + enum class DebugDraw + { + //TODO: Collider2D + Collider3D, + GraphicsAABB, + GraphicsOBB, + + Max = GraphicsOBB + }; +} + +namespace Nz +{ + template<> + struct EnumAsFlags + { + static constexpr Ndk::DebugDraw max = Ndk::DebugDraw::GraphicsOBB; + }; +} + +namespace Ndk +{ + using DebugDrawFlags = Nz::Flags; + + constexpr DebugDrawFlags DebugDraw_None = 0; + + class NDK_API DebugComponent : public Component + { + friend class DebugSystem; + + public: + inline DebugComponent(DebugDrawFlags flags = DebugDraw_None); + inline DebugComponent(const DebugComponent& debug); + ~DebugComponent() = default; + + inline void Disable(DebugDrawFlags flags); + inline void Enable(DebugDrawFlags flags); + + inline DebugDrawFlags GetFlags() const; + + inline bool IsEnabled(DebugDrawFlags flags) const; + + inline DebugComponent& operator=(const DebugComponent& debug); + + static ComponentIndex componentIndex; + + private: + inline const Nz::InstancedRenderableRef& GetDebugRenderable(DebugDraw option) const; + inline DebugDrawFlags GetEnabledFlags() const; + inline void UpdateDebugRenderable(DebugDraw option, Nz::InstancedRenderableRef renderable); + inline void UpdateEnabledFlags(DebugDrawFlags flags); + + static constexpr std::size_t DebugModeCount = static_cast(DebugDraw::Max) + 1; + + std::array m_debugRenderables; + DebugDrawFlags m_enabledFlags; + DebugDrawFlags m_flags; + }; +} + +#include + +#endif // NDK_COMPONENTS_DEBUGCOMPONENT_HPP +#endif // NDK_SERVER diff --git a/SDK/include/NDK/Components/DebugComponent.inl b/SDK/include/NDK/Components/DebugComponent.inl new file mode 100644 index 000000000..e0f42a560 --- /dev/null +++ b/SDK/include/NDK/Components/DebugComponent.inl @@ -0,0 +1,74 @@ +// 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 Prerequisites.hpp + +#include + +namespace Ndk +{ + inline DebugComponent::DebugComponent(DebugDrawFlags flags) : + m_flags(flags) + { + } + + inline DebugComponent::DebugComponent(const DebugComponent& debug) : + m_flags(debug.m_flags) + { + } + + inline void DebugComponent::Disable(DebugDrawFlags flags) + { + m_flags &= ~flags; + + if (m_entity) + m_entity->Invalidate(); + } + + inline void DebugComponent::Enable(DebugDrawFlags flags) + { + m_flags |= flags; + + if (m_entity) + m_entity->Invalidate(); + } + + inline DebugDrawFlags DebugComponent::GetFlags() const + { + return m_flags; + } + + inline bool DebugComponent::IsEnabled(DebugDrawFlags flags) const + { + return (m_flags & flags) == flags; + } + + inline DebugComponent& DebugComponent::operator=(const DebugComponent& debug) + { + m_flags = debug.m_flags; + + if (m_entity) + m_entity->Invalidate(); + + return *this; + } + + inline const Nz::InstancedRenderableRef& DebugComponent::GetDebugRenderable(DebugDraw option) const + { + return m_debugRenderables[static_cast(option)]; + } + + inline DebugDrawFlags DebugComponent::GetEnabledFlags() const + { + return m_enabledFlags; + } + + inline void DebugComponent::UpdateDebugRenderable(DebugDraw option, Nz::InstancedRenderableRef renderable) + { + m_debugRenderables[static_cast(option)] = std::move(renderable); + } + + inline void DebugComponent::UpdateEnabledFlags(DebugDrawFlags flags) + { + m_enabledFlags = flags; + } +} diff --git a/SDK/include/NDK/Components/GraphicsComponent.hpp b/SDK/include/NDK/Components/GraphicsComponent.hpp index cd6b90c8c..e5dce0144 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.hpp +++ b/SDK/include/NDK/Components/GraphicsComponent.hpp @@ -28,7 +28,7 @@ namespace Ndk public: using RenderableList = std::vector; - GraphicsComponent() = default; + GraphicsComponent(); inline GraphicsComponent(const GraphicsComponent& graphicsComponent); ~GraphicsComponent() = default; @@ -54,6 +54,8 @@ namespace Ndk inline void RemoveFromCullingList(GraphicsComponentCullingList* cullingList) const; + inline void SetScissorRect(const Nz::Recti& scissorRect); + inline void UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix); inline void UpdateRenderOrder(const Nz::InstancedRenderable* instancedRenderable, int renderOrder); @@ -144,6 +146,7 @@ namespace Ndk std::unordered_map m_materialEntries; mutable Nz::BoundingVolumef m_boundingVolume; mutable Nz::Matrix4f m_transformMatrix; + Nz::Recti m_scissorRect; Nz::TextureRef m_reflectionMap; mutable bool m_boundingVolumeUpdated; mutable bool m_transformMatrixUpdated; diff --git a/SDK/include/NDK/Components/GraphicsComponent.inl b/SDK/include/NDK/Components/GraphicsComponent.inl index da8764d73..71b62f367 100644 --- a/SDK/include/NDK/Components/GraphicsComponent.inl +++ b/SDK/include/NDK/Components/GraphicsComponent.inl @@ -9,12 +9,16 @@ namespace Ndk { + inline GraphicsComponent::GraphicsComponent() : + m_scissorRect(-1, -1) + { + } + /*! * \brief Constructs a GraphicsComponent object by copy semantic * * \param graphicsComponent GraphicsComponent to copy */ - inline GraphicsComponent::GraphicsComponent(const GraphicsComponent& graphicsComponent) : Component(graphicsComponent), HandledObject(graphicsComponent), @@ -177,6 +181,14 @@ namespace Ndk } } + inline void GraphicsComponent::SetScissorRect(const Nz::Recti& scissorRect) + { + m_scissorRect = scissorRect; + + for (VolumeCullingEntry& entry : m_volumeCullingEntries) + entry.listEntry.ForceInvalidation(); //< Invalidate render queues + } + inline void GraphicsComponent::UpdateLocalMatrix(const Nz::InstancedRenderable* instancedRenderable, const Nz::Matrix4f& localMatrix) { for (auto& renderable : m_renderables) diff --git a/SDK/include/NDK/Entity.hpp b/SDK/include/NDK/Entity.hpp index 2bf6b6dad..355028fef 100644 --- a/SDK/include/NDK/Entity.hpp +++ b/SDK/include/NDK/Entity.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,7 @@ namespace Ndk public: Entity(const Entity&) = delete; - Entity(Entity&& entity); + Entity(Entity&& entity) noexcept; ~Entity(); BaseComponent& AddComponent(std::unique_ptr&& component); @@ -96,8 +97,8 @@ namespace Ndk Nz::Bitset<> m_componentBits; Nz::Bitset<> m_removedComponentBits; Nz::Bitset<> m_systemBits; + Nz::MovablePtr m_world; EntityId m_id; - World* m_world; bool m_enabled; bool m_valid; }; diff --git a/SDK/include/NDK/EntityList.inl b/SDK/include/NDK/EntityList.inl index ce77c1238..a34165a68 100644 --- a/SDK/include/NDK/EntityList.inl +++ b/SDK/include/NDK/EntityList.inl @@ -169,6 +169,9 @@ namespace Ndk inline EntityList& EntityList::operator=(const EntityList& entityList) { + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + m_entityBits = entityList.m_entityBits; m_world = entityList.m_world; @@ -180,6 +183,12 @@ namespace Ndk inline EntityList& EntityList::operator=(EntityList&& entityList) noexcept { + if (this == &entityList) + return *this; + + for (const Ndk::EntityHandle& entity : *this) + entity->UnregisterEntityList(this); + m_entityBits = std::move(entityList.m_entityBits); m_world = entityList.m_world; diff --git a/SDK/include/NDK/EntityOwner.hpp b/SDK/include/NDK/EntityOwner.hpp index 4dca6010c..fb32f0780 100644 --- a/SDK/include/NDK/EntityOwner.hpp +++ b/SDK/include/NDK/EntityOwner.hpp @@ -25,7 +25,7 @@ namespace Ndk EntityOwner& operator=(Entity* entity); EntityOwner& operator=(const EntityOwner& handle) = delete; - EntityOwner& operator=(EntityOwner&& handle) noexcept = default; + EntityOwner& operator=(EntityOwner&& handle) noexcept; }; } diff --git a/SDK/include/NDK/EntityOwner.inl b/SDK/include/NDK/EntityOwner.inl index a1e28bc2a..566962fb0 100644 --- a/SDK/include/NDK/EntityOwner.inl +++ b/SDK/include/NDK/EntityOwner.inl @@ -31,7 +31,6 @@ namespace Ndk * * \see Reset */ - inline EntityOwner::~EntityOwner() { Reset(nullptr); @@ -68,13 +67,26 @@ namespace Ndk * * \param entity Entity to own */ - inline EntityOwner& EntityOwner::operator=(Entity* entity) { Reset(entity); return *this; } + + /*! + * \brief Steals ownership of a EntityOwner + * + * \param handle Handle to the new entity to own, or an invalid handle + */ + inline EntityOwner& EntityOwner::operator=(EntityOwner&& handle) noexcept + { + Reset(); //< Kill previously owned entity, if any + + EntityHandle::operator=(std::move(handle)); + + return *this; + } } namespace std diff --git a/SDK/include/NDK/Systems.hpp b/SDK/include/NDK/Systems.hpp index a0ee23e77..80571ef45 100644 --- a/SDK/include/NDK/Systems.hpp +++ b/SDK/include/NDK/Systems.hpp @@ -5,6 +5,7 @@ #ifndef NDK_SYSTEMS_GLOBAL_HPP #define NDK_SYSTEMS_GLOBAL_HPP +#include #include #include #include diff --git a/SDK/include/NDK/Systems/DebugSystem.hpp b/SDK/include/NDK/Systems/DebugSystem.hpp new file mode 100644 index 000000000..940feb782 --- /dev/null +++ b/SDK/include/NDK/Systems/DebugSystem.hpp @@ -0,0 +1,51 @@ +// 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 Prerequisites.hpp + +#pragma once + +#ifndef NDK_SERVER +#ifndef NDK_SYSTEMS_DEBUGSYSTEM_HPP +#define NDK_SYSTEMS_DEBUGSYSTEM_HPP + +#include +#include +#include +#include +#include + +namespace Ndk +{ + class NDK_API DebugSystem : public System + { + public: + DebugSystem(); + ~DebugSystem() = default; + + static SystemIndex systemIndex; + + private: + Nz::InstancedRenderableRef GenerateBox(Nz::Boxf box); + Nz::InstancedRenderableRef GenerateCollision3DMesh(Entity* entity); + + Nz::MaterialRef GetAABBMaterial(); + Nz::MaterialRef GetCollisionMaterial(); + Nz::MaterialRef GetOBBMaterial(); + std::pair GetBoxMesh(); + + void OnEntityValidation(Entity* entity, bool justAdded) override; + + void OnUpdate(float elapsedTime) override; + + Nz::MaterialRef m_aabbMaterial; + Nz::MaterialRef m_collisionMaterial; + Nz::MaterialRef m_obbMaterial; + Nz::IndexBufferRef m_boxMeshIndexBuffer; + Nz::VertexBufferRef m_boxMeshVertexBuffer; + }; +} + +#include + +#endif // NDK_SYSTEMS_DEBUGSYSTEM_HPP +#endif // NDK_SERVER diff --git a/SDK/include/NDK/Systems/DebugSystem.inl b/SDK/include/NDK/Systems/DebugSystem.inl new file mode 100644 index 000000000..b7439fc12 --- /dev/null +++ b/SDK/include/NDK/Systems/DebugSystem.inl @@ -0,0 +1,6 @@ +// 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 Prerequisites.hpp + +#include + diff --git a/SDK/include/NDK/Widgets/LabelWidget.hpp b/SDK/include/NDK/Widgets/LabelWidget.hpp index 5cb01b92a..f4f43bf1e 100644 --- a/SDK/include/NDK/Widgets/LabelWidget.hpp +++ b/SDK/include/NDK/Widgets/LabelWidget.hpp @@ -28,7 +28,7 @@ namespace Ndk //virtual LabelWidget* Clone() const = 0; - void ResizeToContent(); + void ResizeToContent() override; inline void UpdateText(const Nz::AbstractTextDrawer& drawer); @@ -36,6 +36,8 @@ namespace Ndk LabelWidget& operator=(LabelWidget&&) = default; private: + void Layout() override; + EntityHandle m_textEntity; Nz::TextSpriteRef m_textSprite; }; diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.hpp b/SDK/include/NDK/Widgets/TextAreaWidget.hpp index e0f08053e..e7cdc2f7a 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.hpp +++ b/SDK/include/NDK/Widgets/TextAreaWidget.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace Ndk { @@ -30,15 +31,20 @@ namespace Ndk inline void EnableMultiline(bool enable = true); + void EraseSelection(); + inline unsigned int GetCharacterSize() const; inline const Nz::Vector2ui& GetCursorPosition() const; + inline Nz::Vector2ui GetCursorPosition(std::size_t glyphIndex) const; inline const Nz::String& GetDisplayText() const; inline EchoMode GetEchoMode() const; inline std::size_t GetGlyphIndex(const Nz::Vector2ui& cursorPosition); inline const Nz::String& GetText() const; inline const Nz::Color& GetTextColor() const; - std::size_t GetHoveredGlyph(float x, float y) const; + Nz::Vector2ui GetHoveredGlyph(float x, float y) const; + + inline bool HasSelection() const; inline bool IsMultilineEnabled() const; inline bool IsReadOnly() const; @@ -53,6 +59,7 @@ namespace Ndk inline void SetCursorPosition(Nz::Vector2ui cursorPosition); inline void SetEchoMode(EchoMode echoMode); inline void SetReadOnly(bool readOnly = true); + inline void SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition); inline void SetText(const Nz::String& text); inline void SetTextColor(const Nz::Color& text); @@ -64,6 +71,8 @@ namespace Ndk NazaraSignal(OnTextAreaCursorMove, const TextAreaWidget* /*textArea*/, std::size_t* /*newCursorPosition*/); NazaraSignal(OnTextAreaKeyBackspace, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyDown, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); + NazaraSignal(OnTextAreaKeyEnd, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); + NazaraSignal(OnTextAreaKeyHome, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyLeft, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyReturn, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); NazaraSignal(OnTextAreaKeyRight, const TextAreaWidget* /*textArea*/, bool* /*ignoreDefaultAction*/); @@ -79,6 +88,9 @@ namespace Ndk bool OnKeyPressed(const Nz::WindowEvent::KeyEvent& key) override; void OnKeyReleased(const Nz::WindowEvent::KeyEvent& key) override; void OnMouseButtonPress(int /*x*/, int /*y*/, Nz::Mouse::Button button) override; + void OnMouseButtonRelease(int /*x*/, int /*y*/, Nz::Mouse::Button button) override; + void OnMouseEnter() override; + void OnMouseMoved(int x, int y, int deltaX, int deltaY) override; void OnTextEntered(char32_t character, bool repeated) override; void RefreshCursor(); @@ -88,10 +100,13 @@ namespace Ndk EntityHandle m_cursorEntity; EntityHandle m_textEntity; Nz::SimpleTextDrawer m_drawer; - Nz::SpriteRef m_cursorSprite; Nz::String m_text; Nz::TextSpriteRef m_textSprite; - Nz::Vector2ui m_cursorPosition; + Nz::Vector2ui m_cursorPositionBegin; + Nz::Vector2ui m_cursorPositionEnd; + Nz::Vector2ui m_selectionCursor; + std::vector m_cursorSprites; + bool m_isMouseButtonDown; bool m_multiLineEnabled; bool m_readOnly; }; diff --git a/SDK/include/NDK/Widgets/TextAreaWidget.inl b/SDK/include/NDK/Widgets/TextAreaWidget.inl index 07daf7896..274d46a02 100644 --- a/SDK/include/NDK/Widgets/TextAreaWidget.inl +++ b/SDK/include/NDK/Widgets/TextAreaWidget.inl @@ -8,7 +8,8 @@ namespace Ndk { inline void TextAreaWidget::Clear() { - m_cursorPosition.MakeZero(); + m_cursorPositionBegin.MakeZero(); + m_cursorPositionEnd.MakeZero(); m_drawer.Clear(); m_text.Clear(); m_textSprite->Update(m_drawer); @@ -29,7 +30,30 @@ namespace Ndk inline const Nz::Vector2ui& TextAreaWidget::GetCursorPosition() const { - return m_cursorPosition; + return m_cursorPositionBegin; + } + + Nz::Vector2ui TextAreaWidget::GetCursorPosition(std::size_t glyphIndex) const + { + glyphIndex = 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 > glyphIndex) + break; + + line = i; + } + + const auto& lineInfo = m_drawer.GetLine(line); + + Nz::Vector2ui cursorPos; + cursorPos.y = static_cast(line); + cursorPos.x = static_cast(glyphIndex - lineInfo.glyphIndex); + + return cursorPos; } inline const Nz::String& TextAreaWidget::GetDisplayText() const @@ -63,7 +87,12 @@ namespace Ndk return m_drawer.GetColor(); } - inline bool Ndk::TextAreaWidget::IsMultilineEnabled() const + inline bool TextAreaWidget::HasSelection() const + { + return m_cursorPositionBegin != m_cursorPositionEnd; + } + + inline bool TextAreaWidget::IsMultilineEnabled() const { return m_multiLineEnabled; } @@ -75,7 +104,7 @@ namespace Ndk inline void TextAreaWidget::MoveCursor(int offset) { - std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition); + std::size_t cursorGlyph = GetGlyphIndex(m_cursorPositionBegin); if (offset >= 0) SetCursorPosition(cursorGlyph + static_cast(offset)); else @@ -104,7 +133,7 @@ namespace Ndk } }; - Nz::Vector2ui cursorPosition = m_cursorPosition; + Nz::Vector2ui cursorPosition = m_cursorPositionBegin; cursorPosition.x = ClampOffset(static_cast(cursorPosition.x), offset.x); cursorPosition.y = ClampOffset(static_cast(cursorPosition.y), offset.y); @@ -120,22 +149,8 @@ namespace Ndk { OnTextAreaCursorMove(this, &glyphIndex); - glyphIndex = 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 > glyphIndex) - break; - - line = i; - } - - const auto& lineInfo = m_drawer.GetLine(line); - - m_cursorPosition.y = static_cast(line); - m_cursorPosition.x = static_cast(glyphIndex - lineInfo.glyphIndex); + m_cursorPositionBegin = GetCursorPosition(glyphIndex); + m_cursorPositionEnd = m_cursorPositionBegin; RefreshCursor(); } @@ -146,7 +161,7 @@ namespace Ndk if (cursorPosition.y >= lineCount) cursorPosition.y = static_cast(lineCount - 1); - m_cursorPosition = cursorPosition; + m_cursorPositionBegin = cursorPosition; const auto& lineInfo = m_drawer.GetLine(cursorPosition.y); if (cursorPosition.y + 1 < lineCount) @@ -155,6 +170,8 @@ namespace Ndk cursorPosition.x = std::min(cursorPosition.x, static_cast(nextLineInfo.glyphIndex - lineInfo.glyphIndex - 1)); } + m_cursorPositionEnd = m_cursorPositionBegin; + std::size_t glyphIndex = lineInfo.glyphIndex + cursorPosition.x; OnTextAreaCursorMove(this, &glyphIndex); @@ -175,6 +192,23 @@ namespace Ndk m_cursorEntity->Enable(!m_readOnly && HasFocus()); } + inline void TextAreaWidget::SetSelection(Nz::Vector2ui fromPosition, Nz::Vector2ui toPosition) + { + ///TODO: Check if position are valid + + // Ensure begin is before end + if (toPosition.y < fromPosition.y || (toPosition.y == fromPosition.y && toPosition.x < fromPosition.x)) + std::swap(fromPosition, toPosition); + + if (m_cursorPositionBegin != fromPosition || m_cursorPositionEnd != toPosition) + { + m_cursorPositionBegin = fromPosition; + m_cursorPositionEnd = toPosition; + + RefreshCursor(); + } + } + inline void TextAreaWidget::SetText(const Nz::String& text) { m_text = text; diff --git a/SDK/include/NDK/World.hpp b/SDK/include/NDK/World.hpp index 8a0fe2648..9b1d4c970 100644 --- a/SDK/include/NDK/World.hpp +++ b/SDK/include/NDK/World.hpp @@ -50,11 +50,16 @@ namespace Ndk inline void DisableProfiler(); inline void EnableProfiler(bool enable = true); + template void ForEachSystem(const F& iterationFunc); + template void ForEachSystem(const F& iterationFunc) const; + inline const EntityHandle& GetEntity(EntityId id); inline const EntityList& GetEntities() const; inline const ProfilerData& GetProfilerData() const; inline BaseSystem& GetSystem(SystemIndex index); + inline const BaseSystem& GetSystem(SystemIndex index) const; template SystemType& GetSystem(); + template const SystemType& GetSystem() const; inline bool HasSystem(SystemIndex index) const; template bool HasSystem() const; diff --git a/SDK/include/NDK/World.inl b/SDK/include/NDK/World.inl index 32903502d..942ce4d36 100644 --- a/SDK/include/NDK/World.inl +++ b/SDK/include/NDK/World.inl @@ -133,6 +133,40 @@ namespace Ndk } } + /*! + * \brief Executes a function on every present system + * + * Calls iterationFunc on every previously added system, in the same order as their indexes + * + * \param iterationFunc Function to be called + */ + template + void World::ForEachSystem(const F& iterationFunc) + { + for (const auto& systemPtr : m_systems) + { + if (systemPtr) + iterationFunc(*systemPtr); + } + } + + /*! + * \brief Executes a function on every present system + * + * Calls iterationFunc on every previously added system, in the same order as their indexes + * + * \param iterationFunc Function to be called + */ + template + void World::ForEachSystem(const F& iterationFunc) const + { + for (const auto& systemPtr : m_systems) + { + if (systemPtr) + iterationFunc(static_cast(*systemPtr)); //< Force const reference + } + } + /*! * \brief Gets an entity * \return A constant reference to a handle of the entity @@ -177,9 +211,8 @@ namespace Ndk * * \param index Index of the system * - * \remark Produces a NazaraAssert if system is not available in this world + * \remark The world must have the system before calling this function */ - inline BaseSystem& World::GetSystem(SystemIndex index) { NazaraAssert(HasSystem(index), "This system is not part of the world"); @@ -190,13 +223,30 @@ namespace Ndk return *system; } + /*! + * \brief Gets a system in the world by index + * \return A const reference to the system + * + * \param index Index of the system + * + * \remark The world must have the system before calling this function + */ + inline const BaseSystem& World::GetSystem(SystemIndex index) const + { + NazaraAssert(HasSystem(index), "This system is not part of the world"); + + const BaseSystem* system = m_systems[index].get(); + NazaraAssert(system, "Invalid system pointer"); + + return *system; + } + /*! * \brief Gets a system in the world by type * \return A reference to the system * * \remark Produces a NazaraAssert if system is not available in this world */ - template SystemType& World::GetSystem() { @@ -206,6 +256,21 @@ namespace Ndk return static_cast(GetSystem(index)); } + /*! + * \brief Gets a system in the world by type + * \return A const reference to the system + * + * \remark Produces a NazaraAssert if system is not available in this world + */ + template + const SystemType& World::GetSystem() const + { + static_assert(std::is_base_of::value, "SystemType is not a system"); + + SystemIndex index = GetSystemIndex(); + return static_cast(GetSystem(index)); + } + /*! * \brief Checks whether or not a system is present in the world by index * \return true If it is the case @@ -361,7 +426,7 @@ namespace Ndk m_orderedSystems = std::move(world.m_orderedSystems); m_orderedSystemsUpdated = world.m_orderedSystemsUpdated; m_profilerData = std::move(world.m_profilerData); - m_isProfilerEnabled = m_isProfilerEnabled; + m_isProfilerEnabled = world.m_isProfilerEnabled; m_entities = std::move(world.m_entities); for (EntityBlock& block : m_entities) diff --git a/SDK/src/NDK/BaseWidget.cpp b/SDK/src/NDK/BaseWidget.cpp index d8aa9fbfa..dc33252e2 100644 --- a/SDK/src/NDK/BaseWidget.cpp +++ b/SDK/src/NDK/BaseWidget.cpp @@ -81,7 +81,7 @@ namespace Ndk m_backgroundSprite->SetColor(m_backgroundColor); m_backgroundSprite->SetMaterial(Nz::Material::New((m_backgroundColor.IsOpaque()) ? "Basic2D" : "Translucent2D")); //< TODO: Use a shared material instead of creating one everytime - m_backgroundEntity = CreateEntity(); + m_backgroundEntity = CreateEntity(false); m_backgroundEntity->AddComponent().Attach(m_backgroundSprite, -1); m_backgroundEntity->AddComponent().SetParent(this); @@ -147,26 +147,30 @@ namespace Ndk else UnregisterFromCanvas(); - for (const EntityHandle& entity : m_entities) - entity->Enable(show); + for (WidgetEntity& entity : m_entities) + entity.handle->Enable(show); for (const auto& widgetPtr : m_children) widgetPtr->Show(show); } } - const Ndk::EntityHandle& BaseWidget::CreateEntity() + const Ndk::EntityHandle& BaseWidget::CreateEntity(bool isContentEntity) { const EntityHandle& newEntity = m_world->CreateEntity(); newEntity->Enable(m_visible); - m_entities.emplace_back(newEntity); + m_entities.emplace_back(); + WidgetEntity& widgetEntity = m_entities.back(); + widgetEntity.handle = newEntity; + widgetEntity.isContent = isContentEntity; + return newEntity; } void BaseWidget::DestroyEntity(Entity* entity) { - auto it = std::find(m_entities.begin(), m_entities.end(), entity); + auto it = std::find_if(m_entities.begin(), m_entities.end(), [&](const WidgetEntity& widgetEntity) { return widgetEntity.handle == entity; }); NazaraAssert(it != m_entities.end(), "Entity does not belong to this widget"); m_entities.erase(it); @@ -174,19 +178,17 @@ namespace Ndk void BaseWidget::Layout() { - if (IsRegisteredToCanvas()) - m_canvas->NotifyWidgetBoxUpdate(m_canvasIndex); - if (m_backgroundEntity) m_backgroundSprite->SetSize(m_contentSize.x + m_padding.left + m_padding.right, m_contentSize.y + m_padding.top + m_padding.bottom); + + UpdatePositionAndSize(); } void BaseWidget::InvalidateNode() { Node::InvalidateNode(); - if (IsRegisteredToCanvas()) - m_canvas->NotifyWidgetBoxUpdate(m_canvasIndex); + UpdatePositionAndSize(); } bool BaseWidget::IsFocusable() const @@ -271,4 +273,25 @@ namespace Ndk m_canvasIndex = InvalidCanvasIndex; } } + + void BaseWidget::UpdatePositionAndSize() + { + if (IsRegisteredToCanvas()) + m_canvas->NotifyWidgetBoxUpdate(m_canvasIndex); + + Nz::Vector2f widgetPos = Nz::Vector2f(GetPosition()); + Nz::Vector2f widgetSize = GetSize(); + + Nz::Vector2f contentPos = widgetPos + GetContentOrigin(); + Nz::Vector2f contentSize = GetContentSize(); + + Nz::Recti fullBounds(Nz::Rectf(widgetPos.x, widgetPos.y, widgetSize.x, widgetSize.y)); + Nz::Recti contentBounds(Nz::Rectf(contentPos.x, contentPos.y, contentSize.x, contentSize.y)); + for (WidgetEntity& widgetEntity : m_entities) + { + const Ndk::EntityHandle& entity = widgetEntity.handle; + if (entity->HasComponent()) + entity->GetComponent().SetScissorRect((widgetEntity.isContent) ? contentBounds : fullBounds); + } + } } diff --git a/SDK/src/NDK/Components/CollisionComponent2D.cpp b/SDK/src/NDK/Components/CollisionComponent2D.cpp index 2fe1c8b22..9e88f396b 100644 --- a/SDK/src/NDK/Components/CollisionComponent2D.cpp +++ b/SDK/src/NDK/Components/CollisionComponent2D.cpp @@ -59,6 +59,7 @@ namespace Ndk Nz::PhysWorld2D& physWorld = entityWorld->GetSystem().GetWorld(); m_staticBody = std::make_unique(&physWorld, 0.f, m_geom); + m_staticBody->SetUserdata(reinterpret_cast(static_cast(m_entity->GetId()))); Nz::Matrix4f matrix; if (m_entity->HasComponent()) diff --git a/SDK/src/NDK/Components/DebugComponent.cpp b/SDK/src/NDK/Components/DebugComponent.cpp new file mode 100644 index 000000000..6c8ab9f1c --- /dev/null +++ b/SDK/src/NDK/Components/DebugComponent.cpp @@ -0,0 +1,10 @@ +// 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 Prerequisites.hpp + +#include + +namespace Ndk +{ + ComponentIndex DebugComponent::componentIndex; +} diff --git a/SDK/src/NDK/Components/GraphicsComponent.cpp b/SDK/src/NDK/Components/GraphicsComponent.cpp index a4bc6e439..f865e749b 100644 --- a/SDK/src/NDK/Components/GraphicsComponent.cpp +++ b/SDK/src/NDK/Components/GraphicsComponent.cpp @@ -35,7 +35,7 @@ namespace Ndk object.dataUpdated = true; } - object.renderable->AddToRenderQueue(renderQueue, object.data); + object.renderable->AddToRenderQueue(renderQueue, object.data, m_scissorRect); } } @@ -277,12 +277,13 @@ namespace Ndk { Nz::Boxf localBox = boundingVolume.obb.localBox; Nz::Vector3f newPos = r.data.localMatrix * localBox.GetPosition(); - Nz::Vector3f newLengths = r.data.localMatrix * localBox.GetLengths(); + Nz::Vector3f newCorner = r.data.localMatrix * (localBox.GetPosition() + localBox.GetLengths()); + Nz::Vector3f newLengths = newCorner - newPos; boundingVolume.Set(Nz::Boxf(newPos.x, newPos.y, newPos.z, newLengths.x, newLengths.y, newLengths.z)); } - m_boundingVolume.ExtendTo(r.renderable->GetBoundingVolume()); + m_boundingVolume.ExtendTo(boundingVolume); } RenderSystem& renderSystem = m_entity->GetWorld()->GetSystem(); diff --git a/SDK/src/NDK/Components/PhysicsComponent2D.cpp b/SDK/src/NDK/Components/PhysicsComponent2D.cpp index 087eee04d..e2e199a22 100644 --- a/SDK/src/NDK/Components/PhysicsComponent2D.cpp +++ b/SDK/src/NDK/Components/PhysicsComponent2D.cpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace Ndk { @@ -40,8 +41,9 @@ namespace Ndk else matrix.MakeIdentity(); - m_object.reset(new Nz::RigidBody2D(&world, 1.f, geom)); + m_object = std::make_unique(&world, 1.f, geom); m_object->SetPosition(Nz::Vector2f(matrix.GetTranslation())); + m_object->SetUserdata(reinterpret_cast(static_cast(m_entity->GetId()))); } /*! diff --git a/SDK/src/NDK/Entity.cpp b/SDK/src/NDK/Entity.cpp index 863428d2a..ffcce07f0 100644 --- a/SDK/src/NDK/Entity.cpp +++ b/SDK/src/NDK/Entity.cpp @@ -14,26 +14,8 @@ namespace Ndk * \brief NDK class that represents an entity in a world */ - /*! - * \brief Constructs a Entity object by move semantic - * - * \param entity Entity to move into this - */ - - 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; - } + // Must exists in .cpp file because of BaseComponent unique_ptr + Entity::Entity(Entity&&) noexcept = default; /*! * \brief Constructs a Entity object linked to a world and with an id @@ -41,7 +23,6 @@ namespace Ndk * \param world World in which the entity interact * \param id Identifier of the entity */ - Entity::Entity(World* world, EntityId id) : m_id(id), m_world(world) @@ -53,7 +34,6 @@ namespace Ndk * * \see Destroy */ - Entity::~Entity() { if (m_world && m_valid) diff --git a/SDK/src/NDK/Sdk.cpp b/SDK/src/NDK/Sdk.cpp index e4a7008b7..90d07c738 100644 --- a/SDK/src/NDK/Sdk.cpp +++ b/SDK/src/NDK/Sdk.cpp @@ -28,11 +28,13 @@ #ifndef NDK_SERVER #include +#include #include #include #include #include #include +#include #include #include #include @@ -95,6 +97,7 @@ namespace Ndk #ifndef NDK_SERVER // Client components InitializeComponent("NdkCam"); + InitializeComponent("NdkDebug"); InitializeComponent("NdkLight"); InitializeComponent("NdkList"); InitializeComponent("NdkGfx"); @@ -113,6 +116,7 @@ namespace Ndk #ifndef NDK_SERVER // Client systems + InitializeSystem(); InitializeSystem(); InitializeSystem(); InitializeSystem(); diff --git a/SDK/src/NDK/Systems/DebugSystem.cpp b/SDK/src/NDK/Systems/DebugSystem.cpp new file mode 100644 index 000000000..d7ce4bb3d --- /dev/null +++ b/SDK/src/NDK/Systems/DebugSystem.cpp @@ -0,0 +1,366 @@ +// 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 Prerequisites.hpp + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Ndk +{ + namespace + { + class DebugRenderable : public Nz::InstancedRenderable + { + public: + DebugRenderable(Ndk::Entity* owner, Nz::MaterialRef mat, Nz::IndexBufferRef indexBuffer, Nz::VertexBufferRef vertexBuffer) : + m_entityOwner(owner), + m_material(std::move(mat)), + m_indexBuffer(std::move(indexBuffer)), + m_vertexBuffer(std::move(vertexBuffer)) + { + ResetMaterials(1); + + m_meshData.indexBuffer = m_indexBuffer; + m_meshData.primitiveMode = Nz::PrimitiveMode_LineList; + m_meshData.vertexBuffer = m_vertexBuffer; + } + + void UpdateBoundingVolume(InstanceData* instanceData) const override + { + } + + void MakeBoundingVolume() const override + { + m_boundingVolume.MakeNull(); + } + + protected: + Ndk::EntityHandle m_entityOwner; + Nz::IndexBufferRef m_indexBuffer; + Nz::MaterialRef m_material; + Nz::MeshData m_meshData; + Nz::VertexBufferRef m_vertexBuffer; + }; + + class AABBDebugRenderable : public DebugRenderable + { + public: + using DebugRenderable::DebugRenderable; + + void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Nz::Recti& scissorRect) const override + { + NazaraAssert(m_entityOwner, "DebugRenderable has no owner"); + + const DebugComponent& entityDebug = m_entityOwner->GetComponent(); + const GraphicsComponent& entityGfx = m_entityOwner->GetComponent(); + + Nz::Matrix4f transformMatrix = Nz::Matrix4f::Identity(); + transformMatrix.SetScale(entityGfx.GetBoundingVolume().aabb.GetLengths()); + transformMatrix.SetTranslation(entityGfx.GetBoundingVolume().aabb.GetCenter()); + + renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect); + } + }; + + class OBBDebugRenderable : public DebugRenderable + { + public: + using DebugRenderable::DebugRenderable; + + void AddToRenderQueue(Nz::AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Nz::Recti& scissorRect) const override + { + NazaraAssert(m_entityOwner, "DebugRenderable has no owner"); + + const DebugComponent& entityDebug = m_entityOwner->GetComponent(); + const GraphicsComponent& entityGfx = m_entityOwner->GetComponent(); + + Nz::Matrix4f transformMatrix = instanceData.transformMatrix; + transformMatrix.ApplyScale(entityGfx.GetBoundingVolume().obb.localBox.GetLengths()); + + renderQueue->AddMesh(0, m_material, m_meshData, Nz::Boxf::Zero(), transformMatrix, scissorRect); + } + }; + } + + /*! + * \ingroup NDK + * \class Ndk::DebugSystem + * \brief NDK class that represents the debug system + * + * \remark This system is enabled if the entity owns the trait: DebugComponent and GraphicsComponent + */ + + /*! + * \brief Constructs an DebugSystem object by default + */ + DebugSystem::DebugSystem() + { + Requires(); + SetUpdateOrder(1000); //< Update last + } + + std::pair DebugSystem::GetBoxMesh() + { + if (!m_boxMeshIndexBuffer) + { + std::array indices = { + { + 0, 1, + 1, 2, + 2, 3, + 3, 0, + + 4, 5, + 5, 6, + 6, 7, + 7, 4, + + 0, 4, + 1, 5, + 2, 6, + 3, 7 + } + }; + + m_boxMeshIndexBuffer = Nz::IndexBuffer::New(false, Nz::UInt32(indices.size()), Nz::DataStorage_Hardware, 0); + m_boxMeshIndexBuffer->Fill(indices.data(), 0, Nz::UInt32(indices.size())); + } + + if (!m_boxMeshVertexBuffer) + { + Nz::Boxf box(-0.5f, -0.5f, -0.5f, 1.f, 1.f, 1.f); + + std::array positions = { + { + box.GetCorner(Nz::BoxCorner_FarLeftBottom), + box.GetCorner(Nz::BoxCorner_NearLeftBottom), + box.GetCorner(Nz::BoxCorner_NearRightBottom), + box.GetCorner(Nz::BoxCorner_FarRightBottom), + box.GetCorner(Nz::BoxCorner_FarLeftTop), + box.GetCorner(Nz::BoxCorner_NearLeftTop), + box.GetCorner(Nz::BoxCorner_NearRightTop), + box.GetCorner(Nz::BoxCorner_FarRightTop) + } + }; + + m_boxMeshVertexBuffer = Nz::VertexBuffer::New(Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ), Nz::UInt32(positions.size()), Nz::DataStorage_Hardware, 0); + m_boxMeshVertexBuffer->Fill(positions.data(), 0, Nz::UInt32(positions.size())); + } + + return { m_boxMeshIndexBuffer, m_boxMeshVertexBuffer }; + } + + void DebugSystem::OnEntityValidation(Entity* entity, bool /*justAdded*/) + { + static constexpr int DebugDrawOrder = 1'000; + + DebugComponent& entityDebug = entity->GetComponent(); + GraphicsComponent& entityGfx = entity->GetComponent(); + + DebugDrawFlags enabledFlags = entityDebug.GetEnabledFlags(); + DebugDrawFlags flags = entityDebug.GetFlags(); + + DebugDrawFlags flagsToEnable = flags & ~enabledFlags; + for (std::size_t i = 0; i <= static_cast(DebugDraw::Max); ++i) + { + DebugDraw option = static_cast(i); + if (flagsToEnable & option) + { + switch (option) + { + case DebugDraw::Collider3D: + { + const Nz::Boxf& obb = entityGfx.GetBoundingVolume().obb.localBox; + + Nz::InstancedRenderableRef renderable = GenerateCollision3DMesh(entity); + if (renderable) + { + renderable->SetPersistent(false); + + entityGfx.Attach(renderable, Nz::Matrix4f::Translate(obb.GetCenter()), DebugDrawOrder); + } + + entityDebug.UpdateDebugRenderable(option, std::move(renderable)); + break; + } + + case DebugDraw::GraphicsAABB: + { + auto indexVertexBuffers = GetBoxMesh(); + + Nz::InstancedRenderableRef renderable = new AABBDebugRenderable(entity, GetAABBMaterial(), indexVertexBuffers.first, indexVertexBuffers.second); + renderable->SetPersistent(false); + + entityGfx.Attach(renderable, Nz::Matrix4f::Identity(), DebugDrawOrder); + + entityDebug.UpdateDebugRenderable(option, std::move(renderable)); + break; + } + + case DebugDraw::GraphicsOBB: + { + auto indexVertexBuffers = GetBoxMesh(); + + Nz::InstancedRenderableRef renderable = new OBBDebugRenderable(entity, GetOBBMaterial(), indexVertexBuffers.first, indexVertexBuffers.second); + renderable->SetPersistent(false); + + entityGfx.Attach(renderable, Nz::Matrix4f::Identity(), DebugDrawOrder); + + entityDebug.UpdateDebugRenderable(option, std::move(renderable)); + break; + } + + default: + break; + } + } + } + + DebugDrawFlags flagsToDisable = enabledFlags & ~flags; + for (std::size_t i = 0; i <= static_cast(DebugDraw::Max); ++i) + { + DebugDraw option = static_cast(i); + if (flagsToDisable & option) + entityGfx.Detach(entityDebug.GetDebugRenderable(option)); + } + + entityDebug.UpdateEnabledFlags(flags); + } + + void DebugSystem::OnUpdate(float elapsedTime) + { + // Nothing to do + } + + Nz::InstancedRenderableRef DebugSystem::GenerateBox(Nz::Boxf box) + { + Nz::MeshRef mesh = Nz::Mesh::New(); + mesh->CreateStatic(); + + mesh->BuildSubMesh(Nz::Primitive::Box(box.GetLengths())); + mesh->SetMaterialCount(1); + + Nz::ModelRef model = Nz::Model::New(); + model->SetMesh(mesh); + model->SetMaterial(0, GetOBBMaterial()); + + return model; + } + + Nz::InstancedRenderableRef DebugSystem::GenerateCollision3DMesh(Entity* entity) + { + if (entity->HasComponent()) + { + CollisionComponent3D& entityCollision = entity->GetComponent(); + const Nz::Collider3DRef& geom = entityCollision.GetGeom(); + + std::vector vertices; + std::vector indices; + + geom->ForEachPolygon([&](const float* polygonVertices, std::size_t vertexCount) + { + std::size_t firstIndex = vertices.size(); + + for (std::size_t i = 0; i < vertexCount; ++i) + { + const float* vertexData = &polygonVertices[i * 3]; + vertices.emplace_back(vertexData[0], vertexData[1], vertexData[2]); + } + + for (std::size_t i = 0; i < vertexCount - 1; ++i) + { + indices.push_back(firstIndex + i); + indices.push_back(firstIndex + i + 1); + } + + indices.push_back(firstIndex + vertexCount - 1); + indices.push_back(firstIndex); + }); + + Nz::IndexBufferRef indexBuffer = Nz::IndexBuffer::New(vertices.size() > 0xFFFF, Nz::UInt32(indices.size()), Nz::DataStorage_Hardware, 0); + Nz::IndexMapper indexMapper(indexBuffer, Nz::BufferAccess_WriteOnly); + + Nz::IndexIterator indexPtr = indexMapper.begin(); + for (std::size_t index : indices) + *indexPtr++ = static_cast(index); + + indexMapper.Unmap(); + + Nz::VertexBufferRef vertexBuffer = Nz::VertexBuffer::New(Nz::VertexDeclaration::Get(Nz::VertexLayout_XYZ), Nz::UInt32(vertices.size()), Nz::DataStorage_Hardware, 0); + vertexBuffer->Fill(vertices.data(), 0, Nz::UInt32(vertices.size())); + + Nz::MeshRef mesh = Nz::Mesh::New(); + mesh->CreateStatic(); + + Nz::StaticMeshRef subMesh = Nz::StaticMesh::New(mesh); + subMesh->Create(vertexBuffer); + subMesh->SetIndexBuffer(indexBuffer); + subMesh->SetPrimitiveMode(Nz::PrimitiveMode_LineList); + subMesh->SetMaterialIndex(0); + subMesh->GenerateAABB(); + + mesh->SetMaterialCount(1); + mesh->AddSubMesh(subMesh); + + Nz::ModelRef model = Nz::Model::New(); + model->SetMesh(mesh); + model->SetMaterial(0, GetCollisionMaterial()); + + return model; + } + else + return nullptr; + } + + Nz::MaterialRef DebugSystem::GetAABBMaterial() + { + if (!m_aabbMaterial) + { + m_aabbMaterial = Nz::Material::New(); + m_aabbMaterial->EnableFaceCulling(false); + m_aabbMaterial->EnableDepthBuffer(true); + m_aabbMaterial->SetDiffuseColor(Nz::Color::Red); + m_aabbMaterial->SetFaceFilling(Nz::FaceFilling_Line); + } + + return m_aabbMaterial; + } + + Nz::MaterialRef DebugSystem::GetCollisionMaterial() + { + if (!m_collisionMaterial) + { + m_collisionMaterial = Nz::Material::New(); + m_collisionMaterial->EnableFaceCulling(false); + m_collisionMaterial->EnableDepthBuffer(true); + m_collisionMaterial->SetDiffuseColor(Nz::Color::Blue); + m_collisionMaterial->SetFaceFilling(Nz::FaceFilling_Line); + } + + return m_collisionMaterial; + } + + Nz::MaterialRef DebugSystem::GetOBBMaterial() + { + if (!m_obbMaterial) + { + m_obbMaterial = Nz::Material::New(); + m_obbMaterial->EnableFaceCulling(false); + m_obbMaterial->EnableDepthBuffer(true); + m_obbMaterial->SetDiffuseColor(Nz::Color::Green); + m_obbMaterial->SetFaceFilling(Nz::FaceFilling_Line); + } + + return m_obbMaterial; + } + + SystemIndex DebugSystem::systemIndex; +} diff --git a/SDK/src/NDK/Systems/ListenerSystem.cpp b/SDK/src/NDK/Systems/ListenerSystem.cpp index b6cdd55d9..c725bc368 100644 --- a/SDK/src/NDK/Systems/ListenerSystem.cpp +++ b/SDK/src/NDK/Systems/ListenerSystem.cpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace Ndk { @@ -34,7 +33,7 @@ namespace Ndk * \param elapsedTime Delta time used for the update */ - void ListenerSystem::OnUpdate(float /*elapsedTime*/) + void ListenerSystem::OnUpdate(float elapsedTime) { std::size_t activeListenerCount = 0; @@ -45,18 +44,18 @@ namespace Ndk if (!listener.IsActive()) continue; + Nz::Vector3f oldPos = Nz::Audio::GetListenerPosition(); + // We get the position and the rotation to affect these to the listener const NodeComponent& node = entity->GetComponent(); - Nz::Audio::SetListenerPosition(node.GetPosition(Nz::CoordSys_Global)); + Nz::Vector3f newPos = node.GetPosition(Nz::CoordSys_Global); + + Nz::Audio::SetListenerPosition(newPos); Nz::Audio::SetListenerRotation(node.GetRotation(Nz::CoordSys_Global)); - // We verify the presence of a component of velocity - // (The listener'speed does not move it, but disturbs the sound like Doppler effect) - if (entity->HasComponent()) - { - const VelocityComponent& velocity = entity->GetComponent(); - Nz::Audio::SetListenerVelocity(velocity.linearVelocity); - } + // Compute listener velocity based on their old/new position + Nz::Vector3f velocity = (newPos - oldPos) / elapsedTime; + Nz::Audio::SetListenerVelocity(velocity); activeListenerCount++; } diff --git a/SDK/src/NDK/Systems/RenderSystem.cpp b/SDK/src/NDK/Systems/RenderSystem.cpp index 9798731b7..01ae6b2ac 100644 --- a/SDK/src/NDK/Systems/RenderSystem.cpp +++ b/SDK/src/NDK/Systems/RenderSystem.cpp @@ -206,7 +206,7 @@ namespace Ndk std::size_t visibilityHash = m_drawableCulling.Cull(camComponent.GetFrustum(), &forceInvalidation); // Always regenerate renderqueue if particle groups are present for now (FIXME) - if (!m_particleGroups.empty()) + if (!m_lights.empty() || !m_particleGroups.empty()) forceInvalidation = true; if (camComponent.UpdateVisibility(visibilityHash) || m_forceRenderQueueInvalidation || forceInvalidation) diff --git a/SDK/src/NDK/Widgets/ButtonWidget.cpp b/SDK/src/NDK/Widgets/ButtonWidget.cpp index e44348dc6..5d8360635 100644 --- a/SDK/src/NDK/Widgets/ButtonWidget.cpp +++ b/SDK/src/NDK/Widgets/ButtonWidget.cpp @@ -30,13 +30,13 @@ namespace Ndk m_gradientSprite->SetCornerColor(Nz::RectCorner_RightBottom, m_cornerColor); m_gradientSprite->SetMaterial(Nz::Material::New("Basic2D")); - m_gradientEntity = CreateEntity(); + m_gradientEntity = CreateEntity(false); m_gradientEntity->AddComponent().SetParent(this); m_gradientEntity->AddComponent().Attach(m_gradientSprite); m_textSprite = Nz::TextSprite::New(); - m_textEntity = CreateEntity(); + m_textEntity = CreateEntity(true); m_textEntity->AddComponent().SetParent(this); m_textEntity->AddComponent().Attach(m_textSprite, 1); @@ -82,12 +82,11 @@ namespace Ndk { BaseWidget::Layout(); + m_gradientSprite->SetSize(GetSize()); + Nz::Vector2f origin = GetContentOrigin(); const Nz::Vector2f& contentSize = GetContentSize(); - m_gradientEntity->GetComponent().SetPosition(origin); - m_gradientSprite->SetSize(contentSize); - Nz::Boxf textBox = m_textEntity->GetComponent().GetBoundingVolume().obb.localBox; m_textEntity->GetComponent().SetPosition(origin.x + contentSize.x / 2 - textBox.width / 2, origin.y + contentSize.y / 2 - textBox.height / 2); } diff --git a/SDK/src/NDK/Widgets/CheckboxWidget.cpp b/SDK/src/NDK/Widgets/CheckboxWidget.cpp index 237aff415..3f20ff7c6 100644 --- a/SDK/src/NDK/Widgets/CheckboxWidget.cpp +++ b/SDK/src/NDK/Widgets/CheckboxWidget.cpp @@ -28,19 +28,19 @@ namespace Ndk m_checkboxContentSprite = Nz::Sprite::New(Nz::Material::New("Translucent2D")); m_textSprite = Nz::TextSprite::New(); - m_checkboxBorderEntity = CreateEntity(); + m_checkboxBorderEntity = CreateEntity(false); m_checkboxBorderEntity->AddComponent().SetParent(this); m_checkboxBorderEntity->AddComponent().Attach(m_checkboxBorderSprite); - m_checkboxBackgroundEntity = CreateEntity(); + m_checkboxBackgroundEntity = CreateEntity(false); m_checkboxBackgroundEntity->AddComponent().SetParent(this); m_checkboxBackgroundEntity->AddComponent().Attach(m_checkboxBackgroundSprite, 1); - m_checkboxContentEntity = CreateEntity(); + m_checkboxContentEntity = CreateEntity(true); m_checkboxContentEntity->AddComponent().SetParent(this); m_checkboxContentEntity->AddComponent().Attach(m_checkboxContentSprite, 2); - m_textEntity = CreateEntity(); + m_textEntity = CreateEntity(true); m_textEntity->AddComponent().SetParent(this); m_textEntity->AddComponent().Attach(m_textSprite); diff --git a/SDK/src/NDK/Widgets/ImageWidget.cpp b/SDK/src/NDK/Widgets/ImageWidget.cpp index d03c67651..b43d5ba8d 100644 --- a/SDK/src/NDK/Widgets/ImageWidget.cpp +++ b/SDK/src/NDK/Widgets/ImageWidget.cpp @@ -11,7 +11,7 @@ namespace Ndk ImageWidget::ImageWidget(BaseWidget* parent) : BaseWidget(parent) { - m_entity = CreateEntity(); + m_entity = CreateEntity(true); m_entity->AddComponent(); auto& gfx = m_entity->AddComponent(); diff --git a/SDK/src/NDK/Widgets/LabelWidget.cpp b/SDK/src/NDK/Widgets/LabelWidget.cpp index a93503d60..98deb8da3 100644 --- a/SDK/src/NDK/Widgets/LabelWidget.cpp +++ b/SDK/src/NDK/Widgets/LabelWidget.cpp @@ -13,13 +13,20 @@ namespace Ndk { m_textSprite = Nz::TextSprite::New(); - m_textEntity = CreateEntity(); + m_textEntity = CreateEntity(true); m_textEntity->AddComponent().Attach(m_textSprite); m_textEntity->AddComponent().SetParent(this); Layout(); } + void LabelWidget::Layout() + { + BaseWidget::Layout(); + + m_textEntity->GetComponent().SetPosition(GetContentOrigin()); + } + void LabelWidget::ResizeToContent() { SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths())); diff --git a/SDK/src/NDK/Widgets/ProgressBarWidget.cpp b/SDK/src/NDK/Widgets/ProgressBarWidget.cpp index 721636ffc..80f01d43a 100644 --- a/SDK/src/NDK/Widgets/ProgressBarWidget.cpp +++ b/SDK/src/NDK/Widgets/ProgressBarWidget.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Samy Bensaid +// Copyright (C) 2017 Samy Bensaid // This file is part of the "Nazara Development Kit" // For conditions of distribution and use, see copyright notice in Prerequisites.hpp @@ -30,11 +30,11 @@ namespace Ndk SetBarColor(s_barColor, s_barCornerColor); - m_borderEntity = CreateEntity(); + m_borderEntity = CreateEntity(false); m_borderEntity->AddComponent().SetParent(this); m_borderEntity->AddComponent().Attach(m_borderSprite); - m_barEntity = CreateEntity(); + m_barEntity = CreateEntity(true); m_barEntity->AddComponent().SetParent(this); GraphicsComponent& graphics = m_barEntity->AddComponent(); @@ -43,7 +43,7 @@ namespace Ndk m_textSprite = Nz::TextSprite::New(); - m_textEntity = CreateEntity(); + m_textEntity = CreateEntity(true); m_textEntity->AddComponent().SetParent(this); m_textEntity->AddComponent().Attach(m_textSprite); diff --git a/SDK/src/NDK/Widgets/TextAreaWidget.cpp b/SDK/src/NDK/Widgets/TextAreaWidget.cpp index a46089fc3..f10f57953 100644 --- a/SDK/src/NDK/Widgets/TextAreaWidget.cpp +++ b/SDK/src/NDK/Widgets/TextAreaWidget.cpp @@ -12,22 +12,20 @@ namespace Ndk TextAreaWidget::TextAreaWidget(BaseWidget* parent) : BaseWidget(parent), m_echoMode(EchoMode_Normal), - m_cursorPosition(0U, 0U), + m_cursorPositionBegin(0U, 0U), + m_cursorPositionEnd(0U, 0U), + m_isMouseButtonDown(false), m_multiLineEnabled(false), m_readOnly(false) { - m_cursorSprite = Nz::Sprite::New(); - m_cursorSprite->SetColor(Nz::Color::Black); - m_cursorSprite->SetSize(1.f, float(m_drawer.GetFont()->GetSizeInfo(m_drawer.GetCharacterSize()).lineHeight)); - - m_cursorEntity = CreateEntity(); - m_cursorEntity->AddComponent().Attach(m_cursorSprite, 10); + m_cursorEntity = CreateEntity(true); + m_cursorEntity->AddComponent(); m_cursorEntity->AddComponent().SetParent(this); m_cursorEntity->Enable(false); m_textSprite = Nz::TextSprite::New(); - m_textEntity = CreateEntity(); + m_textEntity = CreateEntity(true); m_textEntity->AddComponent().Attach(m_textSprite); m_textEntity->AddComponent().SetParent(this); @@ -72,7 +70,29 @@ namespace Ndk OnTextChanged(this, m_text); } - std::size_t TextAreaWidget::GetHoveredGlyph(float x, float y) const + void TextAreaWidget::EraseSelection() + { + if (!HasSelection()) + return; + + std::size_t cursorGlyphBegin = GetGlyphIndex(m_cursorPositionBegin); + std::size_t cursorGlyphEnd = GetGlyphIndex(m_cursorPositionEnd); + + std::size_t textLength = m_text.GetLength(); + if (cursorGlyphBegin > textLength) + return; + + Nz::String newText; + if (cursorGlyphBegin > 0) + newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyphBegin) - 1)); + + if (cursorGlyphEnd < textLength) + newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyphEnd))); + + SetText(newText); + } + + Nz::Vector2ui TextAreaWidget::GetHoveredGlyph(float x, float y) const { std::size_t glyphCount = m_drawer.GetGlyphCount(); if (glyphCount > 0) @@ -88,7 +108,8 @@ namespace Ndk std::size_t upperLimit = (line != lineCount - 1) ? m_drawer.GetLine(line + 1).glyphIndex : glyphCount + 1; - std::size_t i = m_drawer.GetLine(line).glyphIndex; + std::size_t firstLineGlyph = m_drawer.GetLine(line).glyphIndex; + std::size_t i = firstLineGlyph; for (; i < upperLimit - 1; ++i) { Nz::Rectf bounds = m_drawer.GetGlyph(i).bounds; @@ -96,10 +117,10 @@ namespace Ndk break; } - return i; + return Nz::Vector2ui(i - firstLineGlyph, line); } - return 0; + return Nz::Vector2ui::Zero(); } void TextAreaWidget::ResizeToContent() @@ -109,7 +130,7 @@ namespace Ndk void TextAreaWidget::Write(const Nz::String& text) { - std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition); + std::size_t cursorGlyph = GetGlyphIndex(m_cursorPositionBegin); if (cursorGlyph >= m_drawer.GetGlyphCount()) { @@ -156,20 +177,27 @@ namespace Ndk { case Nz::Keyboard::Delete: { - std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition); + if (HasSelection()) + EraseSelection(); + else + { + std::size_t cursorGlyphBegin = GetGlyphIndex(m_cursorPositionBegin); + std::size_t cursorGlyphEnd = GetGlyphIndex(m_cursorPositionEnd); - std::size_t textLength = m_text.GetLength(); - if (cursorGlyph > textLength) - return true; + std::size_t textLength = m_text.GetLength(); + if (cursorGlyphBegin > textLength) + return true; - Nz::String newText; - if (cursorGlyph > 0) - newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyph) - 1)); + Nz::String newText; + if (cursorGlyphBegin > 0) + newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyphBegin) - 1)); - if (cursorGlyph < textLength) - newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyph + 1))); + if (cursorGlyphEnd < textLength) + newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyphEnd + 1))); + + SetText(newText); + } - SetText(newText); return true; } @@ -181,10 +209,38 @@ namespace Ndk if (ignoreDefaultAction) return true; + if (HasSelection()) + SetCursorPosition(m_cursorPositionEnd); + MoveCursor({0, 1}); return true; } + case Nz::Keyboard::End: + { + bool ignoreDefaultAction = false; + OnTextAreaKeyEnd(this, &ignoreDefaultAction); + + if (ignoreDefaultAction) + return true; + + const auto& lineInfo = m_drawer.GetLine(m_cursorPositionEnd.y); + SetCursorPosition({ static_cast(m_drawer.GetLineGlyphCount(m_cursorPositionEnd.y)), m_cursorPositionEnd.y }); + return true; + } + + case Nz::Keyboard::Home: + { + bool ignoreDefaultAction = false; + OnTextAreaKeyHome(this, &ignoreDefaultAction); + + if (ignoreDefaultAction) + return true; + + SetCursorPosition({ 0U, m_cursorPositionEnd.y }); + return true; + } + case Nz::Keyboard::Left: { bool ignoreDefaultAction = false; @@ -193,7 +249,11 @@ namespace Ndk if (ignoreDefaultAction) return true; - MoveCursor(-1); + if (HasSelection()) + SetCursorPosition(m_cursorPositionBegin); + else + MoveCursor(-1); + return true; } @@ -205,7 +265,11 @@ namespace Ndk if (ignoreDefaultAction) return true; - MoveCursor(1); + if (HasSelection()) + SetCursorPosition(m_cursorPositionEnd); + else + MoveCursor(1); + return true; } @@ -217,6 +281,9 @@ namespace Ndk if (ignoreDefaultAction) return true; + if (HasSelection()) + SetCursorPosition(m_cursorPositionBegin); + MoveCursor({0, -1}); return true; } @@ -236,7 +303,40 @@ namespace Ndk { SetFocus(); - SetCursorPosition(GetHoveredGlyph(float(x), float(y))); + const Padding& padding = GetPadding(); + Nz::Vector2ui hoveredGlyph = GetHoveredGlyph(float(x - padding.left), float(y - padding.top)); + + // Shift extends selection + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::LShift) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::RShift)) + SetSelection(hoveredGlyph, m_selectionCursor); + else + { + SetCursorPosition(hoveredGlyph); + m_selectionCursor = m_cursorPositionBegin; + } + + m_isMouseButtonDown = true; + } + } + + void TextAreaWidget::OnMouseButtonRelease(int, int, Nz::Mouse::Button button) + { + if (button == Nz::Mouse::Left) + m_isMouseButtonDown = false; + } + + void TextAreaWidget::OnMouseEnter() + { + if (!Nz::Mouse::IsButtonPressed(Nz::Mouse::Left)) + m_isMouseButtonDown = false; + } + + void TextAreaWidget::OnMouseMoved(int x, int y, int deltaX, int deltaY) + { + if (m_isMouseButtonDown) + { + const Padding& padding = GetPadding(); + SetSelection(m_selectionCursor, GetHoveredGlyph(float(x - padding.left), float(y - padding.top))); } } @@ -252,20 +352,30 @@ namespace Ndk bool ignoreDefaultAction = false; OnTextAreaKeyBackspace(this, &ignoreDefaultAction); - std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition); - if (ignoreDefaultAction || cursorGlyph == 0) + std::size_t cursorGlyphBegin = GetGlyphIndex(m_cursorPositionBegin); + std::size_t cursorGlyphEnd = GetGlyphIndex(m_cursorPositionEnd); + + if (ignoreDefaultAction || cursorGlyphEnd == 0) break; - Nz::String newText; + // When a text is selected, delete key does the same as delete and leave the character behind it + if (HasSelection()) + EraseSelection(); + else + { + Nz::String newText; - if (cursorGlyph > 1) - newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyph - 1) - 1)); + if (cursorGlyphBegin > 1) + newText.Append(m_text.SubString(0, m_text.GetCharacterPosition(cursorGlyphBegin - 1) - 1)); - if (cursorGlyph < m_text.GetLength()) - newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyph))); + if (cursorGlyphEnd < m_text.GetLength()) + newText.Append(m_text.SubString(m_text.GetCharacterPosition(cursorGlyphEnd))); - MoveCursor(-1); - SetText(newText); + // Move cursor before setting text (to prevent SetText to move our cursor) + MoveCursor(-1); + + SetText(newText); + } break; } @@ -287,6 +397,9 @@ namespace Ndk if (Nz::Unicode::GetCategory(character) == Nz::Unicode::Category_Other_Control) break; + if (HasSelection()) + EraseSelection(); + Write(Nz::String::Unicode(character)); break; } @@ -298,24 +411,68 @@ namespace Ndk if (m_readOnly) return; - const auto& lineInfo = m_drawer.GetLine(m_cursorPosition.y); - std::size_t cursorGlyph = GetGlyphIndex(m_cursorPosition); + m_cursorEntity->GetComponent().SetPosition(GetContentOrigin()); - std::size_t glyphCount = m_drawer.GetGlyphCount(); - float position; - if (glyphCount > 0 && lineInfo.glyphIndex < cursorGlyph) + std::size_t selectionLineCount = m_cursorPositionEnd.y - m_cursorPositionBegin.y + 1; + std::size_t oldSpriteCount = m_cursorSprites.size(); + if (m_cursorSprites.size() != selectionLineCount) { - const auto& glyph = m_drawer.GetGlyph(std::min(cursorGlyph, glyphCount - 1)); - position = glyph.bounds.x; - if (cursorGlyph >= glyphCount) - position += glyph.bounds.width; + m_cursorSprites.resize(m_cursorPositionEnd.y - m_cursorPositionBegin.y + 1); + for (std::size_t i = oldSpriteCount; i < m_cursorSprites.size(); ++i) + { + m_cursorSprites[i] = Nz::Sprite::New(); + m_cursorSprites[i]->SetMaterial(Nz::Material::New("Translucent2D")); + } } - else - position = 0.f; - Nz::Vector2f contentOrigin = GetContentOrigin(); + float lineHeight = float(m_drawer.GetFont()->GetSizeInfo(m_drawer.GetCharacterSize()).lineHeight); - m_cursorEntity->GetComponent().SetPosition(contentOrigin.x + position, contentOrigin.y + lineInfo.bounds.y); + GraphicsComponent& gfxComponent = m_cursorEntity->GetComponent(); + gfxComponent.Clear(); + + for (unsigned int i = m_cursorPositionBegin.y; i <= m_cursorPositionEnd.y; ++i) + { + const auto& lineInfo = m_drawer.GetLine(i); + + Nz::SpriteRef& cursorSprite = m_cursorSprites[i - m_cursorPositionBegin.y]; + if (i == m_cursorPositionBegin.y || i == m_cursorPositionEnd.y) + { + auto GetGlyphPos = [&](unsigned int localGlyphPos) + { + std::size_t cursorGlyph = GetGlyphIndex({ localGlyphPos, i }); + + std::size_t glyphCount = m_drawer.GetGlyphCount(); + float position; + if (glyphCount > 0 && lineInfo.glyphIndex < cursorGlyph) + { + const auto& glyph = m_drawer.GetGlyph(std::min(cursorGlyph, glyphCount - 1)); + position = glyph.bounds.x; + if (cursorGlyph >= glyphCount) + position += glyph.bounds.width; + } + else + position = 0.f; + + return position; + }; + + float beginX = (i == m_cursorPositionBegin.y) ? GetGlyphPos(m_cursorPositionBegin.x) : 0.f; + float endX = (i == m_cursorPositionEnd.y) ? GetGlyphPos(m_cursorPositionEnd.x) : lineInfo.bounds.width; + float spriteSize = std::max(endX - beginX, 1.f); + + cursorSprite->SetColor((m_cursorPositionBegin == m_cursorPositionEnd) ? Nz::Color::Black : Nz::Color(0, 0, 0, 50)); + cursorSprite->SetSize(spriteSize, float(m_drawer.GetFont()->GetSizeInfo(m_drawer.GetCharacterSize()).lineHeight)); + + gfxComponent.Attach(cursorSprite, Nz::Matrix4f::Translate({ beginX, lineInfo.bounds.y, 0.f })); + } + else + { + cursorSprite->SetColor(Nz::Color(0, 0, 0, 50)); + cursorSprite->SetSize(lineInfo.bounds.width, float(m_drawer.GetFont()->GetSizeInfo(m_drawer.GetCharacterSize()).lineHeight)); + + gfxComponent.Attach(cursorSprite, Nz::Matrix4f::Translate({ 0.f, lineInfo.bounds.y, 0.f })); + } + } } void TextAreaWidget::UpdateDisplayText() @@ -334,6 +491,6 @@ namespace Ndk m_textSprite->Update(m_drawer); - SetCursorPosition(m_cursorPosition); //< Refresh cursor position (prevent it from being outside of the text) + SetCursorPosition(m_cursorPositionBegin); //< Refresh cursor position (prevent it from being outside of the text) } } diff --git a/SDK/src/NDK/World.cpp b/SDK/src/NDK/World.cpp index 7582461b9..bfbe0140c 100644 --- a/SDK/src/NDK/World.cpp +++ b/SDK/src/NDK/World.cpp @@ -11,6 +11,7 @@ #include #ifndef NDK_SERVER +#include #include #include #include @@ -47,6 +48,7 @@ namespace Ndk AddSystem(); #ifndef NDK_SERVER + AddSystem(); AddSystem(); AddSystem(); AddSystem(); diff --git a/appveyor.yml b/appveyor.yml index 8c53f2bd8..73d011778 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,9 +41,9 @@ after_build: - cd build && "./premake5.exe" package && cd ../package - 7z a NazaraEngine.7z * && cd .. -artifacts: - - path: package/NazaraEngine.7z - name: 'NazaraEngine-$(CONFIGURATION)-$(PLATFORM)-$(APPVEYOR_REPO_COMMIT)' +#artifacts: +# - path: package/NazaraEngine.7z +# name: 'NazaraEngine-$(CONFIGURATION)-$(PLATFORM)-$(APPVEYOR_REPO_COMMIT)' on_success: - cd tests && "./NazaraUnitTestsServer.exe" diff --git a/build/scripts/common.lua b/build/scripts/common.lua index f4572322e..750e2211b 100644 --- a/build/scripts/common.lua +++ b/build/scripts/common.lua @@ -1,7 +1,7 @@ NazaraBuild = {} -- I wish Premake had a way to know the compiler in advance -local clangGccActions = "action:" .. table.concat({"codeblocks", "codelite", "gmake", "xcode3", "xcode4"}, " or ") +local clangGccActions = "action:" .. table.concat({"codeblocks", "codelite", "gmake*", "xcode3", "xcode4"}, " or ") function NazaraBuild:AddExecutablePath(path) table.insert(self.ExecutableDir, path) @@ -13,16 +13,16 @@ function NazaraBuild:AddInstallPath(path) end function NazaraBuild:FilterLibDirectory(prefix, func) - filter({"action:codeblocks or codelite or gmake", "architecture:x86", "system:Windows"}) + filter({"action:codeblocks or codelite or gmake*", "architecture:x86", "system:Windows"}) func(prefix .. "mingw/x86") - filter({"action:codeblocks or codelite or gmake", "architecture:x86_64", "system:Windows"}) + filter({"action:codeblocks or codelite or gmake*", "architecture:x86_64", "system:Windows"}) func(prefix .. "mingw/x64") - filter({"action:codeblocks or codelite or gmake", "architecture:x86", "system:not Windows"}) + filter({"action:codeblocks or codelite or gmake*", "architecture:x86", "system:not Windows"}) func(prefix .. "gmake/x86") - filter({"action:codeblocks or codelite or gmake", "architecture:x86_64", "system:not Windows"}) + filter({"action:codeblocks or codelite or gmake*", "architecture:x86_64", "system:not Windows"}) func(prefix .. "gmake/x64") filter({"action:vs*", "architecture:x86"}) diff --git a/build/scripts/modules/platform.lua b/build/scripts/modules/platform.lua index c90f6663a..ad013c306 100644 --- a/build/scripts/modules/platform.lua +++ b/build/scripts/modules/platform.lua @@ -1,5 +1,7 @@ MODULE.Name = "Platform" +MODULE.ClientOnly = true + MODULE.Libraries = { "NazaraCore", "NazaraUtility" diff --git a/build/scripts/tools/ndk_server.lua b/build/scripts/tools/ndk_server.lua index cea295f7e..e235b1343 100644 --- a/build/scripts/tools/ndk_server.lua +++ b/build/scripts/tools/ndk_server.lua @@ -27,6 +27,8 @@ TOOL.FilesExcluded = { "../SDK/**/CameraComponent.*", "../SDK/**/Canvas.*", "../SDK/**/Console.*", + "../SDK/**/DebugComponent.*", + "../SDK/**/DebugSystem.*", "../SDK/**/GraphicsComponent.*", "../SDK/**/LightComponent.*", "../SDK/**/ListenerComponent.*", diff --git a/examples/FirstScene/main.cpp b/examples/FirstScene/main.cpp index 2aec4861e..a4ce40454 100644 --- a/examples/FirstScene/main.cpp +++ b/examples/FirstScene/main.cpp @@ -324,12 +324,11 @@ int main() // Début de la boucle de rendu du programme (s'occupant par exemple de mettre à jour le monde) while (application.Run()) { - - Nz::UInt64 elapsedUS = updateClock.Restart() / 1'000'000; + Nz::UInt64 elapsedUs = updateClock.Restart(); // Mise à jour (Caméra) const Nz::UInt64 updateRate = 1000000 / 60; // 60 fois par seconde - updateAccumulator += elapsedUS; + updateAccumulator += elapsedUs; if (updateAccumulator >= updateRate) { diff --git a/examples/Particles/LogoDemo.cpp b/examples/Particles/LogoDemo.cpp index e5e6c0925..0811191e1 100644 --- a/examples/Particles/LogoDemo.cpp +++ b/examples/Particles/LogoDemo.cpp @@ -113,7 +113,7 @@ class SpriteRenderer : public Nz::ParticleRenderer Nz::SparsePtr sizePtr(&size, 0); Nz::SparsePtr sinCosPtr(nullptr, 0); - renderQueue->AddBillboards(0, m_material, endId - startId + 1, mapper.GetComponentPtr(Nz::ParticleComponent_Position), sizePtr, sinCosPtr, mapper.GetComponentPtr(Nz::ParticleComponent_Color)); + renderQueue->AddBillboards(0, m_material, endId - startId + 1, Nz::Recti(-1, -1), mapper.GetComponentPtr(Nz::ParticleComponent_Position), sizePtr, sinCosPtr, mapper.GetComponentPtr(Nz::ParticleComponent_Color)); } private: diff --git a/examples/Particles/SpacebattleDemo.cpp b/examples/Particles/SpacebattleDemo.cpp index 1dd7eb0ec..8fa72bfff 100644 --- a/examples/Particles/SpacebattleDemo.cpp +++ b/examples/Particles/SpacebattleDemo.cpp @@ -267,6 +267,8 @@ ParticleDemo("Space battle", sharedData) if (!m_spacestationModel.LoadFromFile("resources/SpaceStation/space_station.obj", parameters)) NazaraWarning("Failed to load space_station.obj"); + m_spacestationModel.GetMesh()->GenerateNormalsAndTangents(); + parameters.mesh.texCoordScale.Set(1.f, -1.f); parameters.mesh.matrix.MakeRotation(Nz::EulerAnglesf(0.f, -90.f, 0.f)); @@ -343,7 +345,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) CreateSpaceShip(); CreateTurret(); - Ndk::EntityHandle light = m_shared.world3D->CreateEntity(); + const Ndk::EntityHandle& light = m_shared.world3D->CreateEntity(); Ndk::NodeComponent& lightNode = light->AddComponent(); Ndk::LightComponent& lightComp = light->AddComponent(Nz::LightType_Directional); lightNode.SetRotation(Nz::EulerAnglesf(-30.f, 0.f, 0.f)); @@ -360,7 +362,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) m_turretCannonBaseRotation = 0.f; m_turretShootTimer = 0.f; - Ndk::EntityHandle torpedoGroupEntity = m_shared.world3D->CreateEntity(); + const Ndk::EntityHandle& torpedoGroupEntity = m_shared.world3D->CreateEntity(); m_torpedoGroup = torpedoGroupEntity->AddComponent(200, m_torpedoDeclaration).CreateHandle(); RegisterParticleGroup(torpedoGroupEntity); @@ -471,7 +473,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) auto rotationPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Rotation); auto sizePtr = mapper.GetComponentPtr(Nz::ParticleComponent_Size); - renderQueue->AddBillboards(0, sparkleMat1, endId - startId + 1, positionPtr, sizePtr, rotationPtr); + renderQueue->AddBillboards(0, sparkleMat1, endId - startId + 1, Nz::Recti(-1, -1), positionPtr, sizePtr, rotationPtr); for (unsigned int i = startId; i <= endId; ++i) { Nz::AbstractRenderQueue::PointLight pointLight; @@ -607,6 +609,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) fireMat->EnableFaceCulling(true); fireMat->SetDiffuseMap("resources/fire_particle.png"); // Additive blending for fire + fireMat->EnableDepthSorting(false); //< No need for depth sort fireMat->SetDstBlend(Nz::BlendFunc_One); fireMat->SetSrcBlend(Nz::BlendFunc_SrcAlpha); @@ -622,7 +625,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) auto rotPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Rotation); auto sizePtr = mapper.GetComponentPtr(Nz::ParticleComponent_Size); - renderQueue->AddBillboards(0, fireMat, endId - startId + 1, posPtr, sizePtr, rotPtr, colorPtr); + renderQueue->AddBillboards(0, fireMat, endId - startId + 1, Nz::Recti(-1, -1), posPtr, sizePtr, rotPtr, colorPtr); })); m_smokeGroup->SetRenderer(Nz::ParticleFunctionRenderer::New([smokeMat] (const Nz::ParticleGroup& /*group*/, const Nz::ParticleMapper& mapper, unsigned int startId, unsigned int endId, Nz::AbstractRenderQueue* renderQueue) @@ -632,7 +635,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) auto rotPtr = mapper.GetComponentPtr(Nz::ParticleComponent_Rotation); auto sizePtr = mapper.GetComponentPtr(Nz::ParticleComponent_Size); - renderQueue->AddBillboards(0, smokeMat, endId - startId + 1, posPtr, sizePtr, rotPtr, colorPtr); + renderQueue->AddBillboards(0, smokeMat, endId - startId + 1, Nz::Recti(-1, -1), posPtr, sizePtr, rotPtr, colorPtr); })); ////////////////////////////////////////////////////////////////////////// @@ -647,6 +650,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm) ////////////////////////////////////////////////////////////////////////// Nz::TextSpriteRef introText = Nz::TextSprite::New(); + introText->SetMaterial(Nz::Material::New("Translucent3D")); introText->Update(Nz::SimpleTextDrawer::Draw("--Tourelle de défense du secteur A407M2--\nLes contrôles ont été adaptés à vos contrôleurs:\nLa souris contrôle l'orientation de la tourelle, cliquez pour tirer.\n", 72)); introText->SetScale(0.5f); diff --git a/examples/Particles/main.cpp b/examples/Particles/main.cpp index da61aad4b..084c33da8 100644 --- a/examples/Particles/main.cpp +++ b/examples/Particles/main.cpp @@ -59,7 +59,7 @@ int main() shared.particleCount->Update(Nz::SimpleTextDrawer::Draw("XXXXX particles", 36)); world2D.GetSystem().SetGlobalUp(Nz::Vector3f::Down()); - //world3D.GetSystem().ChangeRenderTechnique(); + world3D.GetSystem().ChangeRenderTechnique(); Ndk::EntityHandle viewEntity = world2D.CreateEntity(); diff --git a/include/Nazara/Audio/Algorithm.inl b/include/Nazara/Audio/Algorithm.inl index 64f0b9f46..a2b5c5fe5 100644 --- a/include/Nazara/Audio/Algorithm.inl +++ b/include/Nazara/Audio/Algorithm.inl @@ -22,8 +22,8 @@ namespace Nz void MixToMono(T* input, T* output, UInt32 channelCount, UInt64 frameCount) { // To avoid overflow, we use, as an accumulator, a type which is large enough: (u)int 64 bits for integers, double for floatings - typedef typename std::conditional::value, UInt64, Int64>::type BiggestInt; - typedef typename std::conditional::value, BiggestInt, double>::type Biggest; + using BiggestInt = typename std::conditional::value, UInt64, Int64>::type; + using Biggest = typename std::conditional::value, BiggestInt, double>::type; for (UInt64 i = 0; i < frameCount; ++i) { diff --git a/include/Nazara/Audio/Music.hpp b/include/Nazara/Audio/Music.hpp index fc43d514c..27e742063 100644 --- a/include/Nazara/Audio/Music.hpp +++ b/include/Nazara/Audio/Music.hpp @@ -38,7 +38,7 @@ namespace Nz public: Music() = default; Music(const Music&) = delete; - Music(Music&&) = delete; + Music(Music&&) noexcept = default; ~Music(); bool Create(SoundStream* soundStream); @@ -67,10 +67,10 @@ namespace Nz void Stop() override; Music& operator=(const Music&) = delete; - Music& operator=(Music&&) = delete; + Music& operator=(Music&&) noexcept = default; private: - MovablePtr m_impl = nullptr; + MovablePtr m_impl; bool FillAndQueueBuffer(unsigned int buffer); void MusicThread(); diff --git a/include/Nazara/Audio/Sound.hpp b/include/Nazara/Audio/Sound.hpp index f416f208a..55cc2f97a 100644 --- a/include/Nazara/Audio/Sound.hpp +++ b/include/Nazara/Audio/Sound.hpp @@ -20,7 +20,7 @@ namespace Nz Sound() = default; Sound(const SoundBuffer* soundBuffer); Sound(const Sound& sound); - Sound(Sound&&) = default; + Sound(Sound&&) noexcept = default; ~Sound(); void EnableLooping(bool loop) override; @@ -47,7 +47,7 @@ namespace Nz void Stop() override; Sound& operator=(const Sound&) = delete; ///TODO? - Sound& operator=(Sound&&) = default; + Sound& operator=(Sound&&) noexcept = default; private: SoundBufferConstRef m_buffer; diff --git a/include/Nazara/Audio/SoundEmitter.hpp b/include/Nazara/Audio/SoundEmitter.hpp index 614a1058e..725c6cf76 100644 --- a/include/Nazara/Audio/SoundEmitter.hpp +++ b/include/Nazara/Audio/SoundEmitter.hpp @@ -11,6 +11,7 @@ #include #include #include +#include ///TODO: Inherit SoundEmitter from Node @@ -19,6 +20,7 @@ namespace Nz class NAZARA_AUDIO_API SoundEmitter { public: + SoundEmitter(SoundEmitter&& emitter) noexcept; virtual ~SoundEmitter(); virtual void EnableLooping(bool loop) = 0; @@ -51,16 +53,17 @@ namespace Nz virtual void Stop() = 0; - SoundEmitter& operator=(const SoundEmitter&) = delete; ///TODO - SoundEmitter& operator=(SoundEmitter&&) = delete; + SoundEmitter& operator=(const SoundEmitter&) = delete; + SoundEmitter& operator=(SoundEmitter&&) noexcept; protected: SoundEmitter(); SoundEmitter(const SoundEmitter& emitter); - SoundEmitter(SoundEmitter&&) = delete; SoundStatus GetInternalStatus() const; + static constexpr unsigned int InvalidSource = std::numeric_limits::max(); + unsigned int m_source; }; } diff --git a/include/Nazara/Core.hpp b/include/Nazara/Core.hpp index b4481b1a6..515d8c545 100644 --- a/include/Nazara/Core.hpp +++ b/include/Nazara/Core.hpp @@ -88,6 +88,7 @@ #include #include #include +#include #include #include diff --git a/include/Nazara/Core/Algorithm.hpp b/include/Nazara/Core/Algorithm.hpp index 1425c6220..faf80e6cb 100644 --- a/include/Nazara/Core/Algorithm.hpp +++ b/include/Nazara/Core/Algorithm.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -37,19 +38,22 @@ namespace Nz }; template - struct TypeTag {}; + bool Serialize(SerializationContext& context, T&& value); - inline bool Serialize(SerializationContext& context, bool value); - inline bool Serialize(SerializationContext& context, const std::string& value); + inline bool Serialize(SerializationContext& context, bool value, TypeTag); + inline bool Serialize(SerializationContext& context, const std::string& value, TypeTag); template - std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value); - - inline bool Unserialize(SerializationContext& context, bool* value); - inline bool Unserialize(SerializationContext& context, std::string* value); + std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value, TypeTag); template - std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value); + bool Unserialize(SerializationContext& context, T* value); + + inline bool Unserialize(SerializationContext& context, bool* value, TypeTag); + inline bool Unserialize(SerializationContext& context, std::string* value, TypeTag); + + template + std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value, TypeTag); } #include diff --git a/include/Nazara/Core/Algorithm.inl b/include/Nazara/Core/Algorithm.inl index 095ef3710..969c07bdd 100644 --- a/include/Nazara/Core/Algorithm.inl +++ b/include/Nazara/Core/Algorithm.inl @@ -12,6 +12,7 @@ #include #include #include +#include #include namespace Nz @@ -194,10 +195,17 @@ namespace Nz return reversed; } - template struct PointedType {typedef T type;}; - template struct PointedType {typedef T type;}; - template struct PointedType {typedef T type;}; - template struct PointedType {typedef T type;}; + template struct PointedType { using type = T; }; + template struct PointedType { using type = T; }; + template struct PointedType { using type = T; }; + template struct PointedType { using type = T; }; + + + template + bool Serialize(SerializationContext& context, T&& value) + { + return Serialize(context, std::forward(value), TypeTag>()); + } /*! * \ingroup core @@ -209,7 +217,7 @@ namespace Nz * * \see Serialize, Unserialize */ - inline bool Serialize(SerializationContext& context, bool value) + inline bool Serialize(SerializationContext& context, bool value, TypeTag) { if (context.currentBitPos == 8) { @@ -221,7 +229,7 @@ namespace Nz context.currentByte |= 1 << context.currentBitPos; if (++context.currentBitPos >= 8) - return Serialize(context, context.currentByte); + return Serialize(context, context.currentByte, TypeTag()); else return true; } @@ -234,9 +242,9 @@ namespace Nz * \param context Context for the serialization * \param value String to serialize */ - bool Serialize(SerializationContext& context, const std::string& value) + bool Serialize(SerializationContext& context, const std::string& value, TypeTag) { - if (!Serialize(context, UInt32(value.size()))) + if (!Serialize(context, UInt32(value.size()), TypeTag())) return false; return context.stream->Write(value.data(), value.size()) == value.size(); @@ -253,7 +261,7 @@ namespace Nz * \see Serialize, Unserialize */ template - std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value) + std::enable_if_t::value, bool> Serialize(SerializationContext& context, T value, TypeTag) { // Flush bits in case a writing is in progress context.FlushBits(); @@ -264,6 +272,13 @@ namespace Nz return context.stream->Write(&value, sizeof(T)) == sizeof(T); } + + template + bool Unserialize(SerializationContext& context, T* value) + { + return Unserialize(context, value, TypeTag()); + } + /*! * \ingroup core * \brief Unserializes a boolean @@ -274,11 +289,11 @@ namespace Nz * * \see Serialize, Unserialize */ - inline bool Unserialize(SerializationContext& context, bool* value) + inline bool Unserialize(SerializationContext& context, bool* value, TypeTag) { if (context.currentBitPos == 8) { - if (!Unserialize(context, &context.currentByte)) + if (!Unserialize(context, &context.currentByte, TypeTag())) return false; context.currentBitPos = 0; @@ -299,10 +314,10 @@ namespace Nz * \param context Context of unserialization * \param string std::string to unserialize */ - bool Unserialize(SerializationContext& context, std::string* string) + bool Unserialize(SerializationContext& context, std::string* string, TypeTag) { UInt32 size; - if (!Unserialize(context, &size)) + if (!Unserialize(context, &size, TypeTag())) return false; string->resize(size); @@ -322,7 +337,7 @@ namespace Nz * \see Serialize, Unserialize */ template - std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value) + std::enable_if_t::value, bool> Unserialize(SerializationContext& context, T* value, TypeTag) { NazaraAssert(value, "Invalid data pointer"); diff --git a/include/Nazara/Core/Bitset.hpp b/include/Nazara/Core/Bitset.hpp index 16cca14fb..1ac7a74b2 100644 --- a/include/Nazara/Core/Bitset.hpp +++ b/include/Nazara/Core/Bitset.hpp @@ -51,9 +51,6 @@ namespace Nz std::size_t GetCapacity() const; std::size_t GetSize() const; - PointerSequence Read(const void* ptr, std::size_t bitCount); - PointerSequence Read(const PointerSequence& sequence, std::size_t bitCount); - void PerformsAND(const Bitset& a, const Bitset& b); void PerformsNOT(const Bitset& a); void PerformsOR(const Bitset& a, const Bitset& b); @@ -90,6 +87,9 @@ namespace Nz void UnboundedSet(std::size_t bit, bool val = true); bool UnboundedTest(std::size_t bit) const; + PointerSequence Write(const void* ptr, std::size_t bitCount); + PointerSequence Write(const PointerSequence& sequence, std::size_t bitCount); + Bit operator[](std::size_t index); bool operator[](std::size_t index) const; diff --git a/include/Nazara/Core/Bitset.inl b/include/Nazara/Core/Bitset.inl index 3b24586bd..1feda0b59 100644 --- a/include/Nazara/Core/Bitset.inl +++ b/include/Nazara/Core/Bitset.inl @@ -328,9 +328,9 @@ namespace Nz } /*! - * \brief Read a byte sequence into a bitset + * \brief Writes a byte sequence into a bitset * - * This function extends the bitset with bits read from a byte sequence + * This function extends the bitset with bits read from a byte sequence. * * \param ptr A pointer to the start of the byte sequence * \param bitCount Number of bits to read from the byte sequence @@ -341,17 +341,18 @@ namespace Nz * * \see AppendBits * \see Read + * \see Write */ template - typename Bitset::PointerSequence Bitset::Read(const void* ptr, std::size_t bitCount) + typename Bitset::PointerSequence Bitset::Write(const void* ptr, std::size_t bitCount) { - return Read(PointerSequence(ptr, 0U), bitCount); + return Write(PointerSequence(ptr, 0U), bitCount); } /*! - * \brief Read a byte sequence into a bitset + * \brief Writes a byte sequence into a bitset * - * This function extends the bitset with bits read from a pointer sequence (made of a pointer and a bit index) + * This function extends the bitset with bits read from a pointer sequence (made of a pointer and a bit index). * * \param sequence A pointer sequence to the start of the byte sequence * \param bitCount Number of bits to read from the byte sequence @@ -362,9 +363,10 @@ namespace Nz * * \see AppendBits * \see Read + * \see Write */ template - typename Bitset::PointerSequence Bitset::Read(const PointerSequence& sequence, std::size_t bitCount) + typename Bitset::PointerSequence Bitset::Write(const PointerSequence& sequence, std::size_t bitCount) { NazaraAssert(sequence.first, "Invalid pointer sequence"); NazaraAssert(sequence.second < 8, "Invalid next bit index (must be < 8)"); @@ -1161,9 +1163,9 @@ namespace Nz Bitset bitset; if (sequence) - *sequence = bitset.Read(ptr, bitCount); + *sequence = bitset.Write(ptr, bitCount); else - bitset.Read(ptr, bitCount); + bitset.Write(ptr, bitCount); return bitset; } diff --git a/include/Nazara/Core/ByteStream.inl b/include/Nazara/Core/ByteStream.inl index 49d51b7d6..0b32215e7 100644 --- a/include/Nazara/Core/ByteStream.inl +++ b/include/Nazara/Core/ByteStream.inl @@ -90,7 +90,7 @@ namespace Nz { m_context.currentBitPos = 8; //< To prevent Serialize to flush bits itself - if (!Serialize(m_context, m_context.currentByte)) + if (!Serialize(m_context, m_context.currentByte)) return false; } diff --git a/include/Nazara/Core/Color.hpp b/include/Nazara/Core/Color.hpp index 3f3447710..16977c2e0 100644 --- a/include/Nazara/Core/Color.hpp +++ b/include/Nazara/Core/Color.hpp @@ -71,8 +71,8 @@ namespace Nz static float Hue2RGB(float v1, float v2, float vH); }; - inline bool Serialize(SerializationContext& context, const Color& color); - inline bool Unserialize(SerializationContext& context, Color* color); + inline bool Serialize(SerializationContext& context, const Color& color, TypeTag); + inline bool Unserialize(SerializationContext& context, Color* color, TypeTag); } std::ostream& operator<<(std::ostream& out, const Nz::Color& color); diff --git a/include/Nazara/Core/Color.inl b/include/Nazara/Core/Color.inl index f391f0c76..ace951dd0 100644 --- a/include/Nazara/Core/Color.inl +++ b/include/Nazara/Core/Color.inl @@ -617,7 +617,7 @@ namespace Nz * \param context Serialization context * \param color Input color */ - inline bool Serialize(SerializationContext& context, const Color& color) + inline bool Serialize(SerializationContext& context, const Color& color, TypeTag) { if (!Serialize(context, color.r)) return false; @@ -641,7 +641,7 @@ namespace Nz * \param context Serialization context * \param color Output color */ - inline bool Unserialize(SerializationContext& context, Color* color) + inline bool Unserialize(SerializationContext& context, Color* color, TypeTag) { if (!Unserialize(context, &color->r)) return false; diff --git a/include/Nazara/Core/HandledObject.hpp b/include/Nazara/Core/HandledObject.hpp index 4377377de..633f7e9fe 100644 --- a/include/Nazara/Core/HandledObject.hpp +++ b/include/Nazara/Core/HandledObject.hpp @@ -23,16 +23,16 @@ namespace Nz public: HandledObject() = default; HandledObject(const HandledObject& object); - HandledObject(HandledObject&& object); + HandledObject(HandledObject&& object) noexcept; ~HandledObject(); ObjectHandle CreateHandle(); HandledObject& operator=(const HandledObject& object); - HandledObject& operator=(HandledObject&& object); + HandledObject& operator=(HandledObject&& object) noexcept; protected: - void UnregisterAllHandles(); + void UnregisterAllHandles() noexcept; private: void RegisterHandle(ObjectHandle* handle); diff --git a/include/Nazara/Core/HandledObject.inl b/include/Nazara/Core/HandledObject.inl index 2b0bb3f23..3349fa7e1 100644 --- a/include/Nazara/Core/HandledObject.inl +++ b/include/Nazara/Core/HandledObject.inl @@ -34,7 +34,7 @@ namespace Nz * \param object HandledObject to move into this */ template - HandledObject::HandledObject(HandledObject&& object) : + HandledObject::HandledObject(HandledObject&& object) noexcept : m_handles(std::move(object.m_handles)) { for (ObjectHandle* handle : m_handles) @@ -84,8 +84,10 @@ namespace Nz * \param object HandledObject to move in this */ template - HandledObject& HandledObject::operator=(HandledObject&& object) + HandledObject& HandledObject::operator=(HandledObject&& object) noexcept { + UnregisterAllHandles(); + m_handles = std::move(object.m_handles); for (ObjectHandle* handle : m_handles) handle->OnObjectMoved(static_cast(this)); @@ -110,7 +112,7 @@ namespace Nz * \brief Unregisters all handles */ template - void HandledObject::UnregisterAllHandles() + void HandledObject::UnregisterAllHandles() noexcept { // Tell every handle we got destroyed, to null them for (ObjectHandle* handle : m_handles) diff --git a/include/Nazara/Core/ObjectHandle.hpp b/include/Nazara/Core/ObjectHandle.hpp index 022344488..9dadbc832 100644 --- a/include/Nazara/Core/ObjectHandle.hpp +++ b/include/Nazara/Core/ObjectHandle.hpp @@ -49,8 +49,8 @@ namespace Nz static const ObjectHandle InvalidHandle; protected: - void OnObjectDestroyed(); - void OnObjectMoved(T* newObject); + void OnObjectDestroyed() noexcept; + void OnObjectMoved(T* newObject) noexcept; T* m_object; }; @@ -81,8 +81,8 @@ namespace Nz template bool operator>=(const T& lhs, const ObjectHandle& rhs); template bool operator>=(const ObjectHandle& lhs, const T& rhs); - template struct PointedType> { typedef T type; }; - template struct PointedType> { typedef T type; }; + template struct PointedType> { using type = T; }; + template struct PointedType> { using type = T; }; } namespace std diff --git a/include/Nazara/Core/ObjectHandle.inl b/include/Nazara/Core/ObjectHandle.inl index f4c70ae85..f415f93de 100644 --- a/include/Nazara/Core/ObjectHandle.inl +++ b/include/Nazara/Core/ObjectHandle.inl @@ -268,7 +268,7 @@ namespace Nz * \brief Action to do on object destruction */ template - void ObjectHandle::OnObjectDestroyed() + void ObjectHandle::OnObjectDestroyed() noexcept { // Shortcut m_object = nullptr; @@ -278,7 +278,7 @@ namespace Nz * \brief Action to do on object move */ template - void ObjectHandle::OnObjectMoved(T* newObject) + void ObjectHandle::OnObjectMoved(T* newObject) noexcept { // The object has been moved, update our pointer m_object = newObject; diff --git a/include/Nazara/Core/ObjectRef.hpp b/include/Nazara/Core/ObjectRef.hpp index 379f56e02..c7959efc8 100644 --- a/include/Nazara/Core/ObjectRef.hpp +++ b/include/Nazara/Core/ObjectRef.hpp @@ -69,8 +69,8 @@ namespace Nz template bool operator>=(const ObjectRef& lhs, const T& rhs); - template struct PointedType> { typedef T type; }; - template struct PointedType const> { typedef T type; }; + template struct PointedType> { using type = T; }; + template struct PointedType const> { using type = T; }; } #include diff --git a/include/Nazara/Core/SerializationContext.hpp b/include/Nazara/Core/SerializationContext.hpp index 102e82850..94951666d 100644 --- a/include/Nazara/Core/SerializationContext.hpp +++ b/include/Nazara/Core/SerializationContext.hpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace Nz { diff --git a/include/Nazara/Core/String.hpp b/include/Nazara/Core/String.hpp index 0c8f2c7f8..42dacc191 100644 --- a/include/Nazara/Core/String.hpp +++ b/include/Nazara/Core/String.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -188,10 +189,10 @@ namespace Nz //char* rend(); //const char* rend() const; - typedef const char& const_reference; - typedef char* iterator; - //typedef char* reverse_iterator; - typedef char value_type; + using const_reference = const char&; + using iterator = char*; + //using reverse_iterator = char*; + using value_type = char; // Méthodes STD char& operator[](std::size_t pos); @@ -328,8 +329,8 @@ namespace Nz class AbstractHash; inline bool HashAppend(AbstractHash* hash, const String& string); - NAZARA_CORE_API bool Serialize(SerializationContext& context, const String& string); - NAZARA_CORE_API bool Unserialize(SerializationContext& context, String* string); + NAZARA_CORE_API bool Serialize(SerializationContext& context, const String& string, TypeTag); + NAZARA_CORE_API bool Unserialize(SerializationContext& context, String* string, TypeTag); } namespace std diff --git a/include/Nazara/Core/TypeTag.hpp b/include/Nazara/Core/TypeTag.hpp new file mode 100644 index 000000000..150802b01 --- /dev/null +++ b/include/Nazara/Core/TypeTag.hpp @@ -0,0 +1,16 @@ +// 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_TYPETAG_HPP +#define NAZARA_TYPETAG_HPP + +namespace Nz +{ + template + struct TypeTag {}; +} + +#endif // NAZARA_TYPETAG_HPP diff --git a/include/Nazara/Graphics.hpp b/include/Nazara/Graphics.hpp index 3d7edd264..0d14c14a1 100644 --- a/include/Nazara/Graphics.hpp +++ b/include/Nazara/Graphics.hpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -45,14 +46,13 @@ #include #include #include +#include #include -#include #include #include #include #include #include -#include #include #include #include @@ -73,6 +73,7 @@ #include #include #include +#include #include #include #include diff --git a/include/Nazara/Graphics/AbstractRenderQueue.hpp b/include/Nazara/Graphics/AbstractRenderQueue.hpp index db4139c73..f4d268786 100644 --- a/include/Nazara/Graphics/AbstractRenderQueue.hpp +++ b/include/Nazara/Graphics/AbstractRenderQueue.hpp @@ -37,20 +37,20 @@ namespace Nz // Je ne suis vraiment pas fan du nombre de surcharges pour AddBillboards, // mais je n'ai pas d'autre solution tout aussi performante pour le moment... - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) = 0; - virtual void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) = 0; + virtual void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) = 0; virtual void AddDrawable(int renderOrder, const Drawable* drawable) = 0; virtual void AddDirectionalLight(const DirectionalLight& light); - virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) = 0; + virtual void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect) = 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, std::size_t 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 Recti& scissorRect, const Texture* overlay = nullptr) = 0; virtual void Clear(bool fully = false); diff --git a/include/Nazara/Graphics/BasicRenderQueue.hpp b/include/Nazara/Graphics/BasicRenderQueue.hpp new file mode 100644 index 000000000..1be56b5fd --- /dev/null +++ b/include/Nazara/Graphics/BasicRenderQueue.hpp @@ -0,0 +1,142 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_BASICRENDERQUEUE_HPP +#define NAZARA_BASICRENDERQUEUE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class AbstractViewer; + + class NAZARA_GRAPHICS_API BasicRenderQueue : public AbstractRenderQueue + { + friend class ForwardRenderTechnique; + + public: + struct BillboardData; + + BasicRenderQueue() = default; + ~BasicRenderQueue() = default; + + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, 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, const Recti& scissorRect) override; + void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay = nullptr) override; + + void Clear(bool fully = false) override; + + inline const BillboardData* GetBillboardData(std::size_t billboardIndex) const; + + void Sort(const AbstractViewer* viewer); + + struct BillboardData + { + Color color; + Vector3f center; + Vector2f size; + Vector2f sinCos; + }; + + struct Billboard + { + int layerIndex; + MovablePtr material; + Nz::Recti scissorRect; + BillboardData data; + }; + + struct BillboardChain + { + int layerIndex; + MovablePtr material; + Nz::Recti scissorRect; + std::size_t billboardCount; + std::size_t billboardIndex; + }; + + RenderQueue billboards; + RenderQueue depthSortedBillboards; + + struct CustomDrawable + { + int layerIndex; + MovablePtr drawable; + }; + + RenderQueue customDrawables; + + struct Model + { + int layerIndex; + MeshData meshData; + MovablePtr material; + Nz::Matrix4f matrix; + Nz::Recti scissorRect; + Nz::Spheref obbSphere; + }; + + RenderQueue models; + RenderQueue depthSortedModels; + + struct SpriteChain + { + int layerIndex; + std::size_t spriteCount; + MovablePtr material; + MovablePtr overlay; + MovablePtr vertices; + Nz::Recti scissorRect; + }; + + RenderQueue basicSprites; + RenderQueue depthSortedSprites; + + private: + inline Color ComputeColor(float alpha); + inline Vector2f ComputeSinCos(float angle); + inline Vector2f ComputeSize(float size); + + inline void RegisterLayer(int layerIndex); + + std::unordered_map m_pipelineCache; + std::unordered_map m_materialCache; + std::unordered_map m_overlayCache; + std::unordered_map m_shaderCache; + std::unordered_map m_textureCache; + std::unordered_map m_vertexBufferCache; + std::unordered_map m_layerCache; + + std::vector m_billboards; + std::vector m_renderLayers; + }; +} + +#include + +#endif // NAZARA_BASICRENDERQUEUE_HPP diff --git a/include/Nazara/Graphics/BasicRenderQueue.inl b/include/Nazara/Graphics/BasicRenderQueue.inl new file mode 100644 index 000000000..14dde08dc --- /dev/null +++ b/include/Nazara/Graphics/BasicRenderQueue.inl @@ -0,0 +1,38 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline const BasicRenderQueue::BillboardData* BasicRenderQueue::GetBillboardData(std::size_t billboardIndex) const + { + assert(billboardIndex < m_billboards.size()); + return &m_billboards[billboardIndex]; + } + + inline Color BasicRenderQueue::ComputeColor(float alpha) + { + return Color(255, 255, 255, static_cast(255.f * alpha)); + } + + inline Vector2f BasicRenderQueue::ComputeSinCos(float angle) + { + float radians = ToRadians(angle); + return { std::sin(radians), std::cos(radians) }; + } + + inline Vector2f BasicRenderQueue::ComputeSize(float size) + { + return Vector2f(size, size); + } + + inline void BasicRenderQueue::RegisterLayer(int layerIndex) + { + auto it = std::lower_bound(m_renderLayers.begin(), m_renderLayers.end(), layerIndex); + if (it == m_renderLayers.end() || *it != layerIndex) + m_renderLayers.insert(it, layerIndex); + } +} diff --git a/include/Nazara/Graphics/Billboard.hpp b/include/Nazara/Graphics/Billboard.hpp index af77001bd..62f872f39 100644 --- a/include/Nazara/Graphics/Billboard.hpp +++ b/include/Nazara/Graphics/Billboard.hpp @@ -29,7 +29,7 @@ namespace Nz Billboard(Billboard&&) = delete; ~Billboard() = default; - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override; + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const override; inline const Color& GetColor() const; inline float GetRotation() const; diff --git a/include/Nazara/Graphics/DeferredGeometryPass.hpp b/include/Nazara/Graphics/DeferredGeometryPass.hpp index aaa8f6471..3c7890bfe 100644 --- a/include/Nazara/Graphics/DeferredGeometryPass.hpp +++ b/include/Nazara/Graphics/DeferredGeometryPass.hpp @@ -8,6 +8,7 @@ #define NAZARA_DEFERREDGEOMETRYPASS_HPP #include +#include #include #include #include @@ -17,6 +18,8 @@ namespace Nz { class NAZARA_GRAPHICS_API DeferredGeometryPass : public DeferredRenderPass { + friend class DeferredRenderTechnique; + public: DeferredGeometryPass(); virtual ~DeferredGeometryPass(); @@ -27,9 +30,17 @@ namespace Nz protected: struct ShaderUniforms; + void DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const; + void DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const; + void DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& models) const; + void DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& sprites) const; + const ShaderUniforms* GetShaderUniforms(const Shader* shader) const; void OnShaderInvalidated(const Shader* shader) const; + static bool Initialize(); + static void Uninitialize(); + struct ShaderUniforms { NazaraSlot(Shader, OnShaderUniformInvalidated, shaderUniformInvalidatedSlot); @@ -41,8 +52,18 @@ namespace Nz }; mutable std::unordered_map m_shaderUniforms; + mutable std::vector> m_spriteChains; + Buffer m_vertexBuffer; RenderStates m_clearStates; ShaderRef m_clearShader; + TextureRef m_whiteTexture; + VertexBuffer m_billboardPointBuffer; + VertexBuffer m_spriteBuffer; + + static IndexBuffer s_quadIndexBuffer; + static VertexBuffer s_quadVertexBuffer; + static VertexDeclaration s_billboardInstanceDeclaration; + static VertexDeclaration s_billboardVertexDeclaration; }; } diff --git a/include/Nazara/Graphics/DeferredProxyRenderQueue.hpp b/include/Nazara/Graphics/DeferredProxyRenderQueue.hpp new file mode 100644 index 000000000..98155b0fd --- /dev/null +++ b/include/Nazara/Graphics/DeferredProxyRenderQueue.hpp @@ -0,0 +1,58 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_DEFERREDRENDERQUEUE_HPP +#define NAZARA_DEFERREDRENDERQUEUE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Nz +{ + class BasicRenderQueue; + + class NAZARA_GRAPHICS_API DeferredProxyRenderQueue final : public AbstractRenderQueue + { + public: + struct BillboardData; + + inline DeferredProxyRenderQueue(BasicRenderQueue* deferredQueue, BasicRenderQueue* forwardQueue); + ~DeferredProxyRenderQueue() = default; + + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, 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, const Recti& scissorRect) override; + void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay = nullptr) override; + + void Clear(bool fully = false) override; + + inline BasicRenderQueue* GetDeferredRenderQueue(); + inline BasicRenderQueue* GetForwardRenderQueue(); + + private: + BasicRenderQueue * m_deferredRenderQueue; + BasicRenderQueue* m_forwardRenderQueue; + }; +} + +#include + +#endif // NAZARA_DEFERREDRENDERQUEUE_HPP diff --git a/include/Nazara/Graphics/DeferredProxyRenderQueue.inl b/include/Nazara/Graphics/DeferredProxyRenderQueue.inl new file mode 100644 index 000000000..e56545e0d --- /dev/null +++ b/include/Nazara/Graphics/DeferredProxyRenderQueue.inl @@ -0,0 +1,30 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +namespace Nz +{ + /*! + * \brief Constructs a DeferredProxyRenderQueue using a deferred and a forward queues + * + * \param deferredQueue Deferred queue which will be used for non-blended objects + * \param forwardQueue Forward queue which will be used for blended objects + */ + inline DeferredProxyRenderQueue::DeferredProxyRenderQueue(BasicRenderQueue* deferredQueue, BasicRenderQueue* forwardQueue) : + m_deferredRenderQueue(deferredQueue), + m_forwardRenderQueue(forwardQueue) + { + } + + inline BasicRenderQueue* DeferredProxyRenderQueue::GetDeferredRenderQueue() + { + return m_deferredRenderQueue; + } + + inline BasicRenderQueue* DeferredProxyRenderQueue::GetForwardRenderQueue() + { + return m_forwardRenderQueue; + } +} diff --git a/include/Nazara/Graphics/DeferredRenderPass.hpp b/include/Nazara/Graphics/DeferredRenderPass.hpp index 4c54d5777..ca4cdce3d 100644 --- a/include/Nazara/Graphics/DeferredRenderPass.hpp +++ b/include/Nazara/Graphics/DeferredRenderPass.hpp @@ -14,10 +14,10 @@ namespace Nz { class DeferredRenderTechnique; - class DeferredRenderQueue; - struct SceneData; + class DeferredProxyRenderQueue; class RenderTexture; class Texture; + struct SceneData; class NAZARA_GRAPHICS_API DeferredRenderPass { @@ -42,7 +42,7 @@ namespace Nz protected: Vector2ui m_dimensions; DeferredRenderTechnique* m_deferredTechnique; - DeferredRenderQueue* m_renderQueue; + DeferredProxyRenderQueue* m_renderQueue; RenderTexture* m_GBufferRTT; RenderTexture* m_workRTT; Texture* m_depthStencilTexture; diff --git a/include/Nazara/Graphics/DeferredRenderQueue.hpp b/include/Nazara/Graphics/DeferredRenderQueue.hpp deleted file mode 100644 index 0cb390ace..000000000 --- a/include/Nazara/Graphics/DeferredRenderQueue.hpp +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Graphics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_DEFERREDRENDERQUEUE_HPP -#define NAZARA_DEFERREDRENDERQUEUE_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class NAZARA_GRAPHICS_API DeferredRenderQueue : public AbstractRenderQueue - { - public: - DeferredRenderQueue(ForwardRenderQueue* forwardQueue); - ~DeferredRenderQueue() = default; - - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; - 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, std::size_t spriteCount, const Texture* overlay = nullptr) override; - - void Clear(bool fully = false) override; - - struct MeshInstanceEntry - { - NazaraSlot(IndexBuffer, OnIndexBufferRelease, indexBufferReleaseSlot); - NazaraSlot(VertexBuffer, OnVertexBufferRelease, vertexBufferReleaseSlot); - - std::vector instances; - }; - - typedef std::map MeshInstanceContainer; - - struct BatchedModelEntry - { - NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot); - - MeshInstanceContainer meshMap; - bool enabled = false; - }; - - typedef std::map MeshMaterialBatches; - - struct BatchedMaterialEntry - { - std::size_t maxInstanceCount = 0; - MeshMaterialBatches materialMap; - }; - - typedef std::map MeshPipelineBatches; - - struct Layer - { - MeshPipelineBatches opaqueModels; - unsigned int clearCount = 0; - }; - - std::map layers; - - private: - Layer& GetLayer(unsigned int i); ///TODO: Inline - - ForwardRenderQueue* m_forwardQueue; - - void OnIndexBufferInvalidation(const IndexBuffer* indexBuffer); - void OnMaterialInvalidation(const Material* material); - void OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer); - }; -} - -#endif // NAZARA_DEFERREDRENDERQUEUE_HPP diff --git a/include/Nazara/Graphics/DeferredRenderQueue.inl b/include/Nazara/Graphics/DeferredRenderQueue.inl new file mode 100644 index 000000000..e69de29bb diff --git a/include/Nazara/Graphics/DeferredRenderTechnique.hpp b/include/Nazara/Graphics/DeferredRenderTechnique.hpp index 96f7df1fa..fc9588ae5 100644 --- a/include/Nazara/Graphics/DeferredRenderTechnique.hpp +++ b/include/Nazara/Graphics/DeferredRenderTechnique.hpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -64,8 +64,9 @@ namespace Nz }; std::map>, RenderPassComparator> m_passes; - ForwardRenderTechnique m_forwardTechnique; // Must be initialized before the RenderQueue - DeferredRenderQueue m_renderQueue; + BasicRenderQueue m_deferredRenderQueue; // Must be initialized before the ProxyRenderQueue + ForwardRenderTechnique m_forwardTechnique; // Must be initialized before the ProxyRenderQueue + DeferredProxyRenderQueue m_renderQueue; mutable TextureRef m_depthStencilTexture; mutable RenderTexture m_GBufferRTT; mutable RenderTexture m_workRTT; diff --git a/include/Nazara/Graphics/DepthRenderQueue.hpp b/include/Nazara/Graphics/DepthRenderQueue.hpp index 69f1ceae9..10a00783e 100644 --- a/include/Nazara/Graphics/DepthRenderQueue.hpp +++ b/include/Nazara/Graphics/DepthRenderQueue.hpp @@ -8,33 +8,33 @@ #define NAZARA_DEPTHRENDERQUEUE_HPP #include -#include +#include #include #include namespace Nz { - class NAZARA_GRAPHICS_API DepthRenderQueue : public ForwardRenderQueue + class NAZARA_GRAPHICS_API DepthRenderQueue : public BasicRenderQueue { public: DepthRenderQueue(); ~DepthRenderQueue() = default; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; + void AddBillboards(int renderOrder, const Material* material, std::size_t count, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; void AddDirectionalLight(const DirectionalLight& light) override; - void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) override; + void AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect) 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, std::size_t spriteCount, const Texture* overlay = nullptr) override; + void AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay = nullptr) override; - private: + private: inline bool IsMaterialSuitable(const Material* material) const; MaterialRef m_baseMaterial; diff --git a/include/Nazara/Graphics/DepthRenderTechnique.hpp b/include/Nazara/Graphics/DepthRenderTechnique.hpp index 0e1e6daea..f8f7bc4e3 100644 --- a/include/Nazara/Graphics/DepthRenderTechnique.hpp +++ b/include/Nazara/Graphics/DepthRenderTechnique.hpp @@ -35,9 +35,12 @@ namespace Nz private: struct ShaderUniforms; - 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 DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const; + void DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const; + void DrawCustomDrawables(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& customDrawables) const; + void DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& models) const; + void DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& sprites) const; + const ShaderUniforms* GetShaderUniforms(const Shader* shader) const; void OnShaderInvalidated(const Shader* shader) const; @@ -59,11 +62,14 @@ namespace Nz }; mutable std::unordered_map m_shaderUniforms; + mutable std::vector> m_spriteChains; Buffer m_vertexBuffer; - mutable DepthRenderQueue m_renderQueue; - Texture m_whiteTexture; + RenderStates m_clearStates; + ShaderRef m_clearShader; + TextureRef m_whiteTexture; VertexBuffer m_billboardPointBuffer; VertexBuffer m_spriteBuffer; + mutable DepthRenderQueue m_renderQueue; static IndexBuffer s_quadIndexBuffer; static VertexBuffer s_quadVertexBuffer; diff --git a/include/Nazara/Graphics/ForwardRenderQueue.hpp b/include/Nazara/Graphics/ForwardRenderQueue.hpp deleted file mode 100644 index 37f1db554..000000000 --- a/include/Nazara/Graphics/ForwardRenderQueue.hpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Graphics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#pragma once - -#ifndef NAZARA_FORWARDRENDERQUEUE_HPP -#define NAZARA_FORWARDRENDERQUEUE_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Nz -{ - class AbstractViewer; - - class NAZARA_GRAPHICS_API ForwardRenderQueue : public AbstractRenderQueue - { - friend class ForwardRenderTechnique; - - public: - ForwardRenderQueue() = default; - ~ForwardRenderQueue() = default; - - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr = nullptr, SparsePtr colorPtr = nullptr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) override; - void AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr = nullptr) override; - 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, std::size_t spriteCount, const Texture* overlay = nullptr) override; - - void Clear(bool fully = false) override; - - void Sort(const AbstractViewer* viewer); - - struct MaterialComparator - { - bool operator()(const Material* mat1, const Material* mat2) const; - }; - - struct MaterialPipelineComparator - { - bool operator()(const MaterialPipeline* pipeline1, const MaterialPipeline* pipeline2) const; - }; - - /// Billboards - struct BillboardData - { - Color color; - Vector3f center; - Vector2f size; - Vector2f sinCos; - }; - - struct BatchedBillboardEntry - { - NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot); - - std::vector billboards; - }; - - using BatchedBillboardContainer = std::map; - - struct BatchedBillboardPipelineEntry - { - BatchedBillboardContainer materialMap; - bool enabled = false; - }; - - using BillboardPipelineBatches = std::map; - - /// Sprites - struct SpriteChain_XYZ_Color_UV - { - const VertexStruct_XYZ_Color_UV* vertices; - std::size_t spriteCount; - }; - - struct BatchedSpriteEntry - { - NazaraSlot(Texture, OnTextureRelease, textureReleaseSlot); - - std::vector spriteChains; - }; - - using SpriteOverlayBatches = std::map; - - struct BatchedBasicSpriteEntry - { - NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot); - - SpriteOverlayBatches overlayMap; - bool enabled = false; - }; - - using SpriteMaterialBatches = std::map; - - struct BatchedSpritePipelineEntry - { - SpriteMaterialBatches materialMap; - bool enabled = false; - }; - - using SpritePipelineBatches = std::map; - - /// Meshes - struct MeshDataComparator - { - bool operator()(const MeshData& data1, const MeshData& data2) const; - }; - - struct MeshInstanceEntry - { - NazaraSlot(IndexBuffer, OnIndexBufferRelease, indexBufferReleaseSlot); - NazaraSlot(VertexBuffer, OnVertexBufferRelease, vertexBufferReleaseSlot); - - std::vector instances; - Spheref squaredBoundingSphere; - }; - - using MeshInstanceContainer = std::map; - - struct BatchedModelEntry - { - NazaraSlot(Material, OnMaterialRelease, materialReleaseSlot); - - MeshInstanceContainer meshMap; - bool enabled = false; - }; - - using MeshMaterialBatches = std::map; - - struct BatchedMaterialEntry - { - std::size_t maxInstanceCount = 0; - MeshMaterialBatches materialMap; - }; - - using MeshPipelineBatches = std::map; - - struct UnbatchedModelData - { - Matrix4f transformMatrix; - MeshData meshData; - Spheref obbSphere; - const Material* material; - }; - - struct UnbatchedSpriteData - { - std::size_t spriteCount; - const Material* material; - const Texture* overlay; - const VertexStruct_XYZ_Color_UV* vertices; - }; - - struct Layer - { - BillboardPipelineBatches billboards; - SpritePipelineBatches opaqueSprites; - MeshPipelineBatches opaqueModels; - std::vector depthSortedMeshes; - std::vector depthSortedSprites; - std::vector depthSortedMeshData; - std::vector depthSortedSpriteData; - std::vector otherDrawables; - unsigned int clearCount = 0; - }; - - std::map layers; - - private: - 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); - void OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer); - }; -} - -#endif // NAZARA_FORWARDRENDERQUEUE_HPP diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.hpp b/include/Nazara/Graphics/ForwardRenderTechnique.hpp index f5972d974..640986e62 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.hpp +++ b/include/Nazara/Graphics/ForwardRenderTechnique.hpp @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -40,11 +40,12 @@ namespace Nz struct ShaderUniforms; void ChooseLights(const Spheref& object, bool includeDirectionalLights = true) const; - 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; + void DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const; + void DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const; + void DrawCustomDrawables(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& customDrawables) const; + void DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& models) const; + void DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& sprites) const; + const ShaderUniforms* GetShaderUniforms(const Shader* shader) const; void OnShaderInvalidated(const Shader* shader) const; void SendLightUniforms(const Shader* shader, const LightUniforms& uniforms, unsigned int index, unsigned int lightIndex, unsigned int uniformOffset) const; @@ -84,15 +85,16 @@ namespace Nz mutable std::unordered_map m_shaderUniforms; mutable std::vector m_lights; + mutable std::vector> m_spriteChains; Buffer m_vertexBuffer; - mutable ForwardRenderQueue m_renderQueue; - Texture m_whiteTexture; + mutable BasicRenderQueue m_renderQueue; + TextureRef m_whiteCubemap; + TextureRef m_whiteTexture; VertexBuffer m_billboardPointBuffer; VertexBuffer m_spriteBuffer; unsigned int m_maxLightPassPerObject; static IndexBuffer s_quadIndexBuffer; - static Texture s_dummyReflection; static TextureSampler s_reflectionSampler; static TextureSampler s_shadowSampler; static VertexBuffer s_quadVertexBuffer; diff --git a/include/Nazara/Graphics/ForwardRenderTechnique.inl b/include/Nazara/Graphics/ForwardRenderTechnique.inl index ae22668ec..564da3d22 100644 --- a/include/Nazara/Graphics/ForwardRenderTechnique.inl +++ b/include/Nazara/Graphics/ForwardRenderTechnique.inl @@ -2,7 +2,7 @@ // This file is part of the "Nazara Engine - Graphics module" // For conditions of distribution and use, see copyright notice in Config.hpp -#include +#include namespace Nz { diff --git a/include/Nazara/Graphics/InstancedRenderable.hpp b/include/Nazara/Graphics/InstancedRenderable.hpp index 56e7bc0a1..25f6064a8 100644 --- a/include/Nazara/Graphics/InstancedRenderable.hpp +++ b/include/Nazara/Graphics/InstancedRenderable.hpp @@ -37,7 +37,7 @@ namespace Nz InstancedRenderable(InstancedRenderable&& renderable) = delete; virtual ~InstancedRenderable(); - virtual void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const = 0; + virtual void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const = 0; virtual bool Cull(const Frustumf& frustum, const InstanceData& instanceData) const; diff --git a/include/Nazara/Graphics/Model.hpp b/include/Nazara/Graphics/Model.hpp index 32cfdfada..b37d68a2e 100644 --- a/include/Nazara/Graphics/Model.hpp +++ b/include/Nazara/Graphics/Model.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -44,8 +45,8 @@ namespace Nz Model(Model&& model) = default; virtual ~Model(); - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override; - inline void AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix, unsigned int renderOrder = 0); + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const override; + inline void AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix, int renderOrder = 0, const Recti& scissorRect = Recti(-1, -1, -1, -1)) const; using InstancedRenderable::GetMaterial; const MaterialRef& GetMaterial(const String& subMeshName) const; diff --git a/include/Nazara/Graphics/Model.inl b/include/Nazara/Graphics/Model.inl index fa1138f78..486665f3a 100644 --- a/include/Nazara/Graphics/Model.inl +++ b/include/Nazara/Graphics/Model.inl @@ -22,14 +22,15 @@ namespace Nz * * \param renderQueue Queue to be added * \param transformMatrix Transform matrix to be used for rendering the model - * \param renderOrder Specify the renderqueue layer to be used + * \param renderOrder Specify the render queue layer to be used + * \param scissorRect The Scissor rect to uses for rendering */ - inline void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix, unsigned int renderOrder) - { + void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const Matrix4f& transformMatrix, int renderOrder, const Recti& scissorRect) const +{ InstanceData instanceData(Nz::Matrix4f::Identity()); instanceData.renderOrder = renderOrder; instanceData.transformMatrix = transformMatrix; - return AddToRenderQueue(renderQueue, instanceData); + return AddToRenderQueue(renderQueue, instanceData, scissorRect); } /*! diff --git a/include/Nazara/Graphics/RenderQueue.hpp b/include/Nazara/Graphics/RenderQueue.hpp new file mode 100644 index 000000000..8ddb725ca --- /dev/null +++ b/include/Nazara/Graphics/RenderQueue.hpp @@ -0,0 +1,96 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_RENDERQUEUE_HPP +#define NAZARA_RENDERQUEUE_HPP + +#include +#include +#include + +namespace Nz +{ + class RenderQueueInternal + { + public: + using Index = Nz::UInt64; + + RenderQueueInternal() = default; + ~RenderQueueInternal() = default; + + protected: + using RenderDataPair = std::pair; + + void Sort(); + + std::vector m_orderedRenderQueue; + }; + + template + class RenderQueue : public RenderQueueInternal + { + public: + class const_iterator; + friend const_iterator; + using size_type = std::size_t; + + RenderQueue() = default; + RenderQueue(const RenderQueue&) = default; + RenderQueue(RenderQueue&&) = default; + ~RenderQueue() = default; + + void Clear(); + + void Insert(RenderData&& data); + + template void Sort(IndexFunc&& func); + + // STL API + inline const_iterator begin() const; + inline bool empty() const; + inline const_iterator end() const; + inline size_type size() const; + + RenderQueue& operator=(const RenderQueue&) = default; + RenderQueue& operator=(RenderQueue&&) = default; + + private: + const RenderData& GetData(std::size_t i) const; + + std::vector m_data; + }; + + template + class RenderQueue::const_iterator : public std::iterator + { + friend RenderQueue; + + public: + const_iterator(const const_iterator& it); + + const RenderData& operator*() const; + + const_iterator& operator=(const const_iterator& it); + const_iterator& operator++(); + const_iterator operator++(int); + + bool operator==(const const_iterator& rhs) const; + bool operator!=(const const_iterator& rhs) const; + + void swap(const_iterator& rhs); + + private: + const_iterator(const RenderQueue* queue, std::size_t nextId); + + std::size_t m_nextDataId; + const RenderQueue* m_queue; + }; + +} + +#include + +#endif // NAZARA_RENDERQUEUE_HPP diff --git a/include/Nazara/Graphics/RenderQueue.inl b/include/Nazara/Graphics/RenderQueue.inl new file mode 100644 index 000000000..47ec03c98 --- /dev/null +++ b/include/Nazara/Graphics/RenderQueue.inl @@ -0,0 +1,136 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + template + void RenderQueue::Clear() + { + m_orderedRenderQueue.clear(); + m_data.clear(); + } + + template + void RenderQueue::Insert(RenderData&& data) + { + m_data.emplace_back(std::move(data)); + } + + template + template + void RenderQueue::Sort(IndexFunc&& func) + { + m_orderedRenderQueue.clear(); + m_orderedRenderQueue.reserve(m_data.size()); + + std::size_t dataIndex = 0; + for (const RenderData& renderData : m_data) + m_orderedRenderQueue.emplace_back(func(renderData), dataIndex++); + + RenderQueueInternal::Sort(); + } + + template + typename RenderQueue::const_iterator RenderQueue::begin() const + { + return const_iterator(this, 0); + } + + template + bool RenderQueue::empty() const + { + return m_orderedRenderQueue.empty(); + } + + template + typename RenderQueue::const_iterator RenderQueue::end() const + { + return const_iterator(this, m_orderedRenderQueue.size()); + } + + template + typename RenderQueue::size_type RenderQueue::size() const + { + return m_orderedRenderQueue.size(); + } + + template + const RenderData& RenderQueue::GetData(std::size_t i) const + { + NazaraAssert(i < m_orderedRenderQueue.size(), "Cannot dereference post-end iterator"); + + return m_data[m_orderedRenderQueue[i].second]; + } + + + template + RenderQueue::const_iterator::const_iterator(const RenderQueue* queue, std::size_t nextId) : + m_nextDataId(nextId), + m_queue(queue) + { + } + + template + RenderQueue::const_iterator::const_iterator(const const_iterator& it) : + m_nextDataId(it.m_nextDataId), + m_queue(it.m_queue) + { + } + + template + const RenderData& RenderQueue::const_iterator::operator*() const + { + return m_queue->GetData(m_nextDataId); + } + + template + typename RenderQueue::const_iterator& RenderQueue::const_iterator::operator=(const const_iterator& it) + { + m_nextDataId = it.m_nextDataId; + m_queue = it.m_queue; + + return *this; + } + + template + typename RenderQueue::const_iterator& RenderQueue::const_iterator::operator++() + { + ++m_nextDataId; + + return *this; + } + + template + typename RenderQueue::const_iterator RenderQueue::const_iterator::operator++(int) + { + return iterator(m_queue, m_nextDataId++); + } + + template + bool RenderQueue::const_iterator::operator==(const typename RenderQueue::const_iterator& rhs) const + { + NazaraAssert(m_queue == rhs.m_queue, "Cannot compare iterator coming from different queues"); + + return m_nextDataId == rhs.m_nextDataId; + } + + template + bool RenderQueue::const_iterator::operator!=(const typename RenderQueue::const_iterator& rhs) const + { + return !operator==(rhs); + } + + template + void RenderQueue::const_iterator::swap(typename RenderQueue::const_iterator& rhs) + { + NazaraAssert(m_queue == rhs.m_queue, "Cannot swap iterator coming from different queues"); + + using std::swap; + + swap(m_nextDataId, rhs.m_nextDataId); + } +} diff --git a/include/Nazara/Graphics/SkeletalModel.hpp b/include/Nazara/Graphics/SkeletalModel.hpp index 72489d905..86943b676 100644 --- a/include/Nazara/Graphics/SkeletalModel.hpp +++ b/include/Nazara/Graphics/SkeletalModel.hpp @@ -38,7 +38,7 @@ namespace Nz SkeletalModel(SkeletalModel&& model) = default; ~SkeletalModel() = default; - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override; + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const override; void AdvanceAnimation(float elapsedTime); SkeletalModel* Clone() const; diff --git a/include/Nazara/Graphics/Sprite.hpp b/include/Nazara/Graphics/Sprite.hpp index 34e75f353..bf9edc0d1 100644 --- a/include/Nazara/Graphics/Sprite.hpp +++ b/include/Nazara/Graphics/Sprite.hpp @@ -33,7 +33,7 @@ namespace Nz Sprite(Sprite&&) = delete; ~Sprite() = default; - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override; + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const override; inline const Color& GetColor() const; inline const Color& GetCornerColor(RectCorner corner) const; diff --git a/include/Nazara/Graphics/Sprite.inl b/include/Nazara/Graphics/Sprite.inl index 7ecf80cf8..a296f5d61 100644 --- a/include/Nazara/Graphics/Sprite.inl +++ b/include/Nazara/Graphics/Sprite.inl @@ -172,6 +172,7 @@ namespace Nz { MaterialRef material = Material::New(); material->EnableFaceCulling(false); + material->EnableScissorTest(true); SetMaterial(std::move(material)); } diff --git a/include/Nazara/Graphics/TextSprite.hpp b/include/Nazara/Graphics/TextSprite.hpp index 5fddf7e99..355d17fe4 100644 --- a/include/Nazara/Graphics/TextSprite.hpp +++ b/include/Nazara/Graphics/TextSprite.hpp @@ -30,7 +30,7 @@ namespace Nz inline TextSprite(const TextSprite& sprite); ~TextSprite() = default; - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override; + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const override; inline void Clear(); diff --git a/include/Nazara/Graphics/TextSprite.inl b/include/Nazara/Graphics/TextSprite.inl index 2caec3254..c35cd562e 100644 --- a/include/Nazara/Graphics/TextSprite.inl +++ b/include/Nazara/Graphics/TextSprite.inl @@ -110,14 +110,7 @@ namespace Nz inline void TextSprite::SetDefaultMaterial() { - MaterialRef material = Material::New(); - material->EnableBlending(true); - material->EnableDepthWrite(false); - material->EnableFaceCulling(false); - material->SetDstBlend(BlendFunc_InvSrcAlpha); - material->SetSrcBlend(BlendFunc_SrcAlpha); - - SetMaterial(material); + SetMaterial(Material::New("Translucent2D")); } /*! diff --git a/include/Nazara/Graphics/TileMap.hpp b/include/Nazara/Graphics/TileMap.hpp index 4a8499599..3692eb3c2 100644 --- a/include/Nazara/Graphics/TileMap.hpp +++ b/include/Nazara/Graphics/TileMap.hpp @@ -33,7 +33,7 @@ namespace Nz TileMap(TileMap&&) = delete; ~TileMap() = default; - void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const override; + void AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const override; inline void DisableTile(const Vector2ui& tilePos); inline void DisableTiles(); diff --git a/include/Nazara/Math/BoundingVolume.hpp b/include/Nazara/Math/BoundingVolume.hpp index b5c4e8b9e..235259b2e 100644 --- a/include/Nazara/Math/BoundingVolume.hpp +++ b/include/Nazara/Math/BoundingVolume.hpp @@ -69,11 +69,11 @@ namespace Nz OrientedBox obb; }; - typedef BoundingVolume BoundingVolumed; - typedef BoundingVolume BoundingVolumef; + using BoundingVolumed = BoundingVolume; + using BoundingVolumef = BoundingVolume; - template bool Serialize(SerializationContext& context, const BoundingVolume& boundingVolume); - template bool Unserialize(SerializationContext& context, BoundingVolume* boundingVolume); + template bool Serialize(SerializationContext& context, const BoundingVolume& boundingVolume, TypeTag>); + template bool Unserialize(SerializationContext& context, BoundingVolume* boundingVolume, TypeTag>); } template diff --git a/include/Nazara/Math/BoundingVolume.inl b/include/Nazara/Math/BoundingVolume.inl index 5bbd83f31..5d80e2730 100644 --- a/include/Nazara/Math/BoundingVolume.inl +++ b/include/Nazara/Math/BoundingVolume.inl @@ -603,7 +603,7 @@ namespace Nz * \remark Does not save OBB corners */ template - bool Serialize(SerializationContext& context, const BoundingVolume& boundingVolume) + bool Serialize(SerializationContext& context, const BoundingVolume& boundingVolume, TypeTag>) { if (!Serialize(context, static_cast(boundingVolume.extend))) return false; @@ -627,7 +627,7 @@ namespace Nz * \remark The resulting oriented box corners will *not* be updated, a call to Update is required */ template - bool Unserialize(SerializationContext& context, BoundingVolume* boundingVolume) + bool Unserialize(SerializationContext& context, BoundingVolume* boundingVolume, TypeTag>) { UInt8 extend; if (!Unserialize(context, &extend)) diff --git a/include/Nazara/Math/Box.hpp b/include/Nazara/Math/Box.hpp index 9434cda27..555e10130 100644 --- a/include/Nazara/Math/Box.hpp +++ b/include/Nazara/Math/Box.hpp @@ -93,15 +93,15 @@ namespace Nz T x, y, z, width, height, depth; }; - typedef Box Boxd; - typedef Box Boxf; - typedef Box Boxi; - typedef Box Boxui; - typedef Box Boxi32; - typedef Box Boxui32; + using Boxd = Box; + using Boxf = Box; + using Boxi = Box; + using Boxui = Box; + using Boxi32 = Box; + using Boxui32 = Box; - template bool Serialize(SerializationContext& context, const Box& box); - template bool Unserialize(SerializationContext& context, Box* box); + template bool Serialize(SerializationContext& context, const Box& box, TypeTag>); + template bool Unserialize(SerializationContext& context, Box* box, TypeTag>); } template diff --git a/include/Nazara/Math/Box.inl b/include/Nazara/Math/Box.inl index 60275b206..6b0ed9112 100644 --- a/include/Nazara/Math/Box.inl +++ b/include/Nazara/Math/Box.inl @@ -912,7 +912,7 @@ namespace Nz * \param box Input Box */ template - bool Serialize(SerializationContext& context, const Box& box) + bool Serialize(SerializationContext& context, const Box& box, TypeTag>) { if (!Serialize(context, box.x)) return false; @@ -943,7 +943,7 @@ namespace Nz * \param box Output Box */ template - bool Unserialize(SerializationContext& context, Box* box) + bool Unserialize(SerializationContext& context, Box* box, TypeTag>) { if (!Unserialize(context, &box->x)) return false; diff --git a/include/Nazara/Math/EulerAngles.hpp b/include/Nazara/Math/EulerAngles.hpp index b55adc4dd..126ea399e 100644 --- a/include/Nazara/Math/EulerAngles.hpp +++ b/include/Nazara/Math/EulerAngles.hpp @@ -62,11 +62,11 @@ namespace Nz T pitch, yaw, roll; }; - typedef EulerAngles EulerAnglesd; - typedef EulerAngles EulerAnglesf; + using EulerAnglesd = EulerAngles; + using EulerAnglesf = EulerAngles; - template bool Serialize(SerializationContext& context, const EulerAngles& eulerAngles); - template bool Unserialize(SerializationContext& context, EulerAngles* eulerAngles); + template bool Serialize(SerializationContext& context, const EulerAngles& eulerAngles, TypeTag>); + template bool Unserialize(SerializationContext& context, EulerAngles* eulerAngles, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::EulerAngles& angles); diff --git a/include/Nazara/Math/EulerAngles.inl b/include/Nazara/Math/EulerAngles.inl index 0fc972164..2c35503ec 100644 --- a/include/Nazara/Math/EulerAngles.inl +++ b/include/Nazara/Math/EulerAngles.inl @@ -340,7 +340,7 @@ namespace Nz * \param angles Input euler angles */ template - bool Serialize(SerializationContext& context, const EulerAngles& angles) + bool Serialize(SerializationContext& context, const EulerAngles& angles, TypeTag>) { if (!Serialize(context, angles.pitch)) return false; @@ -362,7 +362,7 @@ namespace Nz * \param angles Output euler angles */ template - bool Unserialize(SerializationContext& context, EulerAngles* angles) + bool Unserialize(SerializationContext& context, EulerAngles* angles, TypeTag>) { if (!Unserialize(context, &angles->pitch)) return false; diff --git a/include/Nazara/Math/Frustum.hpp b/include/Nazara/Math/Frustum.hpp index 26242caef..042d55cee 100644 --- a/include/Nazara/Math/Frustum.hpp +++ b/include/Nazara/Math/Frustum.hpp @@ -58,17 +58,18 @@ namespace Nz String ToString() const; template - friend bool Serialize(SerializationContext& context, const Frustum& frustum); + friend bool Serialize(SerializationContext& context, const Frustum& frustum, TypeTag>); + template - friend bool Unserialize(SerializationContext& context, Frustum* frustum); + friend bool Unserialize(SerializationContext& context, Frustum* frustum, TypeTag>); private: Vector3 m_corners[BoxCorner_Max+1]; Plane m_planes[FrustumPlane_Max+1]; }; - typedef Frustum Frustumd; - typedef Frustum Frustumf; + using Frustumd = Frustum; + using Frustumf = Frustum; } template diff --git a/include/Nazara/Math/Frustum.inl b/include/Nazara/Math/Frustum.inl index f459a0526..6d6d38500 100644 --- a/include/Nazara/Math/Frustum.inl +++ b/include/Nazara/Math/Frustum.inl @@ -684,7 +684,7 @@ namespace Nz * \param matrix Input frustum */ template - bool Serialize(SerializationContext& context, const Frustum& frustum) + bool Serialize(SerializationContext& context, const Frustum& frustum, TypeTag>) { for (unsigned int i = 0; i <= BoxCorner_Max; ++i) { @@ -709,7 +709,7 @@ namespace Nz * \param matrix Output frustum */ template - bool Unserialize(SerializationContext& context, Frustum* frustum) + bool Unserialize(SerializationContext& context, Frustum* frustum, TypeTag>) { for (unsigned int i = 0; i <= BoxCorner_Max; ++i) { diff --git a/include/Nazara/Math/Matrix4.hpp b/include/Nazara/Math/Matrix4.hpp index c90439de4..cb8667036 100644 --- a/include/Nazara/Math/Matrix4.hpp +++ b/include/Nazara/Math/Matrix4.hpp @@ -138,11 +138,11 @@ namespace Nz m41, m42, m43, m44; }; - typedef Matrix4 Matrix4d; - typedef Matrix4 Matrix4f; + using Matrix4d = Matrix4; + using Matrix4f = Matrix4; - template bool Serialize(SerializationContext& context, const Matrix4& matrix); - template bool Unserialize(SerializationContext& context, Matrix4* matrix); + template bool Serialize(SerializationContext& context, const Matrix4& matrix, TypeTag>); + template bool Unserialize(SerializationContext& context, Matrix4* matrix, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::Matrix4& matrix); diff --git a/include/Nazara/Math/Matrix4.inl b/include/Nazara/Math/Matrix4.inl index f259607a6..297edf8a8 100644 --- a/include/Nazara/Math/Matrix4.inl +++ b/include/Nazara/Math/Matrix4.inl @@ -242,8 +242,8 @@ namespace Nz } #endif - const T* ptr = (&m11) + column*4; - return Vector4(ptr); + const T* ptr = &m11 + column * 4; + return Vector4(ptr[0], ptr[1], ptr[2], ptr[3]); } /*! @@ -1767,7 +1767,7 @@ namespace Nz * \param matrix Input matrix */ template - bool Serialize(SerializationContext& context, const Matrix4& matrix) + bool Serialize(SerializationContext& context, const Matrix4& matrix, TypeTag>) { for (unsigned int i = 0; i < 16; ++i) { @@ -1786,7 +1786,7 @@ namespace Nz * \param matrix Output matrix */ template - bool Unserialize(SerializationContext& context, Matrix4* matrix) + bool Unserialize(SerializationContext& context, Matrix4* matrix, TypeTag>) { T* head = matrix->operator T*(); for (unsigned int i = 0; i < 16; ++i) diff --git a/include/Nazara/Math/OrientedBox.hpp b/include/Nazara/Math/OrientedBox.hpp index dfd8f6b28..ab136a530 100644 --- a/include/Nazara/Math/OrientedBox.hpp +++ b/include/Nazara/Math/OrientedBox.hpp @@ -68,11 +68,11 @@ namespace Nz Vector3 m_corners[BoxCorner_Max+1]; // Ne peuvent pas être modifiés directement }; - typedef OrientedBox OrientedBoxd; - typedef OrientedBox OrientedBoxf; + using OrientedBoxd = OrientedBox; + using OrientedBoxf = OrientedBox; - template bool Serialize(SerializationContext& context, const OrientedBox& obb); - template bool Unserialize(SerializationContext& context, OrientedBox* obb); + template bool Serialize(SerializationContext& context, const OrientedBox& obb, TypeTag>); + template bool Unserialize(SerializationContext& context, OrientedBox* obb, TypeTag>); } template diff --git a/include/Nazara/Math/OrientedBox.inl b/include/Nazara/Math/OrientedBox.inl index 92ebada1d..df864fe26 100644 --- a/include/Nazara/Math/OrientedBox.inl +++ b/include/Nazara/Math/OrientedBox.inl @@ -442,7 +442,7 @@ namespace Nz * \remark Does not save OBB corners */ template - bool Serialize(SerializationContext& context, const OrientedBox& obb) + bool Serialize(SerializationContext& context, const OrientedBox& obb, TypeTag>) { if (!Serialize(context, obb.localBox)) return false; @@ -460,7 +460,7 @@ namespace Nz * \remark The resulting oriented box corners will *not* be updated, a call to Update is required */ template - bool Unserialize(SerializationContext& context, OrientedBox* obb) + bool Unserialize(SerializationContext& context, OrientedBox* obb, TypeTag>) { if (!Unserialize(context, &obb->localBox)) return false; diff --git a/include/Nazara/Math/Plane.hpp b/include/Nazara/Math/Plane.hpp index 0970b5a6d..d5384b3fe 100644 --- a/include/Nazara/Math/Plane.hpp +++ b/include/Nazara/Math/Plane.hpp @@ -59,11 +59,11 @@ namespace Nz T distance; }; - typedef Plane Planed; - typedef Plane Planef; + using Planed = Plane; + using Planef = Plane; - template bool Serialize(SerializationContext& context, const Plane& plane); - template bool Unserialize(SerializationContext& context, Plane* plane); + template bool Serialize(SerializationContext& context, const Plane& plane, TypeTag>); + template bool Unserialize(SerializationContext& context, Plane* plane, TypeTag>); } template diff --git a/include/Nazara/Math/Plane.inl b/include/Nazara/Math/Plane.inl index d80809988..4c2adc90c 100644 --- a/include/Nazara/Math/Plane.inl +++ b/include/Nazara/Math/Plane.inl @@ -434,7 +434,7 @@ namespace Nz * \param plane Input Vector2 */ template - bool Serialize(SerializationContext& context, const Plane& plane) + bool Serialize(SerializationContext& context, const Plane& plane, TypeTag>) { if (!Serialize(context, plane.normal)) return false; @@ -453,7 +453,7 @@ namespace Nz * \param plane Output Plane */ template - bool Unserialize(SerializationContext& context, Plane* plane) + bool Unserialize(SerializationContext& context, Plane* plane, TypeTag>) { if (!Unserialize(context, &plane->normal)) return false; diff --git a/include/Nazara/Math/Quaternion.hpp b/include/Nazara/Math/Quaternion.hpp index 27adb8b36..17c9a8757 100644 --- a/include/Nazara/Math/Quaternion.hpp +++ b/include/Nazara/Math/Quaternion.hpp @@ -88,11 +88,11 @@ namespace Nz T w, x, y, z; }; - typedef Quaternion Quaterniond; - typedef Quaternion Quaternionf; + using Quaterniond = Quaternion; + using Quaternionf = Quaternion; - template bool Serialize(SerializationContext& context, const Quaternion& quat); - template bool Unserialize(SerializationContext& context, Quaternion* quat); + template bool Serialize(SerializationContext& context, const Quaternion& quat, TypeTag>); + template bool Unserialize(SerializationContext& context, Quaternion* quat, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::Quaternion& quat); diff --git a/include/Nazara/Math/Quaternion.inl b/include/Nazara/Math/Quaternion.inl index f07524c0f..59099f3b8 100644 --- a/include/Nazara/Math/Quaternion.inl +++ b/include/Nazara/Math/Quaternion.inl @@ -220,7 +220,7 @@ namespace Nz T norm = SquaredMagnitude(); if (norm > F(0.0)) { - T invNorm = F(1.0) / norm; + T invNorm = F(1.0) / std::sqrt(norm); w *= invNorm; x *= -invNorm; @@ -826,7 +826,7 @@ namespace Nz * \param quat Input Quaternion */ template - bool Serialize(SerializationContext& context, const Quaternion& quat) + bool Serialize(SerializationContext& context, const Quaternion& quat, TypeTag>) { if (!Serialize(context, quat.x)) return false; @@ -851,7 +851,7 @@ namespace Nz * \param quat Output Quaternion */ template - bool Unserialize(SerializationContext& context, Quaternion* quat) + bool Unserialize(SerializationContext& context, Quaternion* quat, TypeTag>) { if (!Unserialize(context, &quat->x)) return false; diff --git a/include/Nazara/Math/Ray.hpp b/include/Nazara/Math/Ray.hpp index 01e86afaf..677bf50b9 100644 --- a/include/Nazara/Math/Ray.hpp +++ b/include/Nazara/Math/Ray.hpp @@ -74,11 +74,11 @@ namespace Nz Vector3 direction, origin; }; - typedef Ray Rayd; - typedef Ray Rayf; + using Rayd = Ray; + using Rayf = Ray; - template bool Serialize(SerializationContext& context, const Ray& ray); - template bool Unserialize(SerializationContext& context, Ray* ray); + template bool Serialize(SerializationContext& context, const Ray& ray, TypeTag>); + template bool Unserialize(SerializationContext& context, Ray* ray, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::Ray& vec); diff --git a/include/Nazara/Math/Ray.inl b/include/Nazara/Math/Ray.inl index 813226bb1..673dca796 100644 --- a/include/Nazara/Math/Ray.inl +++ b/include/Nazara/Math/Ray.inl @@ -772,7 +772,7 @@ namespace Nz * \param ray Input Ray */ template - bool Serialize(SerializationContext& context, const Ray& ray) + bool Serialize(SerializationContext& context, const Ray& ray, TypeTag>) { if (!Serialize(context, ray.origin)) return false; @@ -791,7 +791,7 @@ namespace Nz * \param ray Output Ray */ template - bool Unserialize(SerializationContext& context, Ray* ray) + bool Unserialize(SerializationContext& context, Ray* ray, TypeTag>) { if (!Unserialize(context, &ray->origin)) return false; diff --git a/include/Nazara/Math/Rect.hpp b/include/Nazara/Math/Rect.hpp index 9ca7f2ef5..db7ee15f0 100644 --- a/include/Nazara/Math/Rect.hpp +++ b/include/Nazara/Math/Rect.hpp @@ -87,15 +87,15 @@ namespace Nz T x, y, width, height; }; - typedef Rect Rectd; - typedef Rect Rectf; - typedef Rect Recti; - typedef Rect Rectui; - typedef Rect Recti32; - typedef Rect Rectui32; + using Rectd = Rect; + using Rectf = Rect; + using Recti = Rect; + using Rectui = Rect; + using Recti32 = Rect; + using Rectui32 = Rect; - template bool Serialize(SerializationContext& context, const Rect& rect); - template bool Unserialize(SerializationContext& context, Rect* rect); + template bool Serialize(SerializationContext& context, const Rect& rect, TypeTag>); + template bool Unserialize(SerializationContext& context, Rect* rect, TypeTag>); } template diff --git a/include/Nazara/Math/Rect.inl b/include/Nazara/Math/Rect.inl index f5d96c249..93b6e6d79 100644 --- a/include/Nazara/Math/Rect.inl +++ b/include/Nazara/Math/Rect.inl @@ -808,7 +808,7 @@ namespace Nz * \param rect Input Rect */ template - bool Serialize(SerializationContext& context, const Rect& rect) + bool Serialize(SerializationContext& context, const Rect& rect, TypeTag>) { if (!Serialize(context, rect.x)) return false; @@ -833,7 +833,7 @@ namespace Nz * \param rect Output Rect */ template - bool Unserialize(SerializationContext& context, Rect* rect) + bool Unserialize(SerializationContext& context, Rect* rect, TypeTag>) { if (!Unserialize(context, &rect->x)) return false; diff --git a/include/Nazara/Math/Sphere.hpp b/include/Nazara/Math/Sphere.hpp index cfa693507..0c9880287 100644 --- a/include/Nazara/Math/Sphere.hpp +++ b/include/Nazara/Math/Sphere.hpp @@ -78,11 +78,11 @@ namespace Nz T x, y, z, radius; }; - typedef Sphere Sphered; - typedef Sphere Spheref; + using Sphered = Sphere; + using Spheref = Sphere; - template bool Serialize(SerializationContext& context, const Sphere& sphere); - template bool Unserialize(SerializationContext& context, Sphere* sphere); + template bool Serialize(SerializationContext& context, const Sphere& sphere, TypeTag>); + template bool Unserialize(SerializationContext& context, Sphere* sphere, TypeTag>); } template diff --git a/include/Nazara/Math/Sphere.inl b/include/Nazara/Math/Sphere.inl index 48930be94..643fcee82 100644 --- a/include/Nazara/Math/Sphere.inl +++ b/include/Nazara/Math/Sphere.inl @@ -623,7 +623,7 @@ namespace Nz * \param sphere Input Sphere */ template - bool Serialize(SerializationContext& context, const Sphere& sphere) + bool Serialize(SerializationContext& context, const Sphere& sphere, TypeTag>) { if (!Serialize(context, sphere.x)) return false; @@ -648,7 +648,7 @@ namespace Nz * \param sphere Output Sphere */ template - bool Unserialize(SerializationContext& context, Sphere* sphere) + bool Unserialize(SerializationContext& context, Sphere* sphere, TypeTag>) { if (!Unserialize(context, &sphere->x)) return false; diff --git a/include/Nazara/Math/Vector2.hpp b/include/Nazara/Math/Vector2.hpp index 5bb5573ba..6a7f925f6 100644 --- a/include/Nazara/Math/Vector2.hpp +++ b/include/Nazara/Math/Vector2.hpp @@ -24,7 +24,6 @@ namespace Nz Vector2() = default; Vector2(T X, T Y); explicit Vector2(T scale); - explicit Vector2(const T vec[2]); template explicit Vector2(const Vector2& vec); Vector2(const Vector2& vec) = default; explicit Vector2(const Vector3& vec); @@ -104,15 +103,15 @@ namespace Nz T x, y; }; - typedef Vector2 Vector2d; - typedef Vector2 Vector2f; - typedef Vector2 Vector2i; - typedef Vector2 Vector2ui; - typedef Vector2 Vector2i32; - typedef Vector2 Vector2ui32; + using Vector2d = Vector2; + using Vector2f = Vector2; + using Vector2i = Vector2; + using Vector2ui = Vector2; + using Vector2i32 = Vector2; + using Vector2ui32 = Vector2; - template bool Serialize(SerializationContext& context, const Vector2& vector); - template bool Unserialize(SerializationContext& context, Vector2* vector); + template bool Serialize(SerializationContext& context, const Vector2& vector, TypeTag>); + template bool Unserialize(SerializationContext& context, Vector2* vector, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::Vector2& vec); diff --git a/include/Nazara/Math/Vector2.inl b/include/Nazara/Math/Vector2.inl index f3e6609bd..c33af8102 100644 --- a/include/Nazara/Math/Vector2.inl +++ b/include/Nazara/Math/Vector2.inl @@ -45,18 +45,6 @@ namespace Nz Set(scale); } - /*! - * \brief Constructs a Vector2 object from an array of two elements - * - * \param vec[2] vec[0] is X component and vec[1] is Y component - */ - - template - Vector2::Vector2(const T vec[2]) - { - Set(vec); - } - /*! * \brief Constructs a Vector2 object from another type of Vector2 * @@ -973,7 +961,7 @@ namespace Nz * \param vector Input Vector2 */ template - bool Serialize(SerializationContext& context, const Vector2& vector) + bool Serialize(SerializationContext& context, const Vector2& vector, TypeTag>) { if (!Serialize(context, vector.x)) return false; @@ -992,7 +980,7 @@ namespace Nz * \param vector Output Vector2 */ template - bool Unserialize(SerializationContext& context, Vector2* vector) + bool Unserialize(SerializationContext& context, Vector2* vector, TypeTag>) { if (!Unserialize(context, &vector->x)) return false; diff --git a/include/Nazara/Math/Vector3.hpp b/include/Nazara/Math/Vector3.hpp index acb87d6c1..7aed07d6a 100644 --- a/include/Nazara/Math/Vector3.hpp +++ b/include/Nazara/Math/Vector3.hpp @@ -25,7 +25,6 @@ namespace Nz Vector3(T X, T Y, T Z); Vector3(T X, const Vector2& vec); explicit Vector3(T scale); - explicit Vector3(const T vec[3]); Vector3(const Vector2& vec, T Z = 0.0); template explicit Vector3(const Vector3& vec); Vector3(const Vector3& vec) = default; @@ -126,15 +125,15 @@ namespace Nz T x, y, z; }; - typedef Vector3 Vector3d; - typedef Vector3 Vector3f; - typedef Vector3 Vector3i; - typedef Vector3 Vector3ui; - typedef Vector3 Vector3i32; - typedef Vector3 Vector3ui32; + using Vector3d = Vector3; + using Vector3f = Vector3; + using Vector3i = Vector3; + using Vector3ui = Vector3; + using Vector3i32 = Vector3; + using Vector3ui32 = Vector3; - template bool Serialize(SerializationContext& context, const Vector3& vector); - template bool Unserialize(SerializationContext& context, Vector3* vector); + template bool Serialize(SerializationContext& context, const Vector3& vector, TypeTag>); + template bool Unserialize(SerializationContext& context, Vector3* vector, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::Vector3& vec); diff --git a/include/Nazara/Math/Vector3.inl b/include/Nazara/Math/Vector3.inl index b7a884749..8ed7c6977 100644 --- a/include/Nazara/Math/Vector3.inl +++ b/include/Nazara/Math/Vector3.inl @@ -58,17 +58,6 @@ namespace Nz Set(scale); } - /*! - * \brief Constructs a Vector3 object from an array of three elements - * - * \param vec[3] vec[0] is X component, vec[1] is Y component and vec[2] is Z component - */ - template - Vector3::Vector3(const T vec[3]) - { - Set(vec); - } - /*! * \brief Constructs a Vector3 object from a Vector2 and a component * @@ -522,7 +511,9 @@ namespace Nz template Vector3& Vector3::Set(const T vec[3]) { - std::memcpy(&x, vec, 3*sizeof(T)); + x = vec[0]; + y = vec[1]; + z = vec[2]; return *this; } @@ -1257,7 +1248,7 @@ namespace Nz * \param vector Input Vector3 */ template - bool Serialize(SerializationContext& context, const Vector3& vector) + bool Serialize(SerializationContext& context, const Vector3& vector, TypeTag>) { if (!Serialize(context, vector.x)) return false; @@ -1279,7 +1270,7 @@ namespace Nz * \param vector Output Vector3 */ template - bool Unserialize(SerializationContext& context, Vector3* vector) + bool Unserialize(SerializationContext& context, Vector3* vector, TypeTag>) { if (!Unserialize(context, &vector->x)) return false; diff --git a/include/Nazara/Math/Vector4.hpp b/include/Nazara/Math/Vector4.hpp index de04884e1..f1a799fb3 100644 --- a/include/Nazara/Math/Vector4.hpp +++ b/include/Nazara/Math/Vector4.hpp @@ -27,7 +27,6 @@ namespace Nz Vector4(T X, const Vector2& vec, T W); Vector4(T X, const Vector3& vec); explicit Vector4(T scale); - explicit Vector4(const T vec[4]); Vector4(const Vector2& vec, T Z = 0.0, T W = 1.0); Vector4(const Vector3& vec, T W = 1.0); template explicit Vector4(const Vector4& vec); @@ -102,15 +101,15 @@ namespace Nz T x, y, z, w; }; - typedef Vector4 Vector4d; - typedef Vector4 Vector4f; - typedef Vector4 Vector4i; - typedef Vector4 Vector4ui; - typedef Vector4 Vector4i32; - typedef Vector4 Vector4ui32; + using Vector4d = Vector4; + using Vector4f = Vector4; + using Vector4i = Vector4; + using Vector4ui = Vector4; + using Vector4i32 = Vector4; + using Vector4ui32 = Vector4; - template bool Serialize(SerializationContext& context, const Vector4& vector); - template bool Unserialize(SerializationContext& context, Vector4* vector); + template bool Serialize(SerializationContext& context, const Vector4& vector, TypeTag>); + template bool Unserialize(SerializationContext& context, Vector4* vector, TypeTag>); } template std::ostream& operator<<(std::ostream& out, const Nz::Vector4& vec); diff --git a/include/Nazara/Math/Vector4.inl b/include/Nazara/Math/Vector4.inl index 873cea235..69d0b513f 100644 --- a/include/Nazara/Math/Vector4.inl +++ b/include/Nazara/Math/Vector4.inl @@ -17,7 +17,7 @@ namespace Nz { /*! - * \ingroup math + * \ingroup math * \class Nz::Vector4 * \brief Math class that represents an element of the three dimensional vector space with the notion of projectivity. When the fourth component is 1, it describes an 'usual' point and when it is 0, it represents the point at infinity */ @@ -90,18 +90,6 @@ namespace Nz Set(scale); } - /*! - * \brief Constructs a Vector4 object from an array of four elements - * - * \param vec[4] vec[0] is X component, vec[1] is Y component, vec[2] is Z component and vec[3] is W component - */ - - template - Vector4::Vector4(const T vec[4]) - { - Set(vec); - } - /*! * \brief Constructs a Vector4 object from a Vector2 and two components * @@ -1023,7 +1011,7 @@ namespace Nz * \param vector Input Vector3 */ template - bool Serialize(SerializationContext& context, const Vector4& vector) + bool Serialize(SerializationContext& context, const Vector4& vector, TypeTag>) { if (!Serialize(context, vector.x)) return false; @@ -1048,7 +1036,7 @@ namespace Nz * \param vector Output Vector3 */ template - bool Unserialize(SerializationContext& context, Vector4* vector) + bool Unserialize(SerializationContext& context, Vector4* vector, TypeTag>) { if (!Unserialize(context, &vector->x)) return false; diff --git a/include/Nazara/Network/ENetCompressor.hpp b/include/Nazara/Network/ENetCompressor.hpp index 3ff6cbca2..27bccdace 100644 --- a/include/Nazara/Network/ENetCompressor.hpp +++ b/include/Nazara/Network/ENetCompressor.hpp @@ -29,7 +29,7 @@ namespace Nz { public: ENetCompressor() = default; - ~ENetCompressor(); + virtual ~ENetCompressor(); virtual std::size_t Compress(const ENetPeer* peer, const NetBuffer* buffers, std::size_t bufferCount, std::size_t totalInputSize, UInt8* output, std::size_t maxOutputSize) = 0; virtual std::size_t Decompress(const ENetPeer* peer, const UInt8* input, std::size_t inputSize, UInt8* output, std::size_t maxOutputSize) = 0; diff --git a/include/Nazara/Network/ENetHost.hpp b/include/Nazara/Network/ENetHost.hpp index 39bc0be62..d6e1a8018 100644 --- a/include/Nazara/Network/ENetHost.hpp +++ b/include/Nazara/Network/ENetHost.hpp @@ -156,6 +156,7 @@ namespace Nz UInt64 m_totalReceivedData; bool m_allowsIncomingConnections; bool m_continueSending; + bool m_isUsingDualStack; bool m_isSimulationEnabled; bool m_recalculateBandwidthLimits; diff --git a/include/Nazara/Network/ENetHost.inl b/include/Nazara/Network/ENetHost.inl index 667750ff0..11ee91c80 100644 --- a/include/Nazara/Network/ENetHost.inl +++ b/include/Nazara/Network/ENetHost.inl @@ -9,6 +9,7 @@ namespace Nz { inline ENetHost::ENetHost() : m_packetPool(sizeof(ENetPacket)), + m_isUsingDualStack(false), m_isSimulationEnabled(false) { } @@ -20,21 +21,22 @@ namespace Nz 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"); + NazaraInternalError("Invalid protocol"); return false; case NetProtocol_IPv4: any = IpAddress::AnyIpV4; break; + case NetProtocol_Any: + m_isUsingDualStack = true; + // fallthrough case NetProtocol_IPv6: any = IpAddress::AnyIpV6; break; diff --git a/include/Nazara/Network/UdpSocket.inl b/include/Nazara/Network/UdpSocket.inl index 2925c1935..ed43b3428 100644 --- a/include/Nazara/Network/UdpSocket.inl +++ b/include/Nazara/Network/UdpSocket.inl @@ -51,15 +51,15 @@ namespace Nz IpAddress any; switch (m_protocol) { - case NetProtocol_Any: case NetProtocol_Unknown: - NazaraInternalError("Invalid protocol Any at this point"); + NazaraInternalError("Invalid protocol"); return SocketState_NotConnected; case NetProtocol_IPv4: any = IpAddress::AnyIpV4; break; + case NetProtocol_Any: case NetProtocol_IPv6: any = IpAddress::AnyIpV6; break; diff --git a/include/Nazara/Physics3D/Collider3D.hpp b/include/Nazara/Physics3D/Collider3D.hpp index b8a239349..a7a59a2d1 100644 --- a/include/Nazara/Physics3D/Collider3D.hpp +++ b/include/Nazara/Physics3D/Collider3D.hpp @@ -54,6 +54,8 @@ namespace Nz virtual void ComputeInertialMatrix(Vector3f* inertia, Vector3f* center) const; virtual float ComputeVolume() const; + virtual void ForEachPolygon(const std::function& callback) const; + NewtonCollision* GetHandle(PhysWorld3D* world) const; virtual ColliderType3D GetType() const = 0; diff --git a/include/Nazara/Physics3D/PhysWorld3D.hpp b/include/Nazara/Physics3D/PhysWorld3D.hpp index cae9e4178..e32ba2528 100644 --- a/include/Nazara/Physics3D/PhysWorld3D.hpp +++ b/include/Nazara/Physics3D/PhysWorld3D.hpp @@ -8,6 +8,7 @@ #define NAZARA_PHYSWORLD_HPP #include +#include #include #include #include @@ -26,22 +27,22 @@ namespace Nz class NAZARA_PHYSICS3D_API PhysWorld3D { public: - using BodyIterator = std::function; + using BodyIterator = std::function; using AABBOverlapCallback = std::function; using CollisionCallback = std::function; PhysWorld3D(); PhysWorld3D(const PhysWorld3D&) = delete; - PhysWorld3D(PhysWorld3D&&) = delete; ///TODO + PhysWorld3D(PhysWorld3D&&) = default; ~PhysWorld3D(); - int CreateMaterial(Nz::String name = Nz::String()); + int CreateMaterial(String name = String()); - void ForEachBodyInAABB(const Nz::Boxf& box, const BodyIterator& iterator); + void ForEachBodyInAABB(const Boxf& box, const BodyIterator& iterator); Vector3f GetGravity() const; NewtonWorld* GetHandle() const; - int GetMaterial(const Nz::String& name); + int GetMaterial(const String& name); std::size_t GetMaxStepCount() const; float GetStepSize() const; @@ -60,7 +61,7 @@ namespace Nz void Step(float timestep); PhysWorld3D& operator=(const PhysWorld3D&) = delete; - PhysWorld3D& operator=(PhysWorld3D&&) = delete; ///TODO + PhysWorld3D& operator=(PhysWorld3D&&) = default; private: struct Callback @@ -75,8 +76,8 @@ namespace Nz std::unordered_map> m_callbacks; std::unordered_map m_materialIds; std::size_t m_maxStepCount; + MovablePtr m_world; Vector3f m_gravity; - NewtonWorld* m_world; float m_stepSize; float m_timestepAccumulator; }; diff --git a/include/Nazara/Physics3D/RigidBody3D.hpp b/include/Nazara/Physics3D/RigidBody3D.hpp index 28f53536f..a5c5a1956 100644 --- a/include/Nazara/Physics3D/RigidBody3D.hpp +++ b/include/Nazara/Physics3D/RigidBody3D.hpp @@ -59,7 +59,7 @@ namespace Nz bool IsSimulationEnabled() const; bool IsSleeping() const; - void SetAngularDamping(const Nz::Vector3f& angularDamping); + void SetAngularDamping(const Vector3f& angularDamping); void SetAngularVelocity(const Vector3f& angularVelocity); void SetGeom(Collider3DRef geom); void SetGravityFactor(float gravityFactor); @@ -67,7 +67,7 @@ namespace Nz void SetLinearVelocity(const Vector3f& velocity); void SetMass(float mass); void SetMassCenter(const Vector3f& center); - void SetMaterial(const Nz::String& materialName); + void SetMaterial(const String& materialName); void SetMaterial(int materialIndex); void SetPosition(const Vector3f& position); void SetRotation(const Quaternionf& rotation); diff --git a/include/Nazara/Platform/WindowHandle.hpp b/include/Nazara/Platform/WindowHandle.hpp index b0916498c..88274f3f9 100644 --- a/include/Nazara/Platform/WindowHandle.hpp +++ b/include/Nazara/Platform/WindowHandle.hpp @@ -16,7 +16,7 @@ namespace Nz { #if defined(NAZARA_PLATFORM_WINDOWS) // http://msdn.microsoft.com/en-us/library/aa383751(v=vs.85).aspx - typedef void* WindowHandle; + using WindowHandle = void*; #elif defined(NAZARA_PLATFORM_X11) // http://en.wikipedia.org/wiki/Xlib#Data_types using WindowHandle = xcb_window_t; diff --git a/include/Nazara/Prerequisites.hpp b/include/Nazara/Prerequisites.hpp index 765d14b52..ddb2796fc 100644 --- a/include/Nazara/Prerequisites.hpp +++ b/include/Nazara/Prerequisites.hpp @@ -166,17 +166,17 @@ static_assert(sizeof(uint64_t) == 8, "uint64_t is not of the correct size"); namespace Nz { - typedef int8_t Int8; - typedef uint8_t UInt8; + using Int8 = int8_t; + using UInt8 = uint8_t; - typedef int16_t Int16; - typedef uint16_t UInt16; + using Int16 = int16_t; + using UInt16 = uint16_t; - typedef int32_t Int32; - typedef uint32_t UInt32; + using Int32 = int32_t; + using UInt32 = uint32_t; - typedef int64_t Int64; - typedef uint64_t UInt64; + using Int64 = int64_t; + using UInt64 = uint64_t; } #endif // NAZARA_PREREQUISITES_HPP diff --git a/include/Nazara/Utility/AbstractTextDrawer.hpp b/include/Nazara/Utility/AbstractTextDrawer.hpp index 2ef500aab..c52051a5c 100644 --- a/include/Nazara/Utility/AbstractTextDrawer.hpp +++ b/include/Nazara/Utility/AbstractTextDrawer.hpp @@ -34,6 +34,7 @@ namespace Nz virtual std::size_t GetGlyphCount() const = 0; virtual const Line& GetLine(std::size_t index) const = 0; virtual std::size_t GetLineCount() const = 0; + inline std::size_t GetLineGlyphCount(std::size_t index) const; struct Glyph { @@ -53,4 +54,6 @@ namespace Nz }; } +#include + #endif // NAZARA_ABSTRACTTEXTDRAWER_HPP diff --git a/include/Nazara/Utility/AbstractTextDrawer.inl b/include/Nazara/Utility/AbstractTextDrawer.inl new file mode 100644 index 000000000..a10a16892 --- /dev/null +++ b/include/Nazara/Utility/AbstractTextDrawer.inl @@ -0,0 +1,23 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Utility module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include + +namespace Nz +{ + inline std::size_t AbstractTextDrawer::GetLineGlyphCount(std::size_t index) const + { + std::size_t lineCount = GetLineCount(); + const auto& lineInfo = GetLine(index); + if (index == lineCount - 1) + return GetGlyphCount() - lineInfo.glyphIndex; + + const auto& nextLineInfo = GetLine(index + 1); + + return nextLineInfo.glyphIndex - lineInfo.glyphIndex; + } +} + +#include diff --git a/include/Nazara/Utility/Formats/MD5MeshParser.hpp b/include/Nazara/Utility/Formats/MD5MeshParser.hpp index 8f3165fc8..f5cdb8637 100644 --- a/include/Nazara/Utility/Formats/MD5MeshParser.hpp +++ b/include/Nazara/Utility/Formats/MD5MeshParser.hpp @@ -28,7 +28,7 @@ namespace Nz Vector3f bindPos; }; - typedef Vector3ui Triangle; + using Triangle = Vector3ui; struct Vertex { diff --git a/include/Nazara/Utility/Formats/MTLParser.hpp b/include/Nazara/Utility/Formats/MTLParser.hpp index 0cacd0886..7eb10aaa9 100644 --- a/include/Nazara/Utility/Formats/MTLParser.hpp +++ b/include/Nazara/Utility/Formats/MTLParser.hpp @@ -45,6 +45,8 @@ namespace Nz String decalMap; String diffuseMap; String displacementMap; + String emissiveMap; //< Custom addition: not present in MTL + String normalMap; //< Custom addition: not present in MTL String reflectionMap; String shininessMap; String specularMap; diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 61e290bca..0dcd5fbcb 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -97,16 +97,15 @@ bool Load(Mesh* mesh, Stream& stream, const MeshParams& parameters) fileIO.OpenProc = StreamOpener; fileIO.UserData = reinterpret_cast(&userdata); - unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_JoinIdenticalVertices - | aiProcess_MakeLeftHanded | aiProcess_Triangulate - | aiProcess_RemoveComponent | aiProcess_GenSmoothNormals - | aiProcess_SplitLargeMeshes | aiProcess_LimitBoneWeights - | aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials - | aiProcess_FixInfacingNormals | aiProcess_SortByPType - | aiProcess_FindInvalidData | aiProcess_GenUVCoords - | aiProcess_TransformUVCoords | aiProcess_OptimizeMeshes - | aiProcess_OptimizeGraph | aiProcess_FlipWindingOrder - | aiProcess_Debone; + unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_Debone + | aiProcess_FindInvalidData | aiProcess_FixInfacingNormals + | aiProcess_FlipWindingOrder | aiProcess_GenSmoothNormals + | aiProcess_GenUVCoords | aiProcess_JoinIdenticalVertices + | aiProcess_LimitBoneWeights | aiProcess_MakeLeftHanded + | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes + | aiProcess_RemoveComponent | aiProcess_RemoveRedundantMaterials + | aiProcess_SortByPType | aiProcess_SplitLargeMeshes + | aiProcess_TransformUVCoords | aiProcess_Triangulate; if (parameters.optimizeIndexBuffers) postProcess |= aiProcess_ImproveCacheLocality; diff --git a/src/Nazara/Audio/Music.cpp b/src/Nazara/Audio/Music.cpp index 185b911b6..221cb9d50 100644 --- a/src/Nazara/Audio/Music.cpp +++ b/src/Nazara/Audio/Music.cpp @@ -262,6 +262,8 @@ namespace Nz */ void Music::Pause() { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcePause(m_source); } diff --git a/src/Nazara/Audio/Sound.cpp b/src/Nazara/Audio/Sound.cpp index a3beac029..6937e1ec2 100644 --- a/src/Nazara/Audio/Sound.cpp +++ b/src/Nazara/Audio/Sound.cpp @@ -37,6 +37,7 @@ namespace Nz SoundEmitter(sound) { SetBuffer(sound.m_buffer); + EnableLooping(sound.IsLooping()); } /*! @@ -56,6 +57,8 @@ namespace Nz */ void Sound::EnableLooping(bool loop) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcei(m_source, AL_LOOPING, loop); } @@ -87,6 +90,8 @@ namespace Nz */ UInt32 Sound::GetPlayingOffset() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALint samples = 0; alGetSourcei(m_source, AL_SAMPLE_OFFSET, &samples); @@ -108,6 +113,8 @@ namespace Nz */ bool Sound::IsLooping() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALint loop; alGetSourcei(m_source, AL_LOOPING, &loop); @@ -205,6 +212,8 @@ namespace Nz */ void Sound::Pause() { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcePause(m_source); } @@ -215,6 +224,7 @@ namespace Nz */ void Sound::Play() { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); NazaraAssert(IsPlayable(), "Music is not playable"); alSourcePlay(m_source); @@ -229,6 +239,7 @@ namespace Nz */ void Sound::SetBuffer(const SoundBuffer* buffer) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); NazaraAssert(!buffer || buffer->IsValid(), "Invalid sound buffer"); if (m_buffer == buffer) @@ -251,14 +262,19 @@ namespace Nz */ void Sound::SetPlayingOffset(UInt32 offset) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcei(m_source, AL_SAMPLE_OFFSET, static_cast(offset/1000.f * m_buffer->GetSampleRate())); } /*! * \brief Stops the sound + * + * \remark This is one of the only function that can be called on a moved sound (and does nothing) */ void Sound::Stop() { - alSourceStop(m_source); + if (m_source != InvalidSource) + alSourceStop(m_source); } } diff --git a/src/Nazara/Audio/SoundEmitter.cpp b/src/Nazara/Audio/SoundEmitter.cpp index 4492771f4..40b7ccd59 100644 --- a/src/Nazara/Audio/SoundEmitter.cpp +++ b/src/Nazara/Audio/SoundEmitter.cpp @@ -23,7 +23,6 @@ namespace Nz /*! * \brief Constructs a SoundEmitter object */ - SoundEmitter::SoundEmitter() { alGenSources(1, &m_source); @@ -39,22 +38,40 @@ namespace Nz SoundEmitter::SoundEmitter(const SoundEmitter& emitter) { - alGenSources(1, &m_source); + if (emitter.m_source != InvalidSource) + { + alGenSources(1, &m_source); - SetAttenuation(emitter.GetAttenuation()); - SetMinDistance(emitter.GetMinDistance()); - SetPitch(emitter.GetPitch()); - // No copy for position or velocity - SetVolume(emitter.GetVolume()); + SetAttenuation(emitter.GetAttenuation()); + SetMinDistance(emitter.GetMinDistance()); + SetPitch(emitter.GetPitch()); + // No copy for position or velocity + SetVolume(emitter.GetVolume()); + } + else + m_source = InvalidSource; + } + + /*! + * \brief Constructs a SoundEmitter object by moving another + * + * \param emitter SoundEmitter to move + * + * \remark The moved sound emitter cannot be used after being moved + */ + SoundEmitter::SoundEmitter(SoundEmitter&& emitter) noexcept : + m_source(emitter.m_source) + { + emitter.m_source = InvalidSource; } /*! * \brief Destructs the object */ - SoundEmitter::~SoundEmitter() { - alDeleteSources(1, &m_source); + if (m_source != InvalidSource) + alDeleteSources(1, &m_source); } /*! @@ -65,6 +82,8 @@ namespace Nz void SoundEmitter::EnableSpatialization(bool spatialization) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcei(m_source, AL_SOURCE_RELATIVE, !spatialization); } @@ -75,6 +94,8 @@ namespace Nz float SoundEmitter::GetAttenuation() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALfloat attenuation; alGetSourcef(m_source, AL_ROLLOFF_FACTOR, &attenuation); @@ -88,6 +109,8 @@ namespace Nz float SoundEmitter::GetMinDistance() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALfloat distance; alGetSourcef(m_source, AL_REFERENCE_DISTANCE, &distance); @@ -101,6 +124,8 @@ namespace Nz float SoundEmitter::GetPitch() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALfloat pitch; alGetSourcef(m_source, AL_PITCH, &pitch); @@ -114,6 +139,8 @@ namespace Nz Vector3f SoundEmitter::GetPosition() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + Vector3f position; alGetSourcefv(m_source, AL_POSITION, position); @@ -127,6 +154,8 @@ namespace Nz Vector3f SoundEmitter::GetVelocity() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + Vector3f velocity; alGetSourcefv(m_source, AL_VELOCITY, velocity); @@ -140,6 +169,8 @@ namespace Nz float SoundEmitter::GetVolume() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALfloat gain; alGetSourcef(m_source, AL_GAIN, &gain); @@ -153,6 +184,8 @@ namespace Nz bool SoundEmitter::IsSpatialized() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALint relative; alGetSourcei(m_source, AL_SOURCE_RELATIVE, &relative); @@ -167,6 +200,8 @@ namespace Nz void SoundEmitter::SetAttenuation(float attenuation) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcef(m_source, AL_ROLLOFF_FACTOR, attenuation); } @@ -178,6 +213,8 @@ namespace Nz void SoundEmitter::SetMinDistance(float minDistance) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcef(m_source, AL_REFERENCE_DISTANCE, minDistance); } @@ -189,6 +226,8 @@ namespace Nz void SoundEmitter::SetPitch(float pitch) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcef(m_source, AL_PITCH, pitch); } @@ -200,6 +239,8 @@ namespace Nz void SoundEmitter::SetPosition(const Vector3f& position) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcefv(m_source, AL_POSITION, position); } @@ -211,6 +252,8 @@ namespace Nz void SoundEmitter::SetPosition(float x, float y, float z) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSource3f(m_source, AL_POSITION, x, y, z); } @@ -222,6 +265,8 @@ namespace Nz void SoundEmitter::SetVelocity(const Vector3f& velocity) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcefv(m_source, AL_VELOCITY, velocity); } @@ -233,6 +278,8 @@ namespace Nz void SoundEmitter::SetVelocity(float velX, float velY, float velZ) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSource3f(m_source, AL_VELOCITY, velX, velY, velZ); } @@ -244,9 +291,25 @@ namespace Nz void SoundEmitter::SetVolume(float volume) { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + alSourcef(m_source, AL_GAIN, volume * 0.01f); } + /*! + * \brief Assign a sound emitter by moving it + * + * \param emitter SoundEmitter to move + * + * \return *this + */ + SoundEmitter& SoundEmitter::operator=(SoundEmitter&& emitter) noexcept + { + std::swap(m_source, emitter.m_source); + + return *this; + } + /*! * \brief Gets the status of the sound emitter * \return Enumeration of type SoundStatus (Playing, Stopped, ...) @@ -254,6 +317,8 @@ namespace Nz SoundStatus SoundEmitter::GetInternalStatus() const { + NazaraAssert(m_source != InvalidSource, "Invalid sound emitter"); + ALint state; alGetSourcei(m_source, AL_SOURCE_STATE, &state); diff --git a/src/Nazara/Core/Posix/DirectoryImpl.cpp b/src/Nazara/Core/Posix/DirectoryImpl.cpp index e52328def..e688aabf6 100644 --- a/src/Nazara/Core/Posix/DirectoryImpl.cpp +++ b/src/Nazara/Core/Posix/DirectoryImpl.cpp @@ -3,8 +3,11 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include +#include #include +#include #include #include #include @@ -13,9 +16,9 @@ namespace Nz { - DirectoryImpl::DirectoryImpl(const Directory* parent) + DirectoryImpl::DirectoryImpl(const Directory* parent) : + m_parent(parent) { - NazaraUnused(parent); } void DirectoryImpl::Close() @@ -30,19 +33,29 @@ namespace Nz UInt64 DirectoryImpl::GetResultSize() const { - struct stat64 resulststat; - stat64(m_result->d_name, &resulststat); + String path = m_parent->GetPath(); + std::size_t pathSize = path.GetSize(); - return static_cast(resulststat.st_size); + std::size_t resultNameSize = std::strlen(m_result->d_name); + + std::size_t fullNameSize = pathSize + 1 + resultNameSize; + StackArray fullName = NazaraStackAllocationNoInit(char, fullNameSize + 1); + std::memcpy(&fullName[0], path.GetConstBuffer(), pathSize * sizeof(char)); + fullName[pathSize] = '/'; + std::memcpy(&fullName[pathSize + 1], m_result->d_name, resultNameSize * sizeof(char)); + fullName[fullNameSize] = '\0'; + + struct stat64 results; + stat64(fullName.data(), &results); + + return results.st_size; } bool DirectoryImpl::IsResultDirectory() const { - struct stat64 filestats; - if (stat64(m_result->d_name, &filestats) == -1) // error - return false; + //TODO: Fix d_type handling (field can be missing or be a symbolic link, both cases which must be handled by calling stat) - return S_ISDIR(filestats.st_mode); + return m_result->d_type == DT_DIR; } bool DirectoryImpl::NextResult() diff --git a/src/Nazara/Core/Posix/DirectoryImpl.hpp b/src/Nazara/Core/Posix/DirectoryImpl.hpp index 50d1b96aa..907947371 100644 --- a/src/Nazara/Core/Posix/DirectoryImpl.hpp +++ b/src/Nazara/Core/Posix/DirectoryImpl.hpp @@ -43,6 +43,7 @@ namespace Nz static bool Remove(const String& dirPath); private: + const Directory* m_parent; DIR* m_handle; dirent64* m_result; }; diff --git a/src/Nazara/Core/SerializationContext.cpp b/src/Nazara/Core/SerializationContext.cpp index e1665a416..5949281e3 100644 --- a/src/Nazara/Core/SerializationContext.cpp +++ b/src/Nazara/Core/SerializationContext.cpp @@ -28,7 +28,7 @@ namespace Nz ResetBitPosition(); // Serialize will reset the bit position - if (!Serialize(*this, currentByte)) + if (!Serialize(*this, currentByte)) NazaraWarning("Failed to flush bits"); } } diff --git a/src/Nazara/Core/Stream.cpp b/src/Nazara/Core/Stream.cpp index afc213814..7ae91ed93 100644 --- a/src/Nazara/Core/Stream.cpp +++ b/src/Nazara/Core/Stream.cpp @@ -52,7 +52,7 @@ namespace Nz * * \param lineSize Maximum number of characters to read, or zero for no limit * - * \return Line containing characters + * \return Line read from file * * \remark With the text stream option, "\r\n" is treated as "\n" * \remark The line separator character is not returned as part of the string @@ -87,8 +87,7 @@ namespace Nz if (!SetCursorPos(GetCursorPos() - readSize + pos + 1)) NazaraWarning("Failed to reset cursor pos"); - if (!line.IsEmpty()) - break; + break; } else { diff --git a/src/Nazara/Core/String.cpp b/src/Nazara/Core/String.cpp index 7a5b01d19..9e4e2ae32 100644 --- a/src/Nazara/Core/String.cpp +++ b/src/Nazara/Core/String.cpp @@ -5932,7 +5932,7 @@ namespace Nz * \param context Context of serialization * \param string String to serialize */ - bool Serialize(SerializationContext& context, const String& string) + bool Serialize(SerializationContext& context, const String& string, TypeTag) { if (!Serialize(context, UInt32(string.GetSize()))) return false; @@ -5947,7 +5947,7 @@ namespace Nz * \param context Context of unserialization * \param string String to unserialize */ - bool Unserialize(SerializationContext& context, String* string) + bool Unserialize(SerializationContext& context, String* string, TypeTag) { UInt32 size; if (!Unserialize(context, &size)) diff --git a/src/Nazara/Graphics/BasicRenderQueue.cpp b/src/Nazara/Graphics/BasicRenderQueue.cpp new file mode 100644 index 000000000..fb358d8a8 --- /dev/null +++ b/src/Nazara/Graphics/BasicRenderQueue.cpp @@ -0,0 +1,947 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include +#include + +///TODO: Replace sinus/cosinus by a lookup table (which will lead to a speed up about 10x) + +namespace Nz +{ + /*! + * \ingroup graphics + * \class Nz::BasicRenderQueue + * \brief Graphics class that represents a simple rendering queue + */ + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 + + if (!sinCosPtr) + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + if (!colorPtr) + colorPtr.Reset(&Color::White, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + *colorPtr++, + *positionPtr++, + *sizePtr++, + *sinCosPtr++ + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = *colorPtr++; + data->sinCos = *sinCosPtr++; + data->size = *sizePtr++; + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 + + if (!sinCosPtr) + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + float defaultAlpha = 1.f; + + if (!alphaPtr) + alphaPtr.Reset(&defaultAlpha, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + ComputeColor(*alphaPtr++), + *positionPtr++, + *sizePtr++, + *sinCosPtr++ + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = ComputeColor(*alphaPtr++); + data->sinCos = *sinCosPtr++; + data->size = *sizePtr++; + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + float defaultRotation = 0.f; + + if (!anglePtr) + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + if (!colorPtr) + colorPtr.Reset(&Color::White, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + *colorPtr++, + *positionPtr++, + *sizePtr++, + ComputeSinCos(*anglePtr++) + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = *colorPtr++; + data->sinCos = ComputeSinCos(*anglePtr++); + data->size = *sizePtr++; + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + float defaultRotation = 0.f; + + if (!anglePtr) + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + float defaultAlpha = 1.f; + + if (!alphaPtr) + alphaPtr.Reset(&defaultAlpha, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + ComputeColor(*alphaPtr++), + *positionPtr++, + *sizePtr++, + ComputeSinCos(*anglePtr++) + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = ComputeColor(*alphaPtr++); + data->sinCos = ComputeSinCos(*anglePtr++); + data->size = *sizePtr++; + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 + + if (!sinCosPtr) + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + if (!colorPtr) + colorPtr.Reset(&Color::White, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + *colorPtr++, + *positionPtr++, + ComputeSize(*sizePtr++), + *sinCosPtr++ + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = *colorPtr++; + data->sinCos = *sinCosPtr++; + data->size = ComputeSize(*sizePtr++); + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 + + if (!sinCosPtr) + sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + float defaultAlpha = 1.f; + + if (!alphaPtr) + alphaPtr.Reset(&defaultAlpha, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + ComputeColor(*alphaPtr++), + *positionPtr++, + ComputeSize(*sizePtr++), + *sinCosPtr++ + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = ComputeColor(*alphaPtr++); + data->sinCos = *sinCosPtr++; + data->size = ComputeSize(*sizePtr++); + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + float defaultRotation = 0.f; + + if (!anglePtr) + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + if (!colorPtr) + colorPtr.Reset(&Color::White, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + *colorPtr++, + *positionPtr++, + ComputeSize(*sizePtr++), + ComputeSinCos(*anglePtr++) + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = *colorPtr++; + data->sinCos = ComputeSinCos(*anglePtr++); + data->size = ComputeSize(*sizePtr++); + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + * + * \remark Produces a NazaraAssert if material is invalid + */ + + void BasicRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + float defaultRotation = 0.f; + + if (!anglePtr) + anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile + + float defaultAlpha = 1.f; + + if (!alphaPtr) + alphaPtr.Reset(&defaultAlpha, 0); // Same + + if (material->IsDepthSortingEnabled()) + { + for (std::size_t i = 0; i < billboardCount; ++i) + { + depthSortedBillboards.Insert({ + renderOrder, + material, + scissorRect, + { + ComputeColor(*alphaPtr++), + *positionPtr++, + ComputeSize(*sizePtr++), + ComputeSinCos(*anglePtr++) + } + }); + } + } + else + { + std::size_t billboardIndex = m_billboards.size(); + m_billboards.resize(billboardIndex + billboardCount); + BillboardData* data = &m_billboards[billboardIndex]; + + for (std::size_t i = 0; i < billboardCount; ++i) + { + data->center = *positionPtr++; + data->color = ComputeColor(*alphaPtr++); + data->sinCos = ComputeSinCos(*anglePtr++); + data->size = ComputeSize(*sizePtr++); + data++; + } + + billboards.Insert({ + renderOrder, + material, + scissorRect, + billboardCount, + billboardIndex + }); + } + } + + /*! + * \brief Adds drawable to the queue + * + * \param renderOrder Order of rendering + * \param drawable Drawable user defined + * + * \remark Produces a NazaraError if drawable is invalid + */ + void BasicRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) + { + NazaraAssert(drawable, "Invalid material"); + + RegisterLayer(renderOrder); + + customDrawables.Insert({ + renderOrder, + drawable + }); + } + + /*! + * \brief Adds mesh to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the mesh + * \param meshData Data of the mesh + * \param meshAABB Box of the mesh + * \param transformMatrix Matrix of the mesh + * + * \remark Produces a NazaraAssert if material is invalid + */ + void BasicRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect) + { + NazaraAssert(material, "Invalid material"); + + RegisterLayer(renderOrder); + + Spheref obbSphere(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius()); + + if (material->IsDepthSortingEnabled()) + { + depthSortedModels.Insert({ + renderOrder, + meshData, + material, + transformMatrix, + scissorRect, + obbSphere + }); + } + else + { + models.Insert({ + renderOrder, + meshData, + material, + transformMatrix, + scissorRect, + obbSphere + }); + } + } + + /*! + * \brief Adds sprites to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the sprites + * \param vertices Buffer of data for the sprites + * \param spriteCount Number of sprites + * \param overlay Texture of the sprites + * + * \remark Produces a NazaraAssert if material is invalid + */ + void BasicRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay /*= nullptr*/) + { + NazaraAssert(material, "Invalid material"); + + RegisterLayer(renderOrder); + + if (material->IsDepthSortingEnabled()) + { + depthSortedSprites.Insert({ + renderOrder, + spriteCount, + material, + overlay, + vertices, + scissorRect + }); + } + else + { + basicSprites.Insert({ + renderOrder, + spriteCount, + material, + overlay, + vertices, + scissorRect + }); + } + } + + /*! + * \brief Clears the queue + * + * \param fully Should everything be cleared or we can keep layers + */ + + void BasicRenderQueue::Clear(bool fully) + { + AbstractRenderQueue::Clear(fully); + + basicSprites.Clear(); + billboards.Clear(); + depthSortedBillboards.Clear(); + depthSortedModels.Clear(); + depthSortedSprites.Clear(); + models.Clear(); + + m_pipelineCache.clear(); + m_materialCache.clear(); + m_overlayCache.clear(); + m_shaderCache.clear(); + m_textureCache.clear(); + m_vertexBufferCache.clear(); + + m_billboards.clear(); + m_renderLayers.clear(); + } + + /*! + * \brief Sorts the object according to the viewer position, furthest to nearest + * + * \param viewer Viewer of the scene + */ + + void BasicRenderQueue::Sort(const AbstractViewer* viewer) + { + m_layerCache.clear(); + for (int layer : m_renderLayers) + m_layerCache.emplace(layer, m_layerCache.size()); + + auto GetOrInsert = [](auto& container, auto&& value) + { + auto it = container.find(value); + if (it == container.end()) + it = container.emplace(value, container.size()).first; + + return it->second; + }; + + basicSprites.Sort([&](const SpriteChain& vertices) + { + // RQ index: + // - Layer (4bits) + // - Pipeline (8bits) + // - Material (8bits) + // - Shader? (8bits) + // - Textures (8bits) + // - Overlay (8bits) + // - Scissor (4bits) + // - Depth? (16bits) + + UInt64 layerIndex = m_layerCache[vertices.layerIndex]; + UInt64 pipelineIndex = GetOrInsert(m_pipelineCache, vertices.material->GetPipeline()); + UInt64 materialIndex = GetOrInsert(m_materialCache, vertices.material); + UInt64 shaderIndex = GetOrInsert(m_shaderCache, vertices.material->GetShader()); + UInt64 textureIndex = GetOrInsert(m_textureCache, vertices.material->GetDiffuseMap()); + UInt64 overlayIndex = GetOrInsert(m_overlayCache, vertices.overlay); + UInt64 scissorIndex = 0; //< TODO + UInt64 depthIndex = 0; //< TODO + + UInt64 index = (layerIndex & 0x0F) << 60 | + (pipelineIndex & 0xFF) << 52 | + (materialIndex & 0xFF) << 44 | + (shaderIndex & 0xFF) << 36 | + (textureIndex & 0xFF) << 28 | + (overlayIndex & 0xFF) << 20 | + (scissorIndex & 0x0F) << 16 | + (depthIndex & 0xFFFF) << 0; + + return index; + }); + + billboards.Sort([&](const BillboardChain& billboard) + { + // RQ index: + // - Layer (4bits) + // - Pipeline (8bits) + // - Material (8bits) + // - Shader? (8bits) + // - Textures (8bits) + // - ??? (8bits) + // - Scissor (4bits) + // - Depth? (16bits) + + UInt64 layerIndex = m_layerCache[billboard.layerIndex]; + UInt64 pipelineIndex = GetOrInsert(m_pipelineCache, billboard.material->GetPipeline()); + UInt64 materialIndex = GetOrInsert(m_materialCache, billboard.material); + UInt64 shaderIndex = GetOrInsert(m_shaderCache, billboard.material->GetShader()); + UInt64 textureIndex = GetOrInsert(m_textureCache, billboard.material->GetDiffuseMap()); + UInt64 unknownIndex = 0; //< ??? + UInt64 scissorIndex = 0; //< TODO + UInt64 depthIndex = 0; //< TODO? + + UInt64 index = (layerIndex & 0x0F) << 60 | + (pipelineIndex & 0xFF) << 52 | + (materialIndex & 0xFF) << 44 | + (shaderIndex & 0xFF) << 36 | + (textureIndex & 0xFF) << 28 | + (unknownIndex & 0xFF) << 20 | + (scissorIndex & 0x0F) << 16 | + (depthIndex & 0xFFFF) << 0; + + return index; + }); + + customDrawables.Sort([&](const CustomDrawable& drawable) + { + // RQ index: + // - Layer (4bits) + + UInt64 layerIndex = m_layerCache[drawable.layerIndex]; + + UInt64 index = (layerIndex & 0x0F) << 60; + + return index; + + }); + + models.Sort([&](const Model& renderData) + { + // RQ index: + // - Layer (4bits) + // - Pipeline (8bits) + // - Material (8bits) + // - Shader? (8bits) + // - Textures (8bits) + // - Buffers (8bits) + // - Scissor (4bits) + // - Depth? (16bits) + + UInt64 layerIndex = m_layerCache[renderData.layerIndex]; + UInt64 pipelineIndex = GetOrInsert(m_pipelineCache, renderData.material->GetPipeline()); + UInt64 materialIndex = GetOrInsert(m_materialCache, renderData.material); + UInt64 shaderIndex = GetOrInsert(m_shaderCache, renderData.material->GetShader()); + UInt64 textureIndex = GetOrInsert(m_textureCache, renderData.material->GetDiffuseMap()); + UInt64 bufferIndex = GetOrInsert(m_vertexBufferCache, renderData.meshData.vertexBuffer); + UInt64 scissorIndex = 0; //< TODO + UInt64 depthIndex = 0; //< TODO + + UInt64 index = (layerIndex & 0x0F) << 60 | + (pipelineIndex & 0xFF) << 52 | + (materialIndex & 0xFF) << 44 | + (shaderIndex & 0xFF) << 36 | + (textureIndex & 0xFF) << 28 | + (bufferIndex & 0xFF) << 20 | + (scissorIndex & 0x0F) << 16 | + (depthIndex & 0xFFFF) << 0; + + return index; + }); + + static_assert(std::numeric_limits::is_iec559, "The following sorting functions relies on IEEE 754 floatings-points"); + +#if defined(arm) && \ + ((defined(__MAVERICK__) && defined(NAZARA_BIG_ENDIAN)) || \ + (!defined(__SOFTFP__) && !defined(__VFP_FP__) && !defined(__MAVERICK__))) + #error The following code relies on native-endian IEEE-754 representation, which your platform does not guarantee +#endif + + Planef nearPlane = viewer->GetFrustum().GetPlane(FrustumPlane_Near); + + depthSortedBillboards.Sort([&](const Billboard& billboard) + { + // RQ index: + // - Layer (4bits) + // - Depth (32bits) + // - ?? (28bits) + + // Reinterpret depth as UInt32 (this will work as long as they're all either positive or negative, + // a negative distance may happen with billboard behind the camera which we don't care about since they'll be rendered) + float depth = nearPlane.Distance(billboard.data.center); + + UInt64 layerIndex = m_layerCache[billboard.layerIndex]; + UInt64 depthIndex = ~reinterpret_cast(depth); + + UInt64 index = (layerIndex & 0x0F) << 60 | + (depthIndex & 0xFFFFFFFF) << 28; + + return index; + }); + + if (viewer->GetProjectionType() == ProjectionType_Orthogonal) + { + depthSortedModels.Sort([&](const Model& model) + { + // RQ index: + // - Layer (4bits) + // - Depth (32bits) + // - ?? (28bits) + + float depth = nearPlane.Distance(model.obbSphere.GetPosition()); + + UInt64 layerIndex = m_layerCache[model.layerIndex]; + UInt64 depthIndex = ~reinterpret_cast(depth); + + UInt64 index = (layerIndex & 0x0F) << 60 | + (depthIndex & 0xFFFFFFFF) << 28; + + return index; + }); + + depthSortedSprites.Sort([&](const SpriteChain& spriteChain) + { + // RQ index: + // - Layer (4bits) + // - Depth (32bits) + // - ?? (28bits) + + float depth = nearPlane.Distance(spriteChain.vertices[0].position); + + UInt64 layerIndex = m_layerCache[spriteChain.layerIndex]; + UInt64 depthIndex = ~reinterpret_cast(depth); + + UInt64 index = (layerIndex & 0x0F) << 60 | + (depthIndex & 0xFFFFFFFF) << 28; + + return index; + }); + } + else + { + Vector3f viewerPos = viewer->GetEyePosition(); + + depthSortedModels.Sort([&](const Model& model) + { + // RQ index: + // - Layer (4bits) + // - Depth (32bits) + // - ?? (28bits) + + float depth = viewerPos.SquaredDistance(model.obbSphere.GetPosition()); + + UInt64 layerIndex = m_layerCache[model.layerIndex]; + UInt64 depthIndex = ~reinterpret_cast(depth); + + UInt64 index = (layerIndex & 0x0F) << 60 | + (depthIndex & 0xFFFFFFFF) << 28; + + return index; + }); + + depthSortedSprites.Sort([&](const SpriteChain& sprites) + { + // RQ index: + // - Layer (4bits) + // - Depth (32bits) + // - ?? (28bits) + + float depth = viewerPos.SquaredDistance(sprites.vertices[0].position); + + UInt64 layerIndex = m_layerCache[sprites.layerIndex]; + UInt64 depthIndex = ~reinterpret_cast(depth); + + UInt64 index = (layerIndex & 0x0F) << 60 | + (depthIndex & 0xFFFFFFFF) << 28; + + return index; + }); + } + } +} diff --git a/src/Nazara/Graphics/Billboard.cpp b/src/Nazara/Graphics/Billboard.cpp index e228a2a59..9cc79acce 100644 --- a/src/Nazara/Graphics/Billboard.cpp +++ b/src/Nazara/Graphics/Billboard.cpp @@ -21,10 +21,10 @@ namespace Nz * \param instanceData Data used for instance */ - void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const + void Billboard::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const { Nz::Vector3f position = instanceData.transformMatrix.GetTranslation(); - renderQueue->AddBillboards(instanceData.renderOrder, GetMaterial(), 1, &position, &m_size, &m_sinCos, &m_color); + renderQueue->AddBillboards(instanceData.renderOrder, GetMaterial(), 1, scissorRect, &position, &m_size, &m_sinCos, &m_color); } /* @@ -33,9 +33,12 @@ namespace Nz void Billboard::MakeBoundingVolume() const { - constexpr float sqrt2 = float(M_SQRT2); + // As billboard always face the screen, we must take its maximum size in account on every axis + float maxSize = float(M_SQRT2) * std::max(m_size.x, m_size.y); - m_boundingVolume.Set(Vector3f(0.f), sqrt2 * m_size.x * Vector3f::Right() + sqrt2 * m_size.y * Vector3f::Down()); + Nz::Vector3f halfSize = (maxSize * Vector3f::Right() + maxSize * Vector3f::Down() + maxSize * Vector3f::Forward()) / 2.f; + + m_boundingVolume.Set(-halfSize, halfSize); } BillboardLibrary::LibraryMap Billboard::s_library; diff --git a/src/Nazara/Graphics/ColorBackground.cpp b/src/Nazara/Graphics/ColorBackground.cpp index 6004783ac..b5c41e7c2 100644 --- a/src/Nazara/Graphics/ColorBackground.cpp +++ b/src/Nazara/Graphics/ColorBackground.cpp @@ -50,6 +50,7 @@ namespace Nz ParameterList list; list.SetParameter("UNIFORM_VERTEX_DEPTH", true); + m_uberShaderInstance = m_uberShader->Get(list); const Shader* shader = m_uberShaderInstance->GetShader(); diff --git a/src/Nazara/Graphics/DeferredGeometryPass.cpp b/src/Nazara/Graphics/DeferredGeometryPass.cpp index b679c873a..dbd500ea4 100644 --- a/src/Nazara/Graphics/DeferredGeometryPass.cpp +++ b/src/Nazara/Graphics/DeferredGeometryPass.cpp @@ -5,16 +5,34 @@ #include #include #include +#include #include #include +#include #include #include #include #include +#include #include namespace Nz { + namespace + { + struct BillboardPoint + { + Color color; + Vector3f position; + Vector2f size; + Vector2f sinCos; // must follow `size` (both will be sent as a Vector4f) + Vector2f uv; + }; + + UInt32 s_maxQuads = std::numeric_limits::max() / 6; + UInt32 s_vertexBufferSize = 4 * 1024 * 1024; // 4 MiB + } + /*! * \ingroup graphics * \class Nz::DeferredGeometryPass @@ -25,8 +43,18 @@ namespace Nz * \brief Constructs a DeferredGeometryPass object by default */ - DeferredGeometryPass::DeferredGeometryPass() + DeferredGeometryPass::DeferredGeometryPass() : + m_vertexBuffer(BufferType_Vertex) { + ErrorFlags flags(ErrorFlag_ThrowException, true); + + m_whiteTexture = Nz::TextureLibrary::Get("White2D"); + + m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic); + + m_billboardPointBuffer.Reset(&s_billboardVertexDeclaration, &m_vertexBuffer); + m_spriteBuffer.Reset(VertexDeclaration::Get(VertexLayout_XYZ_Color_UV), &m_vertexBuffer); + m_clearShader = ShaderLibrary::Get("DeferredGBufferClear"); m_clearStates.depthBuffer = true; m_clearStates.faceCulling = true; @@ -57,6 +85,7 @@ namespace Nz m_GBufferRTT->SetColorTargets({0, 1, 2}); // G-Buffer Renderer::SetTarget(m_GBufferRTT); + Renderer::SetScissorRect(Recti(0, 0, m_dimensions.x, m_dimensions.y)); Renderer::SetViewport(Recti(0, 0, m_dimensions.x, m_dimensions.y)); Renderer::SetRenderStates(m_clearStates); @@ -67,131 +96,27 @@ namespace Nz Renderer::SetMatrix(MatrixType_Projection, sceneData.viewer->GetProjectionMatrix()); Renderer::SetMatrix(MatrixType_View, sceneData.viewer->GetViewMatrix()); - const Shader* lastShader = nullptr; - const ShaderUniforms* shaderUniforms = nullptr; + BasicRenderQueue& renderQueue = *m_renderQueue->GetDeferredRenderQueue(); - for (auto& layerPair : m_renderQueue->layers) - { - for (auto& pipelinePair : layerPair.second.opaqueModels) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; + renderQueue.Sort(sceneData.viewer); - if (pipelineEntry.maxInstanceCount > 0) - { - bool instancing = instancingEnabled && (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT); + if (!renderQueue.models.empty()) + DrawModels(sceneData, renderQueue, renderQueue.models); - UInt32 flags = ShaderFlags_Deferred; - if (instancing) - flags |= ShaderFlags_Instancing; + if (!renderQueue.basicSprites.empty()) + DrawSprites(sceneData, renderQueue, renderQueue.basicSprites); - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(flags); + if (!renderQueue.billboards.empty()) + DrawBillboards(sceneData, renderQueue, renderQueue.billboards); - const Shader* shader = pipelineInstance.uberInstance->GetShader(); + if (!renderQueue.depthSortedModels.empty()) + DrawModels(sceneData, renderQueue, renderQueue.depthSortedModels); - // 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 - shaderUniforms = GetShaderUniforms(shader); + if (!renderQueue.depthSortedSprites.empty()) + DrawSprites(sceneData, renderQueue, renderQueue.depthSortedSprites); - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position of the camera - shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - - lastShader = shader; - } - - for (auto& materialPair : pipelineEntry.materialMap) - { - const Material* material = materialPair.first; - auto& matEntry = materialPair.second; - - if (matEntry.enabled) - { - DeferredRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap; - - if (!meshInstances.empty()) - { - material->Apply(pipelineInstance); - - // Meshes - for (auto& meshIt : meshInstances) - { - const MeshData& meshData = meshIt.first; - auto& meshEntry = meshIt.second; - - std::vector& instances = meshEntry.instances; - if (!instances.empty()) - { - const IndexBuffer* indexBuffer = meshData.indexBuffer; - const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - - // Handle draw call before rendering loop - Renderer::DrawCall drawFunc; - Renderer::DrawCallInstanced instancedDrawFunc; - unsigned int indexCount; - - if (indexBuffer) - { - drawFunc = Renderer::DrawIndexedPrimitives; - instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced; - indexCount = indexBuffer->GetIndexCount(); - } - else - { - drawFunc = Renderer::DrawPrimitives; - instancedDrawFunc = Renderer::DrawPrimitivesInstanced; - indexCount = vertexBuffer->GetVertexCount(); - } - - Renderer::SetIndexBuffer(indexBuffer); - Renderer::SetVertexBuffer(vertexBuffer); - - if (instancing) - { - // We get the buffer for instance of Renderer and we configure it to work with matrices - VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); - instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); - - const Matrix4f* instanceMatrices = &instances[0]; - std::size_t instanceCount = instances.size(); - std::size_t maxInstanceCount = instanceBuffer->GetVertexCount(); // The number of matrices that can be hold in the buffer - - while (instanceCount > 0) - { - // We compute the number of instances that we will be able to show this time (Depending on the instance buffer size) - std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount); - instanceCount -= renderedInstanceCount; - - // We fill the instancing buffer with our world matrices - instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount); - instanceMatrices += renderedInstanceCount; - - // And we show - instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); - } - } - else - { - // Without instancing, we must do one draw call for each instance - // This may be faster than instancing under a threshold - // Due to the time to modify the instancing buffer - for (const Matrix4f& matrix : instances) - { - Renderer::SetMatrix(MatrixType_World, matrix); - drawFunc(meshData.primitiveMode, 0, indexCount); - } - } - } - } - } - } - } - } - } - } + if (!renderQueue.depthSortedBillboards.empty()) + DrawBillboards(sceneData, renderQueue, renderQueue.depthSortedBillboards); return false; // We only fill the G-Buffer, the work texture are unchanged } @@ -266,13 +191,409 @@ namespace Nz return false; } } + + void DeferredGeometryPass::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const + { + VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); + instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); - /*! - * \brief Gets the uniforms of a shader - * \return Uniforms of the shader - * - * \param shader Shader to get uniforms from - */ + Renderer::SetVertexBuffer(&s_quadVertexBuffer); + + Nz::BufferMapper instanceBufferMapper; + std::size_t billboardCount = 0; + std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); + + auto Commit = [&]() + { + if (billboardCount > 0) + { + instanceBufferMapper.Unmap(); + + Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4); + + billboardCount = 0; + } + }; + + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::Billboard& billboard : billboards) + { + const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect; + + if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = billboard.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + 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()); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != billboard.material) + { + billboard.material->Apply(*pipelineInstance); + lastMaterial = billboard.material; + } + + if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + if (!instanceBufferMapper.GetBuffer()) + instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite); + + std::memcpy(static_cast(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, &billboard.data, sizeof(BasicRenderQueue::BillboardData)); + if (++billboardCount >= maxBillboardPerDraw) + Commit(); + } + + Commit(); + } + + void DeferredGeometryPass::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const + { + VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); + instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); + + Renderer::SetVertexBuffer(&s_quadVertexBuffer); + + Nz::BufferMapper instanceBufferMapper; + std::size_t billboardCount = 0; + std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); + + auto Commit = [&]() + { + if (billboardCount > 0) + { + instanceBufferMapper.Unmap(); + + Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4); + + billboardCount = 0; + } + }; + + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::BillboardChain& billboard : billboards) + { + const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect; + + if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = billboard.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + 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()); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != billboard.material) + { + billboard.material->Apply(*pipelineInstance); + lastMaterial = billboard.material; + } + + if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + std::size_t billboardRemaining = billboard.billboardCount; + const BasicRenderQueue::BillboardData* billboardData = renderQueue.GetBillboardData(billboard.billboardIndex); + do + { + std::size_t renderedBillboardCount = std::min(billboardRemaining, maxBillboardPerDraw - billboardCount); + billboardRemaining -= renderedBillboardCount; + + if (!instanceBufferMapper.GetBuffer()) + instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite); + + std::memcpy(static_cast(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, billboardData, renderedBillboardCount * sizeof(BasicRenderQueue::BillboardData)); + billboardCount += renderedBillboardCount; + billboardData += renderedBillboardCount; + + if (billboardCount >= maxBillboardPerDraw) + Commit(); + } + while (billboardRemaining > 0); + } + + Commit(); + } + + void DeferredGeometryPass::DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const Nz::RenderQueue& models) const + { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + ///TODO: Reimplement instancing + + for (const BasicRenderQueue::Model& model : models) + { + const MaterialPipeline* pipeline = model.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &model.material->GetPipeline()->Apply(ShaderFlags_Deferred); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + 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()); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != model.material) + { + model.material->Apply(*pipelineInstance); + lastMaterial = model.material; + } + + if (model.material->IsScissorTestEnabled()) + { + const Nz::Recti& scissorRect = (model.scissorRect.width > 0) ? model.scissorRect : fullscreenScissorRect; + if (scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + // Handle draw call before rendering loop + Renderer::DrawCall drawFunc; + Renderer::DrawCallInstanced instancedDrawFunc; + unsigned int indexCount; + + if (model.meshData.indexBuffer) + { + drawFunc = Renderer::DrawIndexedPrimitives; + instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced; + indexCount = model.meshData.indexBuffer->GetIndexCount(); + } + else + { + drawFunc = Renderer::DrawPrimitives; + instancedDrawFunc = Renderer::DrawPrimitivesInstanced; + indexCount = model.meshData.vertexBuffer->GetVertexCount(); + } + + Renderer::SetIndexBuffer(model.meshData.indexBuffer); + Renderer::SetVertexBuffer(model.meshData.vertexBuffer); + + Renderer::SetMatrix(MatrixType_World, model.matrix); + drawFunc(model.meshData.primitiveMode, 0, indexCount); + } + } + + void DeferredGeometryPass::DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& spriteList) const + { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + Renderer::SetIndexBuffer(&s_quadIndexBuffer); + Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); + Renderer::SetVertexBuffer(&m_spriteBuffer); + + const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); + const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); + + m_spriteChains.clear(); + + auto Commit = [&]() + { + std::size_t spriteChainCount = m_spriteChains.size(); + if (spriteChainCount > 0) + { + std::size_t spriteChain = 0; // Which chain of sprites are we treating + std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain + + do + { + // 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 spriteCount = 0; + + do + { + const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first; + std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second; + std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset); + + std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += count * 4; + + spriteCount += count; + spriteChainOffset += count; + + // Have we treated the entire chain ? + if (spriteChainOffset == currentChainSpriteCount) + { + spriteChain++; + spriteChainOffset = 0; + } + } + while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); + + vertexMapper.Unmap(); + + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); + } + while (spriteChain < spriteChainCount); + } + + m_spriteChains.clear(); + }; + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) + { + const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; + + if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = basicSprites.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + 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; + } + + if (lastMaterial != basicSprites.material) + { + basicSprites.material->Apply(*pipelineInstance); + + Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); + + lastMaterial = basicSprites.material; + } + + const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); + if (overlayTexture != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, overlayTexture); + lastOverlay = overlayTexture; + } + + if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); + } + + Commit(); + } const DeferredGeometryPass::ShaderUniforms* DeferredGeometryPass::GetShaderUniforms(const Shader* shader) const { @@ -303,4 +624,73 @@ namespace Nz { m_shaderUniforms.erase(shader); } + + bool DeferredGeometryPass::Initialize() + { + try + { + ErrorFlags flags(ErrorFlag_ThrowException, true); + + s_quadIndexBuffer.Reset(false, s_maxQuads * 6, DataStorage_Hardware, 0); + + BufferMapper mapper(s_quadIndexBuffer, BufferAccess_WriteOnly); + UInt16* indices = static_cast(mapper.GetPointer()); + + for (unsigned int i = 0; i < s_maxQuads; ++i) + { + *indices++ = i * 4 + 0; + *indices++ = i * 4 + 2; + *indices++ = i * 4 + 1; + + *indices++ = i * 4 + 2; + *indices++ = i * 4 + 3; + *indices++ = i * 4 + 1; + } + + mapper.Unmap(); // No point to keep the buffer open any longer + + // Quad buffer (used for instancing of billboards and sprites) + //Note: UV are computed in the shader + s_quadVertexBuffer.Reset(VertexDeclaration::Get(VertexLayout_XY), 4, DataStorage_Hardware, 0); + + float vertices[2 * 4] = { + -0.5f, -0.5f, + 0.5f, -0.5f, + -0.5f, 0.5f, + 0.5f, 0.5f, + }; + + s_quadVertexBuffer.FillRaw(vertices, 0, sizeof(vertices)); + + // Declaration used when rendering the vertex billboards + s_billboardVertexDeclaration.EnableComponent(VertexComponent_Color, ComponentType_Color, NazaraOffsetOf(BillboardPoint, color)); + s_billboardVertexDeclaration.EnableComponent(VertexComponent_Position, ComponentType_Float3, NazaraOffsetOf(BillboardPoint, position)); + s_billboardVertexDeclaration.EnableComponent(VertexComponent_TexCoord, ComponentType_Float2, NazaraOffsetOf(BillboardPoint, uv)); + s_billboardVertexDeclaration.EnableComponent(VertexComponent_Userdata0, ComponentType_Float4, NazaraOffsetOf(BillboardPoint, size)); // Includes sincos + + // Declaration used when rendering the billboards with intancing + // The main advantage is the direct copy (std::memcpy) of data in the RenderQueue to the GPU buffer + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(BasicRenderQueue::BillboardData, center)); + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(BasicRenderQueue::BillboardData, size)); // Englobe sincos + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(BasicRenderQueue::BillboardData, color)); + } + catch (const std::exception& e) + { + NazaraError("Failed to initialise: " + String(e.what())); + return false; + } + + return true; + } + + void DeferredGeometryPass::Uninitialize() + { + s_quadIndexBuffer.Reset(); + s_quadVertexBuffer.Reset(); + } + + IndexBuffer DeferredGeometryPass::s_quadIndexBuffer; + VertexBuffer DeferredGeometryPass::s_quadVertexBuffer; + VertexDeclaration DeferredGeometryPass::s_billboardInstanceDeclaration; + VertexDeclaration DeferredGeometryPass::s_billboardVertexDeclaration; } diff --git a/src/Nazara/Graphics/DeferredPhongLightingPass.cpp b/src/Nazara/Graphics/DeferredPhongLightingPass.cpp index 3902c9d9d..7e4ef2480 100644 --- a/src/Nazara/Graphics/DeferredPhongLightingPass.cpp +++ b/src/Nazara/Graphics/DeferredPhongLightingPass.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/Nazara/Graphics/DeferredProxyRenderQueue.cpp b/src/Nazara/Graphics/DeferredProxyRenderQueue.cpp new file mode 100644 index 000000000..56d2b76d3 --- /dev/null +++ b/src/Nazara/Graphics/DeferredProxyRenderQueue.cpp @@ -0,0 +1,261 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +namespace Nz +{ + /*! + * \ingroup graphics + * \class Nz::DeferredProxyRenderQueue + * \brief Graphics class sorting the objects into a deferred and forward render queue (depending on blending) + */ + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Sizes of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param colorPtr Color of the billboards if null, Color::White is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr); + } + + /*! + * \brief Adds multiple billboards to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the billboards + * \param count Number of billboards + * \param positionPtr Position of the billboards + * \param sizePtr Size of the billboards + * \param anglePtr Rotation of the billboards if null, 0.f is used + * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used + */ + + void DeferredProxyRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr); + else + m_forwardRenderQueue->AddBillboards(renderOrder, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr); + } + + /*! + * \brief Adds drawable to the queue + * + * \param renderOrder Order of rendering + * \param drawable Drawable user defined + * + * \remark Produces a NazaraError if drawable is invalid + */ + + void DeferredProxyRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) + { + m_forwardRenderQueue->AddDrawable(renderOrder, drawable); + } + + /*! + * \brief Adds mesh to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the mesh + * \param meshData Data of the mesh + * \param meshAABB Box of the mesh + * \param transformMatrix Matrix of the mesh + */ + + void DeferredProxyRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix, scissorRect); + else + m_forwardRenderQueue->AddMesh(renderOrder, material, meshData, meshAABB, transformMatrix, scissorRect); + } + + /*! + * \brief Adds sprites to the queue + * + * \param renderOrder Order of rendering + * \param material Material of the sprites + * \param vertices Buffer of data for the sprites + * \param spriteCount Number of sprites + * \param overlay Texture of the sprites + */ + + void DeferredProxyRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay) + { + NazaraAssert(material, "Invalid material"); + + if (!material->IsBlendingEnabled()) + m_deferredRenderQueue->AddSprites(renderOrder, material, vertices, spriteCount, scissorRect, overlay); + else + m_forwardRenderQueue->AddSprites(renderOrder, material, vertices, spriteCount, scissorRect, overlay); + } + + /*! + * \brief Clears the queue + * + * \param fully Should everything be cleared or we can keep layers + */ + + void DeferredProxyRenderQueue::Clear(bool fully) + { + AbstractRenderQueue::Clear(fully); + + m_deferredRenderQueue->Clear(fully); + m_forwardRenderQueue->Clear(fully); + } +} diff --git a/src/Nazara/Graphics/DeferredRenderPass.cpp b/src/Nazara/Graphics/DeferredRenderPass.cpp index 8b0b7fde5..d3f89e348 100644 --- a/src/Nazara/Graphics/DeferredRenderPass.cpp +++ b/src/Nazara/Graphics/DeferredRenderPass.cpp @@ -3,8 +3,8 @@ // For conditions of distribution and use, see copyright notice in Config.hpp #include +#include #include -#include #include #include @@ -47,7 +47,7 @@ namespace Nz void DeferredRenderPass::Initialize(DeferredRenderTechnique* technique) { m_deferredTechnique = technique; - m_renderQueue = static_cast(technique->GetRenderQueue()); + m_renderQueue = static_cast(technique->GetRenderQueue()); m_depthStencilTexture = technique->GetDepthStencilTexture(); diff --git a/src/Nazara/Graphics/DeferredRenderQueue.cpp b/src/Nazara/Graphics/DeferredRenderQueue.cpp deleted file mode 100644 index 76bc666be..000000000 --- a/src/Nazara/Graphics/DeferredRenderQueue.cpp +++ /dev/null @@ -1,410 +0,0 @@ -// Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Graphics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include - -///TODO: Render billboards using Deferred Shading if possible - -namespace Nz -{ - /*! - * \ingroup graphics - * \class Nz::DeferredRenderQueue - * \brief Graphics class that represents the rendering queue for deferred rendering - */ - - /*! - * \brief Constructs a DeferredRenderQueue object with the rendering queue of forward rendering - * - * \param forwardQueue Queue of data to render - */ - - DeferredRenderQueue::DeferredRenderQueue(ForwardRenderQueue* forwardQueue) : - m_forwardQueue(forwardQueue) - { - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param colorPtr Color of the billboards if null, Color::White is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param colorPtr Color of the billboards if null, Color::White is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param colorPtr Color of the billboards if null, Color::White is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param colorPtr Color of the billboards if null, Color::White is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, colorPtr); - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - */ - - void DeferredRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) - { - m_forwardQueue->AddBillboards(renderOrder, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); - } - - /*! - * \brief Adds drawable to the queue - * - * \param renderOrder Order of rendering - * \param drawable Drawable user defined - * - * \remark Produces a NazaraError if drawable is invalid - */ - - void DeferredRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) - { - m_forwardQueue->AddDrawable(renderOrder, drawable); - } - - /*! - * \brief Adds mesh to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the mesh - * \param meshData Data of the mesh - * \param meshAABB Box of the mesh - * \param transformMatrix Matrix of the mesh - */ - - void DeferredRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) - { - 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 - { - Layer& currentLayer = GetLayer(renderOrder); - MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels; - - const MaterialPipeline* materialPipeline = material->GetPipeline(); - - auto pipelineIt = opaqueModels.find(materialPipeline); - if (pipelineIt == opaqueModels.end()) - { - BatchedMaterialEntry materialEntry; - pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first; - } - - BatchedMaterialEntry& materialEntry = pipelineIt->second; - MeshMaterialBatches& materialMap = materialEntry.materialMap; - - auto materialIt = materialMap.find(material); - if (materialIt == materialMap.end()) - { - BatchedModelEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &DeferredRenderQueue::OnMaterialInvalidation); - - materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first; - } - - BatchedModelEntry& entry = materialIt->second; - entry.enabled = true; - - MeshInstanceContainer& meshMap = entry.meshMap; - - auto it2 = meshMap.find(meshData); - if (it2 == meshMap.end()) - { - MeshInstanceEntry instanceEntry; - if (meshData.indexBuffer) - instanceEntry.indexBufferReleaseSlot.Connect(meshData.indexBuffer->OnIndexBufferRelease, this, &DeferredRenderQueue::OnIndexBufferInvalidation); - - instanceEntry.vertexBufferReleaseSlot.Connect(meshData.vertexBuffer->OnVertexBufferRelease, this, &DeferredRenderQueue::OnVertexBufferInvalidation); - - it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first; - } - - std::vector& instances = it2->second.instances; - instances.push_back(transformMatrix); - - materialEntry.maxInstanceCount = std::max(materialEntry.maxInstanceCount, instances.size()); - } - } - - /*! - * \brief Adds sprites to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the sprites - * \param vertices Buffer of data for the sprites - * \param spriteCount Number of sprites - * \param overlay Texture of the sprites - */ - - 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); - } - - /*! - * \brief Clears the queue - * - * \param fully Should everything be cleared or we can keep layers - */ - - void DeferredRenderQueue::Clear(bool fully) - { - AbstractRenderQueue::Clear(fully); - - if (fully) - layers.clear(); - else - { - for (auto it = layers.begin(); it != layers.end();) - { - Layer& layer = it->second; - if (layer.clearCount++ >= 100) - it = layers.erase(it); - else - { - for (auto& pipelinePair : layer.opaqueModels) - { - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.maxInstanceCount > 0) - { - for (auto& materialPair : pipelineEntry.materialMap) - { - auto& matEntry = materialPair.second; - - if (matEntry.enabled) - { - MeshInstanceContainer& meshInstances = matEntry.meshMap; - - for (auto& meshIt : meshInstances) - { - auto& meshEntry = meshIt.second; - - meshEntry.instances.clear(); - } - matEntry.enabled = false; - } - } - pipelineEntry.maxInstanceCount = 0; - } - } - - ++it; - } - } - } - - m_forwardQueue->Clear(fully); - } - - /*! - * \brief Gets the ith layer - * \return Reference to the ith layer for the queue - * - * \param i Index of the layer - */ - - DeferredRenderQueue::Layer& DeferredRenderQueue::GetLayer(unsigned int i) - { - 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; - } - - /*! - * \brief Handle the invalidation of an index buffer - * - * \param indexBuffer Index buffer being invalidated - */ - - void DeferredRenderQueue::OnIndexBufferInvalidation(const IndexBuffer* indexBuffer) - { - for (auto& pair : layers) - { - Layer& layer = pair.second; - - for (auto& pipelineEntry : layer.opaqueModels) - { - for (auto& materialEntry : pipelineEntry.second.materialMap) - { - MeshInstanceContainer& meshes = materialEntry.second.meshMap; - for (auto it = meshes.begin(); it != meshes.end();) - { - const MeshData& renderData = it->first; - if (renderData.indexBuffer == indexBuffer) - it = meshes.erase(it); - else - ++it; - } - } - } - } - } - - /*! - * \brief Handle the invalidation of a material - * - * \param material Material being invalidated - */ - - void DeferredRenderQueue::OnMaterialInvalidation(const Material* material) - { - for (auto& pair : layers) - { - Layer& layer = pair.second; - - for (auto& pipelineEntry : layer.opaqueModels) - pipelineEntry.second.materialMap.erase(material); - } - } - - /*! - * \brief Handle the invalidation of a vertex buffer - * - * \param vertexBuffer Vertex buffer being invalidated - */ - - void DeferredRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer) - { - for (auto& pair : layers) - { - Layer& layer = pair.second; - for (auto& pipelineEntry : layer.opaqueModels) - { - for (auto& materialEntry : pipelineEntry.second.materialMap) - { - MeshInstanceContainer& meshes = materialEntry.second.meshMap; - for (auto it = meshes.begin(); it != meshes.end();) - { - const MeshData& renderData = it->first; - if (renderData.vertexBuffer == vertexBuffer) - it = meshes.erase(it); - else - ++it; - } - } - } - } - } -} diff --git a/src/Nazara/Graphics/DeferredRenderTechnique.cpp b/src/Nazara/Graphics/DeferredRenderTechnique.cpp index f930871fe..34db9e271 100644 --- a/src/Nazara/Graphics/DeferredRenderTechnique.cpp +++ b/src/Nazara/Graphics/DeferredRenderTechnique.cpp @@ -127,7 +127,7 @@ namespace Nz */ DeferredRenderTechnique::DeferredRenderTechnique() : - m_renderQueue(static_cast(m_forwardTechnique.GetRenderQueue())), + m_renderQueue(&m_deferredRenderQueue, static_cast(m_forwardTechnique.GetRenderQueue())), m_GBufferSize(0U) { m_depthStencilTexture = Texture::New(); @@ -455,35 +455,35 @@ namespace Nz switch (renderPass) { case RenderPassType_AA: - smartPtr.reset(new DeferredFXAAPass); + smartPtr = std::make_unique(); break; case RenderPassType_Bloom: - smartPtr.reset(new DeferredBloomPass); + smartPtr = std::make_unique(); break; case RenderPassType_DOF: - smartPtr.reset(new DeferredDOFPass); + smartPtr = std::make_unique(); break; case RenderPassType_Final: - smartPtr.reset(new DeferredFinalPass); + smartPtr = std::make_unique(); break; case RenderPassType_Fog: - smartPtr.reset(new DeferredFogPass); + smartPtr = std::make_unique(); break; case RenderPassType_Forward: - smartPtr.reset(new DeferredForwardPass); + smartPtr = std::make_unique(); break; case RenderPassType_Geometry: - smartPtr.reset(new DeferredGeometryPass); + smartPtr = std::make_unique(); break; case RenderPassType_Lighting: - smartPtr.reset(new DeferredPhongLightingPass); + smartPtr = std::make_unique(); break; case RenderPassType_SSAO: @@ -701,6 +701,12 @@ namespace Nz NazaraWarning("Failed to register gaussian blur shader, certain features will not work: " + error); } + if (!DeferredGeometryPass::Initialize()) + { + NazaraError("Failed to initialize geometry pass"); + return false; + } + return true; } @@ -710,6 +716,8 @@ namespace Nz void DeferredRenderTechnique::Uninitialize() { + DeferredGeometryPass::Uninitialize(); + ShaderLibrary::Unregister("DeferredGBufferClear"); ShaderLibrary::Unregister("DeferredDirectionnalLight"); ShaderLibrary::Unregister("DeferredPointSpotLight"); diff --git a/src/Nazara/Graphics/DepthRenderQueue.cpp b/src/Nazara/Graphics/DepthRenderQueue.cpp index 775276c37..71c985097 100644 --- a/src/Nazara/Graphics/DepthRenderQueue.cpp +++ b/src/Nazara/Graphics/DepthRenderQueue.cpp @@ -43,7 +43,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -56,7 +56,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr); } /*! @@ -73,7 +73,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -86,7 +86,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr); } /*! @@ -103,7 +103,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -116,7 +116,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr); } /*! @@ -133,7 +133,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -146,7 +146,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr); } /*! @@ -163,7 +163,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -176,7 +176,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, colorPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, colorPtr); } /*! @@ -193,7 +193,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -206,7 +206,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, sinCosPtr, alphaPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, sinCosPtr, alphaPtr); } /*! @@ -223,7 +223,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -236,7 +236,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, colorPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, colorPtr); } /*! @@ -253,7 +253,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) + void DepthRenderQueue::AddBillboards(int renderOrder, const Material* material, std::size_t billboardCount, const Recti& scissorRect, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -266,11 +266,11 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddBillboards(0, material, count, positionPtr, sizePtr, anglePtr, alphaPtr); + BasicRenderQueue::AddBillboards(0, material, billboardCount, scissorRect, positionPtr, sizePtr, anglePtr, alphaPtr); } /*! - * \brief Adds a direcitonal light to the queue + * \brief Adds a directional light to the queue * * \param light Light to add * @@ -295,7 +295,7 @@ namespace Nz * \remark Produces a NazaraAssert if material is invalid */ - void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) + void DepthRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix, const Recti& scissorRect) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -309,7 +309,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix); + BasicRenderQueue::AddMesh(0, material, meshData, meshAABB, transformMatrix, scissorRect); } /*! @@ -352,7 +352,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, std::size_t spriteCount, const Texture* overlay) + void DepthRenderQueue::AddSprites(int renderOrder, const Material* material, const VertexStruct_XYZ_Color_UV* vertices, std::size_t spriteCount, const Recti& scissorRect, const Texture* overlay /*= nullptr*/) { NazaraAssert(material, "Invalid material"); NazaraUnused(renderOrder); @@ -366,7 +366,7 @@ namespace Nz else material = m_baseMaterial; - ForwardRenderQueue::AddSprites(0, material, vertices, spriteCount, overlay); + BasicRenderQueue::AddSprites(0, material, vertices, spriteCount, scissorRect, overlay); } } diff --git a/src/Nazara/Graphics/DepthRenderTechnique.cpp b/src/Nazara/Graphics/DepthRenderTechnique.cpp index c58b4e4ee..5435d7497 100644 --- a/src/Nazara/Graphics/DepthRenderTechnique.cpp +++ b/src/Nazara/Graphics/DepthRenderTechnique.cpp @@ -5,11 +5,14 @@ #include #include #include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -47,9 +50,7 @@ namespace Nz { ErrorFlags flags(ErrorFlag_ThrowException, true); - std::array whitePixel = { {255, 255, 255, 255} }; - m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1); - m_whiteTexture.Update(whitePixel.data()); + m_whiteTexture = Nz::TextureLibrary::Get("White2D"); m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic); @@ -63,15 +64,20 @@ namespace Nz * \param sceneData Data of the scene */ - void DepthRenderTechnique::Clear(const SceneData& /*sceneData*/) const + void DepthRenderTechnique::Clear(const SceneData& sceneData) const { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + Renderer::SetScissorRect(fullscreenScissorRect); + Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthWrite, true); Renderer::Clear(RendererBuffer_Depth); // Just in case the background does render depth - //if (sceneData.background) - // sceneData.background->Draw(sceneData.viewer); + if (sceneData.background) + sceneData.background->Draw(sceneData.viewer); } /*! @@ -83,22 +89,28 @@ namespace Nz bool DepthRenderTechnique::Draw(const SceneData& sceneData) const { - for (auto& pair : m_renderQueue.layers) - { - ForwardRenderQueue::Layer& layer = pair.second; + m_renderQueue.Sort(sceneData.viewer); - if (!layer.opaqueModels.empty()) - DrawOpaqueModels(sceneData, layer); + if (!m_renderQueue.models.empty()) + DrawModels(sceneData, m_renderQueue, m_renderQueue.models); - if (!layer.opaqueSprites.empty()) - DrawBasicSprites(sceneData, layer); + if (!m_renderQueue.basicSprites.empty()) + DrawSprites(sceneData, m_renderQueue, m_renderQueue.basicSprites); - if (!layer.billboards.empty()) - DrawBillboards(sceneData, layer); + if (!m_renderQueue.billboards.empty()) + DrawBillboards(sceneData, m_renderQueue, m_renderQueue.billboards); - for (const Drawable* drawable : layer.otherDrawables) - drawable->Draw(); - } + if (!m_renderQueue.depthSortedModels.empty()) + DrawModels(sceneData, m_renderQueue, m_renderQueue.depthSortedModels); + + if (!m_renderQueue.depthSortedSprites.empty()) + DrawSprites(sceneData, m_renderQueue, m_renderQueue.depthSortedSprites); + + if (!m_renderQueue.depthSortedBillboards.empty()) + DrawBillboards(sceneData, m_renderQueue, m_renderQueue.depthSortedBillboards); + + if (!m_renderQueue.customDrawables.empty()) + DrawCustomDrawables(sceneData, m_renderQueue, m_renderQueue.customDrawables); return true; } @@ -175,9 +187,9 @@ namespace Nz // Declaration utilisée lors du rendu des billboards par instancing // L'avantage ici est la copie directe (std::memcpy) des données de la RenderQueue vers le buffer GPU - s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(ForwardRenderQueue::BillboardData, center)); - s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos - s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color)); + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(BasicRenderQueue::BillboardData, center)); + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(BasicRenderQueue::BillboardData, size)); // Englobe sincos + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(BasicRenderQueue::BillboardData, color)); } catch (const std::exception& e) { @@ -197,411 +209,406 @@ namespace Nz s_quadIndexBuffer.Reset(); s_quadVertexBuffer.Reset(); } - - /*! - * \brief Draws basic sprites - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - */ - - void DepthRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const + + void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const { + VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); + instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); + + Renderer::SetVertexBuffer(&s_quadVertexBuffer); + + Nz::BufferMapper instanceBufferMapper; + std::size_t billboardCount = 0; + std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); + + auto Commit = [&]() + { + if (billboardCount > 0) + { + instanceBufferMapper.Unmap(); + + Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4); + + billboardCount = 0; + } + }; + + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; const Shader* lastShader = nullptr; const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::Billboard& billboard : billboards) + { + const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect; + + if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = billboard.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + shaderUniforms = GetShaderUniforms(shader); + + // Ambient color of the scene + shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != billboard.material) + { + billboard.material->Apply(*pipelineInstance); + lastMaterial = billboard.material; + } + + if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + if (!instanceBufferMapper.GetBuffer()) + instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite); + + std::memcpy(static_cast(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, &billboard.data, sizeof(BasicRenderQueue::BillboardData)); + if (++billboardCount >= maxBillboardPerDraw) + Commit(); + } + + Commit(); + } + + void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const + { + VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); + instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); + + Renderer::SetVertexBuffer(&s_quadVertexBuffer); + + Nz::BufferMapper instanceBufferMapper; + std::size_t billboardCount = 0; + std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); + + auto Commit = [&]() + { + if (billboardCount > 0) + { + instanceBufferMapper.Unmap(); + + Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4); + + billboardCount = 0; + } + }; + + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::BillboardChain& billboard : billboards) + { + const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect; + + if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = billboard.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Deferred | ShaderFlags_Instancing | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + shaderUniforms = GetShaderUniforms(shader); + + // Ambient color of the scene + shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != billboard.material) + { + billboard.material->Apply(*pipelineInstance); + lastMaterial = billboard.material; + } + + if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + std::size_t billboardRemaining = billboard.billboardCount; + const BasicRenderQueue::BillboardData* billboardData = renderQueue.GetBillboardData(billboard.billboardIndex); + do + { + std::size_t renderedBillboardCount = std::min(billboardRemaining, maxBillboardPerDraw - billboardCount); + billboardRemaining -= renderedBillboardCount; + + if (!instanceBufferMapper.GetBuffer()) + instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite); + + std::memcpy(static_cast(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, billboardData, renderedBillboardCount * sizeof(BasicRenderQueue::BillboardData)); + billboardCount += renderedBillboardCount; + billboardData += renderedBillboardCount; + + if (billboardCount >= maxBillboardPerDraw) + Commit(); + } + while (billboardRemaining > 0); + } + + Commit(); + } + + void DepthRenderTechnique::DrawCustomDrawables(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& customDrawables) const + { + for (const BasicRenderQueue::CustomDrawable& customDrawable : customDrawables) + customDrawable.drawable->Draw(); + } + + void DepthRenderTechnique::DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const Nz::RenderQueue& models) const + { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + ///TODO: Reimplement instancing + + for (const BasicRenderQueue::Model& model : models) + { + const MaterialPipeline* pipeline = model.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &model.material->GetPipeline()->Apply(ShaderFlags_Deferred); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + shaderUniforms = GetShaderUniforms(shader); + + // Ambient color of the scene + shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != model.material) + { + model.material->Apply(*pipelineInstance); + lastMaterial = model.material; + } + + if (model.material->IsScissorTestEnabled()) + { + const Nz::Recti& scissorRect = (model.scissorRect.width > 0) ? model.scissorRect : fullscreenScissorRect; + if (scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + // Handle draw call before rendering loop + Renderer::DrawCall drawFunc; + Renderer::DrawCallInstanced instancedDrawFunc; + unsigned int indexCount; + + if (model.meshData.indexBuffer) + { + drawFunc = Renderer::DrawIndexedPrimitives; + instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced; + indexCount = model.meshData.indexBuffer->GetIndexCount(); + } + else + { + drawFunc = Renderer::DrawPrimitives; + instancedDrawFunc = Renderer::DrawPrimitivesInstanced; + indexCount = model.meshData.vertexBuffer->GetVertexCount(); + } + + Renderer::SetIndexBuffer(model.meshData.indexBuffer); + Renderer::SetVertexBuffer(model.meshData.vertexBuffer); + + Renderer::SetMatrix(MatrixType_World, model.matrix); + drawFunc(model.meshData.primitiveMode, 0, indexCount); + } + } + + void DepthRenderTechnique::DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& spriteList) const + { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); Renderer::SetIndexBuffer(&s_quadIndexBuffer); Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetVertexBuffer(&m_spriteBuffer); - for (auto& pipelinePair : layer.opaqueSprites) + const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); + const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); + + m_spriteChains.clear(); + + auto Commit = [&]() { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) + std::size_t spriteChainCount = m_spriteChains.size(); + if (spriteChainCount > 0) { - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + std::size_t spriteChain = 0; // Which chain of sprites are we treating + std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain - 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) + do { - // Index of uniforms in the shader - shaderUniforms = GetShaderUniforms(shader); + // We open the buffer in writing mode + BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); + VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + std::size_t spriteCount = 0; - lastShader = shader; - } - - for (auto& materialPair : pipelineEntry.materialMap) - { - const Material* material = materialPair.first; - auto& matEntry = materialPair.second; - - if (matEntry.enabled) + do { - unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); - material->Apply(pipelineInstance); + const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first; + std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second; + std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset); + std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += count * 4; + + spriteCount += count; + spriteChainOffset += count; + + // Have we treated the entire chain ? + if (spriteChainOffset == currentChainSpriteCount) + { + spriteChain++; + spriteChainOffset = 0; + } + } + while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); + + vertexMapper.Unmap(); + + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); + } + while (spriteChain < spriteChainCount); + } + + m_spriteChains.clear(); + }; + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) + { + const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; + + if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = basicSprites.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &basicSprites.material->GetPipeline()->Apply(ShaderFlags_Deferred | ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + shaderUniforms = GetShaderUniforms(shader); + + // Ambient color of the scene + shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); + + // Overlay texture unit shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); - Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler()); - - auto& overlayMap = matEntry.overlayMap; - for (auto& overlayIt : overlayMap) - { - const Texture* overlay = overlayIt.first; - auto& spriteChainVector = overlayIt.second.spriteChains; - - std::size_t spriteChainCount = spriteChainVector.size(); - if (spriteChainCount > 0) - { - Renderer::SetTexture(overlayTextureUnit, (overlay) ? overlay : &m_whiteTexture); - - std::size_t spriteChain = 0; // Which chain of sprites are we treating - std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain - - do - { - // 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 spriteCount = 0; - std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); - - do - { - ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain]; - std::size_t count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset); - - std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); - vertices += count * 4; - - spriteCount += count; - spriteChainOffset += count; - - // Have we treated the entire chain ? - if (spriteChainOffset == currentChain.spriteCount) - { - spriteChain++; - spriteChainOffset = 0; - } - } while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); - - vertexMapper.Unmap(); - - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); - } while (spriteChain < spriteChainCount); - - spriteChainVector.clear(); - } - } - - // We set it back to zero - matEntry.enabled = false; - } - } - pipelineEntry.enabled = false; - } - } - } - - /*! - * \brief Draws billboards - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - */ - - void DepthRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const - { - const Shader* lastShader = nullptr; - const ShaderUniforms* shaderUniforms = nullptr; - - if (Renderer::HasCapability(RendererCap_Instancing)) - { - VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); - instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); - - Renderer::SetVertexBuffer(&s_quadVertexBuffer); - - for (auto& pipelinePair : layer.billboards) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) - { - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | 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 - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - lastShader = shader; } - for (auto& matIt : pipelinePair.second.materialMap) - { - const Material* material = matIt.first; - auto& entry = matIt.second; - auto& billboardVector = entry.billboards; + lastPipeline = pipeline; + } - std::size_t billboardCount = billboardVector.size(); - if (billboardCount > 0) - { - // We begin to apply the material (and get the shader activated doing so) - material->Apply(pipelineInstance); + if (lastMaterial != basicSprites.material) + { + basicSprites.material->Apply(*pipelineInstance); - const ForwardRenderQueue::BillboardData* data = &billboardVector[0]; - std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); - do - { - std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); - billboardCount -= renderedBillboardCount; + Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); - instanceBuffer->Fill(data, 0, renderedBillboardCount); - data += renderedBillboardCount; + lastMaterial = basicSprites.material; + } - Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4); - } - while (billboardCount > 0); + const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); + if (overlayTexture != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, overlayTexture); + lastOverlay = overlayTexture; + } - billboardVector.clear(); - } - } + if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; } } + + m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); } - else - { - Renderer::SetIndexBuffer(&s_quadIndexBuffer); - Renderer::SetVertexBuffer(&m_billboardPointBuffer); - for (auto& pipelinePair : layer.billboards) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) - { - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | 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 - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - - lastShader = shader; - } - - for (auto& matIt : pipelinePair.second.materialMap) - { - auto& entry = matIt.second; - auto& billboardVector = entry.billboards; - - const ForwardRenderQueue::BillboardData* data = &billboardVector[0]; - std::size_t maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4); - - std::size_t billboardCount = billboardVector.size(); - do - { - std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); - billboardCount -= renderedBillboardCount; - - BufferMapper vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4); - BillboardPoint* vertices = static_cast(vertexMapper.GetPointer()); - - for (unsigned int i = 0; i < renderedBillboardCount; ++i) - { - const ForwardRenderQueue::BillboardData& billboard = *data++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(0.f, 1.f); - vertices++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(1.f, 1.f); - vertices++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(0.f, 0.f); - vertices++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(1.f, 0.f); - vertices++; - } - - vertexMapper.Unmap(); - - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6); - } - while (billboardCount > 0); - - billboardVector.clear(); - } - } - } - } - } - - /*! - * \brief Draws opaques models - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - */ - - void DepthRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const - { - const Shader* lastShader = nullptr; - const ShaderUniforms* shaderUniforms = nullptr; - - for (auto& pipelinePair : layer.opaqueModels) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.maxInstanceCount > 0) - { - bool instancing = (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT); - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0); - - 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 - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - - lastShader = shader; - } - - for (auto& materialPair : pipelineEntry.materialMap) - { - const Material* material = materialPair.first; - auto& matEntry = materialPair.second; - - if (matEntry.enabled) - { - material->Apply(pipelineInstance); - - ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap; - - // Meshes - for (auto& meshIt : meshInstances) - { - const MeshData& meshData = meshIt.first; - auto& meshEntry = meshIt.second; - - std::vector& instances = meshEntry.instances; - if (!instances.empty()) - { - const IndexBuffer* indexBuffer = meshData.indexBuffer; - const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - - // Handle draw call before rendering loop - Renderer::DrawCall drawFunc; - Renderer::DrawCallInstanced instancedDrawFunc; - unsigned int indexCount; - - if (indexBuffer) - { - drawFunc = Renderer::DrawIndexedPrimitives; - instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced; - indexCount = indexBuffer->GetIndexCount(); - } - else - { - drawFunc = Renderer::DrawPrimitives; - instancedDrawFunc = Renderer::DrawPrimitivesInstanced; - indexCount = vertexBuffer->GetVertexCount(); - } - - Renderer::SetIndexBuffer(indexBuffer); - Renderer::SetVertexBuffer(vertexBuffer); - - if (instancing) - { - // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) - VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); - instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); - - const Matrix4f* instanceMatrices = &instances[0]; - std::size_t instanceCount = instances.size(); - std::size_t maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch - - while (instanceCount > 0) - { - // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) - std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount); - instanceCount -= renderedInstanceCount; - - // We fill the instancing buffer with our world matrices - instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount); - instanceMatrices += renderedInstanceCount; - - // And we draw - instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); - } - } - else - { - // Without instancing, we must do a draw call for each instance - // This may be faster than instancing under a certain number - // Due to the time to modify the instancing buffer - for (const Matrix4f& matrix : instances) - { - Renderer::SetMatrix(MatrixType_World, matrix); - drawFunc(meshData.primitiveMode, 0, indexCount); - } - } - instances.clear(); - } - } - - matEntry.enabled = false; - } - } - - pipelineEntry.maxInstanceCount = 0; - } - } + Commit(); } /*! diff --git a/src/Nazara/Graphics/ForwardRenderQueue.cpp b/src/Nazara/Graphics/ForwardRenderQueue.cpp deleted file mode 100644 index d55901de0..000000000 --- a/src/Nazara/Graphics/ForwardRenderQueue.cpp +++ /dev/null @@ -1,931 +0,0 @@ -// Copyright (C) 2017 Jérôme Leclercq -// This file is part of the "Nazara Engine - Graphics module" -// For conditions of distribution and use, see copyright notice in Config.hpp - -#include -#include -#include -#include - -///TODO: Replace sinus/cosinus by a lookup table (which will lead to a speed up about 10x) - -namespace Nz -{ - /*! - * \ingroup graphics - * \class Nz::ForwardRenderQueue - * \brief Graphics class that represents the rendering queue for forward rendering - */ - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param colorPtr Color of the billboards if null, Color::White is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) - { - NazaraAssert(material, "Invalid material"); - - Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 - - if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - billboardData->center = *positionPtr++; - billboardData->color = *colorPtr++; - billboardData->sinCos = *sinCosPtr++; - billboardData->size = *sizePtr++; - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) - { - NazaraAssert(material, "Invalid material"); - - Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 - - if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - float defaultAlpha = 1.f; - - if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - billboardData->center = *positionPtr++; - billboardData->color = Color(255, 255, 255, static_cast(255.f * (*alphaPtr++))); - billboardData->sinCos = *sinCosPtr++; - billboardData->size = *sizePtr++; - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param colorPtr Color of the billboards if null, Color::White is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) - { - NazaraAssert(material, "Invalid material"); - - float defaultRotation = 0.f; - - if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - float sin = std::sin(ToRadians(*anglePtr)); - float cos = std::cos(ToRadians(*anglePtr)); - anglePtr++; - - billboardData->center = *positionPtr++; - billboardData->color = *colorPtr++; - billboardData->sinCos.Set(sin, cos); - billboardData->size = *sizePtr++; - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Sizes of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) - { - NazaraAssert(material, "Invalid material"); - - float defaultRotation = 0.f; - - if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - float defaultAlpha = 1.f; - - if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - float sin = std::sin(ToRadians(*anglePtr)); - float cos = std::cos(ToRadians(*anglePtr)); - anglePtr++; - - billboardData->center = *positionPtr++; - billboardData->color = Color(255, 255, 255, static_cast(255.f * (*alphaPtr++))); - billboardData->sinCos.Set(sin, cos); - billboardData->size = *sizePtr++; - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param colorPtr Color of the billboards if null, Color::White is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr colorPtr) - { - NazaraAssert(material, "Invalid material"); - - Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 - - if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - billboardData->center = *positionPtr++; - billboardData->color = *colorPtr++; - billboardData->sinCos = *sinCosPtr++; - billboardData->size.Set(*sizePtr++); - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param sinCosPtr Rotation of the billboards if null, Vector2f(0.f, 1.f) is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr sinCosPtr, SparsePtr alphaPtr) - { - NazaraAssert(material, "Invalid material"); - - Vector2f defaultSinCos(0.f, 1.f); // sin(0) = 0, cos(0) = 1 - - if (!sinCosPtr) - sinCosPtr.Reset(&defaultSinCos, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - float defaultAlpha = 1.f; - - if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - billboardData->center = *positionPtr++; - billboardData->color = Color(255, 255, 255, static_cast(255.f * (*alphaPtr++))); - billboardData->sinCos = *sinCosPtr++; - billboardData->size.Set(*sizePtr++); - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param colorPtr Color of the billboards if null, Color::White is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr colorPtr) - { - NazaraAssert(material, "Invalid material"); - - float defaultRotation = 0.f; - - if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - if (!colorPtr) - colorPtr.Reset(&Color::White, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - float sin = std::sin(ToRadians(*anglePtr)); - float cos = std::cos(ToRadians(*anglePtr)); - anglePtr++; - - billboardData->center = *positionPtr++; - billboardData->color = *colorPtr++; - billboardData->sinCos.Set(sin, cos); - billboardData->size.Set(*sizePtr++); - billboardData++; - } - } - - /*! - * \brief Adds multiple billboards to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the billboards - * \param count Number of billboards - * \param positionPtr Position of the billboards - * \param sizePtr Size of the billboards - * \param anglePtr Rotation of the billboards if null, 0.f is used - * \param alphaPtr Alpha parameters of the billboards if null, 1.f is used - * - * \remark Produces a NazaraAssert if material is invalid - */ - - void ForwardRenderQueue::AddBillboards(int renderOrder, const Material* material, unsigned int count, SparsePtr positionPtr, SparsePtr sizePtr, SparsePtr anglePtr, SparsePtr alphaPtr) - { - NazaraAssert(material, "Invalid material"); - - float defaultRotation = 0.f; - - if (!anglePtr) - anglePtr.Reset(&defaultRotation, 0); // The trick here is to put the stride to zero, which leads the pointer to be immobile - - float defaultAlpha = 1.f; - - if (!alphaPtr) - alphaPtr.Reset(&defaultAlpha, 0); // Same - - BillboardData* billboardData = GetBillboardData(renderOrder, material, count); - for (unsigned int i = 0; i < count; ++i) - { - float sin = std::sin(ToRadians(*anglePtr)); - float cos = std::cos(ToRadians(*anglePtr)); - anglePtr++; - - billboardData->center = *positionPtr++; - billboardData->color = Color(255, 255, 255, static_cast(255.f * (*alphaPtr++))); - billboardData->sinCos.Set(sin, cos); - billboardData->size.Set(*sizePtr++); - billboardData++; - } - } - - /*! - * \brief Adds drawable to the queue - * - * \param renderOrder Order of rendering - * \param drawable Drawable user defined - * - * \remark Produces a NazaraError if drawable is invalid - */ - - void ForwardRenderQueue::AddDrawable(int renderOrder, const Drawable* drawable) - { - #if NAZARA_GRAPHICS_SAFE - if (!drawable) - { - NazaraError("Invalid drawable"); - return; - } - #endif - - auto& otherDrawables = GetLayer(renderOrder).otherDrawables; - - otherDrawables.push_back(drawable); - } - - /*! - * \brief Adds mesh to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the mesh - * \param meshData Data of the mesh - * \param meshAABB Box of the mesh - * \param transformMatrix Matrix of the mesh - * - * \remark Produces a NazaraAssert if material is invalid - */ - void ForwardRenderQueue::AddMesh(int renderOrder, const Material* material, const MeshData& meshData, const Boxf& meshAABB, const Matrix4f& transformMatrix) - { - NazaraAssert(material, "Invalid material"); - - if (material->IsDepthSortingEnabled()) - { - Layer& currentLayer = GetLayer(renderOrder); - auto& transparentMeshes = currentLayer.depthSortedMeshes; - auto& transparentData = currentLayer.depthSortedMeshData; - - // 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); - - UnbatchedModelData& data = transparentData.back(); - data.material = material; - data.meshData = meshData; - data.obbSphere = Spheref(transformMatrix.GetTranslation() + meshAABB.GetCenter(), meshAABB.GetSquaredRadius()); - data.transformMatrix = transformMatrix; - - transparentMeshes.push_back(index); - } - else - { - Layer& currentLayer = GetLayer(renderOrder); - MeshPipelineBatches& opaqueModels = currentLayer.opaqueModels; - - const MaterialPipeline* materialPipeline = material->GetPipeline(); - - auto pipelineIt = opaqueModels.find(materialPipeline); - if (pipelineIt == opaqueModels.end()) - { - BatchedMaterialEntry materialEntry; - pipelineIt = opaqueModels.insert(MeshPipelineBatches::value_type(materialPipeline, std::move(materialEntry))).first; - } - - BatchedMaterialEntry& materialEntry = pipelineIt->second; - MeshMaterialBatches& materialMap = materialEntry.materialMap; - - auto materialIt = materialMap.find(material); - if (materialIt == materialMap.end()) - { - BatchedModelEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - materialIt = materialMap.insert(MeshMaterialBatches::value_type(material, std::move(entry))).first; - } - - BatchedModelEntry& entry = materialIt->second; - entry.enabled = true; - - MeshInstanceContainer& meshMap = entry.meshMap; - - auto it2 = meshMap.find(meshData); - if (it2 == meshMap.end()) - { - MeshInstanceEntry instanceEntry; - instanceEntry.squaredBoundingSphere = meshAABB.GetSquaredBoundingSphere(); - - if (meshData.indexBuffer) - instanceEntry.indexBufferReleaseSlot.Connect(meshData.indexBuffer->OnIndexBufferRelease, this, &ForwardRenderQueue::OnIndexBufferInvalidation); - - instanceEntry.vertexBufferReleaseSlot.Connect(meshData.vertexBuffer->OnVertexBufferRelease, this, &ForwardRenderQueue::OnVertexBufferInvalidation); - - it2 = meshMap.insert(std::make_pair(meshData, std::move(instanceEntry))).first; - } - - std::vector& instances = it2->second.instances; - instances.push_back(transformMatrix); - - materialEntry.maxInstanceCount = std::max(materialEntry.maxInstanceCount, instances.size()); - } - } - - /*! - * \brief Adds sprites to the queue - * - * \param renderOrder Order of rendering - * \param material Material of the sprites - * \param vertices Buffer of data for the sprites - * \param spriteCount Number of sprites - * \param overlay Texture of the sprites - * - * \remark Produces a NazaraAssert if material is invalid - */ - 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); - - if (material->IsDepthSortingEnabled()) - { - auto& transparentSprites = currentLayer.depthSortedSprites; - auto& transparentData = currentLayer.depthSortedSpriteData; - - // The material is marked for depth sorting, we must draw this mesh using another way (after the rendering of opaques objects while sorting them) - std::size_t index = transparentData.size(); - transparentData.resize(index + 1); - - UnbatchedSpriteData& data = transparentData.back(); - data.material = material; - data.overlay = overlay; - data.spriteCount = spriteCount; - data.vertices = vertices; - - transparentSprites.push_back(index); - } - else - { - SpritePipelineBatches& sprites = currentLayer.opaqueSprites; - - const MaterialPipeline* materialPipeline = material->GetPipeline(); - - 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})); - } - } - - /*! - * \brief Clears the queue - * - * \param fully Should everything be cleared or we can keep layers - */ - - void ForwardRenderQueue::Clear(bool fully) - { - AbstractRenderQueue::Clear(fully); - - if (fully) - layers.clear(); - else - { - for (auto it = layers.begin(); it != layers.end();) - { - Layer& layer = it->second; - if (layer.clearCount++ >= 100) - layers.erase(it++); - else - { - for (auto& pipelinePair : layer.billboards) - { - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) - { - for (auto& matIt : pipelinePair.second.materialMap) - { - auto& entry = matIt.second; - auto& billboardVector = entry.billboards; - - billboardVector.clear(); - } - } - - pipelineEntry.enabled = false; - } - - for (auto& pipelinePair : layer.opaqueSprites) - { - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) - { - for (auto& materialPair : pipelineEntry.materialMap) - { - auto& matEntry = materialPair.second; - - if (matEntry.enabled) - { - auto& overlayMap = matEntry.overlayMap; - for (auto& overlayIt : overlayMap) - { - auto& spriteChainVector = overlayIt.second.spriteChains; - spriteChainVector.clear(); - } - - matEntry.enabled = false; - } - } - pipelineEntry.enabled = false; - } - } - - for (auto& pipelinePair : layer.opaqueModels) - { - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.maxInstanceCount > 0) - { - for (auto& materialPair : pipelineEntry.materialMap) - { - auto& matEntry = materialPair.second; - if (matEntry.enabled) - { - MeshInstanceContainer& meshInstances = matEntry.meshMap; - - for (auto& meshIt : meshInstances) - { - auto& meshEntry = meshIt.second; - meshEntry.instances.clear(); - } - matEntry.enabled = false; - } - } - pipelineEntry.maxInstanceCount = 0; - } - } - - layer.depthSortedMeshes.clear(); - layer.depthSortedMeshData.clear(); - layer.depthSortedSpriteData.clear(); - layer.depthSortedSprites.clear(); - layer.otherDrawables.clear(); - ++it; - } - } - } - } - - /*! - * \brief Sorts the object according to the viewer position, furthest to nearest - * - * \param viewer Viewer of the scene - */ - - void ForwardRenderQueue::Sort(const AbstractViewer* viewer) - { - if (viewer->GetProjectionType() == ProjectionType_Orthogonal) - SortForOrthographic(viewer); - else - SortForPerspective(viewer); - } - - /*! - * \brief Gets the billboard data - * \return Pointer to the data of the billboards - * - * \param renderOrder Order of rendering - * \param material Material of the billboard - */ - - ForwardRenderQueue::BillboardData* ForwardRenderQueue::GetBillboardData(int renderOrder, const Material* material, unsigned int count) - { - auto& billboards = GetLayer(renderOrder).billboards; - - const MaterialPipeline* materialPipeline = material->GetPipeline(); - - auto pipelineIt = billboards.find(materialPipeline); - if (pipelineIt == billboards.end()) - { - BatchedBillboardPipelineEntry pipelineEntry; - pipelineIt = billboards.insert(BillboardPipelineBatches::value_type(materialPipeline, std::move(pipelineEntry))).first; - } - BatchedBillboardPipelineEntry& pipelineEntry = pipelineIt->second; - pipelineEntry.enabled = true; - - BatchedBillboardContainer& materialMap = pipelineEntry.materialMap; - - auto it = materialMap.find(material); - if (it == materialMap.end()) - { - BatchedBillboardEntry entry; - entry.materialReleaseSlot.Connect(material->OnMaterialRelease, this, &ForwardRenderQueue::OnMaterialInvalidation); - - it = materialMap.insert(BatchedBillboardContainer::value_type(material, std::move(entry))).first; - } - - BatchedBillboardEntry& entry = it->second; - - auto& billboardVector = entry.billboards; - std::size_t prevSize = billboardVector.size(); - billboardVector.resize(prevSize + count); - - return &billboardVector[prevSize]; - } - - /*! - * \brief Gets the ith layer - * \return Reference to the ith layer for the queue - * - * \param i Index of the layer - */ - - ForwardRenderQueue::Layer& ForwardRenderQueue::GetLayer(int i) - { - 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) - { - Layer& layer = pair.second; - - for (auto& pipelineEntry : layer.opaqueModels) - { - for (auto& materialEntry : pipelineEntry.second.materialMap) - { - MeshInstanceContainer& meshes = materialEntry.second.meshMap; - for (auto it = meshes.begin(); it != meshes.end();) - { - const MeshData& renderData = it->first; - if (renderData.indexBuffer == indexBuffer) - it = meshes.erase(it); - else - ++it; - } - } - } - } - } - - /*! - * \brief Handle the invalidation of a material - * - * \param material Material being invalidated - */ - - void ForwardRenderQueue::OnMaterialInvalidation(const Material* material) - { - for (auto& pair : layers) - { - Layer& layer = pair.second; - - for (auto& pipelineEntry : layer.opaqueSprites) - pipelineEntry.second.materialMap.erase(material); - - for (auto& pipelineEntry : layer.billboards) - pipelineEntry.second.materialMap.erase(material); - - for (auto& pipelineEntry : layer.opaqueModels) - pipelineEntry.second.materialMap.erase(material); - } - } - - /*! - * \brief Handle the invalidation of a texture - * - * \param texture Texture being invalidated - */ - - void ForwardRenderQueue::OnTextureInvalidation(const Texture* texture) - { - for (auto& pair : layers) - { - Layer& layer = pair.second; - for (auto& pipelineEntry : layer.opaqueSprites) - { - for (auto& materialEntry : pipelineEntry.second.materialMap) - materialEntry.second.overlayMap.erase(texture); - } - } - } - - /*! - * \brief Handle the invalidation of a vertex buffer - * - * \param vertexBuffer Vertex buffer being invalidated - */ - - void ForwardRenderQueue::OnVertexBufferInvalidation(const VertexBuffer* vertexBuffer) - { - for (auto& pair : layers) - { - Layer& layer = pair.second; - for (auto& pipelineEntry : layer.opaqueModels) - { - for (auto& materialEntry : pipelineEntry.second.materialMap) - { - MeshInstanceContainer& meshes = materialEntry.second.meshMap; - for (auto it = meshes.begin(); it != meshes.end();) - { - const MeshData& renderData = it->first; - if (renderData.vertexBuffer == vertexBuffer) - it = meshes.erase(it); - else - ++it; - } - } - } - } - } - - bool ForwardRenderQueue::MaterialComparator::operator()(const Material* mat1, const Material* mat2) const - { - const Texture* diffuseMap1 = mat1->GetDiffuseMap(); - const Texture* diffuseMap2 = mat2->GetDiffuseMap(); - if (diffuseMap1 != diffuseMap2) - return diffuseMap1 < diffuseMap2; - - return mat1 < mat2; - } - - bool ForwardRenderQueue::MaterialPipelineComparator::operator()(const MaterialPipeline* pipeline1, const MaterialPipeline* pipeline2) const - { - const Shader* shader1 = pipeline1->GetInstance().renderPipeline.GetInfo().shader; - const Shader* shader2 = pipeline2->GetInstance().renderPipeline.GetInfo().shader; - if (shader1 != shader2) - return shader1 < shader2; - - return pipeline1 < pipeline2; - } - - /*! - * \brief Functor to compare two mesh data - * \return true If first mesh is "smaller" than the second one - * - * \param data1 First mesh to compare - * \param data2 Second mesh to compare - */ - - bool ForwardRenderQueue::MeshDataComparator::operator()(const MeshData& data1, const MeshData& data2) const - { - const Buffer* buffer1; - const Buffer* buffer2; - - buffer1 = (data1.indexBuffer) ? data1.indexBuffer->GetBuffer() : nullptr; - buffer2 = (data2.indexBuffer) ? data2.indexBuffer->GetBuffer() : nullptr; - if (buffer1 != buffer2) - return buffer1 < buffer2; - - buffer1 = data1.vertexBuffer->GetBuffer(); - buffer2 = data2.vertexBuffer->GetBuffer(); - if (buffer1 != buffer2) - return buffer1 < buffer2; - - return data1.primitiveMode < data2.primitiveMode; - } -} diff --git a/src/Nazara/Graphics/ForwardRenderTechnique.cpp b/src/Nazara/Graphics/ForwardRenderTechnique.cpp index 99452eaa1..cf3611362 100644 --- a/src/Nazara/Graphics/ForwardRenderTechnique.cpp +++ b/src/Nazara/Graphics/ForwardRenderTechnique.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -51,9 +52,8 @@ namespace Nz { ErrorFlags flags(ErrorFlag_ThrowException, true); - std::array whitePixel = { {255, 255, 255, 255} }; - m_whiteTexture.Create(ImageType_2D, PixelFormatType_RGBA8, 1, 1); - m_whiteTexture.Update(whitePixel.data()); + m_whiteCubemap = Nz::TextureLibrary::Get("WhiteCubemap"); + m_whiteTexture = Nz::TextureLibrary::Get("White2D"); m_vertexBuffer.Create(s_vertexBufferSize, DataStorage_Hardware, BufferUsage_Dynamic); @@ -69,6 +69,11 @@ namespace Nz void ForwardRenderTechnique::Clear(const SceneData& sceneData) const { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + Renderer::SetScissorRect(fullscreenScissorRect); + Renderer::Enable(RendererParameter_DepthBuffer, true); Renderer::Enable(RendererParameter_DepthWrite, true); Renderer::Clear(RendererBuffer_Depth); @@ -92,35 +97,33 @@ namespace Nz m_renderQueue.Sort(sceneData.viewer); - for (auto& pair : m_renderQueue.layers) - { - ForwardRenderQueue::Layer& layer = pair.second; + if (!m_renderQueue.models.empty()) + DrawModels(sceneData, m_renderQueue, m_renderQueue.models); - if (!layer.opaqueModels.empty()) - DrawOpaqueModels(sceneData, layer); + if (!m_renderQueue.basicSprites.empty()) + DrawSprites(sceneData, m_renderQueue, m_renderQueue.basicSprites); - if (!layer.depthSortedMeshes.empty()) - DrawTransparentModels(sceneData, layer); + if (!m_renderQueue.billboards.empty()) + DrawBillboards(sceneData, m_renderQueue, m_renderQueue.billboards); - if (!layer.opaqueSprites.empty()) - DrawBasicSprites(sceneData, layer); + if (!m_renderQueue.depthSortedModels.empty()) + DrawModels(sceneData, m_renderQueue, m_renderQueue.depthSortedModels); - if (!layer.depthSortedSprites.empty()) - DrawOrderedSprites(sceneData, layer); + if (!m_renderQueue.depthSortedSprites.empty()) + DrawSprites(sceneData, m_renderQueue, m_renderQueue.depthSortedSprites); - if (!layer.billboards.empty()) - DrawBillboards(sceneData, layer); + if (!m_renderQueue.depthSortedBillboards.empty()) + DrawBillboards(sceneData, m_renderQueue, m_renderQueue.depthSortedBillboards); - for (const Drawable* drawable : layer.otherDrawables) - drawable->Draw(); - } + if (!m_renderQueue.customDrawables.empty()) + DrawCustomDrawables(sceneData, m_renderQueue, m_renderQueue.customDrawables); return true; } /*! * \brief Gets the maximum number of lights available per pass per object - * \return Maximum number of light simulatenously per object + * \return Maximum number of light simultaneously per object */ unsigned int ForwardRenderTechnique::GetMaxLightPassPerObject() const @@ -211,19 +214,15 @@ namespace Nz // Declaration used when rendering the billboards with intancing // The main advantage is the direct copy (std::memcpy) of data in the RenderQueue to the GPU buffer - s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(ForwardRenderQueue::BillboardData, center)); - s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(ForwardRenderQueue::BillboardData, size)); // Englobe sincos - s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(ForwardRenderQueue::BillboardData, color)); + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData0, ComponentType_Float3, NazaraOffsetOf(BasicRenderQueue::BillboardData, center)); + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData1, ComponentType_Float4, NazaraOffsetOf(BasicRenderQueue::BillboardData, size)); // Englobe sincos + s_billboardInstanceDeclaration.EnableComponent(VertexComponent_InstanceData2, ComponentType_Color, NazaraOffsetOf(BasicRenderQueue::BillboardData, color)); s_reflectionSampler.SetFilterMode(SamplerFilter_Bilinear); s_reflectionSampler.SetWrapMode(SamplerWrap_Clamp); s_shadowSampler.SetFilterMode(SamplerFilter_Bilinear); s_shadowSampler.SetWrapMode(SamplerWrap_Clamp); - - std::array whitePixels = { { 255, 255, 255, 255, 255, 255 } }; - s_dummyReflection.Create(ImageType_Cubemap, PixelFormatType_L8, 1, 1); - s_dummyReflection.Update(whitePixels.data()); } catch (const std::exception& e) { @@ -240,7 +239,6 @@ namespace Nz void ForwardRenderTechnique::Uninitialize() { - s_dummyReflection.Destroy(); s_quadIndexBuffer.Reset(); s_quadVertexBuffer.Reset(); } @@ -248,7 +246,7 @@ namespace Nz /*! * \brief Chooses the nearest lights for one object * - * \param object Sphere symbolising the object + * \param object Sphere symbolizing the object * \param includeDirectionalLights Should directional lights be included in the computation */ @@ -290,41 +288,225 @@ namespace Nz }); } - /*! - * \brief Draws basic sprites - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - * - * \remark Produces a NazaraAssert is viewer is invalid - */ - - void ForwardRenderTechnique::DrawBasicSprites(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const + void ForwardRenderTechnique::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const { - NazaraAssert(sceneData.viewer, "Invalid viewer"); + VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); + instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); + Renderer::SetVertexBuffer(&s_quadVertexBuffer); + + Nz::BufferMapper instanceBufferMapper; + std::size_t billboardCount = 0; + std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); + + auto Commit = [&]() + { + if (billboardCount > 0) + { + instanceBufferMapper.Unmap(); + + Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4); + + billboardCount = 0; + } + }; + + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; const Shader* lastShader = nullptr; const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); - Renderer::SetIndexBuffer(&s_quadIndexBuffer); - Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); - Renderer::SetVertexBuffer(&m_spriteBuffer); + const MaterialPipeline::Instance* pipelineInstance = nullptr; - 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) + for (const BasicRenderQueue::Billboard& billboard : billboards) { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; + const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect; - if (pipelineEntry.enabled) + if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) { - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_TextureOverlay | ShaderFlags_VertexColor); + Commit(); - const Shader* shader = pipelineInstance.uberInstance->GetShader(); + const MaterialPipeline* pipeline = billboard.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor); - // Uniforms are conserved in our program, there's no point to send them back until they change + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + 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()); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != billboard.material) + { + billboard.material->Apply(*pipelineInstance); + lastMaterial = billboard.material; + } + + if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + if (!instanceBufferMapper.GetBuffer()) + instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite); + + std::memcpy(static_cast(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, &billboard.data, sizeof(BasicRenderQueue::BillboardData)); + if (++billboardCount >= maxBillboardPerDraw) + Commit(); + } + + Commit(); + } + + void ForwardRenderTechnique::DrawBillboards(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& billboards) const + { + VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); + instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); + + Renderer::SetVertexBuffer(&s_quadVertexBuffer); + + Nz::BufferMapper instanceBufferMapper; + std::size_t billboardCount = 0; + std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); + + auto Commit = [&]() + { + if (billboardCount > 0) + { + instanceBufferMapper.Unmap(); + + Renderer::DrawPrimitivesInstanced(billboardCount, PrimitiveMode_TriangleStrip, 0, 4); + + billboardCount = 0; + } + }; + + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + for (const BasicRenderQueue::BillboardChain& billboard : billboards) + { + const Nz::Recti& scissorRect = (billboard.scissorRect.width > 0) ? billboard.scissorRect : fullscreenScissorRect; + + if (billboard.material != lastMaterial || (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) + { + Commit(); + + const MaterialPipeline* pipeline = billboard.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &billboard.material->GetPipeline()->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | ShaderFlags_VertexColor); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); + if (shader != lastShader) + { + // Index of uniforms in the shader + 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()); + + lastShader = shader; + } + + lastPipeline = pipeline; + } + + if (lastMaterial != billboard.material) + { + billboard.material->Apply(*pipelineInstance); + lastMaterial = billboard.material; + } + + if (billboard.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } + } + + std::size_t billboardRemaining = billboard.billboardCount; + const BasicRenderQueue::BillboardData* billboardData = renderQueue.GetBillboardData(billboard.billboardIndex); + do + { + std::size_t renderedBillboardCount = std::min(billboardRemaining, maxBillboardPerDraw - billboardCount); + billboardRemaining -= renderedBillboardCount; + + if (!instanceBufferMapper.GetBuffer()) + instanceBufferMapper.Map(instanceBuffer, BufferAccess_DiscardAndWrite); + + std::memcpy(static_cast(instanceBufferMapper.GetPointer()) + sizeof(BasicRenderQueue::BillboardData) * billboardCount, billboardData, renderedBillboardCount * sizeof(BasicRenderQueue::BillboardData)); + billboardCount += renderedBillboardCount; + billboardData += renderedBillboardCount; + + if (billboardCount >= maxBillboardPerDraw) + Commit(); + } + while (billboardRemaining > 0); + } + + Commit(); + } + + void ForwardRenderTechnique::DrawCustomDrawables(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& customDrawables) const + { + for (const BasicRenderQueue::CustomDrawable& customDrawable : customDrawables) + customDrawable.drawable->Draw(); + } + + void ForwardRenderTechnique::DrawModels(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const Nz::RenderQueue& models) const + { + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); + + const Material* lastMaterial = nullptr; + const MaterialPipeline* lastPipeline = nullptr; + const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; + Recti lastScissorRect = Recti(-1, -1); + + const MaterialPipeline::Instance* pipelineInstance = nullptr; + + ///TODO: Reimplement instancing + + for (const BasicRenderQueue::Model& model : models) + { + const MaterialPipeline* pipeline = model.material->GetPipeline(); + if (lastPipeline != pipeline) + { + pipelineInstance = &model.material->GetPipeline()->Apply(); + + const Shader* shader = pipelineInstance->uberInstance->GetShader(); if (shader != lastShader) { // Index of uniforms in the shader @@ -335,560 +517,196 @@ namespace Nz // Position of the camera shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - // Overlay texture unit - shader->SendInteger(shaderUniforms->textureOverlay, overlayTextureUnit); - lastShader = shader; } - for (auto& materialPair : pipelineEntry.materialMap) + lastPipeline = pipeline; + } + + if (lastMaterial != model.material) + { + model.material->Apply(*pipelineInstance); + lastMaterial = model.material; + } + + if (model.material->IsScissorTestEnabled()) + { + const Nz::Recti& scissorRect = (model.scissorRect.width > 0) ? model.scissorRect : fullscreenScissorRect; + if (scissorRect != lastScissorRect) { - const Material* material = materialPair.first; - auto& matEntry = materialPair.second; - - if (matEntry.enabled) - { - material->Apply(pipelineInstance); - - Renderer::SetTextureSampler(overlayTextureUnit, material->GetDiffuseSampler()); - - auto& overlayMap = matEntry.overlayMap; - for (auto& overlayIt : overlayMap) - { - const Texture* overlay = overlayIt.first; - auto& spriteChainVector = overlayIt.second.spriteChains; - - std::size_t spriteChainCount = spriteChainVector.size(); - if (spriteChainCount > 0) - { - Renderer::SetTexture(overlayTextureUnit, (overlay) ? overlay : &m_whiteTexture); - - std::size_t spriteChain = 0; // Which chain of sprites are we treating - std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain - - do - { - // 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 spriteCount = 0; - - do - { - ForwardRenderQueue::SpriteChain_XYZ_Color_UV& currentChain = spriteChainVector[spriteChain]; - std::size_t count = std::min(maxSpriteCount - spriteCount, currentChain.spriteCount - spriteChainOffset); - - std::memcpy(vertices, currentChain.vertices + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); - vertices += count * 4; - - spriteCount += count; - spriteChainOffset += count; - - // Have we treated the entire chain ? - if (spriteChainOffset == currentChain.spriteCount) - { - spriteChain++; - spriteChainOffset = 0; - } - } while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); - - vertexMapper.Unmap(); - - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); - } - while (spriteChain < spriteChainCount); - } - } - } + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; } } + + if (shaderUniforms->reflectionMap != -1) + { + unsigned int textureUnit = Material::GetTextureUnit(TextureMap_ReflectionCube); + + Renderer::SetTexture(textureUnit, sceneData.globalReflectionTexture); + Renderer::SetTextureSampler(textureUnit, s_reflectionSampler); + } + + // Handle draw call before rendering loop + Renderer::DrawCall drawFunc; + Renderer::DrawCallInstanced instancedDrawFunc; + unsigned int indexCount; + + if (model.meshData.indexBuffer) + { + drawFunc = Renderer::DrawIndexedPrimitives; + instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced; + indexCount = model.meshData.indexBuffer->GetIndexCount(); + } + else + { + drawFunc = Renderer::DrawPrimitives; + instancedDrawFunc = Renderer::DrawPrimitivesInstanced; + indexCount = model.meshData.vertexBuffer->GetVertexCount(); + } + + Renderer::SetIndexBuffer(model.meshData.indexBuffer); + Renderer::SetVertexBuffer(model.meshData.vertexBuffer); + + if (shaderUniforms->hasLightUniforms) + { + ChooseLights(model.obbSphere); + + std::size_t lightCount = m_lights.size(); + + Nz::Renderer::SetMatrix(Nz::MatrixType_World, model.matrix); + std::size_t lightIndex = 0; + RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // In the case where we have to change it + + std::size_t passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; + for (std::size_t pass = 0; pass < passCount; ++pass) + { + lightCount -= std::min(lightCount, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS); + + if (pass == 1) + { + // To add the result of light computations + // We won't interfere with materials parameters because we only render opaques objects + // (A.K.A., without blending) + // About the depth function, it must be applied only the first time + Renderer::Enable(RendererParameter_Blend, true); + Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); + Renderer::SetDepthFunc(RendererComparison_Equal); + } + + // Sends the light uniforms to the shader + for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) + SendLightUniforms(lastShader, shaderUniforms->lightUniforms, i, lightIndex++, shaderUniforms->lightOffset*i); + + // And we draw + drawFunc(model.meshData.primitiveMode, 0, indexCount); + } + + Renderer::Enable(RendererParameter_Blend, false); + Renderer::SetDepthFunc(oldDepthFunc); + } + else + { + Renderer::SetMatrix(MatrixType_World, model.matrix); + drawFunc(model.meshData.primitiveMode, 0, indexCount); + } } } - /*! - * \brief Draws billboards - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - * - * \remark Produces a NazaraAssert is viewer is invalid - */ - - void ForwardRenderTechnique::DrawBillboards(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const + void ForwardRenderTechnique::DrawSprites(const SceneData& sceneData, const BasicRenderQueue& renderQueue, const RenderQueue& spriteList) const { - NazaraAssert(sceneData.viewer, "Invalid viewer"); - - const Shader* lastShader = nullptr; - const ShaderUniforms* shaderUniforms = nullptr; - - if (m_instancingEnabled && Renderer::HasCapability(RendererCap_Instancing)) - { - VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); - instanceBuffer->SetVertexDeclaration(&s_billboardInstanceDeclaration); - - Renderer::SetVertexBuffer(&s_quadVertexBuffer); - - for (auto& pipelinePair : layer.billboards) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) - { - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | ShaderFlags_Instancing | 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 - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position of the camera - shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - - lastShader = shader; - } - - for (auto& matIt : pipelinePair.second.materialMap) - { - const Material* material = matIt.first; - auto& entry = matIt.second; - auto& billboardVector = entry.billboards; - - std::size_t billboardCount = billboardVector.size(); - if (billboardCount > 0) - { - // We begin to apply the material (and get the shader activated doing so) - material->Apply(pipelineInstance); - - const ForwardRenderQueue::BillboardData* data = &billboardVector[0]; - std::size_t maxBillboardPerDraw = instanceBuffer->GetVertexCount(); - do - { - std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); - billboardCount -= renderedBillboardCount; - - instanceBuffer->Fill(data, 0, renderedBillboardCount); - data += renderedBillboardCount; - - Renderer::DrawPrimitivesInstanced(renderedBillboardCount, PrimitiveMode_TriangleStrip, 0, 4); - } - while (billboardCount > 0); - - billboardVector.clear(); - } - } - } - } - } - else - { - Renderer::SetIndexBuffer(&s_quadIndexBuffer); - Renderer::SetVertexBuffer(&m_billboardPointBuffer); - - for (auto& pipelinePair : layer.billboards) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.enabled) - { - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply(ShaderFlags_Billboard | 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 - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position of the camera - shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - - lastShader = shader; - } - - for (auto& matIt : pipelinePair.second.materialMap) - { - auto& entry = matIt.second; - auto& billboardVector = entry.billboards; - - const ForwardRenderQueue::BillboardData* data = &billboardVector[0]; - std::size_t maxBillboardPerDraw = std::min(s_maxQuads, m_billboardPointBuffer.GetVertexCount() / 4); - - std::size_t billboardCount = billboardVector.size(); - do - { - std::size_t renderedBillboardCount = std::min(billboardCount, maxBillboardPerDraw); - billboardCount -= renderedBillboardCount; - - BufferMapper vertexMapper(m_billboardPointBuffer, BufferAccess_DiscardAndWrite, 0, renderedBillboardCount * 4); - BillboardPoint* vertices = static_cast(vertexMapper.GetPointer()); - - for (unsigned int i = 0; i < renderedBillboardCount; ++i) - { - const ForwardRenderQueue::BillboardData& billboard = *data++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(0.f, 1.f); - vertices++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(1.f, 1.f); - vertices++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(0.f, 0.f); - vertices++; - - vertices->color = billboard.color; - vertices->position = billboard.center; - vertices->sinCos = billboard.sinCos; - vertices->size = billboard.size; - vertices->uv.Set(1.f, 0.f); - vertices++; - } - - vertexMapper.Unmap(); - - Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, renderedBillboardCount * 6); - } - while (billboardCount > 0); - } - } - } - } - } - - /*! - * \brief Draws opaques models - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - * - * \remark Produces a NazaraAssert is viewer is invalid - */ - - void ForwardRenderTechnique::DrawOpaqueModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const - { - NazaraAssert(sceneData.viewer, "Invalid viewer"); - - const Shader* lastShader = nullptr; - const ShaderUniforms* shaderUniforms = nullptr; - - Texture* reflectionMap = sceneData.globalReflectionTexture; - if (!reflectionMap) - reflectionMap = &s_dummyReflection; - - for (auto& pipelinePair : layer.opaqueModels) - { - const MaterialPipeline* pipeline = pipelinePair.first; - auto& pipelineEntry = pipelinePair.second; - - if (pipelineEntry.maxInstanceCount > 0) - { - bool instancing = m_instancingEnabled && (pipelineEntry.maxInstanceCount > NAZARA_GRAPHICS_INSTANCING_MIN_INSTANCES_COUNT); - const MaterialPipeline::Instance& pipelineInstance = pipeline->Apply((instancing) ? ShaderFlags_Instancing : 0); - - 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 - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position of the camera - shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - - lastShader = shader; - } - - for (auto& materialPair : pipelineEntry.materialMap) - { - const Material* material = materialPair.first; - auto& matEntry = materialPair.second; - - if (matEntry.enabled) - { - material->Apply(pipelineInstance); - - if (shaderUniforms->reflectionMap != -1) - { - unsigned int textureUnit = Material::GetTextureUnit(TextureMap_ReflectionCube); - - Renderer::SetTexture(textureUnit, reflectionMap); - Renderer::SetTextureSampler(textureUnit, s_reflectionSampler); - } - - ForwardRenderQueue::MeshInstanceContainer& meshInstances = matEntry.meshMap; - - // Meshes - for (auto& meshIt : meshInstances) - { - const MeshData& meshData = meshIt.first; - auto& meshEntry = meshIt.second; - - const Spheref& squaredBoundingSphere = meshEntry.squaredBoundingSphere; - std::vector& instances = meshEntry.instances; - - if (!instances.empty()) - { - const IndexBuffer* indexBuffer = meshData.indexBuffer; - const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - - // Handle draw call before rendering loop - Renderer::DrawCall drawFunc; - Renderer::DrawCallInstanced instancedDrawFunc; - unsigned int indexCount; - - if (indexBuffer) - { - drawFunc = Renderer::DrawIndexedPrimitives; - instancedDrawFunc = Renderer::DrawIndexedPrimitivesInstanced; - indexCount = indexBuffer->GetIndexCount(); - } - else - { - drawFunc = Renderer::DrawPrimitives; - instancedDrawFunc = Renderer::DrawPrimitivesInstanced; - indexCount = vertexBuffer->GetVertexCount(); - } - - Renderer::SetIndexBuffer(indexBuffer); - Renderer::SetVertexBuffer(vertexBuffer); - - if (instancing) - { - // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) - VertexBuffer* instanceBuffer = Renderer::GetInstanceBuffer(); - instanceBuffer->SetVertexDeclaration(VertexDeclaration::Get(VertexLayout_Matrix4)); - - // With instancing, impossible to select the lights for each object - // So, it's only activated for directional lights - std::size_t lightCount = m_renderQueue.directionalLights.size(); - std::size_t lightIndex = 0; - RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); - - std::size_t passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; - for (std::size_t pass = 0; pass < passCount; ++pass) - { - if (shaderUniforms->hasLightUniforms) - { - std::size_t renderedLightCount = std::min(lightCount, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS); - lightCount -= renderedLightCount; - - if (pass == 1) - { - // To add the result of light computations - // We won't interfeer with materials parameters because we only render opaques objects - // (A.K.A., without blending) - // About the depth function, it must be applied only the first time - Renderer::Enable(RendererParameter_Blend, true); - Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); - Renderer::SetDepthFunc(RendererComparison_Equal); - } - - // Sends the uniforms - for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - SendLightUniforms(shader, shaderUniforms->lightUniforms, i, lightIndex++, shaderUniforms->lightOffset * i); - } - - const Matrix4f* instanceMatrices = &instances[0]; - std::size_t instanceCount = instances.size(); - std::size_t maxInstanceCount = instanceBuffer->GetVertexCount(); // Maximum number of instance in one batch - - while (instanceCount > 0) - { - // We compute the number of instances that we will be able to draw this time (depending on the instancing buffer size) - std::size_t renderedInstanceCount = std::min(instanceCount, maxInstanceCount); - instanceCount -= renderedInstanceCount; - - // We fill the instancing buffer with our world matrices - instanceBuffer->Fill(instanceMatrices, 0, renderedInstanceCount); - instanceMatrices += renderedInstanceCount; - - // And we draw - instancedDrawFunc(renderedInstanceCount, meshData.primitiveMode, 0, indexCount); - } - } - - // We don't forget to disable the blending to avoid to interferering with the rest of the rendering - Renderer::Enable(RendererParameter_Blend, false); - Renderer::SetDepthFunc(oldDepthFunc); - } - else - { - if (shaderUniforms->hasLightUniforms) - { - for (const Matrix4f& matrix : instances) - { - // Choose the lights depending on an object position and apparent radius - ChooseLights(Spheref(matrix.GetTranslation() + squaredBoundingSphere.GetPosition(), squaredBoundingSphere.radius)); - - std::size_t lightCount = m_lights.size(); - - Renderer::SetMatrix(MatrixType_World, matrix); - std::size_t lightIndex = 0; - RendererComparison oldDepthFunc = Renderer::GetDepthFunc(); // In the case where we have to change it - - std::size_t passCount = (lightCount == 0) ? 1 : (lightCount - 1) / NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS + 1; - for (std::size_t pass = 0; pass < passCount; ++pass) - { - lightCount -= std::min(lightCount, NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS); - - if (pass == 1) - { - // To add the result of light computations - // We won't interfeer with materials parameters because we only render opaques objects - // (A.K.A., without blending) - // About the depth function, it must be applied only the first time - Renderer::Enable(RendererParameter_Blend, true); - Renderer::SetBlendFunc(BlendFunc_One, BlendFunc_One); - Renderer::SetDepthFunc(RendererComparison_Equal); - } - - // Sends the light uniforms to the shader - for (unsigned int i = 0; i < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS; ++i) - SendLightUniforms(shader, shaderUniforms->lightUniforms, i, lightIndex++, shaderUniforms->lightOffset*i); - - // And we draw - drawFunc(meshData.primitiveMode, 0, indexCount); - } - - Renderer::Enable(RendererParameter_Blend, false); - Renderer::SetDepthFunc(oldDepthFunc); - } - } - else - { - // Without instancing, we must do a draw call for each instance - // This may be faster than instancing under a certain number - // Due to the time to modify the instancing buffer - for (const Matrix4f& matrix : instances) - { - Renderer::SetMatrix(MatrixType_World, matrix); - drawFunc(meshData.primitiveMode, 0, indexCount); - } - } - } - } - } - } - } - } - } - } - - void ForwardRenderTechnique::DrawOrderedSprites(const SceneData & sceneData, ForwardRenderQueue::Layer & layer) const - { - NazaraAssert(sceneData.viewer, "Invalid viewer"); + const RenderTarget* renderTarget = sceneData.viewer->GetTarget(); + Recti fullscreenScissorRect = Recti(Vector2i(renderTarget->GetSize())); Renderer::SetIndexBuffer(&s_quadIndexBuffer); Renderer::SetMatrix(MatrixType_World, Matrix4f::Identity()); Renderer::SetVertexBuffer(&m_spriteBuffer); + const unsigned int overlayTextureUnit = Material::GetTextureUnit(TextureMap_Overlay); + const std::size_t maxSpriteCount = std::min(s_maxQuads, m_spriteBuffer.GetVertexCount() / 4); + + m_spriteChains.clear(); + + auto Commit = [&]() + { + std::size_t spriteChainCount = m_spriteChains.size(); + if (spriteChainCount > 0) + { + std::size_t spriteChain = 0; // Which chain of sprites are we treating + std::size_t spriteChainOffset = 0; // Where was the last offset where we stopped in the last chain + + do + { + // 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 spriteCount = 0; + + do + { + const VertexStruct_XYZ_Color_UV* currentChain = m_spriteChains[spriteChain].first; + std::size_t currentChainSpriteCount = m_spriteChains[spriteChain].second; + std::size_t count = std::min(maxSpriteCount - spriteCount, currentChainSpriteCount - spriteChainOffset); + + std::memcpy(vertices, currentChain + spriteChainOffset * 4, 4 * count * sizeof(VertexStruct_XYZ_Color_UV)); + vertices += count * 4; + + spriteCount += count; + spriteChainOffset += count; + + // Have we treated the entire chain ? + if (spriteChainOffset == currentChainSpriteCount) + { + spriteChain++; + spriteChainOffset = 0; + } + } + while (spriteCount < maxSpriteCount && spriteChain < spriteChainCount); + + vertexMapper.Unmap(); + + Renderer::DrawIndexedPrimitives(PrimitiveMode_TriangleList, 0, spriteCount * 6); + } + while (spriteChain < spriteChainCount); + } + + m_spriteChains.clear(); + }; + const Material* lastMaterial = nullptr; const MaterialPipeline* lastPipeline = nullptr; const Shader* lastShader = nullptr; + const ShaderUniforms* shaderUniforms = nullptr; const Texture* lastOverlay = nullptr; + Recti lastScissorRect = Recti(-1, -1); + 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();) + for (const BasicRenderQueue::SpriteChain& basicSprites : spriteList) { - if (updateVertexBuffer) + const Nz::Recti& scissorRect = (basicSprites.scissorRect.width > 0) ? basicSprites.scissorRect : fullscreenScissorRect; + + if (basicSprites.material != lastMaterial || basicSprites.overlay != lastOverlay || (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect)) { - // We open the buffer in writing mode - BufferMapper vertexMapper(m_spriteBuffer, BufferAccess_DiscardAndWrite); - VertexStruct_XYZ_Color_UV* vertices = static_cast(vertexMapper.GetPointer()); + Commit(); - std::size_t availableSpriteSpace = maxSpriteCount; - bool split = false; - for (auto it2 = it; it2 != layer.depthSortedSprites.end(); ++it2) + const MaterialPipeline* pipeline = basicSprites.material->GetPipeline(); + if (lastPipeline != pipeline) { - 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); + pipelineInstance = &basicSprites.material->GetPipeline()->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); + 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); @@ -898,150 +716,34 @@ namespace Nz 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 - * - * \param sceneData Data of the scene - * \param layer Layer of the rendering - * - * \remark Produces a NazaraAssert is viewer is invalid - */ - - void ForwardRenderTechnique::DrawTransparentModels(const SceneData& sceneData, ForwardRenderQueue::Layer& layer) const - { - NazaraAssert(sceneData.viewer, "Invalid viewer"); - - const MaterialPipeline* lastPipeline = nullptr; - const MaterialPipeline::Instance* pipelineInstance = nullptr; - const Shader* lastShader = nullptr; - const ShaderUniforms* shaderUniforms = nullptr; - unsigned int lightCount = 0; - - for (std::size_t index : layer.depthSortedMeshes) - { - const ForwardRenderQueue::UnbatchedModelData& modelData = layer.depthSortedMeshData[index]; - - // Material - const Material* material = modelData.material; - - const MaterialPipeline* pipeline = material->GetPipeline(); - if (pipeline != lastPipeline) - { - pipelineInstance = &pipeline->Apply(); - lastPipeline = pipeline; - } - - // We begin to apply the material - material->Apply(*pipelineInstance); - - // Uniforms are conserved in our program, there's no point to send them back until they change - const Shader* shader = pipelineInstance->uberInstance->GetShader(); - if (shader != lastShader) - { - // Index of uniforms in the shader - shaderUniforms = GetShaderUniforms(shader); - - // Ambiant color of the scene - shader->SendColor(shaderUniforms->sceneAmbient, sceneData.ambientColor); - // Position of the camera - shader->SendVector(shaderUniforms->eyePosition, sceneData.viewer->GetEyePosition()); - - // We send the directional lights if there is one (same for all) - if (shaderUniforms->hasLightUniforms) + if (lastMaterial != basicSprites.material) { - lightCount = std::min(m_renderQueue.directionalLights.size(), static_cast(NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS)); + basicSprites.material->Apply(*pipelineInstance); - for (std::size_t i = 0; i < lightCount; ++i) - SendLightUniforms(shader, shaderUniforms->lightUniforms, i, i, shaderUniforms->lightOffset * i); + Renderer::SetTextureSampler(overlayTextureUnit, basicSprites.material->GetDiffuseSampler()); + + lastMaterial = basicSprites.material; } - lastShader = shader; + const Nz::Texture* overlayTexture = (basicSprites.overlay) ? basicSprites.overlay.Get() : m_whiteTexture.Get(); + if (overlayTexture != lastOverlay) + { + Renderer::SetTexture(overlayTextureUnit, overlayTexture); + lastOverlay = overlayTexture; + } + + if (basicSprites.material->IsScissorTestEnabled() && scissorRect != lastScissorRect) + { + Renderer::SetScissorRect(scissorRect); + lastScissorRect = scissorRect; + } } - // Mesh - const Matrix4f& matrix = modelData.transformMatrix; - const MeshData& meshData = modelData.meshData; - - const IndexBuffer* indexBuffer = meshData.indexBuffer; - const VertexBuffer* vertexBuffer = meshData.vertexBuffer; - - // Handle draw call before the rendering loop - Renderer::DrawCall drawFunc; - unsigned int indexCount; - - if (indexBuffer) - { - drawFunc = Renderer::DrawIndexedPrimitives; - indexCount = indexBuffer->GetIndexCount(); - } - else - { - drawFunc = Renderer::DrawPrimitives; - indexCount = vertexBuffer->GetVertexCount(); - } - - Renderer::SetIndexBuffer(indexBuffer); - Renderer::SetVertexBuffer(vertexBuffer); - - if (shaderUniforms->hasLightUniforms && lightCount < NAZARA_GRAPHICS_MAX_LIGHT_PER_PASS) - { - // Compute the closest lights - 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) - SendLightUniforms(shader, shaderUniforms->lightUniforms, i, i, shaderUniforms->lightOffset*i); - } - - Renderer::SetMatrix(MatrixType_World, matrix); - drawFunc(meshData.primitiveMode, 0, indexCount); + m_spriteChains.emplace_back(basicSprites.vertices, basicSprites.spriteCount); } - } - /*! - * \brief Gets the shader uniforms - * \return Uniforms of the shader - * - * \param shader Shader to get uniforms from - */ + Commit(); + } const ForwardRenderTechnique::ShaderUniforms* ForwardRenderTechnique::GetShaderUniforms(const Shader* shader) const { @@ -1194,7 +896,6 @@ namespace Nz } IndexBuffer ForwardRenderTechnique::s_quadIndexBuffer; - Texture ForwardRenderTechnique::s_dummyReflection; TextureSampler ForwardRenderTechnique::s_reflectionSampler; TextureSampler ForwardRenderTechnique::s_shadowSampler; VertexBuffer ForwardRenderTechnique::s_quadVertexBuffer; diff --git a/src/Nazara/Graphics/Graphics.cpp b/src/Nazara/Graphics/Graphics.cpp index 5ae1d8554..b8538a163 100644 --- a/src/Nazara/Graphics/Graphics.cpp +++ b/src/Nazara/Graphics/Graphics.cpp @@ -156,6 +156,21 @@ namespace Nz Font::SetDefaultAtlas(std::make_shared()); + // Textures + std::array whitePixels = { { 255, 255, 255, 255, 255, 255 } }; + + Nz::TextureRef whiteTexture = Nz::Texture::New(); + whiteTexture->Create(ImageType_2D, PixelFormatType_L8, 1, 1); + whiteTexture->Update(whitePixels.data()); + + TextureLibrary::Register("White2D", std::move(whiteTexture)); + + Nz::TextureRef whiteCubemap = Nz::Texture::New(); + whiteCubemap->Create(ImageType_Cubemap, PixelFormatType_L8, 1, 1); + whiteCubemap->Update(whitePixels.data()); + + TextureLibrary::Register("WhiteCubemap", std::move(whiteCubemap)); + onExit.Reset(); NazaraNotice("Initialized: Graphics module"); @@ -217,6 +232,10 @@ namespace Nz defaultAtlas.reset(); + // Textures + TextureLibrary::Unregister("White2D"); + TextureLibrary::Unregister("WhiteCubemap"); + // Loaders Loaders::UnregisterMesh(); Loaders::UnregisterTexture(); diff --git a/src/Nazara/Graphics/MaterialPipeline.cpp b/src/Nazara/Graphics/MaterialPipeline.cpp index 01d29cafb..6f2d5f173 100644 --- a/src/Nazara/Graphics/MaterialPipeline.cpp +++ b/src/Nazara/Graphics/MaterialPipeline.cpp @@ -160,7 +160,7 @@ namespace Nz OverrideShader("Shaders/Basic/core.vert", &vertexShader); #endif - uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING"); + uberShader->SetShader(ShaderStageType_Fragment, fragmentShader, "FLAG_TEXTUREOVERLAY ALPHA_MAPPING ALPHA_TEST AUTO_TEXCOORDS DIFFUSE_MAPPING TEXTURE_MAPPING"); uberShader->SetShader(ShaderStageType_Vertex, vertexShader, "FLAG_BILLBOARD FLAG_INSTANCING FLAG_VERTEXCOLOR TEXTURE_MAPPING TRANSFORM UNIFORM_VERTEX_DEPTH"); UberShaderLibrary::Register("Basic", uberShader); @@ -188,17 +188,19 @@ namespace Nz MaterialPipelineInfo pipelineInfo; pipelineInfo.uberShader = UberShaderLibrary::Get("Basic"); - // Basic 2D - No depth write/face culling + // Basic 2D - No depth write/face culling with scissoring pipelineInfo.depthWrite = false; pipelineInfo.faceCulling = false; + pipelineInfo.scissorTest = true; MaterialPipelineLibrary::Register("Basic2D", GetPipeline(pipelineInfo)); - // Translucent 2D - Alpha blending with no depth write/face culling + // Translucent 2D - Alpha blending with no depth write/face culling and scissoring pipelineInfo.blending = true; pipelineInfo.depthWrite = false; pipelineInfo.faceCulling = false; - pipelineInfo.depthSorting = true; + pipelineInfo.depthSorting = false; + pipelineInfo.scissorTest = true; pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha; pipelineInfo.srcBlend = BlendFunc_SrcAlpha; @@ -210,6 +212,7 @@ namespace Nz pipelineInfo.depthWrite = false; pipelineInfo.faceCulling = false; pipelineInfo.depthSorting = true; + pipelineInfo.scissorTest = false; pipelineInfo.dstBlend = BlendFunc_InvSrcAlpha; pipelineInfo.srcBlend = BlendFunc_SrcAlpha; diff --git a/src/Nazara/Graphics/Model.cpp b/src/Nazara/Graphics/Model.cpp index 217211f01..05b8bc909 100644 --- a/src/Nazara/Graphics/Model.cpp +++ b/src/Nazara/Graphics/Model.cpp @@ -52,7 +52,7 @@ namespace Nz * \param instanceData Data used for this instance */ - void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const + void Model::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const { unsigned int submeshCount = m_mesh->GetSubMeshCount(); for (unsigned int i = 0; i < submeshCount; ++i) @@ -65,7 +65,7 @@ namespace Nz meshData.primitiveMode = mesh->GetPrimitiveMode(); meshData.vertexBuffer = mesh->GetVertexBuffer(); - renderQueue->AddMesh(instanceData.renderOrder, material, meshData, mesh->GetAABB(), instanceData.transformMatrix); + renderQueue->AddMesh(instanceData.renderOrder, material, meshData, mesh->GetAABB(), instanceData.transformMatrix, scissorRect); } } diff --git a/src/Nazara/Graphics/RenderQueue.cpp b/src/Nazara/Graphics/RenderQueue.cpp new file mode 100644 index 000000000..3baa8ecc1 --- /dev/null +++ b/src/Nazara/Graphics/RenderQueue.cpp @@ -0,0 +1,18 @@ +// Copyright (C) 2017 Jérôme Leclercq +// This file is part of the "Nazara Engine - Graphics module" +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +namespace Nz +{ + void RenderQueueInternal::Sort() + { + std::sort(m_orderedRenderQueue.begin(), m_orderedRenderQueue.end(), [](const RenderDataPair& lhs, const RenderDataPair& rhs) + { + return lhs.first < rhs.first; + }); + } +} diff --git a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag index 53844cbc6..9002e9ded 100644 --- a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag +++ b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag @@ -24,7 +24,7 @@ void main() #if AUTO_TEXCOORDS vec2 texCoord = gl_FragCoord.xy * InvTargetSize; -#else +#elif TEXTURE_MAPPING vec2 texCoord = vTexCoord; #endif diff --git a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h index 0d9530d13..e4f7a19c5 100644 --- a/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h +++ b/src/Nazara/Graphics/Resources/Shaders/Basic/core.frag.h @@ -1 +1 @@ -35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,10,35,101,110,100,105,102,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,105,110,32,118,101,99,52,32,118,67,111,108,111,114,59,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,84,101,120,116,117,114,101,79,118,101,114,108,97,121,59,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,118,111,105,100,32,109,97,105,110,40,41,10,123,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,32,42,32,118,67,111,108,111,114,59,10,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,10,35,101,108,115,101,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,10,35,101,110,100,105,102,10,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,10,35,101,110,100,105,102,10,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,10,35,101,110,100,105,102,10,10,35,105,102,32,70,76,65,71,95,84,69,88,84,85,82,69,79,86,69,82,76,65,89,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,84,101,120,116,117,114,101,79,118,101,114,108,97,121,44,32,116,101,120,67,111,111,114,100,41,59,10,35,101,110,100,105,102,10,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,10,9,9,100,105,115,99,97,114,100,59,10,35,101,110,100,105,102,10,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,10,125, \ No newline at end of file +35,105,102,32,69,65,82,76,89,95,70,82,65,71,77,69,78,84,95,84,69,83,84,83,32,38,38,32,33,65,76,80,72,65,95,84,69,83,84,10,108,97,121,111,117,116,40,101,97,114,108,121,95,102,114,97,103,109,101,110,116,95,116,101,115,116,115,41,32,105,110,59,10,35,101,110,100,105,102,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,69,110,116,114,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,105,110,32,118,101,99,52,32,118,67,111,108,111,114,59,10,105,110,32,118,101,99,50,32,118,84,101,120,67,111,111,114,100,59,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,83,111,114,116,97,110,116,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,111,117,116,32,118,101,99,52,32,82,101,110,100,101,114,84,97,114,103,101,116,48,59,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,85,110,105,102,111,114,109,101,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,117,110,105,102,111,114,109,32,118,101,99,50,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,59,10,117,110,105,102,111,114,109,32,102,108,111,97,116,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,59,10,117,110,105,102,111,114,109,32,118,101,99,52,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,59,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,59,10,117,110,105,102,111,114,109,32,115,97,109,112,108,101,114,50,68,32,84,101,120,116,117,114,101,79,118,101,114,108,97,121,59,10,10,47,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,70,111,110,99,116,105,111,110,115,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,47,10,118,111,105,100,32,109,97,105,110,40,41,10,123,10,9,118,101,99,52,32,102,114,97,103,109,101,110,116,67,111,108,111,114,32,61,32,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,32,42,32,118,67,111,108,111,114,59,10,10,35,105,102,32,65,85,84,79,95,84,69,88,67,79,79,82,68,83,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,103,108,95,70,114,97,103,67,111,111,114,100,46,120,121,32,42,32,73,110,118,84,97,114,103,101,116,83,105,122,101,59,10,35,101,108,105,102,32,84,69,88,84,85,82,69,95,77,65,80,80,73,78,71,10,9,118,101,99,50,32,116,101,120,67,111,111,114,100,32,61,32,118,84,101,120,67,111,111,114,100,59,10,35,101,110,100,105,102,10,10,35,105,102,32,68,73,70,70,85,83,69,95,77,65,80,80,73,78,71,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,68,105,102,102,117,115,101,77,97,112,44,32,116,101,120,67,111,111,114,100,41,59,10,35,101,110,100,105,102,10,10,35,105,102,32,65,76,80,72,65,95,77,65,80,80,73,78,71,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,42,61,32,116,101,120,116,117,114,101,40,77,97,116,101,114,105,97,108,65,108,112,104,97,77,97,112,44,32,116,101,120,67,111,111,114,100,41,46,114,59,10,35,101,110,100,105,102,10,10,35,105,102,32,70,76,65,71,95,84,69,88,84,85,82,69,79,86,69,82,76,65,89,10,9,102,114,97,103,109,101,110,116,67,111,108,111,114,32,42,61,32,116,101,120,116,117,114,101,40,84,101,120,116,117,114,101,79,118,101,114,108,97,121,44,32,116,101,120,67,111,111,114,100,41,59,10,35,101,110,100,105,102,10,10,35,105,102,32,65,76,80,72,65,95,84,69,83,84,10,9,105,102,32,40,102,114,97,103,109,101,110,116,67,111,108,111,114,46,97,32,60,32,77,97,116,101,114,105,97,108,65,108,112,104,97,84,104,114,101,115,104,111,108,100,41,10,9,9,100,105,115,99,97,114,100,59,10,35,101,110,100,105,102,10,10,9,82,101,110,100,101,114,84,97,114,103,101,116,48,32,61,32,102,114,97,103,109,101,110,116,67,111,108,111,114,59,10,125, \ No newline at end of file diff --git a/src/Nazara/Graphics/SkeletalModel.cpp b/src/Nazara/Graphics/SkeletalModel.cpp index 433a748f6..c42b63a83 100644 --- a/src/Nazara/Graphics/SkeletalModel.cpp +++ b/src/Nazara/Graphics/SkeletalModel.cpp @@ -53,7 +53,7 @@ namespace Nz * \param instanceData Data for the instance */ - void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const + void SkeletalModel::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const { if (!m_mesh) return; @@ -69,7 +69,7 @@ namespace Nz meshData.primitiveMode = mesh->GetPrimitiveMode(); meshData.vertexBuffer = SkinningManager::GetBuffer(mesh, &m_skeleton); - renderQueue->AddMesh(instanceData.renderOrder, material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix); + renderQueue->AddMesh(instanceData.renderOrder, material, meshData, m_skeleton.GetAABB(), instanceData.transformMatrix, scissorRect); } } diff --git a/src/Nazara/Graphics/Sprite.cpp b/src/Nazara/Graphics/Sprite.cpp index 5d51a1ae1..70ba21926 100644 --- a/src/Nazara/Graphics/Sprite.cpp +++ b/src/Nazara/Graphics/Sprite.cpp @@ -22,10 +22,10 @@ namespace Nz * \param instanceData Data for the instance */ - void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const + void Sprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const { const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(instanceData.data.data()); - renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), vertices, 1); + renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), vertices, 1, scissorRect); } /*! diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index 3d82037d4..883268963 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -26,7 +26,7 @@ namespace Nz * \param instanceData Data for the instance */ - void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const + void TextSprite::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const { for (auto& pair : m_renderInfos) { @@ -36,7 +36,7 @@ namespace Nz if (indices.count > 0) { const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(instanceData.data.data()); - renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, overlay); + renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(), &vertices[indices.first * 4], indices.count, scissorRect, overlay); } } } diff --git a/src/Nazara/Graphics/TileMap.cpp b/src/Nazara/Graphics/TileMap.cpp index 192341472..26a146f88 100644 --- a/src/Nazara/Graphics/TileMap.cpp +++ b/src/Nazara/Graphics/TileMap.cpp @@ -23,7 +23,7 @@ namespace Nz * \param renderQueue Queue to be added * \param instanceData Data for the instance */ - void TileMap::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData) const + void TileMap::AddToRenderQueue(AbstractRenderQueue* renderQueue, const InstanceData& instanceData, const Recti& scissorRect) const { const VertexStruct_XYZ_Color_UV* vertices = reinterpret_cast(instanceData.data.data()); @@ -31,7 +31,7 @@ namespace Nz std::size_t spriteCount = 0; for (const Layer& layer : m_layers) { - renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(matCount++), &vertices[spriteCount], layer.tiles.size()); + renderQueue->AddSprites(instanceData.renderOrder, GetMaterial(matCount++), &vertices[spriteCount], layer.tiles.size(), scissorRect); spriteCount += layer.tiles.size(); } diff --git a/src/Nazara/Network/AbstractSocket.cpp b/src/Nazara/Network/AbstractSocket.cpp index b070a93cb..879589cd6 100644 --- a/src/Nazara/Network/AbstractSocket.cpp +++ b/src/Nazara/Network/AbstractSocket.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #if defined(NAZARA_PLATFORM_WINDOWS) #include @@ -14,6 +14,8 @@ #error Missing implementation: Socket #endif +#include + namespace Nz { /*! @@ -187,10 +189,23 @@ namespace Nz { if (m_handle == SocketImpl::InvalidHandle || m_protocol != protocol) { - SocketHandle handle = SocketImpl::Create(protocol, m_type, &m_lastError); + SocketHandle handle = SocketImpl::Create((protocol == NetProtocol_Any) ? NetProtocol_IPv6 : protocol, m_type, &m_lastError); if (handle == SocketImpl::InvalidHandle) return false; + if (protocol == NetProtocol_Any) + { + if (!SocketImpl::SetIPv6Only(handle, false, &m_lastError)) + { + SocketImpl::Close(handle); + + NazaraError("Failed to open a dual-stack socket: " + Nz::String(ErrorToString(m_lastError))); + return false; + } + + protocol = NetProtocol_IPv6; + } + m_protocol = protocol; Open(handle); } diff --git a/src/Nazara/Network/ENetHost.cpp b/src/Nazara/Network/ENetHost.cpp index 1bc3d0832..5eb8d5862 100644 --- a/src/Nazara/Network/ENetHost.cpp +++ b/src/Nazara/Network/ENetHost.cpp @@ -320,7 +320,7 @@ namespace Nz bool ENetHost::InitSocket(const IpAddress& address) { - if (!m_socket.Create(address.GetProtocol())) + if (!m_socket.Create((m_isUsingDualStack) ? NetProtocol_Any : address.GetProtocol())) return false; m_socket.EnableBlocking(false); diff --git a/src/Nazara/Network/Posix/IpAddressImpl.cpp b/src/Nazara/Network/Posix/IpAddressImpl.cpp index 13eb10c31..d00d58068 100644 --- a/src/Nazara/Network/Posix/IpAddressImpl.cpp +++ b/src/Nazara/Network/Posix/IpAddressImpl.cpp @@ -59,24 +59,13 @@ namespace Nz IpAddress::IPv6 convertSockaddr6ToIPv6(const in6_addr& addr) { - union byteToInt - { - UInt8 b[sizeof(uint32_t)]; - uint32_t i; - }; + auto& rawIpV6 = addr.s6_addr; - IpAddress::IPv6 ipv6Addr; + IpAddress::IPv6 ipv6; + for (unsigned int i = 0; i < 8; ++i) + ipv6[i] = rawIpV6[i * 2] << 8 | rawIpV6[i * 2 + 1]; - for (auto i = 0; i < 4; ++i) - { - byteToInt hostOrder; - hostOrder.i = 0; - std::copy(addr.s6_addr + 4 * i, addr.s6_addr + 4 * (i + 1), hostOrder.b); - ipv6Addr[2 * i] = (hostOrder.b[3] << 8) + hostOrder.b[2]; - ipv6Addr[2 * i + 1] = (hostOrder.b[1] << 8) + hostOrder.b[0]; - } - - return ipv6Addr; + return ipv6; } } @@ -218,9 +207,9 @@ namespace Nz IpAddress::IPv6 address = ipAddress.ToIPv6(); for (unsigned int i = 0; i < 8; ++i) { - UInt16 networkOrder = htons(address[i]); - socketAddress->sin6_addr.s6_addr[2 * i] = networkOrder / 256; - socketAddress->sin6_addr.s6_addr[2 * i + 1] = networkOrder % 256; + u_short addressPart = htons(address[i]); + socketAddress->sin6_addr.s6_addr[i * 2 + 0] = addressPart >> 0; + socketAddress->sin6_addr.s6_addr[i * 2 + 1] = addressPart >> 8; } return sizeof(sockaddr_in6); diff --git a/src/Nazara/Network/Posix/SocketImpl.cpp b/src/Nazara/Network/Posix/SocketImpl.cpp index 1d3d34e99..d372d6fff 100644 --- a/src/Nazara/Network/Posix/SocketImpl.cpp +++ b/src/Nazara/Network/Posix/SocketImpl.cpp @@ -809,7 +809,7 @@ namespace Nz { NazaraAssert(handle != InvalidHandle, "Invalid handle"); - bool option = broadcasting; + int option = broadcasting; if (setsockopt(handle, SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&option), sizeof(option)) == SOCKET_ERROR) { if (error) @@ -824,6 +824,25 @@ namespace Nz return true; } + bool SocketImpl::SetIPv6Only(SocketHandle handle, bool ipv6Only, SocketError* error) + { + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + int option = ipv6Only; + if (setsockopt(handle, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&option), sizeof(option)) == SOCKET_ERROR) + { + if (error) + *error = TranslateErrnoToResolveError(GetLastErrorCode()); + + return false; //< Error + } + + if (error) + *error = SocketError_NoError; + + return true; + } + bool SocketImpl::SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error) { NazaraAssert(handle != InvalidHandle, "Invalid handle"); diff --git a/src/Nazara/Network/Posix/SocketImpl.hpp b/src/Nazara/Network/Posix/SocketImpl.hpp index e9f094cc3..4bd38380d 100644 --- a/src/Nazara/Network/Posix/SocketImpl.hpp +++ b/src/Nazara/Network/Posix/SocketImpl.hpp @@ -72,6 +72,7 @@ namespace Nz static bool SetBlocking(SocketHandle handle, bool blocking, SocketError* error = nullptr); static bool SetBroadcasting(SocketHandle handle, bool broadcasting, SocketError* error = nullptr); + static bool SetIPv6Only(SocketHandle handle, bool ipv6only, SocketError* error = nullptr); static bool SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error = nullptr); static bool SetNoDelay(SocketHandle handle, bool nodelay, SocketError* error = nullptr); static bool SetReceiveBufferSize(SocketHandle handle, std::size_t size, SocketError* error = nullptr); diff --git a/src/Nazara/Network/Win32/IpAddressImpl.cpp b/src/Nazara/Network/Win32/IpAddressImpl.cpp index 257e50cf6..853dae840 100644 --- a/src/Nazara/Network/Win32/IpAddressImpl.cpp +++ b/src/Nazara/Network/Win32/IpAddressImpl.cpp @@ -93,21 +93,14 @@ namespace Nz { sockaddr_in* ipv4 = reinterpret_cast(info->ai_addr); - auto& rawIpV4 = ipv4->sin_addr; - return IpAddress(rawIpV4.s_net, rawIpV4.s_host, rawIpV4.s_lh, rawIpV4.s_impno, ntohs(ipv4->sin_port)); + return FromSockAddr(ipv4); } case AF_INET6: { sockaddr_in6* ipv6 = reinterpret_cast(info->ai_addr); - auto& rawIpV6 = ipv6->sin6_addr.s6_addr; - - IpAddress::IPv6 structIpV6; - for (unsigned int i = 0; i < 8; ++i) - structIpV6[i] = UInt16(rawIpV6[i * 2]) << 8 | UInt16(rawIpV6[i * 2 + 1]); - - return IpAddress(structIpV6, ntohs(ipv6->sin6_port)); + return FromSockAddr(ipv6); } } @@ -164,7 +157,7 @@ namespace Nz IpAddress::IPv6 ipv6; for (unsigned int i = 0; i < 8; ++i) - ipv6[i] = rawIpV6[i*2] << 8 | rawIpV6[i*2+1]; + ipv6[i] = rawIpV6[i * 2] << 8 | rawIpV6[i * 2 + 1]; return IpAddress(ipv6, ntohs(addressv6->sin6_port)); } @@ -258,8 +251,9 @@ namespace Nz IpAddress::IPv6 address = ipAddress.ToIPv6(); for (unsigned int i = 0; i < 8; ++i) { - socketAddress->sin6_addr.s6_addr[i * 2 + 0] = htons(address[i]) >> 8; - socketAddress->sin6_addr.s6_addr[i * 2 + 1] = htons(address[i]) >> 0; + u_short addressPart = htons(address[i]); + socketAddress->sin6_addr.s6_addr[i * 2 + 0] = addressPart >> 0; + socketAddress->sin6_addr.s6_addr[i * 2 + 1] = addressPart >> 8; } return sizeof(sockaddr_in6); diff --git a/src/Nazara/Network/Win32/SocketImpl.cpp b/src/Nazara/Network/Win32/SocketImpl.cpp index b14202cc7..a0ebe5948 100644 --- a/src/Nazara/Network/Win32/SocketImpl.cpp +++ b/src/Nazara/Network/Win32/SocketImpl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2017 Jérôme Leclercq +// Copyright (C) 2018 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 @@ -10,13 +10,15 @@ // Some compilers (older versions of MinGW) lack Mstcpip.h which defines some structs/defines #if defined(__has_include) - #define NZ_HAS_MSTCPIP_HEADER __has_include() + #define NZ_HAS_MSTCPIP_HEADER __has_include() #else // If this version of MinGW doesn't support __has_include, assume it hasn't Mstcpip.h #define NZ_HAS_MSTCPIP_HEADER !defined(NAZARA_COMPILER_MINGW) #endif #if NZ_HAS_MSTCPIP_HEADER +#include +#else struct tcp_keepalive { u_long onoff; @@ -25,8 +27,6 @@ struct tcp_keepalive }; #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) -#else -#include #endif #include @@ -827,6 +827,32 @@ namespace Nz return true; } + bool SocketImpl::SetIPv6Only(SocketHandle handle, bool ipv6Only, SocketError* error) + { +#if NAZARA_CORE_WINDOWS_NT6 + NazaraAssert(handle != InvalidHandle, "Invalid handle"); + + DWORD option = ipv6Only; + if (setsockopt(handle, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&option), sizeof(option)) == SOCKET_ERROR) + { + if (error) + *error = TranslateWSAErrorToSocketError(WSAGetLastError()); + + return false; //< Error + } + + if (error) + *error = SocketError_NoError; + + return true; +#else + if (error) + *error = SocketError_NotSupported; + + return false; +#endif + } + bool SocketImpl::SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error) { NazaraAssert(handle != InvalidHandle, "Invalid handle"); diff --git a/src/Nazara/Network/Win32/SocketImpl.hpp b/src/Nazara/Network/Win32/SocketImpl.hpp index 864e629dd..1aa4a0495 100644 --- a/src/Nazara/Network/Win32/SocketImpl.hpp +++ b/src/Nazara/Network/Win32/SocketImpl.hpp @@ -72,6 +72,7 @@ namespace Nz static bool SetBlocking(SocketHandle handle, bool blocking, SocketError* error = nullptr); static bool SetBroadcasting(SocketHandle handle, bool broadcasting, SocketError* error = nullptr); + static bool SetIPv6Only(SocketHandle handle, bool ipv6Only, SocketError* error = nullptr); static bool SetKeepAlive(SocketHandle handle, bool enabled, UInt64 msTime, UInt64 msInterval, SocketError* error = nullptr); static bool SetNoDelay(SocketHandle handle, bool nodelay, SocketError* error = nullptr); static bool SetReceiveBufferSize(SocketHandle handle, std::size_t size, SocketError* error = nullptr); diff --git a/src/Nazara/Physics3D/Collider3D.cpp b/src/Nazara/Physics3D/Collider3D.cpp index 454c18037..4dc2f6821 100644 --- a/src/Nazara/Physics3D/Collider3D.cpp +++ b/src/Nazara/Physics3D/Collider3D.cpp @@ -50,7 +50,7 @@ namespace Nz { Vector3f min, max; - // Si nous n'avons aucune instance, nous en cr�ons une temporaire + // Check for existing collision handles, and create a temporary one if none is available if (m_handles.empty()) { PhysWorld3D world; @@ -61,7 +61,7 @@ namespace Nz } NewtonDestroyCollision(collision); } - else // Sinon on utilise une instance au hasard (elles sont toutes identiques de toute fa�on) + else NewtonCollisionCalculateAABB(m_handles.begin()->second, offsetMatrix, min, max); return Boxf(scale * min, scale * max); @@ -72,7 +72,7 @@ namespace Nz float inertiaMatrix[3]; float origin[3]; - // Si nous n'avons aucune instance, nous en cr�ons une temporaire + // Check for existing collision handles, and create a temporary one if none is available if (m_handles.empty()) { PhysWorld3D world; @@ -83,7 +83,7 @@ namespace Nz } NewtonDestroyCollision(collision); } - else // Sinon on utilise une instance au hasard (elles sont toutes identiques de toute fa�on) + else NewtonConvexCollisionCalculateInertialMatrix(m_handles.begin()->second, inertiaMatrix, origin); if (inertia) @@ -97,7 +97,7 @@ namespace Nz { float volume; - // Si nous n'avons aucune instance, nous en cr�ons une temporaire + // Check for existing collision handles, and create a temporary one if none is available if (m_handles.empty()) { PhysWorld3D world; @@ -108,12 +108,35 @@ namespace Nz } NewtonDestroyCollision(collision); } - else // Sinon on utilise une instance au hasard (elles sont toutes identiques de toute fa�on) + else volume = NewtonConvexCollisionCalculateVolume(m_handles.begin()->second); return volume; } + void Collider3D::ForEachPolygon(const std::function& callback) const + { + auto newtCallback = [](void* const userData, int vertexCount, const dFloat* const faceArray, int /*faceId*/) + { + const auto& cb = *static_cast>(userData); + cb(faceArray, vertexCount); + }; + + // Check for existing collision handles, and create a temporary one if none is available + if (m_handles.empty()) + { + PhysWorld3D world; + + NewtonCollision* collision = CreateHandle(&world); + { + NewtonCollisionForEachPolygonDo(collision, Nz::Matrix4f::Identity(), newtCallback, const_cast(static_cast(&callback))); //< This isn't that bad; pointer will not be used for writing + } + NewtonDestroyCollision(collision); + } + else + NewtonCollisionForEachPolygonDo(m_handles.begin()->second, Nz::Matrix4f::Identity(), newtCallback, const_cast(static_cast(&callback))); //< This isn't that bad; pointer will not be used for writing + } + NewtonCollision* Collider3D::GetHandle(PhysWorld3D* world) const { auto it = m_handles.find(world); @@ -332,7 +355,7 @@ namespace Nz ColliderType3D ConvexCollider3D::GetType() const { - return ColliderType3D_Compound; + return ColliderType3D_ConvexHull; } NewtonCollision* ConvexCollider3D::CreateHandle(PhysWorld3D* world) const diff --git a/src/Nazara/Physics3D/PhysWorld3D.cpp b/src/Nazara/Physics3D/PhysWorld3D.cpp index cc7ab7208..e85ddcf0b 100644 --- a/src/Nazara/Physics3D/PhysWorld3D.cpp +++ b/src/Nazara/Physics3D/PhysWorld3D.cpp @@ -27,7 +27,7 @@ namespace Nz NewtonDestroy(m_world); } - int PhysWorld3D::CreateMaterial(Nz::String name) + int PhysWorld3D::CreateMaterial(String name) { NazaraAssert(m_materialIds.find(name) == m_materialIds.end(), "Material \"" + name + "\" already exists"); @@ -37,13 +37,12 @@ namespace Nz return materialId; } - void PhysWorld3D::ForEachBodyInAABB(const Nz::Boxf& box, const BodyIterator& iterator) + void PhysWorld3D::ForEachBodyInAABB(const Boxf& box, const BodyIterator& iterator) { auto NewtonCallback = [](const NewtonBody* const body, void* const userdata) -> int { - const BodyIterator& iterator = *static_cast(userdata); - RigidBody3D* nzBody = static_cast(NewtonBodyGetUserData(body)); - return iterator(*nzBody); + const BodyIterator& bodyIterator = *static_cast(userdata); + return bodyIterator(*static_cast(NewtonBodyGetUserData(body))); }; NewtonWorldForEachBodyInAABBDo(m_world, box.GetMinimum(), box.GetMaximum(), NewtonCallback, const_cast(static_cast(&iterator))); @@ -59,7 +58,7 @@ namespace Nz return m_world; } - int PhysWorld3D::GetMaterial(const Nz::String& name) + int PhysWorld3D::GetMaterial(const String& name) { auto it = m_materialIds.find(name); NazaraAssert(it != m_materialIds.end(), "Material \"" + name + "\" does not exists"); @@ -99,7 +98,7 @@ namespace Nz void PhysWorld3D::SetMaterialCollisionCallback(int firstMaterial, int secondMaterial, AABBOverlapCallback aabbOverlapCallback, CollisionCallback collisionCallback) { - static_assert(sizeof(Nz::UInt64) >= 2 * sizeof(int), "Oops"); + static_assert(sizeof(UInt64) >= 2 * sizeof(int), "Oops"); auto callbackPtr = std::make_unique(); callbackPtr->aabbOverlapCallback = std::move(aabbOverlapCallback); @@ -107,10 +106,10 @@ namespace Nz NewtonMaterialSetCollisionCallback(m_world, firstMaterial, secondMaterial, callbackPtr.get(), (callbackPtr->aabbOverlapCallback) ? OnAABBOverlap : nullptr, (callbackPtr->collisionCallback) ? ProcessContact : nullptr); - Nz::UInt64 firstMaterialId(firstMaterial); - Nz::UInt64 secondMaterialId(secondMaterial); + UInt64 firstMaterialId(firstMaterial); + UInt64 secondMaterialId(secondMaterial); - Nz::UInt64 callbackIndex = firstMaterialId << 32 | secondMaterialId; + UInt64 callbackIndex = firstMaterialId << 32 | secondMaterialId; m_callbacks[callbackIndex] = std::move(callbackPtr); } @@ -154,8 +153,8 @@ namespace Nz int PhysWorld3D::OnAABBOverlap(const NewtonMaterial* const material, const NewtonBody* const body0, const NewtonBody* const body1, int threadIndex) { - Nz::RigidBody3D* bodyA = static_cast(NewtonBodyGetUserData(body0)); - Nz::RigidBody3D* bodyB = static_cast(NewtonBodyGetUserData(body1)); + RigidBody3D* bodyA = static_cast(NewtonBodyGetUserData(body0)); + RigidBody3D* bodyB = static_cast(NewtonBodyGetUserData(body1)); assert(bodyA && bodyB); Callback* callbackData = static_cast(NewtonMaterialGetMaterialPairUserData(material)); @@ -167,14 +166,14 @@ namespace Nz void PhysWorld3D::ProcessContact(const NewtonJoint* const contactJoint, float timestep, int threadIndex) { - Nz::RigidBody3D* bodyA = static_cast(NewtonBodyGetUserData(NewtonJointGetBody0(contactJoint))); - Nz::RigidBody3D* bodyB = static_cast(NewtonBodyGetUserData(NewtonJointGetBody1(contactJoint))); + RigidBody3D* bodyA = static_cast(NewtonBodyGetUserData(NewtonJointGetBody0(contactJoint))); + RigidBody3D* bodyB = static_cast(NewtonBodyGetUserData(NewtonJointGetBody1(contactJoint))); assert(bodyA && bodyB); using ContactJoint = void*; // Query all joints first, to prevent removing a joint from the list while iterating on it - Nz::StackArray contacts = NazaraStackAllocationNoInit(ContactJoint, NewtonContactJointGetContactCount(contactJoint)); + StackArray contacts = NazaraStackAllocationNoInit(ContactJoint, NewtonContactJointGetContactCount(contactJoint)); std::size_t contactIndex = 0; for (ContactJoint contact = NewtonContactJointGetFirstContact(contactJoint); contact; contact = NewtonContactJointGetNextContact(contactJoint, contact)) { diff --git a/src/Nazara/Physics3D/RigidBody3D.cpp b/src/Nazara/Physics3D/RigidBody3D.cpp index 34e6ce12f..ea6e58621 100644 --- a/src/Nazara/Physics3D/RigidBody3D.cpp +++ b/src/Nazara/Physics3D/RigidBody3D.cpp @@ -266,7 +266,7 @@ namespace Nz return NewtonBodyGetSleepState(m_body) != 0; } - void RigidBody3D::SetAngularDamping(const Nz::Vector3f& angularDamping) + void RigidBody3D::SetAngularDamping(const Vector3f& angularDamping) { NewtonBodySetAngularDamping(m_body, angularDamping); } @@ -345,7 +345,7 @@ namespace Nz NewtonBodySetCentreOfMass(m_body, center); } - void RigidBody3D::SetMaterial(const Nz::String& materialName) + void RigidBody3D::SetMaterial(const String& materialName) { SetMaterial(m_world->GetMaterial(materialName)); } diff --git a/src/Nazara/Platform/Win32/WindowImpl.cpp b/src/Nazara/Platform/Win32/WindowImpl.cpp index 0eb2c670d..07f952e96 100644 --- a/src/Nazara/Platform/Win32/WindowImpl.cpp +++ b/src/Nazara/Platform/Win32/WindowImpl.cpp @@ -501,6 +501,7 @@ namespace Nz event.size.height = size.y; m_parent->PushEvent(event); } + break; } case WM_KEYDOWN: diff --git a/src/Nazara/Utility/Font.cpp b/src/Nazara/Utility/Font.cpp index 63cc28495..a0264b9ee 100644 --- a/src/Nazara/Utility/Font.cpp +++ b/src/Nazara/Utility/Font.cpp @@ -514,8 +514,16 @@ namespace Nz FontGlyph fontGlyph; if (ExtractGlyph(characterSize, character, style, &fontGlyph)) { - glyph.atlasRect.width = fontGlyph.image.GetWidth(); - glyph.atlasRect.height = fontGlyph.image.GetHeight(); + if (fontGlyph.image.IsValid()) + { + glyph.atlasRect.width = fontGlyph.image.GetWidth(); + glyph.atlasRect.height = fontGlyph.image.GetHeight(); + } + else + { + glyph.atlasRect.width = 0; + glyph.atlasRect.height = 0; + } // Insertion du rectangle dans l'un des atlas if (glyph.atlasRect.width > 0 && glyph.atlasRect.height > 0) // Si l'image contient quelque chose diff --git a/src/Nazara/Utility/Formats/MD5AnimParser.cpp b/src/Nazara/Utility/Formats/MD5AnimParser.cpp index 2d343f07c..10acc9975 100644 --- a/src/Nazara/Utility/Formats/MD5AnimParser.cpp +++ b/src/Nazara/Utility/Formats/MD5AnimParser.cpp @@ -250,6 +250,9 @@ namespace Nz m_lineCount++; m_currentLine = m_stream.ReadLine(); + if (m_currentLine.IsEmpty()) + continue; + m_currentLine = m_currentLine.SubStringTo("//"); // On ignore les commentaires m_currentLine.Simplify(); // Pour un traitement plus simple } diff --git a/src/Nazara/Utility/Formats/MD5MeshParser.cpp b/src/Nazara/Utility/Formats/MD5MeshParser.cpp index 0e719c90f..c6af0ed96 100644 --- a/src/Nazara/Utility/Formats/MD5MeshParser.cpp +++ b/src/Nazara/Utility/Formats/MD5MeshParser.cpp @@ -182,6 +182,9 @@ namespace Nz m_lineCount++; m_currentLine = m_stream.ReadLine(); + if (m_currentLine.IsEmpty()) + continue; + m_currentLine = m_currentLine.SubStringTo("//"); // On ignore les commentaires m_currentLine.Simplify(); // Pour un traitement plus simple m_currentLine.Trim(); diff --git a/src/Nazara/Utility/Formats/MTLParser.cpp b/src/Nazara/Utility/Formats/MTLParser.cpp index d001588a4..31a377e38 100644 --- a/src/Nazara/Utility/Formats/MTLParser.cpp +++ b/src/Nazara/Utility/Formats/MTLParser.cpp @@ -251,6 +251,32 @@ namespace Nz currentMaterial->reflectionMap = map; } } + else if (keyword == "map_normal" || keyword == "normal") + { + // This is a custom keyword + std::size_t mapPos = m_currentLine.GetWordPosition(1); + if (mapPos != String::npos) + { + String map = m_currentLine.SubString(mapPos); + if (!currentMaterial) + currentMaterial = AddMaterial("default"); + + currentMaterial->normalMap = map; + } + } + else if (keyword == "map_emissive" || keyword == "emissive") + { + // This is a custom keyword + std::size_t mapPos = m_currentLine.GetWordPosition(1); + if (mapPos != String::npos) + { + String map = m_currentLine.SubString(mapPos); + if (!currentMaterial) + currentMaterial = AddMaterial("default"); + + currentMaterial->emissiveMap = map; + } + } else if (keyword == "newmtl") { String materialName = m_currentLine.SubString(m_currentLine.GetWordPosition(1)); @@ -424,6 +450,9 @@ namespace Nz m_lineCount++; m_currentLine = m_currentStream->ReadLine(); + if (m_currentLine.IsEmpty()) + continue; + m_currentLine = m_currentLine.SubStringTo("#"); // On ignore les commentaires m_currentLine.Simplify(); // Pour un traitement plus simple } diff --git a/src/Nazara/Utility/Formats/OBJLoader.cpp b/src/Nazara/Utility/Formats/OBJLoader.cpp index da69bcac7..43e938bf4 100644 --- a/src/Nazara/Utility/Formats/OBJLoader.cpp +++ b/src/Nazara/Utility/Formats/OBJLoader.cpp @@ -107,6 +107,24 @@ namespace Nz data.SetParameter(MaterialData::DiffuseTexturePath, fullPath); } + if (!mtlMat->emissiveMap.IsEmpty()) + { + String fullPath = mtlMat->emissiveMap; + if (!Nz::File::IsAbsolute(fullPath)) + fullPath.Prepend(baseDir); + + data.SetParameter(MaterialData::EmissiveTexturePath, fullPath); + } + + if (!mtlMat->normalMap.IsEmpty()) + { + String fullPath = mtlMat->normalMap; + if (!Nz::File::IsAbsolute(fullPath)) + fullPath.Prepend(baseDir); + + data.SetParameter(MaterialData::NormalTexturePath, fullPath); + } + if (!mtlMat->specularMap.IsEmpty()) { String fullPath = mtlMat->specularMap; diff --git a/src/Nazara/Utility/Formats/OBJParser.cpp b/src/Nazara/Utility/Formats/OBJParser.cpp index 6827641a9..b4766fc56 100644 --- a/src/Nazara/Utility/Formats/OBJParser.cpp +++ b/src/Nazara/Utility/Formats/OBJParser.cpp @@ -617,6 +617,9 @@ namespace Nz m_lineCount++; m_currentLine = m_currentStream->ReadLine(); + if (m_currentLine.IsEmpty()) + continue; + m_currentLine.Simplify(); // Simplify lines (convert multiple blanks into a single space and trims) } while (m_currentLine.IsEmpty()); diff --git a/src/Nazara/Utility/Image.cpp b/src/Nazara/Utility/Image.cpp index 54c47b5a3..81a810e1a 100644 --- a/src/Nazara/Utility/Image.cpp +++ b/src/Nazara/Utility/Image.cpp @@ -839,7 +839,7 @@ namespace Nz if (pixelCount == 0) return false; - auto seq = workingBitset.Read(GetConstPixels(), info.bitsPerPixel); + auto seq = workingBitset.Write(GetConstPixels(), info.bitsPerPixel); do { workingBitset &= info.alphaMask; @@ -847,7 +847,7 @@ namespace Nz return true; workingBitset.Clear(); - workingBitset.Read(seq, info.bitsPerPixel); + workingBitset.Write(seq, info.bitsPerPixel); } while (--pixelCount > 0); diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 62df4412b..89accf012 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -354,42 +354,38 @@ namespace Nz { glyph.atlas = nullptr; - glyph.bounds.Set(float(m_drawPos.x), float(0.f), float(advance), float(sizeInfo.lineHeight)); + glyph.bounds.Set(float(m_drawPos.x), m_lines.back().bounds.y, float(advance), float(sizeInfo.lineHeight)); glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop)); glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop)); glyph.corners[2].Set(glyph.bounds.GetCorner(RectCorner_LeftBottom)); glyph.corners[3].Set(glyph.bounds.GetCorner(RectCorner_RightBottom)); - - switch (character) - { - 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& 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_workingBounds.ExtendTo(m_lines.back().bounds); - m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1}); - break; - } - } } m_lines.back().bounds.ExtendTo(glyph.bounds); + + switch (character) + { + case '\n': + { + // Reset cursor + advance = 0; + m_drawPos.x = 0; + m_drawPos.y += sizeInfo.lineHeight; + + m_workingBounds.ExtendTo(m_lines.back().bounds); + m_lines.emplace_back(Line{Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1}); + break; + } + + default: + m_drawPos.x += advance; + break; + } - m_drawPos.x += advance; m_glyphs.push_back(glyph); } - m_lines.back().bounds.ExtendTo(m_glyphs.back().bounds); + m_workingBounds.ExtendTo(m_lines.back().bounds); m_bounds.Set(Rectf(std::floor(m_workingBounds.x), std::floor(m_workingBounds.y), std::ceil(m_workingBounds.width), std::ceil(m_workingBounds.height))); diff --git a/tests/Engine/Core/Bitset.cpp b/tests/Engine/Core/Bitset.cpp index 9cbd605b3..ed55392e1 100644 --- a/tests/Engine/Core/Bitset.cpp +++ b/tests/Engine/Core/Bitset.cpp @@ -322,9 +322,9 @@ void CheckRead(const char* title) { Nz::Bitset bitset; - auto seq = bitset.Read(data.data(), pair.second); + auto seq = bitset.Write(data.data(), pair.second); for (std::size_t i = pair.second; i < bitCount; i += pair.second) - seq = bitset.Read(seq, pair.second); + seq = bitset.Write(seq, pair.second); REQUIRE(bitset.GetSize() == bitCount); diff --git a/tests/Engine/Core/ObjectHandle.cpp b/tests/Engine/Core/ObjectHandle.cpp new file mode 100644 index 000000000..cffce4ecd --- /dev/null +++ b/tests/Engine/Core/ObjectHandle.cpp @@ -0,0 +1,140 @@ +#include +#include +#include + +struct ObjectHandle_Test : public Nz::HandledObject +{ + ObjectHandle_Test(int value) : + i(value) + { + } + + int i; +}; + +SCENARIO("Handle", "[CORE][HandledObject][ObjectHandle]") +{ + GIVEN("One test with two handles") + { + int defaultValue = 1; + ObjectHandle_Test test(defaultValue); + + Nz::ObjectHandle handle1 = test.CreateHandle(); + Nz::ObjectHandle handle2 = test.CreateHandle(); + + WHEN("We modify from one") + { + const int newI = 2; + handle1->i = newI; + + THEN("The other one should also be modified") + { + REQUIRE(handle2->i == newI); + } + } + + WHEN("We copy construct") + { + ObjectHandle_Test other(test); + Nz::ObjectHandle otherHandle = other.CreateHandle(); + + THEN("Handles should point to 1") + { + CHECK(handle1->i == defaultValue); + CHECK(handle2->i == defaultValue); + CHECK(otherHandle->i == defaultValue); + CHECK(handle2.GetObject() == &test); + CHECK(otherHandle.GetObject() == &other); + } + } + + WHEN("We move construct") + { + ObjectHandle_Test other(std::move(test)); + Nz::ObjectHandle otherHandle = other.CreateHandle(); + + THEN("Handles should point to 1") + { + CHECK(handle1->i == defaultValue); + CHECK(handle2->i == defaultValue); + CHECK(otherHandle->i == defaultValue); + CHECK(handle1.GetObject() == &other); + } + } + + WHEN("We copy assign") + { + int copyValue = 3; + ObjectHandle_Test other(copyValue); + Nz::ObjectHandle otherHandle = other.CreateHandle(); + test = other; + + THEN("Handles should point to 3") + { + CHECK(handle1->i == copyValue); + CHECK(handle2->i == copyValue); + CHECK(otherHandle->i == copyValue); + CHECK(handle1.GetObject() == &test); + CHECK(otherHandle.GetObject() == &other); + } + } + + WHEN("We move assign") + { + int moveValue = 4; + ObjectHandle_Test other(moveValue); + Nz::ObjectHandle otherHandle = other.CreateHandle(); + test = std::move(other); + + THEN("Handles to previous objects should be invalid") + { + CHECK_FALSE(handle1.IsValid()); + CHECK_FALSE(handle2.IsValid()); + } + + THEN("Handles should point to 4") + { + CHECK(otherHandle.GetObject() == &test); + CHECK(otherHandle->i == moveValue); + } + } + } + + GIVEN("One handle pointing to a default test") + { + ObjectHandle_Test test(1); + Nz::ObjectHandle invalidHandle(&test); + + WHEN("We bind it to a HandledObject which is going to die") + { + { + ObjectHandle_Test dyingTest(5); + invalidHandle.Reset(&dyingTest); + } + + THEN("It should not be valid") + { + REQUIRE(!invalidHandle.IsValid()); + } + } + } + + GIVEN("Two handle pointing to two different tests") + { + ObjectHandle_Test test1(1); + Nz::ObjectHandle test1Handle = test1.CreateHandle(); + ObjectHandle_Test test2(2); + Nz::ObjectHandle test2Handle = test2.CreateHandle(); + + WHEN("We swap their content") + { + test1Handle.Swap(test2Handle); + + THEN("They should be pointing to the correct one") + { + CHECK(test1Handle.GetObject() == &test2); + CHECK(test2Handle.GetObject() == &test1); + } + } + } +} diff --git a/tests/Engine/Lua/LuaClass.cpp b/tests/Engine/Lua/LuaClass.cpp index b6963a3bd..5cddb3cb1 100644 --- a/tests/Engine/Lua/LuaClass.cpp +++ b/tests/Engine/Lua/LuaClass.cpp @@ -3,15 +3,15 @@ #include #include -class Test +class LuaClass_Test { public: - Test() = default; - Test(const Test& other) = default; - Test& operator=(const Test& other) = default; - virtual ~Test() = default; + LuaClass_Test() = default; + LuaClass_Test(const LuaClass_Test& other) = default; + LuaClass_Test& operator=(const LuaClass_Test& other) = default; + virtual ~LuaClass_Test() = default; - Test(int i, bool j = false) : + LuaClass_Test(int i, bool j = false) : m_i(i), m_j(j) { @@ -42,21 +42,21 @@ class Test bool m_j; }; -class InheritTest : public Test +class LuaClass_InheritTest : public LuaClass_Test { public: - InheritTest() : - Test(5, true) + LuaClass_InheritTest() : + LuaClass_Test(5, true) { } int GetI() const override { - return Test::GetI() + 3; + return LuaClass_Test::GetI() + 3; } }; -class TestWithHandle : public Nz::HandledObject +class LuaClass_TestWithHandle : public Nz::HandledObject { public: int GetI() const @@ -73,24 +73,24 @@ class TestWithHandle : public Nz::HandledObject int m_i = 8; }; -inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, Test* arg, Nz::TypeTag) +inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, LuaClass_Test* arg, Nz::TypeTag) { REQUIRE(instance.IsOfType(index, "Test")); - *arg = *static_cast(instance.ToUserdata(index)); + *arg = *static_cast(instance.ToUserdata(index)); return 1; } -inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, Nz::ObjectHandle* arg, Nz::TypeTag>) +inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, Nz::ObjectHandle* arg, Nz::TypeTag>) { REQUIRE(instance.IsOfType(index, "TestWithHandle")); - *arg = *static_cast*>(instance.ToUserdata(index)); + *arg = *static_cast*>(instance.ToUserdata(index)); return 1; } -inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, InheritTest* arg, Nz::TypeTag) +inline unsigned int LuaImplQueryArg(const Nz::LuaState& instance, int index, LuaClass_InheritTest* arg, Nz::TypeTag) { REQUIRE(instance.IsOfType(index, "InheritTest")); - *arg = *static_cast(instance.ToUserdata(index)); + *arg = *static_cast(instance.ToUserdata(index)); return 1; } @@ -99,9 +99,9 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") GIVEN("One lua class for our Test class") { Nz::LuaInstance luaInstance; - Nz::LuaClass test; - Nz::LuaClass inheritTest; - using TestHandle = Nz::ObjectHandle; + Nz::LuaClass test; + Nz::LuaClass inheritTest; + using TestHandle = Nz::ObjectHandle; Nz::LuaClass testHandle; WHEN("We bind the methods") @@ -110,7 +110,7 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") test.BindDefaultConstructor(); - test.SetConstructor([] (Nz::LuaState& lua, Test* instance, std::size_t argumentCount) + test.SetConstructor([] (Nz::LuaState& lua, LuaClass_Test* instance, std::size_t argumentCount) { std::size_t argCount = std::min(argumentCount, 2U); @@ -139,14 +139,14 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") return false; }); - test.BindMethod("GetI", &Test::GetI); - test.BindMethod("GetJ", &Test::GetJ); - test.BindMethod("GetDefault", &Test::GetDefault, 0); + test.BindMethod("GetI", &LuaClass_Test::GetI); + test.BindMethod("GetJ", &LuaClass_Test::GetJ); + test.BindMethod("GetDefault", &LuaClass_Test::GetDefault, 0); test.BindStaticMethod("StaticMethodWithArguments", [] (Nz::LuaState& state) -> int { int argIndex = 1; - int result = Test::StaticMethodWithArguments(state.Check(&argIndex), state.Check(&argIndex)); + int result = LuaClass_Test::StaticMethodWithArguments(state.Check(&argIndex), state.Check(&argIndex)); state.Push(result); return 1; @@ -162,7 +162,7 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") luaInstance.PushFunction([=](Nz::LuaState& state) -> int { int argIndex = 1; - Test result = state.Check(&argIndex); + LuaClass_Test result = state.Check(&argIndex); CHECK(result.GetI() == value); CHECK_FALSE(result.GetJ()); return 1; @@ -181,7 +181,7 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") luaInstance.PushFunction([=](Nz::LuaState& state) -> int { int argIndex = 1; - Test result = state.Check(&argIndex); + LuaClass_Test result = state.Check(&argIndex); CHECK(result.GetI() == staticResult); CHECK(result.GetJ()); return 1; @@ -205,7 +205,7 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") luaInstance.PushFunction([=](Nz::LuaState& state) -> int { int argIndex = 1; - InheritTest result = state.Check(&argIndex); + LuaClass_InheritTest result = state.Check(&argIndex); CHECK(result.GetI() == 8); CHECK(result.GetJ()); return 1; @@ -224,8 +224,8 @@ SCENARIO("LuaClass", "[LUA][LUACLASS]") testHandle.Reset("TestHandle"); testHandle.BindMethod("IsValid", &TestHandle::IsValid); - testHandle.BindMethod("GetI", &TestWithHandle::GetI); - testHandle.BindMethod("GetDefault", &TestWithHandle::GetDefault, defaultValue); + testHandle.BindMethod("GetI", &LuaClass_TestWithHandle::GetI); + testHandle.BindMethod("GetDefault", &LuaClass_TestWithHandle::GetDefault, defaultValue); testHandle.Register(luaInstance); THEN("We can ensure the following properties") diff --git a/tests/Engine/Math/Vector3.cpp b/tests/Engine/Math/Vector3.cpp index 2bcfbd361..faeb03cca 100644 --- a/tests/Engine/Math/Vector3.cpp +++ b/tests/Engine/Math/Vector3.cpp @@ -104,8 +104,7 @@ SCENARIO("Vector3", "[MATH][VECTOR3]") Nz::Vector2f unit = Nz::Vector2f::Unit(); Nz::Vector3f smaller(-1.f, unit); - float data[3] = { 1.f, unit.x, unit.y }; - Nz::Vector3f bigger(data); + Nz::Vector3f bigger(1.f, unit.x, unit.y); WHEN("We combine divisions and multiplications") { diff --git a/thirdparty/build/chipmunk.lua b/thirdparty/build/chipmunk.lua index a4793da43..cb3b27ba0 100644 --- a/thirdparty/build/chipmunk.lua +++ b/thirdparty/build/chipmunk.lua @@ -1,6 +1,14 @@ LIBRARY.Name = "chipmunk" -LIBRARY.Defines = {"CP_USE_CGTYPES=0", "TARGET_OS_IPHONE=0", "TARGET_OS_MAC=0"} +LIBRARY.Defines = { + "CP_USE_CGTYPES=0", + "DRAW_CLOSEST=0", + "DRAW_EPA=0", + "DRAW_GJK=0", + "TARGET_IPHONE_SIMULATOR=0", + "TARGET_OS_IPHONE=0", + "TARGET_OS_MAC=0", +} LIBRARY.Language = "C++"