Added TextDrawer classes
Former-commit-id: 4c5ace385f1a9b9ceebb774022bbc001b69a3bb4
This commit is contained in:
parent
48ecb058f0
commit
6d3228477f
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (C) 2015 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_ABSTRACTTEXTDRAWER_HPP
|
||||||
|
#define NAZARA_ABSTRACTTEXTDRAWER_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/Color.hpp>
|
||||||
|
#include <Nazara/Math/Rect.hpp>
|
||||||
|
#include <Nazara/Math/Vector2.hpp>
|
||||||
|
|
||||||
|
class NzAbstractImage;
|
||||||
|
class NzFont;
|
||||||
|
|
||||||
|
class NAZARA_API NzAbstractTextDrawer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Glyph;
|
||||||
|
|
||||||
|
NzAbstractTextDrawer() = default;
|
||||||
|
virtual ~NzAbstractTextDrawer();
|
||||||
|
|
||||||
|
virtual const NzRectui& GetBounds() const = 0;
|
||||||
|
virtual NzFont* GetFont(unsigned int index) const = 0;
|
||||||
|
virtual unsigned int GetFontCount() const = 0;
|
||||||
|
virtual const Glyph& GetGlyph(unsigned int index) const = 0;
|
||||||
|
virtual unsigned int GetGlyphCount() const = 0;
|
||||||
|
|
||||||
|
struct Glyph
|
||||||
|
{
|
||||||
|
NzColor color;
|
||||||
|
NzRectui atlasRect;
|
||||||
|
NzVector2f corners[4];
|
||||||
|
NzAbstractImage* atlas;
|
||||||
|
bool flipped;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NAZARA_ABSTRACTTEXTDRAWER_HPP
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright (C) 2015 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
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_SIMPLETEXTDRAWER_HPP
|
||||||
|
#define NAZARA_SIMPLETEXTDRAWER_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Core/ResourceListener.hpp>
|
||||||
|
#include <Nazara/Core/String.hpp>
|
||||||
|
#include <Nazara/Utility/AbstractTextDrawer.hpp>
|
||||||
|
#include <Nazara/Utility/Enums.hpp>
|
||||||
|
#include <Nazara/Utility/Font.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class NAZARA_API NzSimpleTextDrawer : public NzAbstractTextDrawer, NzResourceListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NzSimpleTextDrawer();
|
||||||
|
virtual ~NzSimpleTextDrawer();
|
||||||
|
|
||||||
|
const NzRectui& GetBounds() const;
|
||||||
|
unsigned int GetCharacterSize() const;
|
||||||
|
const NzColor& GetColor() const;
|
||||||
|
NzFont* GetFont() const;
|
||||||
|
nzUInt32 GetStyle() const;
|
||||||
|
|
||||||
|
void SetCharacterSize(unsigned int characterSize);
|
||||||
|
void SetColor(const NzColor& color);
|
||||||
|
void SetFont(NzFont* font);
|
||||||
|
void SetStyle(nzUInt32 style);
|
||||||
|
void SetText(const NzString& str);
|
||||||
|
|
||||||
|
static NzSimpleTextDrawer Draw(unsigned int characterSize, const NzString& str, nzUInt32 style = nzTextStyle_Regular, const NzColor& color = NzColor::White);
|
||||||
|
static NzSimpleTextDrawer Draw(NzFont* font, unsigned int characterSize, const NzString& str, nzUInt32 style = nzTextStyle_Regular, const NzColor& color = NzColor::White);
|
||||||
|
|
||||||
|
private:
|
||||||
|
NzFont* GetFont(unsigned int index) const override;
|
||||||
|
unsigned int GetFontCount() const override;
|
||||||
|
const Glyph& GetGlyph(unsigned int index) const override;
|
||||||
|
unsigned int GetGlyphCount() const override;
|
||||||
|
|
||||||
|
bool OnResourceModified(const NzResource* resource, int index, unsigned int code) override;
|
||||||
|
void OnResourceReleased(const NzResource* resource, int index) override;
|
||||||
|
void UpdateGlyphs() const;
|
||||||
|
|
||||||
|
mutable std::vector<Glyph> m_glyphs;
|
||||||
|
NzColor m_color;
|
||||||
|
NzFontRef m_font;
|
||||||
|
mutable NzRectui m_bounds;
|
||||||
|
NzString m_text;
|
||||||
|
nzUInt32 m_style;
|
||||||
|
mutable bool m_glyphUpdated;
|
||||||
|
unsigned int m_characterSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NAZARA_SIMPLETEXTDRAWER_HPP
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
// Copyright (C) 2015 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 <Nazara/Utility/AbstractTextDrawer.hpp>
|
||||||
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
|
NzAbstractTextDrawer::~NzAbstractTextDrawer() = default;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,305 @@
|
||||||
|
// Copyright (C) 2015 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 <Nazara/Utility/SimpleTextDrawer.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
|
///TODO: Listener de font (cas où l'atlas a changé)
|
||||||
|
|
||||||
|
NzSimpleTextDrawer::NzSimpleTextDrawer() :
|
||||||
|
m_color(NzColor::White),
|
||||||
|
m_style(nzTextStyle_Regular)
|
||||||
|
{
|
||||||
|
// SetFont(NzFont::GetDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
NzSimpleTextDrawer::~NzSimpleTextDrawer()
|
||||||
|
{
|
||||||
|
if (m_font)
|
||||||
|
m_font->RemoveResourceListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzRectui& NzSimpleTextDrawer::GetBounds() const
|
||||||
|
{
|
||||||
|
if (!m_glyphUpdated)
|
||||||
|
UpdateGlyphs();
|
||||||
|
|
||||||
|
return m_bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NzSimpleTextDrawer::GetCharacterSize() const
|
||||||
|
{
|
||||||
|
return m_characterSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzColor& NzSimpleTextDrawer::GetColor() const
|
||||||
|
{
|
||||||
|
return m_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
NzFont* NzSimpleTextDrawer::GetFont() const
|
||||||
|
{
|
||||||
|
return m_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
nzUInt32 NzSimpleTextDrawer::GetStyle() const
|
||||||
|
{
|
||||||
|
return m_style;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::SetCharacterSize(unsigned int characterSize)
|
||||||
|
{
|
||||||
|
m_characterSize = characterSize;
|
||||||
|
|
||||||
|
m_glyphUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::SetColor(const NzColor& color)
|
||||||
|
{
|
||||||
|
m_color = color;
|
||||||
|
|
||||||
|
m_glyphUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::SetFont(NzFont* font)
|
||||||
|
{
|
||||||
|
if (m_font)
|
||||||
|
m_font->RemoveResourceListener(this);
|
||||||
|
|
||||||
|
m_font = font;
|
||||||
|
if (m_font)
|
||||||
|
m_font->AddResourceListener(this);
|
||||||
|
|
||||||
|
m_glyphUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::SetStyle(nzUInt32 style)
|
||||||
|
{
|
||||||
|
m_style = style;
|
||||||
|
|
||||||
|
m_glyphUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::SetText(const NzString& str)
|
||||||
|
{
|
||||||
|
m_text = str;
|
||||||
|
|
||||||
|
m_glyphUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NzSimpleTextDrawer NzSimpleTextDrawer::Draw(unsigned int characterSize, const NzString& str, nzUInt32 style, const NzColor& color)
|
||||||
|
{
|
||||||
|
///FIXME: Sans default font ça n'a aucun intérêt
|
||||||
|
NzSimpleTextDrawer drawer;
|
||||||
|
drawer.SetCharacterSize(characterSize);
|
||||||
|
drawer.SetColor(color);
|
||||||
|
drawer.SetStyle(style);
|
||||||
|
drawer.SetText(str);
|
||||||
|
|
||||||
|
return drawer;
|
||||||
|
}
|
||||||
|
|
||||||
|
NzSimpleTextDrawer NzSimpleTextDrawer::Draw(NzFont* font, unsigned int characterSize, const NzString& str, nzUInt32 style, const NzColor& color)
|
||||||
|
{
|
||||||
|
NzSimpleTextDrawer drawer;
|
||||||
|
drawer.SetCharacterSize(characterSize);
|
||||||
|
drawer.SetColor(color);
|
||||||
|
drawer.SetFont(font);
|
||||||
|
drawer.SetStyle(style);
|
||||||
|
drawer.SetText(str);
|
||||||
|
|
||||||
|
return drawer;
|
||||||
|
}
|
||||||
|
|
||||||
|
NzFont* NzSimpleTextDrawer::GetFont(unsigned int index) const
|
||||||
|
{
|
||||||
|
#if NAZARA_UTILITY_SAFE
|
||||||
|
if (index > 0)
|
||||||
|
{
|
||||||
|
NazaraError("Font index out of range (" + NzString::Number(index) + " >= 1)");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return m_font;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NzSimpleTextDrawer::GetFontCount() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzAbstractTextDrawer::Glyph& NzSimpleTextDrawer::GetGlyph(unsigned int index) const
|
||||||
|
{
|
||||||
|
if (!m_glyphUpdated)
|
||||||
|
UpdateGlyphs();
|
||||||
|
|
||||||
|
return m_glyphs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int NzSimpleTextDrawer::GetGlyphCount() const
|
||||||
|
{
|
||||||
|
if (!m_glyphUpdated)
|
||||||
|
UpdateGlyphs();
|
||||||
|
|
||||||
|
return m_glyphs.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NzSimpleTextDrawer::OnResourceModified(const NzResource* resource, int index, unsigned int code)
|
||||||
|
{
|
||||||
|
NazaraUnused(resource);
|
||||||
|
NazaraUnused(index);
|
||||||
|
|
||||||
|
#ifdef NAZARA_DEBUG
|
||||||
|
if (m_font != resource)
|
||||||
|
{
|
||||||
|
NazaraInternalError("Not listening to " + NzString::Pointer(resource));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (code == NzFont::ModificationCode_AtlasChanged ||
|
||||||
|
code == NzFont::ModificationCode_AtlasLayerChanged ||
|
||||||
|
code == NzFont::ModificationCode_GlyphCacheCleared)
|
||||||
|
{
|
||||||
|
m_glyphUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::OnResourceReleased(const NzResource* resource, int index)
|
||||||
|
{
|
||||||
|
NazaraUnused(resource);
|
||||||
|
NazaraUnused(index);
|
||||||
|
|
||||||
|
#ifdef NAZARA_DEBUG
|
||||||
|
if (m_font != resource)
|
||||||
|
{
|
||||||
|
NazaraInternalError("Not listening to " + NzString::Pointer(resource));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetFont(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSimpleTextDrawer::UpdateGlyphs() const
|
||||||
|
{
|
||||||
|
m_bounds.MakeZero();
|
||||||
|
m_glyphs.clear();
|
||||||
|
m_glyphUpdated = true;
|
||||||
|
|
||||||
|
#if NAZARA_UTILITY_SAFE
|
||||||
|
if (!m_font || !m_font->IsValid())
|
||||||
|
{
|
||||||
|
NazaraError("Invalid font");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (m_text.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
///TODO: Itération UTF-8 => UTF-32 sans allocation de buffer (Exposer utf8cpp ?)
|
||||||
|
unsigned int size;
|
||||||
|
std::unique_ptr<char32_t[]> characters(m_text.GetUtf32Buffer(&size));
|
||||||
|
if (!characters)
|
||||||
|
{
|
||||||
|
NazaraError("Invalid character set");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzFont::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize);
|
||||||
|
|
||||||
|
// "Curseur" de dessin
|
||||||
|
NzVector2ui drawPos(0, m_characterSize);
|
||||||
|
NzVector2ui lastPos(0, 0);
|
||||||
|
|
||||||
|
m_glyphs.reserve(size);
|
||||||
|
nzUInt32 previousCharacter = 0;
|
||||||
|
for (unsigned int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
char32_t character = characters[i];
|
||||||
|
|
||||||
|
if (previousCharacter != 0)
|
||||||
|
drawPos.x += m_font->GetKerning(m_characterSize, previousCharacter, character);
|
||||||
|
|
||||||
|
previousCharacter = character;
|
||||||
|
|
||||||
|
bool whitespace = true;
|
||||||
|
switch (character)
|
||||||
|
{
|
||||||
|
case ' ':
|
||||||
|
drawPos.x += sizeInfo.spaceAdvance;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
drawPos.x = 0;
|
||||||
|
drawPos.y += sizeInfo.lineHeight;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\t':
|
||||||
|
drawPos.x += sizeInfo.spaceAdvance*4;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
whitespace = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (whitespace)
|
||||||
|
continue; // Inutile d'avoir un glyphe pour un espace blanc
|
||||||
|
|
||||||
|
const NzFont::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, character);
|
||||||
|
if (!fontGlyph.valid)
|
||||||
|
continue; // Le glyphe n'a pas été correctement chargé, que pouvons-nous faire d'autre que le passer
|
||||||
|
|
||||||
|
Glyph glyph;
|
||||||
|
glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
|
||||||
|
glyph.atlasRect = fontGlyph.atlasRect;
|
||||||
|
glyph.color = m_color;
|
||||||
|
glyph.flipped = fontGlyph.flipped;
|
||||||
|
|
||||||
|
float advance = fontGlyph.advance;
|
||||||
|
|
||||||
|
NzRectf bounds(fontGlyph.aabb);
|
||||||
|
bounds.x += drawPos.x;
|
||||||
|
bounds.y += drawPos.y;
|
||||||
|
|
||||||
|
if (fontGlyph.requireFauxBold)
|
||||||
|
{
|
||||||
|
// On va agrandir le glyphe pour simuler le gras (idée moisie, mais idée quand même)
|
||||||
|
NzVector2f center = bounds.GetCenter();
|
||||||
|
|
||||||
|
bounds.width *= 1.1f;
|
||||||
|
bounds.height *= 1.1f;
|
||||||
|
|
||||||
|
// On le replace à la bonne hauteur
|
||||||
|
NzVector2f offset(bounds.GetCenter() - center);
|
||||||
|
bounds.y -= offset.y;
|
||||||
|
|
||||||
|
// On ajuste l'espacement
|
||||||
|
advance *= 1.1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On "penche" le glyphe pour obtenir un semblant d'italique
|
||||||
|
float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
|
||||||
|
float italicTop = italic * bounds.y;
|
||||||
|
float italicBottom = italic * bounds.GetMaximum().y;
|
||||||
|
|
||||||
|
glyph.corners[0].Set(bounds.x - italicTop, bounds.y);
|
||||||
|
glyph.corners[1].Set(bounds.x + bounds.width - italicTop, bounds.y);
|
||||||
|
glyph.corners[2].Set(bounds.x - italicBottom, bounds.y + bounds.height);
|
||||||
|
glyph.corners[3].Set(bounds.x + bounds.width - italicBottom, bounds.y + bounds.height);
|
||||||
|
|
||||||
|
m_glyphs.push_back(glyph);
|
||||||
|
|
||||||
|
lastPos = drawPos;
|
||||||
|
drawPos.x += advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bounds.ExtendTo(lastPos);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue