Merge branch 'master' into vulkan
This commit is contained in:
@@ -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<std::size_t>::max();
|
||||
|
||||
std::size_t m_canvasIndex;
|
||||
std::vector<EntityOwner> m_entities;
|
||||
std::vector<WidgetEntity> m_entities;
|
||||
std::vector<std::unique_ptr<BaseWidget>> m_children;
|
||||
Canvas* m_canvas;
|
||||
EntityOwner m_backgroundEntity;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <NDK/Components/CameraComponent.hpp>
|
||||
#include <NDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NDK/Components/ConstraintComponent2D.hpp>
|
||||
#include <NDK/Components/DebugComponent.hpp>
|
||||
#include <NDK/Components/GraphicsComponent.hpp>
|
||||
#include <NDK/Components/LightComponent.hpp>
|
||||
#include <NDK/Components/ListenerComponent.hpp>
|
||||
@@ -17,6 +19,5 @@
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NDK/Components/VelocityComponent.hpp>
|
||||
#include <NDK/Components/ConstraintComponent2D.hpp>
|
||||
|
||||
#endif // NDK_COMPONENTS_GLOBAL_HPP
|
||||
|
||||
80
SDK/include/NDK/Components/DebugComponent.hpp
Normal file
80
SDK/include/NDK/Components/DebugComponent.hpp
Normal file
@@ -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 <Nazara/Core/Flags.hpp>
|
||||
#include <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
#include <NDK/Component.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
enum class DebugDraw
|
||||
{
|
||||
//TODO: Collider2D
|
||||
Collider3D,
|
||||
GraphicsAABB,
|
||||
GraphicsOBB,
|
||||
|
||||
Max = GraphicsOBB
|
||||
};
|
||||
}
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
template<>
|
||||
struct EnumAsFlags<Ndk::DebugDraw>
|
||||
{
|
||||
static constexpr Ndk::DebugDraw max = Ndk::DebugDraw::GraphicsOBB;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
using DebugDrawFlags = Nz::Flags<DebugDraw>;
|
||||
|
||||
constexpr DebugDrawFlags DebugDraw_None = 0;
|
||||
|
||||
class NDK_API DebugComponent : public Component<DebugComponent>
|
||||
{
|
||||
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<std::size_t>(DebugDraw::Max) + 1;
|
||||
|
||||
std::array<Nz::InstancedRenderableRef, DebugModeCount> m_debugRenderables;
|
||||
DebugDrawFlags m_enabledFlags;
|
||||
DebugDrawFlags m_flags;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NDK/Components/DebugComponent.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_DEBUGCOMPONENT_HPP
|
||||
#endif // NDK_SERVER
|
||||
74
SDK/include/NDK/Components/DebugComponent.inl
Normal file
74
SDK/include/NDK/Components/DebugComponent.inl
Normal file
@@ -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 <NDK/Components/DebugComponent.hpp>
|
||||
|
||||
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<std::size_t>(option)];
|
||||
}
|
||||
|
||||
inline DebugDrawFlags DebugComponent::GetEnabledFlags() const
|
||||
{
|
||||
return m_enabledFlags;
|
||||
}
|
||||
|
||||
inline void DebugComponent::UpdateDebugRenderable(DebugDraw option, Nz::InstancedRenderableRef renderable)
|
||||
{
|
||||
m_debugRenderables[static_cast<std::size_t>(option)] = std::move(renderable);
|
||||
}
|
||||
|
||||
inline void DebugComponent::UpdateEnabledFlags(DebugDrawFlags flags)
|
||||
{
|
||||
m_enabledFlags = flags;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace Ndk
|
||||
public:
|
||||
using RenderableList = std::vector<Nz::InstancedRenderableRef>;
|
||||
|
||||
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<const Nz::Material*, MaterialEntry> 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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <Nazara/Core/MovablePtr.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <NDK/Algorithm.hpp>
|
||||
#include <NDK/Prerequisites.hpp>
|
||||
@@ -33,7 +34,7 @@ namespace Ndk
|
||||
|
||||
public:
|
||||
Entity(const Entity&) = delete;
|
||||
Entity(Entity&& entity);
|
||||
Entity(Entity&& entity) noexcept;
|
||||
~Entity();
|
||||
|
||||
BaseComponent& AddComponent(std::unique_ptr<BaseComponent>&& component);
|
||||
@@ -96,8 +97,8 @@ namespace Ndk
|
||||
Nz::Bitset<> m_componentBits;
|
||||
Nz::Bitset<> m_removedComponentBits;
|
||||
Nz::Bitset<> m_systemBits;
|
||||
Nz::MovablePtr<World> m_world;
|
||||
EntityId m_id;
|
||||
World* m_world;
|
||||
bool m_enabled;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#ifndef NDK_SYSTEMS_GLOBAL_HPP
|
||||
#define NDK_SYSTEMS_GLOBAL_HPP
|
||||
|
||||
#include <NDK/Systems/DebugSystem.hpp>
|
||||
#include <NDK/Systems/ListenerSystem.hpp>
|
||||
#include <NDK/Systems/ParticleSystem.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||
|
||||
51
SDK/include/NDK/Systems/DebugSystem.hpp
Normal file
51
SDK/include/NDK/Systems/DebugSystem.hpp
Normal file
@@ -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 <Nazara/Graphics/InstancedRenderable.hpp>
|
||||
#include <Nazara/Utility/IndexBuffer.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/VertexBuffer.hpp>
|
||||
#include <NDK/System.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API DebugSystem : public System<DebugSystem>
|
||||
{
|
||||
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<Nz::IndexBufferRef, Nz::VertexBufferRef> 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 <NDK/Systems/DebugSystem.inl>
|
||||
|
||||
#endif // NDK_SYSTEMS_DEBUGSYSTEM_HPP
|
||||
#endif // NDK_SERVER
|
||||
6
SDK/include/NDK/Systems/DebugSystem.inl
Normal file
6
SDK/include/NDK/Systems/DebugSystem.inl
Normal file
@@ -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 <NDK/Systems/DebugSystem.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;
|
||||
};
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <Nazara/Utility/SimpleTextDrawer.hpp>
|
||||
#include <NDK/BaseWidget.hpp>
|
||||
#include <NDK/Widgets/Enums.hpp>
|
||||
#include <vector>
|
||||
|
||||
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<Nz::SpriteRef> m_cursorSprites;
|
||||
bool m_isMouseButtonDown;
|
||||
bool m_multiLineEnabled;
|
||||
bool m_readOnly;
|
||||
};
|
||||
|
||||
@@ -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<unsigned int>(line);
|
||||
cursorPos.x = static_cast<unsigned int>(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<std::size_t>(offset));
|
||||
else
|
||||
@@ -104,7 +133,7 @@ namespace Ndk
|
||||
}
|
||||
};
|
||||
|
||||
Nz::Vector2ui cursorPosition = m_cursorPosition;
|
||||
Nz::Vector2ui cursorPosition = m_cursorPositionBegin;
|
||||
cursorPosition.x = ClampOffset(static_cast<unsigned int>(cursorPosition.x), offset.x);
|
||||
cursorPosition.y = ClampOffset(static_cast<unsigned int>(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<unsigned int>(line);
|
||||
m_cursorPosition.x = static_cast<unsigned int>(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<unsigned int>(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<unsigned int>(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;
|
||||
|
||||
@@ -50,11 +50,16 @@ namespace Ndk
|
||||
inline void DisableProfiler();
|
||||
inline void EnableProfiler(bool enable = true);
|
||||
|
||||
template<typename F> void ForEachSystem(const F& iterationFunc);
|
||||
template<typename F> 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<typename SystemType> SystemType& GetSystem();
|
||||
template<typename SystemType> const SystemType& GetSystem() const;
|
||||
|
||||
inline bool HasSystem(SystemIndex index) const;
|
||||
template<typename SystemType> bool HasSystem() const;
|
||||
|
||||
@@ -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<typename F>
|
||||
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<typename F>
|
||||
void World::ForEachSystem(const F& iterationFunc) const
|
||||
{
|
||||
for (const auto& systemPtr : m_systems)
|
||||
{
|
||||
if (systemPtr)
|
||||
iterationFunc(static_cast<const Ndk::BaseSystem&>(*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<typename SystemType>
|
||||
SystemType& World::GetSystem()
|
||||
{
|
||||
@@ -206,6 +256,21 @@ namespace Ndk
|
||||
return static_cast<SystemType&>(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<typename SystemType>
|
||||
const SystemType& World::GetSystem() const
|
||||
{
|
||||
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a system");
|
||||
|
||||
SystemIndex index = GetSystemIndex<SystemType>();
|
||||
return static_cast<const SystemType&>(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)
|
||||
|
||||
@@ -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<GraphicsComponent>().Attach(m_backgroundSprite, -1);
|
||||
m_backgroundEntity->AddComponent<NodeComponent>().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<GraphicsComponent>())
|
||||
entity->GetComponent<GraphicsComponent>().SetScissorRect((widgetEntity.isContent) ? contentBounds : fullBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace Ndk
|
||||
Nz::PhysWorld2D& physWorld = entityWorld->GetSystem<PhysicsSystem2D>().GetWorld();
|
||||
|
||||
m_staticBody = std::make_unique<Nz::RigidBody2D>(&physWorld, 0.f, m_geom);
|
||||
m_staticBody->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
|
||||
Nz::Matrix4f matrix;
|
||||
if (m_entity->HasComponent<NodeComponent>())
|
||||
|
||||
10
SDK/src/NDK/Components/DebugComponent.cpp
Normal file
10
SDK/src/NDK/Components/DebugComponent.cpp
Normal file
@@ -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 <NDK/Components/DebugComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
ComponentIndex DebugComponent::componentIndex;
|
||||
}
|
||||
@@ -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<RenderSystem>();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <NDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <memory>
|
||||
|
||||
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<Nz::RigidBody2D>(&world, 1.f, geom);
|
||||
m_object->SetPosition(Nz::Vector2f(matrix.GetTranslation()));
|
||||
m_object->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -28,11 +28,13 @@
|
||||
|
||||
#ifndef NDK_SERVER
|
||||
#include <NDK/Components/CameraComponent.hpp>
|
||||
#include <NDK/Components/DebugComponent.hpp>
|
||||
#include <NDK/Components/LightComponent.hpp>
|
||||
#include <NDK/Components/ListenerComponent.hpp>
|
||||
#include <NDK/Components/GraphicsComponent.hpp>
|
||||
#include <NDK/Components/ParticleEmitterComponent.hpp>
|
||||
#include <NDK/Components/ParticleGroupComponent.hpp>
|
||||
#include <NDK/Systems/DebugSystem.hpp>
|
||||
#include <NDK/Systems/ParticleSystem.hpp>
|
||||
#include <NDK/Systems/ListenerSystem.hpp>
|
||||
#include <NDK/Systems/RenderSystem.hpp>
|
||||
@@ -95,6 +97,7 @@ namespace Ndk
|
||||
#ifndef NDK_SERVER
|
||||
// Client components
|
||||
InitializeComponent<CameraComponent>("NdkCam");
|
||||
InitializeComponent<DebugComponent>("NdkDebug");
|
||||
InitializeComponent<LightComponent>("NdkLight");
|
||||
InitializeComponent<ListenerComponent>("NdkList");
|
||||
InitializeComponent<GraphicsComponent>("NdkGfx");
|
||||
@@ -113,6 +116,7 @@ namespace Ndk
|
||||
|
||||
#ifndef NDK_SERVER
|
||||
// Client systems
|
||||
InitializeSystem<DebugSystem>();
|
||||
InitializeSystem<ListenerSystem>();
|
||||
InitializeSystem<ParticleSystem>();
|
||||
InitializeSystem<RenderSystem>();
|
||||
|
||||
366
SDK/src/NDK/Systems/DebugSystem.cpp
Normal file
366
SDK/src/NDK/Systems/DebugSystem.cpp
Normal file
@@ -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 <NDK/Systems/DebugSystem.hpp>
|
||||
#include <Nazara/Core/Primitive.hpp>
|
||||
#include <Nazara/Graphics/Model.hpp>
|
||||
#include <Nazara/Utility/IndexIterator.hpp>
|
||||
#include <Nazara/Utility/Mesh.hpp>
|
||||
#include <Nazara/Utility/StaticMesh.hpp>
|
||||
#include <NDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NDK/Components/DebugComponent.hpp>
|
||||
#include <NDK/Components/GraphicsComponent.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
|
||||
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<DebugComponent>();
|
||||
const GraphicsComponent& entityGfx = m_entityOwner->GetComponent<GraphicsComponent>();
|
||||
|
||||
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<DebugComponent>();
|
||||
const GraphicsComponent& entityGfx = m_entityOwner->GetComponent<GraphicsComponent>();
|
||||
|
||||
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<DebugComponent, GraphicsComponent>();
|
||||
SetUpdateOrder(1000); //< Update last
|
||||
}
|
||||
|
||||
std::pair<Nz::IndexBufferRef, Nz::VertexBufferRef> DebugSystem::GetBoxMesh()
|
||||
{
|
||||
if (!m_boxMeshIndexBuffer)
|
||||
{
|
||||
std::array<Nz::UInt16, 24> 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<Nz::Vector3f, 8> 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<DebugComponent>();
|
||||
GraphicsComponent& entityGfx = entity->GetComponent<GraphicsComponent>();
|
||||
|
||||
DebugDrawFlags enabledFlags = entityDebug.GetEnabledFlags();
|
||||
DebugDrawFlags flags = entityDebug.GetFlags();
|
||||
|
||||
DebugDrawFlags flagsToEnable = flags & ~enabledFlags;
|
||||
for (std::size_t i = 0; i <= static_cast<std::size_t>(DebugDraw::Max); ++i)
|
||||
{
|
||||
DebugDraw option = static_cast<DebugDraw>(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<std::size_t>(DebugDraw::Max); ++i)
|
||||
{
|
||||
DebugDraw option = static_cast<DebugDraw>(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>())
|
||||
{
|
||||
CollisionComponent3D& entityCollision = entity->GetComponent<CollisionComponent3D>();
|
||||
const Nz::Collider3DRef& geom = entityCollision.GetGeom();
|
||||
|
||||
std::vector<Nz::Vector3f> vertices;
|
||||
std::vector<std::size_t> 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<Nz::UInt32>(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;
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <NDK/Components/ListenerComponent.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Components/VelocityComponent.hpp>
|
||||
|
||||
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<NodeComponent>();
|
||||
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<VelocityComponent>())
|
||||
{
|
||||
const VelocityComponent& velocity = entity->GetComponent<VelocityComponent>();
|
||||
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++;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<NodeComponent>().SetParent(this);
|
||||
m_gradientEntity->AddComponent<GraphicsComponent>().Attach(m_gradientSprite);
|
||||
|
||||
m_textSprite = Nz::TextSprite::New();
|
||||
|
||||
m_textEntity = CreateEntity();
|
||||
m_textEntity = CreateEntity(true);
|
||||
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
m_textEntity->AddComponent<GraphicsComponent>().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<NodeComponent>().SetPosition(origin);
|
||||
m_gradientSprite->SetSize(contentSize);
|
||||
|
||||
Nz::Boxf textBox = m_textEntity->GetComponent<GraphicsComponent>().GetBoundingVolume().obb.localBox;
|
||||
m_textEntity->GetComponent<NodeComponent>().SetPosition(origin.x + contentSize.x / 2 - textBox.width / 2, origin.y + contentSize.y / 2 - textBox.height / 2);
|
||||
}
|
||||
|
||||
@@ -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<NodeComponent>().SetParent(this);
|
||||
m_checkboxBorderEntity->AddComponent<GraphicsComponent>().Attach(m_checkboxBorderSprite);
|
||||
|
||||
m_checkboxBackgroundEntity = CreateEntity();
|
||||
m_checkboxBackgroundEntity = CreateEntity(false);
|
||||
m_checkboxBackgroundEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
m_checkboxBackgroundEntity->AddComponent<GraphicsComponent>().Attach(m_checkboxBackgroundSprite, 1);
|
||||
|
||||
m_checkboxContentEntity = CreateEntity();
|
||||
m_checkboxContentEntity = CreateEntity(true);
|
||||
m_checkboxContentEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
m_checkboxContentEntity->AddComponent<GraphicsComponent>().Attach(m_checkboxContentSprite, 2);
|
||||
|
||||
m_textEntity = CreateEntity();
|
||||
m_textEntity = CreateEntity(true);
|
||||
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Ndk
|
||||
ImageWidget::ImageWidget(BaseWidget* parent) :
|
||||
BaseWidget(parent)
|
||||
{
|
||||
m_entity = CreateEntity();
|
||||
m_entity = CreateEntity(true);
|
||||
m_entity->AddComponent<NodeComponent>();
|
||||
auto& gfx = m_entity->AddComponent<GraphicsComponent>();
|
||||
|
||||
|
||||
@@ -13,13 +13,20 @@ namespace Ndk
|
||||
{
|
||||
m_textSprite = Nz::TextSprite::New();
|
||||
|
||||
m_textEntity = CreateEntity();
|
||||
m_textEntity = CreateEntity(true);
|
||||
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
|
||||
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
|
||||
Layout();
|
||||
}
|
||||
|
||||
void LabelWidget::Layout()
|
||||
{
|
||||
BaseWidget::Layout();
|
||||
|
||||
m_textEntity->GetComponent<NodeComponent>().SetPosition(GetContentOrigin());
|
||||
}
|
||||
|
||||
void LabelWidget::ResizeToContent()
|
||||
{
|
||||
SetContentSize(Nz::Vector2f(m_textSprite->GetBoundingVolume().obb.localBox.GetLengths()));
|
||||
|
||||
@@ -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<NodeComponent>().SetParent(this);
|
||||
m_borderEntity->AddComponent<GraphicsComponent>().Attach(m_borderSprite);
|
||||
|
||||
m_barEntity = CreateEntity();
|
||||
m_barEntity = CreateEntity(true);
|
||||
m_barEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
GraphicsComponent& graphics = m_barEntity->AddComponent<GraphicsComponent>();
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace Ndk
|
||||
|
||||
|
||||
m_textSprite = Nz::TextSprite::New();
|
||||
m_textEntity = CreateEntity();
|
||||
m_textEntity = CreateEntity(true);
|
||||
|
||||
m_textEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
|
||||
|
||||
@@ -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<GraphicsComponent>().Attach(m_cursorSprite, 10);
|
||||
m_cursorEntity = CreateEntity(true);
|
||||
m_cursorEntity->AddComponent<GraphicsComponent>();
|
||||
m_cursorEntity->AddComponent<NodeComponent>().SetParent(this);
|
||||
m_cursorEntity->Enable(false);
|
||||
|
||||
m_textSprite = Nz::TextSprite::New();
|
||||
|
||||
m_textEntity = CreateEntity();
|
||||
m_textEntity = CreateEntity(true);
|
||||
m_textEntity->AddComponent<GraphicsComponent>().Attach(m_textSprite);
|
||||
m_textEntity->AddComponent<NodeComponent>().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<unsigned int>(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<NodeComponent>().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<NodeComponent>().SetPosition(contentOrigin.x + position, contentOrigin.y + lineInfo.bounds.y);
|
||||
GraphicsComponent& gfxComponent = m_cursorEntity->GetComponent<GraphicsComponent>();
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <NDK/Systems/VelocitySystem.hpp>
|
||||
|
||||
#ifndef NDK_SERVER
|
||||
#include <NDK/Systems/DebugSystem.hpp>
|
||||
#include <NDK/Systems/ListenerSystem.hpp>
|
||||
#include <NDK/Systems/ParticleSystem.hpp>
|
||||
#include <NDK/Systems/RenderSystem.hpp>
|
||||
@@ -47,6 +48,7 @@ namespace Ndk
|
||||
AddSystem<VelocitySystem>();
|
||||
|
||||
#ifndef NDK_SERVER
|
||||
AddSystem<DebugSystem>();
|
||||
AddSystem<ListenerSystem>();
|
||||
AddSystem<ParticleSystem>();
|
||||
AddSystem<RenderSystem>();
|
||||
|
||||
Reference in New Issue
Block a user