Add text outlines!
This commit is contained in:
@@ -10,9 +10,11 @@ namespace Nz
|
||||
{
|
||||
SimpleTextDrawer::SimpleTextDrawer() :
|
||||
m_color(Color::White),
|
||||
m_outlineColor(Color::Black),
|
||||
m_style(TextStyle_Regular),
|
||||
m_colorUpdated(true),
|
||||
m_glyphUpdated(true),
|
||||
m_outlineThickness(0.f),
|
||||
m_characterSize(24)
|
||||
{
|
||||
SetFont(Font::GetDefault());
|
||||
@@ -24,6 +26,8 @@ namespace Nz
|
||||
m_style(drawer.m_style),
|
||||
m_colorUpdated(false),
|
||||
m_glyphUpdated(false),
|
||||
m_outlineColor(drawer.m_outlineColor),
|
||||
m_outlineThickness(drawer.m_outlineThickness),
|
||||
m_characterSize(drawer.m_characterSize)
|
||||
{
|
||||
SetFont(drawer.m_font);
|
||||
@@ -120,6 +124,16 @@ namespace Nz
|
||||
return m_lines.size();
|
||||
}
|
||||
|
||||
const Color& SimpleTextDrawer::GetOutlineColor() const
|
||||
{
|
||||
return m_outlineColor;
|
||||
}
|
||||
|
||||
float SimpleTextDrawer::GetOutlineThickness() const
|
||||
{
|
||||
return m_outlineThickness;
|
||||
}
|
||||
|
||||
TextStyleFlags SimpleTextDrawer::GetStyle() const
|
||||
{
|
||||
return m_style;
|
||||
@@ -159,6 +173,22 @@ namespace Nz
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTextDrawer::SetOutlineColor(const Color& color)
|
||||
{
|
||||
m_outlineColor = color;
|
||||
|
||||
m_glyphUpdated = false;
|
||||
}
|
||||
|
||||
void SimpleTextDrawer::SetOutlineThickness(float thickness)
|
||||
{
|
||||
NazaraAssert(thickness >= 0.f, "Thickness must be zero or positive");
|
||||
|
||||
m_outlineThickness = thickness;
|
||||
|
||||
m_glyphUpdated = false;
|
||||
}
|
||||
|
||||
void SimpleTextDrawer::SetStyle(TextStyleFlags style)
|
||||
{
|
||||
m_style = style;
|
||||
@@ -177,6 +207,8 @@ namespace Nz
|
||||
{
|
||||
m_characterSize = drawer.m_characterSize;
|
||||
m_color = drawer.m_color;
|
||||
m_outlineColor = drawer.m_outlineColor;
|
||||
m_outlineThickness = drawer.m_outlineThickness;
|
||||
m_style = drawer.m_style;
|
||||
m_text = drawer.m_text;
|
||||
|
||||
@@ -198,6 +230,8 @@ namespace Nz
|
||||
m_glyphs = std::move(drawer.m_glyphs);
|
||||
m_glyphUpdated = std::move(drawer.m_glyphUpdated);
|
||||
m_font = std::move(drawer.m_font);
|
||||
m_outlineColor = std::move(drawer.m_outlineColor);
|
||||
m_outlineThickness = std::move(drawer.m_outlineThickness);
|
||||
m_style = std::move(drawer.m_style);
|
||||
m_text = std::move(drawer.m_text);
|
||||
|
||||
@@ -218,6 +252,19 @@ namespace Nz
|
||||
return drawer;
|
||||
}
|
||||
|
||||
SimpleTextDrawer SimpleTextDrawer::Draw(const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor)
|
||||
{
|
||||
SimpleTextDrawer drawer;
|
||||
drawer.SetCharacterSize(characterSize);
|
||||
drawer.SetColor(color);
|
||||
drawer.SetOutlineColor(outlineColor);
|
||||
drawer.SetOutlineThickness(outlineThickness);
|
||||
drawer.SetStyle(style);
|
||||
drawer.SetText(str);
|
||||
|
||||
return drawer;
|
||||
}
|
||||
|
||||
SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color)
|
||||
{
|
||||
SimpleTextDrawer drawer;
|
||||
@@ -230,6 +277,20 @@ namespace Nz
|
||||
return drawer;
|
||||
}
|
||||
|
||||
SimpleTextDrawer SimpleTextDrawer::Draw(Font* font, const String& str, unsigned int characterSize, TextStyleFlags style, const Color& color, float outlineThickness, const Color& outlineColor)
|
||||
{
|
||||
SimpleTextDrawer drawer;
|
||||
drawer.SetCharacterSize(characterSize);
|
||||
drawer.SetColor(color);
|
||||
drawer.SetFont(font);
|
||||
drawer.SetOutlineColor(outlineColor);
|
||||
drawer.SetOutlineThickness(outlineThickness);
|
||||
drawer.SetStyle(style);
|
||||
drawer.SetText(str);
|
||||
|
||||
return drawer;
|
||||
}
|
||||
|
||||
void SimpleTextDrawer::ClearGlyphs() const
|
||||
{
|
||||
m_bounds.MakeZero();
|
||||
@@ -278,7 +339,7 @@ namespace Nz
|
||||
|
||||
const Font::SizeInfo& sizeInfo = m_font->GetSizeInfo(m_characterSize);
|
||||
|
||||
m_glyphs.reserve(m_glyphs.size() + characters.size());
|
||||
m_glyphs.reserve(m_glyphs.size() + characters.size() * (m_outlineThickness > 0.f) ? 2 : 1);
|
||||
for (char32_t character : characters)
|
||||
{
|
||||
if (m_previousCharacter != 0)
|
||||
@@ -304,51 +365,57 @@ namespace Nz
|
||||
break;
|
||||
}
|
||||
|
||||
auto GenerateGlyph = [this](Glyph& glyph, char32_t character, float outlineThickness, Nz::Color color, int renderOrder, int* advance)
|
||||
{
|
||||
const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, outlineThickness, character);
|
||||
if (fontGlyph.valid && fontGlyph.fauxOutlineThickness <= 0.f)
|
||||
{
|
||||
glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
|
||||
glyph.atlasRect = fontGlyph.atlasRect;
|
||||
glyph.color = color;
|
||||
glyph.flipped = fontGlyph.flipped;
|
||||
glyph.renderOrder = renderOrder;
|
||||
|
||||
glyph.bounds.Set(fontGlyph.aabb);
|
||||
glyph.bounds.x += m_drawPos.x;
|
||||
glyph.bounds.y += m_drawPos.y;
|
||||
|
||||
// Faux bold and faux outline thickness are not supported
|
||||
|
||||
// We "lean" the glyph to simulate italics style
|
||||
float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
|
||||
float italicTop = italic * glyph.bounds.y;
|
||||
float italicBottom = italic * glyph.bounds.GetMaximum().y;
|
||||
|
||||
glyph.corners[0].Set(glyph.bounds.x - italicTop - outlineThickness, glyph.bounds.y - outlineThickness);
|
||||
glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop - outlineThickness, glyph.bounds.y - outlineThickness);
|
||||
glyph.corners[2].Set(glyph.bounds.x - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness);
|
||||
glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom - outlineThickness, glyph.bounds.y + glyph.bounds.height - outlineThickness);
|
||||
|
||||
if (advance)
|
||||
*advance = fontGlyph.advance;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
};
|
||||
|
||||
Glyph glyph;
|
||||
if (!whitespace)
|
||||
{
|
||||
const Font::Glyph& fontGlyph = m_font->GetGlyph(m_characterSize, m_style, character);
|
||||
if (!fontGlyph.valid)
|
||||
if (!GenerateGlyph(glyph, character, 0.f, m_color, 0, &advance))
|
||||
continue; // Glyph failed to load, just skip it (can't do much)
|
||||
|
||||
advance = fontGlyph.advance;
|
||||
|
||||
glyph.atlas = m_font->GetAtlas()->GetLayer(fontGlyph.layerIndex);
|
||||
glyph.atlasRect = fontGlyph.atlasRect;
|
||||
glyph.color = m_color;
|
||||
glyph.flipped = fontGlyph.flipped;
|
||||
|
||||
glyph.bounds.Set(fontGlyph.aabb);
|
||||
glyph.bounds.x += m_drawPos.x;
|
||||
glyph.bounds.y += m_drawPos.y;
|
||||
|
||||
if (fontGlyph.requireFauxBold)
|
||||
if (m_outlineThickness > 0.f)
|
||||
{
|
||||
// Let's simulate bold by enlarging the glyph (not a neat idea, but should work)
|
||||
Vector2f center = glyph.bounds.GetCenter();
|
||||
|
||||
// Enlarge by 10%
|
||||
glyph.bounds.width *= 1.1f;
|
||||
glyph.bounds.height *= 1.1f;
|
||||
|
||||
// Replace it at the correct height
|
||||
Vector2f offset(glyph.bounds.GetCenter() - center);
|
||||
glyph.bounds.x -= offset.x;
|
||||
glyph.bounds.y -= offset.y;
|
||||
|
||||
// Adjust advance (+10%)
|
||||
advance += advance / 10;
|
||||
Glyph outlineGlyph;
|
||||
if (GenerateGlyph(outlineGlyph, character, m_outlineThickness, m_outlineColor, -1, nullptr))
|
||||
{
|
||||
m_lines.back().bounds.ExtendTo(outlineGlyph.bounds);
|
||||
m_glyphs.push_back(outlineGlyph);
|
||||
}
|
||||
}
|
||||
|
||||
// We "lean" the glyph to simulate italics style
|
||||
float italic = (fontGlyph.requireFauxItalic) ? 0.208f : 0.f;
|
||||
float italicTop = italic * glyph.bounds.y;
|
||||
float italicBottom = italic * glyph.bounds.GetMaximum().y;
|
||||
|
||||
glyph.corners[0].Set(glyph.bounds.x - italicTop, glyph.bounds.y);
|
||||
glyph.corners[1].Set(glyph.bounds.x + glyph.bounds.width - italicTop, glyph.bounds.y);
|
||||
glyph.corners[2].Set(glyph.bounds.x - italicBottom, glyph.bounds.y + glyph.bounds.height);
|
||||
glyph.corners[3].Set(glyph.bounds.x + glyph.bounds.width - italicBottom, glyph.bounds.y + glyph.bounds.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user