summaryrefslogtreecommitdiff
path: root/src/SFML/Graphics/Text.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/SFML/Graphics/Text.cpp')
-rw-r--r--src/SFML/Graphics/Text.cpp246
1 files changed, 172 insertions, 74 deletions
diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp
index 0635a0e..5942921 100644
--- a/src/SFML/Graphics/Text.cpp
+++ b/src/SFML/Graphics/Text.cpp
@@ -1,7 +1,7 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
-// Copyright (C) 2007-2015 Laurent Gomila (laurent@sfml-dev.org)
+// Copyright (C) 2007-2016 Laurent Gomila (laurent@sfml-dev.org)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
@@ -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,22 +155,58 @@ 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
{
return m_string;
@@ -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);
-
- 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)));
+ addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness);
+
+ 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);
-
- 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)));
+ addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness);
+
+ 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;
}
- // Extract the current glyph's description
- const Glyph& glyph = m_font->getGlyph(curChar, m_characterSize, bold);
+
+ // 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;
+ 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);
+ // 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);
- // 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)));
+ // Add the glyph to the vertices
+ addGlyphQuad(m_vertices, Vector2f(x, y), m_fillColor, glyph, italic);
- // 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);
+ // 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;
+
+ 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);
-
- 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)));
+ addLine(m_vertices, x, y, m_fillColor, underlineOffset, underlineThickness);
+
+ 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);
-
- 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)));
+ addLine(m_vertices, x, y, m_fillColor, strikeThroughOffset, underlineThickness);
+
+ if (m_outlineThickness != 0)
+ addLine(m_outlineVertices, x, y, m_outlineColor, strikeThroughOffset, underlineThickness, m_outlineThickness);
}
// Update the bounding rectangle