Added support for outlined text
This commit is contained in:
parent
7ff9478061
commit
957cabb816
6 changed files with 347 additions and 106 deletions
|
@ -37,6 +37,7 @@
|
|||
#include FT_GLYPH_H
|
||||
#include FT_OUTLINE_H
|
||||
#include FT_BITMAP_H
|
||||
#include FT_STROKER_H
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
|
@ -143,6 +144,15 @@ bool Font::loadFromFile(const std::string& filename)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Load the stroker that will be used to outline the font
|
||||
FT_Stroker stroker;
|
||||
if (FT_Stroker_New(static_cast<FT_Library>(m_library), &stroker) != 0)
|
||||
{
|
||||
err() << "Failed to load font \"" << filename << "\" (failed to create the stroker)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
m_stroker = stroker;
|
||||
|
||||
// Select the unicode character map
|
||||
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
|
||||
{
|
||||
|
@ -197,6 +207,15 @@ bool Font::loadFromMemory(const void* data, std::size_t sizeInBytes)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Load the stroker that will be used to outline the font
|
||||
FT_Stroker stroker;
|
||||
if (FT_Stroker_New(static_cast<FT_Library>(m_library), &stroker) != 0)
|
||||
{
|
||||
err() << "Failed to load font from memory (failed to create the stroker)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
m_stroker = stroker;
|
||||
|
||||
// Select the Unicode character map
|
||||
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
|
||||
{
|
||||
|
@ -261,6 +280,15 @@ bool Font::loadFromStream(InputStream& stream)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Load the stroker that will be used to outline the font
|
||||
FT_Stroker stroker;
|
||||
if (FT_Stroker_New(static_cast<FT_Library>(m_library), &stroker) != 0)
|
||||
{
|
||||
err() << "Failed to load font from stream (failed to create the stroker)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
m_stroker = stroker;
|
||||
|
||||
// Select the Unicode character map
|
||||
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
|
||||
{
|
||||
|
@ -289,13 +317,15 @@ const Font::Info& Font::getInfo() const
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const
|
||||
const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
|
||||
{
|
||||
// Get the page corresponding to the character size
|
||||
GlyphTable& glyphs = m_pages[characterSize].glyphs;
|
||||
|
||||
// Build the key by combining the code point and the bold flag
|
||||
Uint32 key = ((bold ? 1 : 0) << 31) | codePoint;
|
||||
// Build the key by combining the code point, bold flag, and outline thickness
|
||||
Uint64 key = (static_cast<Uint64>(*reinterpret_cast<Uint32*>(&outlineThickness)) << 32)
|
||||
| (static_cast<Uint64>(bold ? 1 : 0) << 31)
|
||||
| static_cast<Uint64>(codePoint);
|
||||
|
||||
// Search the glyph into the cache
|
||||
GlyphTable::const_iterator it = glyphs.find(key);
|
||||
|
@ -307,7 +337,7 @@ const Glyph& Font::getGlyph(Uint32 codePoint, unsigned int characterSize, bool b
|
|||
else
|
||||
{
|
||||
// Not found: we have to load it
|
||||
Glyph glyph = loadGlyph(codePoint, characterSize, bold);
|
||||
Glyph glyph = loadGlyph(codePoint, characterSize, bold, outlineThickness);
|
||||
return glyphs.insert(std::make_pair(key, glyph)).first->second;
|
||||
}
|
||||
}
|
||||
|
@ -442,6 +472,10 @@ void Font::cleanup()
|
|||
// Delete the reference counter
|
||||
delete m_refCount;
|
||||
|
||||
// Destroy the stroker
|
||||
if (m_stroker)
|
||||
FT_Stroker_Done(static_cast<FT_Stroker>(m_stroker));
|
||||
|
||||
// Destroy the font face
|
||||
if (m_face)
|
||||
FT_Done_Face(static_cast<FT_Face>(m_face));
|
||||
|
@ -459,6 +493,7 @@ void Font::cleanup()
|
|||
// Reset members
|
||||
m_library = NULL;
|
||||
m_face = NULL;
|
||||
m_stroker = NULL;
|
||||
m_streamRec = NULL;
|
||||
m_refCount = NULL;
|
||||
m_pages.clear();
|
||||
|
@ -467,7 +502,7 @@ void Font::cleanup()
|
|||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const
|
||||
Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, float outlineThickness) const
|
||||
{
|
||||
// The glyph to return
|
||||
Glyph glyph;
|
||||
|
@ -482,7 +517,10 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
return glyph;
|
||||
|
||||
// Load the glyph corresponding to the code point
|
||||
if (FT_Load_Char(face, codePoint, FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT) != 0)
|
||||
FT_Int32 flags = FT_LOAD_TARGET_NORMAL | FT_LOAD_FORCE_AUTOHINT;
|
||||
if (outlineThickness != 0)
|
||||
flags |= FT_LOAD_NO_BITMAP;
|
||||
if (FT_Load_Char(face, codePoint, flags) != 0)
|
||||
return glyph;
|
||||
|
||||
// Retrieve the glyph
|
||||
|
@ -490,13 +528,24 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
if (FT_Get_Glyph(face->glyph, &glyphDesc) != 0)
|
||||
return glyph;
|
||||
|
||||
// Apply bold if necessary -- first technique using outline (highest quality)
|
||||
// Apply bold and outline (there is no fallback for outline) if necessary -- first technique using outline (highest quality)
|
||||
FT_Pos weight = 1 << 6;
|
||||
bool outline = (glyphDesc->format == FT_GLYPH_FORMAT_OUTLINE);
|
||||
if (bold && outline)
|
||||
if (outline)
|
||||
{
|
||||
FT_OutlineGlyph outlineGlyph = (FT_OutlineGlyph)glyphDesc;
|
||||
FT_Outline_Embolden(&outlineGlyph->outline, weight);
|
||||
if (bold)
|
||||
{
|
||||
FT_OutlineGlyph outlineGlyph = (FT_OutlineGlyph)glyphDesc;
|
||||
FT_Outline_Embolden(&outlineGlyph->outline, weight);
|
||||
}
|
||||
|
||||
if (outlineThickness != 0)
|
||||
{
|
||||
FT_Stroker stroker = static_cast<FT_Stroker>(m_stroker);
|
||||
|
||||
FT_Stroker_Set(stroker, static_cast<FT_Fixed>(outlineThickness * static_cast<float>(1 << 6)), FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
|
||||
FT_Glyph_Stroke(&glyphDesc, stroker, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the glyph to a bitmap (i.e. rasterize it)
|
||||
|
@ -504,9 +553,13 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
FT_Bitmap& bitmap = reinterpret_cast<FT_BitmapGlyph>(glyphDesc)->bitmap;
|
||||
|
||||
// Apply bold if necessary -- fallback technique using bitmap (lower quality)
|
||||
if (bold && !outline)
|
||||
if (!outline)
|
||||
{
|
||||
FT_Bitmap_Embolden(static_cast<FT_Library>(m_library), &bitmap, weight, weight);
|
||||
if (bold)
|
||||
FT_Bitmap_Embolden(static_cast<FT_Library>(m_library), &bitmap, weight, weight);
|
||||
|
||||
if (outlineThickness != 0)
|
||||
err() << "Failed to outline glyph (no fallback available)" << std::endl;
|
||||
}
|
||||
|
||||
// Compute the glyph's advance offset
|
||||
|
@ -537,10 +590,10 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) c
|
|||
glyph.textureRect.height -= 2 * padding;
|
||||
|
||||
// Compute the glyph's bounding box
|
||||
glyph.bounds.left = static_cast<float>(face->glyph->metrics.horiBearingX) / static_cast<float>(1 << 6);
|
||||
glyph.bounds.left = static_cast<float>(face->glyph->metrics.horiBearingX) / static_cast<float>(1 << 6);
|
||||
glyph.bounds.top = -static_cast<float>(face->glyph->metrics.horiBearingY) / static_cast<float>(1 << 6);
|
||||
glyph.bounds.width = static_cast<float>(face->glyph->metrics.width) / static_cast<float>(1 << 6);
|
||||
glyph.bounds.height = static_cast<float>(face->glyph->metrics.height) / static_cast<float>(1 << 6);
|
||||
glyph.bounds.width = static_cast<float>(face->glyph->metrics.width) / static_cast<float>(1 << 6) + outlineThickness * 2;
|
||||
glyph.bounds.height = static_cast<float>(face->glyph->metrics.height) / static_cast<float>(1 << 6) + outlineThickness * 2;
|
||||
|
||||
// Extract the glyph's pixels from the bitmap
|
||||
m_pixelBuffer.resize(width * height * 4, 255);
|
||||
|
|
|
@ -31,6 +31,45 @@
|
|||
#include <cmath>
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Add an underline or strikethrough line to the vertex array
|
||||
void addLine(sf::VertexArray& vertices, float lineLength, float lineTop, const sf::Color& color, float offset, float thickness, float outlineThickness = 0)
|
||||
{
|
||||
float top = std::floor(lineTop + offset - (thickness / 2) + 0.5f);
|
||||
float bottom = top + std::floor(thickness + 0.5f);
|
||||
|
||||
vertices.append(sf::Vertex(sf::Vector2f(-outlineThickness, top - outlineThickness), color, sf::Vector2f(1, 1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(lineLength + outlineThickness, top - outlineThickness), color, sf::Vector2f(1, 1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(-outlineThickness, bottom + outlineThickness), color, sf::Vector2f(1, 1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(-outlineThickness, bottom + outlineThickness), color, sf::Vector2f(1, 1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(lineLength + outlineThickness, top - outlineThickness), color, sf::Vector2f(1, 1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(lineLength + outlineThickness, bottom + outlineThickness), color, sf::Vector2f(1, 1)));
|
||||
}
|
||||
|
||||
// Add a glyph quad to the vertex array
|
||||
void addGlyphQuad(sf::VertexArray& vertices, sf::Vector2f position, const sf::Color& color, const sf::Glyph& glyph, float italic, float outlineThickness = 0)
|
||||
{
|
||||
float left = glyph.bounds.left;
|
||||
float top = glyph.bounds.top;
|
||||
float right = glyph.bounds.left + glyph.bounds.width;
|
||||
float bottom = glyph.bounds.top + glyph.bounds.height;
|
||||
|
||||
float u1 = static_cast<float>(glyph.textureRect.left);
|
||||
float v1 = static_cast<float>(glyph.textureRect.top);
|
||||
float u2 = static_cast<float>(glyph.textureRect.left + glyph.textureRect.width);
|
||||
float v2 = static_cast<float>(glyph.textureRect.top + glyph.textureRect.height);
|
||||
|
||||
vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italic * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u1, v1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italic * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u2, v1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italic * bottom - outlineThickness, position.y + bottom - outlineThickness), color, sf::Vector2f(u1, v2)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(position.x + left - italic * bottom - outlineThickness, position.y + bottom - outlineThickness), color, sf::Vector2f(u1, v2)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italic * top - outlineThickness, position.y + top - outlineThickness), color, sf::Vector2f(u2, v1)));
|
||||
vertices.append(sf::Vertex(sf::Vector2f(position.x + right - italic * bottom - outlineThickness, position.y + bottom - outlineThickness), color, sf::Vector2f(u2, v2)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace sf
|
||||
{
|
||||
////////////////////////////////////////////////////////////
|
||||
|
@ -39,8 +78,11 @@ m_string (),
|
|||
m_font (NULL),
|
||||
m_characterSize (30),
|
||||
m_style (Regular),
|
||||
m_color (255, 255, 255),
|
||||
m_fillColor (255, 255, 255),
|
||||
m_outlineColor (0, 0, 0),
|
||||
m_outlineThickness (0),
|
||||
m_vertices (Triangles),
|
||||
m_outlineVertices (Triangles),
|
||||
m_bounds (),
|
||||
m_geometryNeedUpdate(false)
|
||||
{
|
||||
|
@ -54,8 +96,11 @@ m_string (string),
|
|||
m_font (&font),
|
||||
m_characterSize (characterSize),
|
||||
m_style (Regular),
|
||||
m_color (255, 255, 255),
|
||||
m_fillColor (255, 255, 255),
|
||||
m_outlineColor (0, 0, 0),
|
||||
m_outlineThickness (0),
|
||||
m_vertices (Triangles),
|
||||
m_outlineVertices (Triangles),
|
||||
m_bounds (),
|
||||
m_geometryNeedUpdate(true)
|
||||
{
|
||||
|
@ -110,21 +155,57 @@ void Text::setStyle(Uint32 style)
|
|||
////////////////////////////////////////////////////////////
|
||||
void Text::setColor(const Color& color)
|
||||
{
|
||||
if (color != m_color)
|
||||
setFillColor(color);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::setFillColor(const Color& color)
|
||||
{
|
||||
if (color != m_fillColor)
|
||||
{
|
||||
m_color = color;
|
||||
m_fillColor = color;
|
||||
|
||||
// Change vertex colors directly, no need to update whole geometry
|
||||
// (if geometry is updated anyway, we can skip this step)
|
||||
if (!m_geometryNeedUpdate)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_vertices.getVertexCount(); ++i)
|
||||
m_vertices[i].color = m_color;
|
||||
m_vertices[i].color = m_fillColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::setOutlineColor(const Color& color)
|
||||
{
|
||||
if (color != m_outlineColor)
|
||||
{
|
||||
m_outlineColor = color;
|
||||
|
||||
// Change vertex colors directly, no need to update whole geometry
|
||||
// (if geometry is updated anyway, we can skip this step)
|
||||
if (!m_geometryNeedUpdate)
|
||||
{
|
||||
for (std::size_t i = 0; i < m_outlineVertices.getVertexCount(); ++i)
|
||||
m_outlineVertices[i].color = m_outlineColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
void Text::setOutlineThickness(float thickness)
|
||||
{
|
||||
if (thickness != m_outlineThickness)
|
||||
{
|
||||
m_outlineThickness = thickness;
|
||||
m_geometryNeedUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const String& Text::getString() const
|
||||
{
|
||||
|
@ -156,7 +237,28 @@ Uint32 Text::getStyle() const
|
|||
////////////////////////////////////////////////////////////
|
||||
const Color& Text::getColor() const
|
||||
{
|
||||
return m_color;
|
||||
return getFillColor();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Color& Text::getFillColor() const
|
||||
{
|
||||
return m_fillColor;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
const Color& Text::getOutlineColor() const
|
||||
{
|
||||
return m_outlineColor;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
float Text::getOutlineThickness() const
|
||||
{
|
||||
return m_outlineThickness;
|
||||
}
|
||||
|
||||
|
||||
|
@ -231,6 +333,11 @@ void Text::draw(RenderTarget& target, RenderStates states) const
|
|||
|
||||
states.transform *= getTransform();
|
||||
states.texture = &m_font->getTexture(m_characterSize);
|
||||
|
||||
// Only draw the outline if there is something to draw
|
||||
if (m_outlineThickness != 0)
|
||||
target.draw(m_outlineVertices, states);
|
||||
|
||||
target.draw(m_vertices, states);
|
||||
}
|
||||
}
|
||||
|
@ -248,14 +355,11 @@ void Text::ensureGeometryUpdate() const
|
|||
|
||||
// Clear the previous geometry
|
||||
m_vertices.clear();
|
||||
m_outlineVertices.clear();
|
||||
m_bounds = FloatRect();
|
||||
|
||||
// No font: nothing to draw
|
||||
if (!m_font)
|
||||
return;
|
||||
|
||||
// No text: nothing to draw
|
||||
if (m_string.isEmpty())
|
||||
// No font or text: nothing to draw
|
||||
if (!m_font || m_string.isEmpty())
|
||||
return;
|
||||
|
||||
// Compute values related to the text style
|
||||
|
@ -289,35 +393,25 @@ void Text::ensureGeometryUpdate() const
|
|||
Uint32 curChar = m_string[i];
|
||||
|
||||
// Apply the kerning offset
|
||||
x += static_cast<float>(m_font->getKerning(prevChar, curChar, m_characterSize));
|
||||
x += m_font->getKerning(prevChar, curChar, m_characterSize);
|
||||
prevChar = curChar;
|
||||
|
||||
// If we're using the underlined style and there's a new line, draw a line
|
||||
if (underlined && (curChar == L'\n'))
|
||||
{
|
||||
float top = std::floor(y + underlineOffset - (underlineThickness / 2) + 0.5f);
|
||||
float bottom = top + std::floor(underlineThickness + 0.5f);
|
||||
addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness);
|
||||
|
||||
m_vertices.append(Vertex(Vector2f(0, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, bottom), m_color, Vector2f(1, 1)));
|
||||
if (m_outlineThickness != 0)
|
||||
addLine(m_outlineVertices, x, y, m_outlineColor, underlineOffset, underlineThickness, m_outlineThickness);
|
||||
}
|
||||
|
||||
// If we're using the strike through style and there's a new line, draw a line across all characters
|
||||
if (strikeThrough && (curChar == L'\n'))
|
||||
{
|
||||
float top = std::floor(y + strikeThroughOffset - (underlineThickness / 2) + 0.5f);
|
||||
float bottom = top + std::floor(underlineThickness + 0.5f);
|
||||
addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness);
|
||||
|
||||
m_vertices.append(Vertex(Vector2f(0, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, bottom), m_color, Vector2f(1, 1)));
|
||||
if (m_outlineThickness != 0)
|
||||
addLine(m_outlineVertices, x, y, m_outlineColor, strikeThroughOffset, underlineThickness, m_outlineThickness);
|
||||
}
|
||||
|
||||
// Handle special characters
|
||||
|
@ -342,63 +436,67 @@ void Text::ensureGeometryUpdate() const
|
|||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Apply the outline
|
||||
if (m_outlineThickness != 0)
|
||||
{
|
||||
const Glyph& glyph = m_font->getGlyph(curChar, m_characterSize, bold, m_outlineThickness);
|
||||
|
||||
float left = glyph.bounds.left;
|
||||
float top = glyph.bounds.top;
|
||||
float right = glyph.bounds.left + glyph.bounds.width;
|
||||
float bottom = glyph.bounds.top + glyph.bounds.height;
|
||||
|
||||
// Add the outline glyph to the vertices
|
||||
addGlyphQuad(m_outlineVertices, Vector2f(x, y), m_outlineColor, glyph, italic, m_outlineThickness);
|
||||
|
||||
// Update the current bounds with the outlined glyph bounds
|
||||
minX = std::min(minX, x + left - italic * bottom - m_outlineThickness);
|
||||
maxX = std::max(maxX, x + right - italic * top - m_outlineThickness);
|
||||
minY = std::min(minY, y + top - m_outlineThickness);
|
||||
maxY = std::max(maxY, y + bottom - m_outlineThickness);
|
||||
}
|
||||
|
||||
// Extract the current glyph's description
|
||||
const Glyph& glyph = m_font->getGlyph(curChar, m_characterSize, bold);
|
||||
|
||||
float left = glyph.bounds.left;
|
||||
float top = glyph.bounds.top;
|
||||
float right = glyph.bounds.left + glyph.bounds.width;
|
||||
float bottom = glyph.bounds.top + glyph.bounds.height;
|
||||
// Add the glyph to the vertices
|
||||
addGlyphQuad(m_vertices, Vector2f(x, y), m_fillColor, glyph, italic);
|
||||
|
||||
float u1 = static_cast<float>(glyph.textureRect.left);
|
||||
float v1 = static_cast<float>(glyph.textureRect.top);
|
||||
float u2 = static_cast<float>(glyph.textureRect.left + glyph.textureRect.width);
|
||||
float v2 = static_cast<float>(glyph.textureRect.top + glyph.textureRect.height);
|
||||
// Update the current bounds with the non outlined glyph bounds
|
||||
if (m_outlineThickness == 0)
|
||||
{
|
||||
float left = glyph.bounds.left;
|
||||
float top = glyph.bounds.top;
|
||||
float right = glyph.bounds.left + glyph.bounds.width;
|
||||
float bottom = glyph.bounds.top + glyph.bounds.height;
|
||||
|
||||
// Add a quad for the current character
|
||||
m_vertices.append(Vertex(Vector2f(x + left - italic * top, y + top), m_color, Vector2f(u1, v1)));
|
||||
m_vertices.append(Vertex(Vector2f(x + right - italic * top, y + top), m_color, Vector2f(u2, v1)));
|
||||
m_vertices.append(Vertex(Vector2f(x + left - italic * bottom, y + bottom), m_color, Vector2f(u1, v2)));
|
||||
m_vertices.append(Vertex(Vector2f(x + left - italic * bottom, y + bottom), m_color, Vector2f(u1, v2)));
|
||||
m_vertices.append(Vertex(Vector2f(x + right - italic * top, y + top), m_color, Vector2f(u2, v1)));
|
||||
m_vertices.append(Vertex(Vector2f(x + right - italic * bottom, y + bottom), m_color, Vector2f(u2, v2)));
|
||||
|
||||
// Update the current bounds
|
||||
minX = std::min(minX, x + left - italic * bottom);
|
||||
maxX = std::max(maxX, x + right - italic * top);
|
||||
minY = std::min(minY, y + top);
|
||||
maxY = std::max(maxY, y + bottom);
|
||||
minX = std::min(minX, x + left - italic * bottom);
|
||||
maxX = std::max(maxX, x + right - italic * top);
|
||||
minY = std::min(minY, y + top);
|
||||
maxY = std::max(maxY, y + bottom);
|
||||
}
|
||||
|
||||
// Advance to the next character
|
||||
x += glyph.advance;
|
||||
}
|
||||
|
||||
// If we're using the underlined style, add the last line
|
||||
if (underlined)
|
||||
if (underlined && (x > 0))
|
||||
{
|
||||
float top = std::floor(y + underlineOffset - (underlineThickness / 2) + 0.5f);
|
||||
float bottom = top + std::floor(underlineThickness + 0.5f);
|
||||
addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness);
|
||||
|
||||
m_vertices.append(Vertex(Vector2f(0, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, bottom), m_color, Vector2f(1, 1)));
|
||||
if (m_outlineThickness != 0)
|
||||
addLine(m_outlineVertices, x, y, m_outlineColor, underlineOffset, underlineThickness, m_outlineThickness);
|
||||
}
|
||||
|
||||
// If we're using the strike through style, add the last line across all characters
|
||||
if (strikeThrough)
|
||||
if (strikeThrough && (x > 0))
|
||||
{
|
||||
float top = std::floor(y + strikeThroughOffset - (underlineThickness / 2) + 0.5f);
|
||||
float bottom = top + std::floor(underlineThickness + 0.5f);
|
||||
addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness);
|
||||
|
||||
m_vertices.append(Vertex(Vector2f(0, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(0, bottom), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, top), m_color, Vector2f(1, 1)));
|
||||
m_vertices.append(Vertex(Vector2f(x, bottom), m_color, Vector2f(1, 1)));
|
||||
if (m_outlineThickness != 0)
|
||||
addLine(m_outlineVertices, x, y, m_outlineColor, strikeThroughOffset, underlineThickness, m_outlineThickness);
|
||||
}
|
||||
|
||||
// Update the bounding rectangle
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue