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