diff --git a/ChangeLog.md b/ChangeLog.md index 23ce656dd..bc2e3ea88 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -218,6 +218,7 @@ Nazara Engine: - ⚠ OBJLoader flips UV by default, fixing a lot of models UV - On Windows, Thread::Set(Current)Name now uses `SetThreadDescription` Win32 function if possible instead of triggering a debugger exception. MinGW builds will use this if available too. - ⚠ Removed Texture(const Image\*) constructor, use Texture::LoadFromImage instead +- ⚠ TextDrawers now use floating-point internally and to exposes their Bounds (AbstractTextDrawer::GetBounds() now returns a Rectf) Nazara Development Kit: - Added ImageWidget (#139) diff --git a/include/Nazara/Graphics/TextSprite.hpp b/include/Nazara/Graphics/TextSprite.hpp index 3811fea95..1826aa21b 100644 --- a/include/Nazara/Graphics/TextSprite.hpp +++ b/include/Nazara/Graphics/TextSprite.hpp @@ -102,7 +102,7 @@ namespace Nz mutable std::unordered_map m_renderInfos; mutable std::vector m_localVertices; Color m_color; - Recti m_localBounds; + Rectf m_localBounds; float m_scale; static TextSpriteLibrary::LibraryMap s_library; diff --git a/include/Nazara/Graphics/TextSprite.inl b/include/Nazara/Graphics/TextSprite.inl index 04a3c1170..97b17d888 100644 --- a/include/Nazara/Graphics/TextSprite.inl +++ b/include/Nazara/Graphics/TextSprite.inl @@ -14,7 +14,7 @@ namespace Nz inline TextSprite::TextSprite() : m_color(Color::White), - m_localBounds(Nz::Recti::Zero()), + m_localBounds(Nz::Rectf::Zero()), m_scale(1.f) { ResetMaterials(1U); diff --git a/include/Nazara/Utility/AbstractTextDrawer.hpp b/include/Nazara/Utility/AbstractTextDrawer.hpp index 37204897a..e62338c61 100644 --- a/include/Nazara/Utility/AbstractTextDrawer.hpp +++ b/include/Nazara/Utility/AbstractTextDrawer.hpp @@ -29,7 +29,7 @@ namespace Nz virtual void Clear() = 0; - virtual const Recti& GetBounds() const = 0; + virtual const Rectf& GetBounds() const = 0; virtual Font* GetFont(std::size_t index) const = 0; virtual std::size_t GetFontCount() const = 0; virtual const Glyph& GetGlyph(std::size_t index) const = 0; diff --git a/include/Nazara/Utility/RichTextDrawer.hpp b/include/Nazara/Utility/RichTextDrawer.hpp index 2a1709d8c..67f5ec0de 100644 --- a/include/Nazara/Utility/RichTextDrawer.hpp +++ b/include/Nazara/Utility/RichTextDrawer.hpp @@ -43,7 +43,7 @@ namespace Nz inline const String& GetBlockText(std::size_t index) const; inline BlockRef GetBlock(std::size_t index); - const Recti& GetBounds() const override; + const Rectf& GetBounds() const override; inline unsigned int GetDefaultCharacterSize() const; inline const Color& GetDefaultColor() const; inline const FontRef& GetDefaultFont() const; @@ -86,14 +86,11 @@ namespace Nz static constexpr std::size_t InvalidBlockIndex = std::numeric_limits::max(); - //static RichTextDrawer Draw(const String& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); - //static RichTextDrawer Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style = TextStyle_Regular, const Color& color = Color::White); - private: struct Block; inline void AppendNewLine(const Font* font, unsigned int characterSize) const; - void AppendNewLine(const Font* font, unsigned int characterSize, std::size_t glyphIndex, unsigned int glyphPosition) const; + void AppendNewLine(const Font* font, unsigned int characterSize, std::size_t glyphIndex, float glyphPosition) const; inline void ClearGlyphs() const; inline void ConnectFontSlots(); inline void DisconnectFontSlots(); @@ -145,14 +142,13 @@ namespace Nz std::vector m_fonts; mutable std::vector m_glyphs; mutable std::vector m_lines; - mutable Rectf m_workingBounds; - mutable Recti m_bounds; - mutable Vector2ui m_drawPos; + mutable Rectf m_bounds; + mutable Vector2f m_drawPos; mutable bool m_glyphUpdated; float m_defaultOutlineThickness; float m_maxLineWidth; unsigned int m_defaultCharacterSize; - mutable unsigned int m_lastSeparatorPosition; + mutable float m_lastSeparatorPosition; }; class RichTextDrawer::BlockRef diff --git a/include/Nazara/Utility/RichTextDrawer.inl b/include/Nazara/Utility/RichTextDrawer.inl index e2916d475..ef49a0457 100644 --- a/include/Nazara/Utility/RichTextDrawer.inl +++ b/include/Nazara/Utility/RichTextDrawer.inl @@ -148,7 +148,7 @@ namespace Nz m_lines.clear(); m_glyphs.clear(); m_glyphUpdated = true; - m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly) + m_bounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly) } inline void RichTextDrawer::ConnectFontSlots() diff --git a/include/Nazara/Utility/SimpleTextDrawer.hpp b/include/Nazara/Utility/SimpleTextDrawer.hpp index 6404e72e2..304142d6e 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.hpp +++ b/include/Nazara/Utility/SimpleTextDrawer.hpp @@ -28,7 +28,7 @@ namespace Nz void Clear() override; - const Recti& GetBounds() const override; + const Rectf& GetBounds() const override; inline unsigned int GetCharacterSize() const; inline const Color& GetColor() const; inline Font* GetFont() const; @@ -38,6 +38,7 @@ namespace Nz std::size_t GetGlyphCount() const override; const Line& GetLine(std::size_t index) const override; std::size_t GetLineCount() const override; + inline float GetLineHeight() const; float GetMaxLineWidth() const override; inline const Color& GetOutlineColor() const; inline float GetOutlineThickness() const; @@ -64,7 +65,7 @@ namespace Nz private: inline void AppendNewLine() const; - void AppendNewLine(std::size_t glyphIndex, unsigned int glyphPosition) const; + void AppendNewLine(std::size_t glyphIndex, float glyphPosition) const; void ClearGlyphs() const; @@ -74,6 +75,8 @@ namespace Nz bool GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, Nz::Color color, int renderOrder, int* advance) const; void GenerateGlyphs(const String& text) const; + inline float GetLineHeight(const Font::SizeInfo& sizeInfo) const; + inline void InvalidateColor(); inline void InvalidateGlyphs(); @@ -94,20 +97,19 @@ namespace Nz NazaraSlot(Font, OnFontRelease, m_fontReleaseSlot); mutable std::size_t m_lastSeparatorGlyph; - mutable unsigned int m_lastSeparatorPosition; mutable std::vector m_glyphs; mutable std::vector m_lines; Color m_color; Color m_outlineColor; FontRef m_font; - mutable Rectf m_workingBounds; - mutable Recti m_bounds; + mutable Rectf m_bounds; String m_text; TextStyleFlags m_style; mutable UInt32 m_previousCharacter; - mutable Vector2ui m_drawPos; + mutable Vector2f m_drawPos; mutable bool m_colorUpdated; mutable bool m_glyphUpdated; + mutable float m_lastSeparatorPosition; float m_maxLineWidth; float m_outlineThickness; unsigned int m_characterSize; diff --git a/include/Nazara/Utility/SimpleTextDrawer.inl b/include/Nazara/Utility/SimpleTextDrawer.inl index 13296c0ae..3f8e1ae52 100644 --- a/include/Nazara/Utility/SimpleTextDrawer.inl +++ b/include/Nazara/Utility/SimpleTextDrawer.inl @@ -61,6 +61,12 @@ namespace Nz return m_font; } + inline float SimpleTextDrawer::GetLineHeight() const + { + NazaraAssert(m_font, "SimpleTextDrawer has no font"); + return GetLineHeight(m_font->GetSizeInfo(m_characterSize)); + } + inline const Color& SimpleTextDrawer::GetOutlineColor() const { return m_outlineColor; @@ -205,7 +211,11 @@ namespace Nz // Update slot pointers (TODO: Improve the way of doing this) ConnectFontSlots(); - drawer.DisconnectFontSlots(); + if (m_font) + { + drawer.DisconnectFontSlots(); + ConnectFontSlots(); + } return *this; } @@ -265,6 +275,27 @@ namespace Nz AppendNewLine(InvalidGlyph, 0); } + inline void SimpleTextDrawer::ConnectFontSlots() + { + m_atlasChangedSlot.Connect(m_font->OnFontAtlasChanged, this, &SimpleTextDrawer::OnFontInvalidated); + m_atlasLayerChangedSlot.Connect(m_font->OnFontAtlasLayerChanged, this, &SimpleTextDrawer::OnFontAtlasLayerChanged); + m_fontReleaseSlot.Connect(m_font->OnFontRelease, this, &SimpleTextDrawer::OnFontRelease); + m_glyphCacheClearedSlot.Connect(m_font->OnFontGlyphCacheCleared, this, &SimpleTextDrawer::OnFontInvalidated); + } + + inline void SimpleTextDrawer::DisconnectFontSlots() + { + m_atlasChangedSlot.Disconnect(); + m_atlasLayerChangedSlot.Disconnect(); + m_fontReleaseSlot.Disconnect(); + m_glyphCacheClearedSlot.Disconnect(); + } + + inline float SimpleTextDrawer::GetLineHeight(const Font::SizeInfo& sizeInfo) const + { + return float(sizeInfo.lineHeight); + } + inline void SimpleTextDrawer::InvalidateColor() { m_colorUpdated = false; diff --git a/src/Nazara/Graphics/TextSprite.cpp b/src/Nazara/Graphics/TextSprite.cpp index a694bb563..f253b5539 100644 --- a/src/Nazara/Graphics/TextSprite.cpp +++ b/src/Nazara/Graphics/TextSprite.cpp @@ -215,9 +215,8 @@ namespace Nz void TextSprite::MakeBoundingVolume() const { - Rectf bounds(m_localBounds); - Vector2f max = m_scale * bounds.GetMaximum(); - Vector2f min = m_scale * bounds.GetMinimum(); + Vector2f max = m_scale * m_localBounds.GetMaximum(); + Vector2f min = m_scale * m_localBounds.GetMinimum(); m_boundingVolume.Set(min.x * Vector3f::Right() + min.y * Vector3f::Down(), max.x * Vector3f::Right() + max.y * Vector3f::Down()); } diff --git a/src/Nazara/Utility/RichTextDrawer.cpp b/src/Nazara/Utility/RichTextDrawer.cpp index 98c145474..75745c543 100644 --- a/src/Nazara/Utility/RichTextDrawer.cpp +++ b/src/Nazara/Utility/RichTextDrawer.cpp @@ -110,7 +110,7 @@ namespace Nz ClearGlyphs(); } - const Recti& RichTextDrawer::GetBounds() const + const Rectf& RichTextDrawer::GetBounds() const { if (!m_glyphUpdated) UpdateGlyphs(); @@ -260,7 +260,6 @@ namespace Nz m_glyphs = std::move(m_glyphs); m_lines = std::move(m_lines); m_glyphUpdated = std::move(m_glyphUpdated); - m_workingBounds = std::move(m_workingBounds); drawer.DisconnectFontSlots(); ConnectFontSlots(); @@ -268,21 +267,21 @@ namespace Nz return *this; } - void RichTextDrawer::AppendNewLine(const Font* font, unsigned int characterSize, std::size_t glyphIndex, unsigned int glyphPosition) const + void RichTextDrawer::AppendNewLine(const Font* font, unsigned int characterSize, std::size_t glyphIndex, float glyphPosition) const { // Ensure we're appending from last line Line& lastLine = m_lines.back(); const Font::SizeInfo& sizeInfo = font->GetSizeInfo(characterSize); - unsigned int previousDrawPos = m_drawPos.x; + float previousDrawPos = m_drawPos.x; // Reset cursor m_drawPos.x = 0; m_drawPos.y += sizeInfo.lineHeight; m_lastSeparatorGlyph = InvalidGlyph; - m_workingBounds.ExtendTo(lastLine.bounds); + m_bounds.ExtendTo(lastLine.bounds); m_lines.emplace_back(Line{ Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1 }); if (glyphIndex != InvalidGlyph && glyphIndex > lastLine.glyphIndex) @@ -310,10 +309,10 @@ namespace Nz lastLine.bounds.width -= lastLine.bounds.GetMaximum().x - glyphPosition; - // Regenerate working bounds - m_workingBounds.MakeZero(); - for (std::size_t i = 0; i < m_lines.size(); ++i) - m_workingBounds.ExtendTo(m_lines[i].bounds); + // Regenerate bounds + m_bounds.MakeZero(); + for (auto& line : m_lines) + m_bounds.ExtendTo(line.bounds); } } @@ -403,16 +402,16 @@ namespace Nz previousCharacter = character; bool whitespace = true; - int advance = 0; + float advance = 0.f; switch (character) { case ' ': case '\n': - advance = sizeInfo.spaceAdvance; + advance = float(sizeInfo.spaceAdvance); break; case '\t': - advance = sizeInfo.spaceAdvance * 4; + advance = float(sizeInfo.spaceAdvance) * 4.f; break; default: @@ -423,27 +422,26 @@ namespace Nz Glyph glyph; if (!whitespace) { - if (!GenerateGlyph(glyph, character, 0.f, true, font, color, style, characterSize, 0, &advance)) + int iAdvance; + if (!GenerateGlyph(glyph, character, 0.f, true, font, color, style, characterSize, 0, &iAdvance)) continue; // Glyph failed to load, just skip it (can't do much) + advance = float(iAdvance); + if (outlineThickness > 0.f) { Glyph outlineGlyph; if (GenerateGlyph(outlineGlyph, character, outlineThickness, false, font, outlineColor, style, characterSize, -1, nullptr)) - { m_glyphs.push_back(outlineGlyph); - } } } else { - float glyphAdvance = float(advance); - - if (ShouldLineWrap(glyphAdvance)) + if (ShouldLineWrap(advance)) AppendNewLine(font, characterSize, m_lastSeparatorGlyph, m_lastSeparatorPosition); glyph.atlas = nullptr; - glyph.bounds.Set(float(m_drawPos.x), m_lines.back().bounds.y, glyphAdvance, float(sizeInfo.lineHeight)); + glyph.bounds.Set(m_drawPos.x, m_lines.back().bounds.y, advance, float(sizeInfo.lineHeight)); glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop)); glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop)); @@ -475,9 +473,7 @@ namespace Nz m_glyphs.push_back(glyph); } - 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))); + m_bounds.ExtendTo(m_lines.back().bounds); m_glyphUpdated = true; } @@ -553,7 +549,7 @@ namespace Nz else m_lines.emplace_back(Line{ Rectf::Zero(), 0 }); - m_drawPos.Set(0, firstBlock.characterSize); + m_drawPos.Set(0, float(firstBlock.characterSize)); for (const Block& block : m_blocks) { diff --git a/src/Nazara/Utility/SimpleTextDrawer.cpp b/src/Nazara/Utility/SimpleTextDrawer.cpp index 6a9fd3999..48cbe8c1f 100644 --- a/src/Nazara/Utility/SimpleTextDrawer.cpp +++ b/src/Nazara/Utility/SimpleTextDrawer.cpp @@ -15,7 +15,7 @@ namespace Nz ClearGlyphs(); } - const Recti& SimpleTextDrawer::GetBounds() const + const Rectf& SimpleTextDrawer::GetBounds() const { if (!m_glyphUpdated) UpdateGlyphs(); @@ -76,22 +76,22 @@ namespace Nz return m_maxLineWidth; } - void SimpleTextDrawer::AppendNewLine(std::size_t glyphIndex, unsigned int glyphPosition) const + void SimpleTextDrawer::AppendNewLine(std::size_t glyphIndex, float glyphPosition) const { // Ensure we're appending from last line Line& lastLine = m_lines.back(); - const Font::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize); + float previousDrawPos = m_drawPos.x; - unsigned int previousDrawPos = m_drawPos.x; + float lineHeight = GetLineHeight(); // Reset cursor - m_drawPos.x = 0; - m_drawPos.y += sizeInfo.lineHeight; + m_drawPos.x = 0.f; + m_drawPos.y += lineHeight; m_lastSeparatorGlyph = InvalidGlyph; - m_workingBounds.ExtendTo(lastLine.bounds); - m_lines.emplace_back(Line{ Rectf(0.f, float(sizeInfo.lineHeight * m_lines.size()), 0.f, float(sizeInfo.lineHeight)), m_glyphs.size() + 1 }); + m_bounds.ExtendTo(lastLine.bounds); + m_lines.emplace_back(Line{ Rectf(0.f, lineHeight * m_lines.size(), 0.f, lineHeight), m_glyphs.size() + 1 }); if (glyphIndex != InvalidGlyph && glyphIndex > lastLine.glyphIndex) { @@ -102,12 +102,12 @@ namespace Nz { Glyph& glyph = m_glyphs[i]; glyph.bounds.x -= glyphPosition; - glyph.bounds.y += sizeInfo.lineHeight; + glyph.bounds.y += lineHeight; for (auto& corner : glyph.corners) { corner.x -= glyphPosition; - corner.y += sizeInfo.lineHeight; + corner.y += lineHeight; } newLine.bounds.ExtendTo(glyph.bounds); @@ -118,10 +118,10 @@ namespace Nz lastLine.bounds.width -= lastLine.bounds.GetMaximum().x - glyphPosition; - // Regenerate working bounds - m_workingBounds.MakeZero(); - for (std::size_t i = 0; i < m_lines.size(); ++i) - m_workingBounds.ExtendTo(m_lines[i].bounds); + // Regenerate bounds + m_bounds.MakeZero(); + for (auto& line : m_lines) + m_bounds.ExtendTo(line.bounds); } } @@ -129,36 +129,19 @@ namespace Nz { m_bounds.MakeZero(); m_colorUpdated = true; - m_drawPos.Set(0, m_characterSize); //< Our draw "cursor" + m_drawPos.Set(0, float(m_characterSize)); //< Our draw "cursor" m_lastSeparatorGlyph = InvalidGlyph; m_lines.clear(); m_glyphs.clear(); m_glyphUpdated = true; m_previousCharacter = 0; - m_workingBounds.MakeZero(); //< Compute bounds as float to speedup bounds computation (as casting between floats and integers is costly) if (m_font) - m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, float(m_font->GetSizeInfo(m_characterSize).lineHeight)), 0}); + m_lines.emplace_back(Line{Rectf(0.f, 0.f, 0.f, GetLineHeight()), 0}); else m_lines.emplace_back(Line{Rectf::Zero(), 0}); } - void SimpleTextDrawer::ConnectFontSlots() - { - m_atlasChangedSlot.Connect(m_font->OnFontAtlasChanged, this, &SimpleTextDrawer::OnFontInvalidated); - m_atlasLayerChangedSlot.Connect(m_font->OnFontAtlasLayerChanged, this, &SimpleTextDrawer::OnFontAtlasLayerChanged); - m_fontReleaseSlot.Connect(m_font->OnFontRelease, this, &SimpleTextDrawer::OnFontRelease); - m_glyphCacheClearedSlot.Connect(m_font->OnFontGlyphCacheCleared, this, &SimpleTextDrawer::OnFontInvalidated); - } - - void SimpleTextDrawer::DisconnectFontSlots() - { - m_atlasChangedSlot.Disconnect(); - m_atlasLayerChangedSlot.Disconnect(); - m_fontReleaseSlot.Disconnect(); - m_glyphCacheClearedSlot.Disconnect(); - } - bool SimpleTextDrawer::GenerateGlyph(Glyph& glyph, char32_t character, float outlineThickness, bool lineWrap, Nz::Color color, int renderOrder, int* advance) const { const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, outlineThickness, character); @@ -223,16 +206,16 @@ namespace Nz m_previousCharacter = character; bool whitespace = true; - int advance = 0; + float advance = 0.f; switch (character) { case ' ': case '\n': - advance = sizeInfo.spaceAdvance; + advance = float(sizeInfo.spaceAdvance); break; case '\t': - advance = sizeInfo.spaceAdvance * 4; + advance = float(sizeInfo.spaceAdvance) * 4.f; break; default: @@ -243,27 +226,26 @@ namespace Nz Glyph glyph; if (!whitespace) { - if (!GenerateGlyph(glyph, character, 0.f, true, m_color, 0, &advance)) + int iAdvance; + if (!GenerateGlyph(glyph, character, 0.f, true, m_color, 0, &iAdvance)) continue; // Glyph failed to load, just skip it (can't do much) + advance = float(iAdvance); + if (m_outlineThickness > 0.f) { Glyph outlineGlyph; if (GenerateGlyph(outlineGlyph, character, m_outlineThickness, false, m_outlineColor, -1, nullptr)) - { m_glyphs.push_back(outlineGlyph); - } } } else { - float glyphAdvance = advance; - - if (ShouldLineWrap(glyphAdvance)) + if (ShouldLineWrap(advance)) AppendNewLine(m_lastSeparatorGlyph, m_lastSeparatorPosition); glyph.atlas = nullptr; - glyph.bounds.Set(float(m_drawPos.x), m_lines.back().bounds.y, glyphAdvance, float(sizeInfo.lineHeight)); + glyph.bounds.Set(m_drawPos.x, m_lines.back().bounds.y, advance, GetLineHeight(sizeInfo)); glyph.corners[0].Set(glyph.bounds.GetCorner(RectCorner_LeftTop)); glyph.corners[1].Set(glyph.bounds.GetCorner(RectCorner_RightTop)); @@ -295,9 +277,7 @@ namespace Nz m_glyphs.push_back(glyph); } - 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))); + m_bounds.ExtendTo(m_lines.back().bounds); m_colorUpdated = true; m_glyphUpdated = true; @@ -316,7 +296,7 @@ namespace Nz #endif // Update atlas layer pointer - // Note: This can happen while updating + // Note: This can happen while updating glyphs for (Glyph& glyph : m_glyphs) { if (glyph.atlas == oldLayer)