diff --git a/CSFML/include/SFML/Graphics/Font.h b/CSFML/include/SFML/Graphics/Font.h
index 685da11f..d112ce32 100644
--- a/CSFML/include/SFML/Graphics/Font.h
+++ b/CSFML/include/SFML/Graphics/Font.h
@@ -67,11 +67,12 @@ CSFML_API void sfFont_Destroy(sfFont* font);
/// \param font : Source font
/// \param codePoint : Unicode code point of the character to get
/// \param characterSize : Character size, in pixels
+/// \param bold Retrieve the bold version or the regular one?
///
/// \return The corresponding glyph
///
////////////////////////////////////////////////////////////
-CSFML_API sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize);
+CSFML_API sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize, sfBool bold);
////////////////////////////////////////////////////////////
/// Get the kerning value corresponding to a given pair of characters in a font
diff --git a/CSFML/src/SFML/Graphics/Font.cpp b/CSFML/src/SFML/Graphics/Font.cpp
index e66395a1..8ae737dd 100644
--- a/CSFML/src/SFML/Graphics/Font.cpp
+++ b/CSFML/src/SFML/Graphics/Font.cpp
@@ -74,12 +74,12 @@ void sfFont_Destroy(sfFont* font)
////////////////////////////////////////////////////////////
/// Get a glyph in a font
////////////////////////////////////////////////////////////
-sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize)
+sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize, sfBool bold)
{
sfGlyph glyph = {0, {0, 0, 0, 0}, {0, 0, 0, 0}};
CSFML_CHECK_RETURN(font, glyph);
- sf::Glyph SFMLGlyph = font->This.GetGlyph(codePoint, characterSize);
+ sf::Glyph SFMLGlyph = font->This.GetGlyph(codePoint, characterSize, bold);
glyph.Advance = SFMLGlyph.Advance;
glyph.Rectangle.Left = SFMLGlyph.Rectangle.Left;
diff --git a/dotnet/extlibs/csfml-audio.dll b/dotnet/extlibs/csfml-audio.dll
index 2e2ffb2c..10d3bf77 100644
Binary files a/dotnet/extlibs/csfml-audio.dll and b/dotnet/extlibs/csfml-audio.dll differ
diff --git a/dotnet/extlibs/csfml-graphics.dll b/dotnet/extlibs/csfml-graphics.dll
index 496f2b87..f5e56a8e 100644
Binary files a/dotnet/extlibs/csfml-graphics.dll and b/dotnet/extlibs/csfml-graphics.dll differ
diff --git a/dotnet/extlibs/csfml-window.dll b/dotnet/extlibs/csfml-window.dll
index 556dbca0..25d27359 100644
Binary files a/dotnet/extlibs/csfml-window.dll and b/dotnet/extlibs/csfml-window.dll differ
diff --git a/dotnet/src/Graphics/Font.cs b/dotnet/src/Graphics/Font.cs
index 91ffb66c..746fd7b4 100644
--- a/dotnet/src/Graphics/Font.cs
+++ b/dotnet/src/Graphics/Font.cs
@@ -80,11 +80,12 @@ namespace SFML
///
/// Unicode code point of the character to get
/// Character size
+ /// Retrieve the bold version or the regular one?
/// The glyph corresponding to the character
////////////////////////////////////////////////////////////
- public Glyph GetGlyph(uint codePoint, uint characterSize)
+ public Glyph GetGlyph(uint codePoint, uint characterSize, bool bold)
{
- return sfFont_GetGlyph(This, codePoint, characterSize);
+ return sfFont_GetGlyph(This, codePoint, characterSize, bold);
}
////////////////////////////////////////////////////////////
@@ -193,7 +194,7 @@ namespace SFML
static extern void sfFont_Destroy(IntPtr This);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
- static extern Glyph sfFont_GetGlyph(IntPtr This, uint codePoint, uint characterSize);
+ static extern Glyph sfFont_GetGlyph(IntPtr This, uint codePoint, uint characterSize, bool bold);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern int sfFont_GetKerning(IntPtr This, uint first, uint second, uint characterSize);
diff --git a/include/SFML/Graphics/Font.hpp b/include/SFML/Graphics/Font.hpp
index de3798b8..28ecf0ca 100644
--- a/include/SFML/Graphics/Font.hpp
+++ b/include/SFML/Graphics/Font.hpp
@@ -115,11 +115,12 @@ public :
///
/// \param codePoint Unicode code point of the character to get
/// \param characterSize Reference character size
+ /// \param bold Retrieve the bold version or the regular one?
///
/// \return The glyph corresponding to \a codePoint and \a characterSize
///
////////////////////////////////////////////////////////////
- const Glyph& GetGlyph(Uint32 codePoint, unsigned int characterSize) const;
+ const Glyph& GetGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const;
////////////////////////////////////////////////////////////
/// \brief Get the kerning offset of two glyphs
@@ -246,11 +247,12 @@ private :
///
/// \param codePoint Unicode code point of the character to load
/// \param characterSize Reference character size
+ /// \param bold Retrieve the bold version or the regular one?
///
/// \return The glyph corresponding to \a codePoint and \a characterSize
///
////////////////////////////////////////////////////////////
- GlyphInfo LoadGlyph(Uint32 codePoint, unsigned int characterSize) const;
+ GlyphInfo LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const;
////////////////////////////////////////////////////////////
/// \brief Find a suitable rectangle within the texture for a glyph
diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp
index cdf15494..6cf683b6 100644
--- a/src/SFML/Graphics/Font.cpp
+++ b/src/SFML/Graphics/Font.cpp
@@ -29,6 +29,8 @@
#include
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_BITMAP_H
#include
@@ -148,13 +150,16 @@ bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes)
////////////////////////////////////////////////////////////
-const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize) const
+const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const
{
// Get the page corresponding to the character size
GlyphTable& glyphs = myPages[characterSize].Glyphs;
+ // Build the key by combining the code point and the bold flag
+ Uint32 key = ((bold ? 1 : 0) << 31) | codePoint;
+
// Search the glyph into the cache
- GlyphTable::const_iterator it = glyphs.find(codePoint);
+ GlyphTable::const_iterator it = glyphs.find(key);
if (it != glyphs.end())
{
// Found: just return it
@@ -163,8 +168,8 @@ const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize) const
else
{
// Not found: we have to load it
- GlyphInfo glyph = LoadGlyph(codePoint, characterSize);
- return glyphs.insert(std::make_pair(codePoint, glyph)).first->second.GlyphDesc;
+ GlyphInfo glyph = LoadGlyph(codePoint, characterSize, bold);
+ return glyphs.insert(std::make_pair(key, glyph)).first->second.GlyphDesc;
}
}
@@ -291,7 +296,7 @@ void Font::Cleanup()
////////////////////////////////////////////////////////////
-Font::GlyphInfo Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize) const
+Font::GlyphInfo Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold) const
{
// The glyph to return
GlyphInfo glyphInfo;
@@ -309,16 +314,35 @@ Font::GlyphInfo Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize) co
if (FT_Load_Char(face, codePoint, FT_LOAD_TARGET_NORMAL) != 0)
return glyphInfo;
- // Convert the glyph to a bitmap (i.e. rasterize it)
+ // Retrieve the glyph
FT_Glyph glyphDesc;
if (FT_Get_Glyph(face->glyph, &glyphDesc) != 0)
return glyphInfo;
+
+ // Apply bold if necessary -- first technique using outline (highest quality)
+ FT_Pos weight = 2 << 6;
+ bool outline = (glyphDesc->format == FT_GLYPH_FORMAT_OUTLINE);
+ if (bold && outline)
+ {
+ FT_OutlineGlyph outlineGlyph = (FT_OutlineGlyph)glyphDesc;
+ FT_Outline_Embolden(&outlineGlyph->outline, weight);
+ }
+
+ // Convert the glyph to a bitmap (i.e. rasterize it)
FT_Glyph_To_Bitmap(&glyphDesc, FT_RENDER_MODE_NORMAL, 0, 1);
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyphDesc;
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
+ // Apply bold if necessary -- fallback technique using bitmap (lower quality)
+ if (bold && !outline)
+ {
+ FT_Bitmap_Embolden(static_cast(myLibrary), &bitmap, weight, weight);
+ }
+
// Compute the glyph's advance offset
- glyphInfo.GlyphDesc.Advance = bitmapGlyph->root.advance.x >> 16;
+ glyphInfo.GlyphDesc.Advance = glyphDesc->advance.x >> 16;
+ if (bold)
+ glyphInfo.GlyphDesc.Advance += weight >> 6;
if ((bitmap.width > 0) && (bitmap.rows > 0))
{
@@ -468,10 +492,15 @@ bool Font::SetCurrentSize(unsigned int characterSize) const
////////////////////////////////////////////////////////////
Font::Page::Page() :
-NextRow(0)
+NextRow(2)
{
// Make sure that the texture is initialized by default
Texture.Create(128, 128, Color(255, 255, 255, 0));
+
+ // Reserve a 2x2 white square for texturing underlines
+ for (int x = 0; x < 2; ++x)
+ for (int y = 0; y < 2; ++y)
+ Texture.SetPixel(x, y, Color(255, 255, 255, 255));
}
} // namespace sf
diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp
index a17626e3..ad3ce352 100644
--- a/src/SFML/Graphics/Text.cpp
+++ b/src/SFML/Graphics/Text.cpp
@@ -160,7 +160,8 @@ Vector2f Text::GetCharacterPos(std::size_t index) const
index = myString.GetSize();
// We'll need this a lot
- float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize).Advance);
+ bool bold = (myStyle & Bold) != 0;
+ float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
// Compute the position
sf::Vector2f position;
@@ -184,7 +185,7 @@ Vector2f Text::GetCharacterPos(std::size_t index) const
}
// For regular characters, add the advance offset of the glyph
- position.x += static_cast(myFont->GetGlyph(curChar, myCharacterSize).Advance);
+ position.x += static_cast(myFont->GetGlyph(curChar, myCharacterSize, bold).Advance);
}
return position;
@@ -221,19 +222,20 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
// Bind the font texture
queue.SetTexture(&myFont->GetImage(myCharacterSize));
+ // Computes values related to the text style
+ bool bold = (myStyle & Bold) != 0;
+ bool underlined = (myStyle & Underlined) != 0;
+ float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
+ float outlineOffset = myCharacterSize * 0.1f;
+ float outlineThick = myCharacterSize * (bold ? 0.1f : 0.07f);
+ FloatRect outlineCoords = myFont->GetImage(myCharacterSize).GetTexCoords(IntRect(1, 1, 1, 1));
+
// Initialize the rendering coordinates
- float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize).Advance);
+ float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize));
float x = 0.f;
float y = static_cast(myCharacterSize);
- // Holds the lines to draw later, for underlined style
- std::vector underlineCoords;
- underlineCoords.reserve(16);
-
- // Compute the shearing to apply if we're using the italic style
- float italicCoeff = (myStyle & Italic) ? 0.208f : 0.f; // 12 degrees
-
// Draw one quad for each character
unsigned int index = 0;
Uint32 prevChar = 0;
@@ -246,12 +248,19 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
x += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize));
prevChar = curChar;
- // If we're using the underlined style and there's a new line,
- // we keep track of the previous line to draw it later
- if ((curChar == L'\n') && (myStyle & Underlined))
+ // If we're using the underlined style and there's a new line, draw a line
+ if (underlined && (curChar == L'\n'))
{
- underlineCoords.push_back(x);
- underlineCoords.push_back(y + 2);
+ float top = y + outlineOffset;
+ float bottom = top + outlineThick;
+ queue.AddVertex(0, top, outlineCoords.Left, outlineCoords.Top);
+ queue.AddVertex(0, bottom, outlineCoords.Left, outlineCoords.Bottom);
+ queue.AddVertex(x, bottom, outlineCoords.Right, outlineCoords.Bottom);
+ queue.AddVertex(x, top, outlineCoords.Right, outlineCoords.Top);
+
+ queue.AddTriangle(index + 0, index + 1, index + 3);
+ queue.AddTriangle(index + 3, index + 1, index + 2);
+ index += 4;
}
// Handle special characters
@@ -264,7 +273,7 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
}
// Extract the current glyph's description
- const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize);
+ const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize, bold);
int advance = curGlyph.Advance;
const IntRect& rect = curGlyph.Rectangle;
const FloatRect& coord = curGlyph.TexCoords;
@@ -283,86 +292,19 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
x += advance;
}
- // If we're using the bold style, we must render the string 4 more times,
- // slightly offseted, to simulate a higher weight
- if (myStyle & Bold)
+ // If we're using the underlined style, add the last line
+ if (underlined)
{
- float offset = myCharacterSize * 0.02f;
- static const float offsetsX[] = {-offset, offset, 0.f, 0.f};
- static const float offsetsY[] = {0.f, 0.f, -offset, offset};
+ float top = y + outlineOffset;
+ float bottom = top + outlineThick;
+ queue.AddVertex(0, top, outlineCoords.Left, outlineCoords.Top);
+ queue.AddVertex(0, bottom, outlineCoords.Left, outlineCoords.Bottom);
+ queue.AddVertex(x, bottom, outlineCoords.Right, outlineCoords.Bottom);
+ queue.AddVertex(x, top, outlineCoords.Right, outlineCoords.Top);
- for (int j = 0; j < 4; ++j)
- {
- index = 0;
- x = 0.f;
- y = static_cast(myCharacterSize);
-
- Uint32 prevChar = 0;
- queue.BeginBatch();
- for (std::size_t i = 0; i < myString.GetSize(); ++i)
- {
- Uint32 curChar = myString[i];
-
- // Apply the kerning offset
- x += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize));
- prevChar = curChar;
-
- // Handle special characters
- switch (curChar)
- {
- case L' ' : x += space; continue;
- case L'\t' : x += space * 4; continue;
- case L'\n' : y += lineSpacing; x = 0; continue;
- case L'\v' : y += lineSpacing * 4; continue;
- }
-
- // Extract the current glyph's description
- const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize);
- int advance = curGlyph.Advance;
- const IntRect& rect = curGlyph.Rectangle;
- const FloatRect& coord = curGlyph.TexCoords;
-
- // Draw a textured quad for the current character
- queue.AddVertex(x + offsetsX[j] + rect.Left - italicCoeff * rect.Top, y + offsetsY[j] + rect.Top, coord.Left, coord.Top);
- queue.AddVertex(x + offsetsX[j] + rect.Left - italicCoeff * rect.Bottom, y + offsetsY[j] + rect.Bottom, coord.Left, coord.Bottom);
- queue.AddVertex(x + offsetsX[j] + rect.Right - italicCoeff * rect.Bottom, y + offsetsY[j] + rect.Bottom, coord.Right, coord.Bottom);
- queue.AddVertex(x + offsetsX[j] + rect.Right - italicCoeff * rect.Top, y + offsetsY[j] + rect.Top, coord.Right, coord.Top);
-
- queue.AddTriangle(index + 0, index + 1, index + 3);
- queue.AddTriangle(index + 3, index + 1, index + 2);
- index += 4;
-
- // Advance to the next character
- x += advance;
- }
- }
- }
-
- // Draw the underlines if needed
- if (myStyle & Underlined)
- {
- // Compute the line thickness
- float thickness = (myStyle & Bold) ? 3.f : 2.f;
-
- // Add the last line (which was not finished with a \n)
- underlineCoords.push_back(x);
- underlineCoords.push_back(y + 2);
-
- // Draw the underlines as quads
- index = 0;
- queue.SetTexture(NULL);
- queue.BeginBatch();
- for (std::size_t i = 0; i < underlineCoords.size(); i += 2)
- {
- queue.AddVertex(0, underlineCoords[i + 1]);
- queue.AddVertex(0, underlineCoords[i + 1] + thickness);
- queue.AddVertex(underlineCoords[i], underlineCoords[i + 1] + thickness);
- queue.AddVertex(underlineCoords[i], underlineCoords[i + 1]);
-
- queue.AddTriangle(index + 0, index + 1, index + 3);
- queue.AddTriangle(index + 3, index + 1, index + 2);
- index += 4;
- }
+ queue.AddTriangle(index + 0, index + 1, index + 3);
+ queue.AddTriangle(index + 3, index + 1, index + 2);
+ index += 4;
}
}
@@ -381,14 +323,17 @@ void Text::RecomputeRect()
return;
// Initial values
- float charSize = static_cast(myCharacterSize);
- float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize).Advance);
+ bool bold = (myStyle & Bold) != 0;
+ float outlineOffset = myCharacterSize * 0.1f;
+ float outlineThick = myCharacterSize * (bold ? 0.1f : 0.07f);
+ float charSize = static_cast(myCharacterSize);
+ float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize, bold).Advance);
float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize));
- float curWidth = 0;
- float curHeight = 0;
- float width = 0;
- float height = 0;
- Uint32 prevChar = 0;
+ float curWidth = 0;
+ float curHeight = 0;
+ float width = 0;
+ float height = 0;
+ Uint32 prevChar = 0;
// Go through each character
for (std::size_t i = 0; i < myString.GetSize(); ++i)
@@ -425,7 +370,7 @@ void Text::RecomputeRect()
}
// Extract the current glyph's description
- const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize);
+ const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize, bold);
// Advance to the next character
curWidth += static_cast(curGlyph.Advance);
@@ -441,13 +386,6 @@ void Text::RecomputeRect()
width = curWidth;
height += curHeight;
- // Add a slight width / height if we're using the bold style
- if (myStyle & Bold)
- {
- width += 1.f;
- height += 1.f;
- }
-
// Add a slight width if we're using the italic style
if (myStyle & Italic)
{
@@ -457,8 +395,8 @@ void Text::RecomputeRect()
// Add a slight height if we're using the underlined style
if (myStyle & Underlined)
{
- if (curHeight < charSize + 4.f)
- height += 4.f;
+ if (curHeight < charSize + outlineOffset + outlineThick)
+ height += outlineOffset + outlineThick;
}
// Finally update the rectangle