diff options
Diffstat (limited to 'src/SFML/Graphics/Text.cpp')
-rw-r--r-- | src/SFML/Graphics/Text.cpp | 246 |
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 |