Complete rewrite of sf::Font to make it more flexible (no more fixed charset and size)

FS#125 - Fix tab character not working in sf::String

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1309 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
LaurentGom 2009-12-13 15:49:30 +00:00
parent 839c80556d
commit 3a34f81561
32 changed files with 1016 additions and 3016 deletions

View File

@ -232,6 +232,10 @@
RelativePath="..\..\src\SFML\Graphics\FontStruct.h"
>
</File>
<File
RelativePath="..\..\include\SFML\Graphics\Glyph.h"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\Image.cpp"
>

View File

@ -36,26 +36,22 @@
/// Create a new font from a file
///
/// \param filename : Path of the font file to load
/// \param charSize : Size of characters in bitmap - the bigger, the higher quality
/// \param charset : Characters set to generate (just pass NULL to get the default charset)
///
/// \return A new sfFont object, or NULL if it failed
///
////////////////////////////////////////////////////////////
CSFML_API sfFont* sfFont_CreateFromFile(const char* filename, unsigned int charSize, const sfUint32* charset);
CSFML_API sfFont* sfFont_CreateFromFile(const char* filename);
////////////////////////////////////////////////////////////
/// Create a new image font a file in memory
///
/// \param data : Pointer to the file data in memory
/// \param sizeInBytes : Size of the data to load, in bytes
/// \param charSize : Size of characters in bitmap - the bigger, the higher quality
/// \param charset : Characters set to generate (just pass NULL to get the default charset)
///
/// \return A new sfFont object, or NULL if it failed
///
////////////////////////////////////////////////////////////
CSFML_API sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes, unsigned int charSize, const sfUint32* charset);
CSFML_API sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// Destroy an existing font
@ -66,15 +62,52 @@ CSFML_API sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes,
CSFML_API void sfFont_Destroy(sfFont* font);
////////////////////////////////////////////////////////////
/// Get the base size of characters in a font;
/// All glyphs dimensions are based on this value
/// Get a glyph in a font
///
/// \param font : Font object
/// \param font : Source font
/// \param codePoint : Unicode code point of the character to get
/// \param characterSize : Character size, in pixels
///
/// \return Base size of characters
/// \return The corresponding glyph
///
////////////////////////////////////////////////////////////
CSFML_API unsigned int sfFont_GetCharacterSize(const sfFont* font);
CSFML_API sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize);
////////////////////////////////////////////////////////////
/// Get the kerning value corresponding to a given pair of characters in a font
///
/// \param font : Source font
/// \param first : Unicode code point of the first character
/// \param second : Unicode code point of the second character
/// \param characterSize : Character size, in pixels
///
/// \return Kerning offset, in pixels
///
////////////////////////////////////////////////////////////
CSFML_API int sfFont_GetKerning(sfFont* font, sfUint32 first, sfUint32 second, unsigned int characterSize);
////////////////////////////////////////////////////////////
/// Get the line spacing value
///
/// \param font : Source font
/// \param codePoint : Unicode code point of the character to get
/// \param characterSize : Character size, in pixels
///
/// \return Line spacing, in pixels
///
////////////////////////////////////////////////////////////
CSFML_API int sfFont_GetLineSpacing(sfFont* font, unsigned int characterSize);
////////////////////////////////////////////////////////////
/// Get the image containing the glyphs of a given size in a font
///
/// \param font : Source font
/// \param characterSize : Character size, in pixels
///
/// \return Read-only pointer to the image
///
////////////////////////////////////////////////////////////
CSFML_API const sfImage* sfFont_GetImage(sfFont* font, unsigned int characterSize);
////////////////////////////////////////////////////////////
/// Get the built-in default font (Arial)

View File

@ -336,7 +336,7 @@ CSFML_API void sfText_SetFont(sfText* text, const sfFont* font);
/// \param size : New size, in pixels
///
////////////////////////////////////////////////////////////
CSFML_API void sfText_SetSize(sfText* text, float size);
CSFML_API void sfText_SetCharacterSize(sfText* text, unsigned int size);
////////////////////////////////////////////////////////////
/// Set the style of a text
@ -385,7 +385,7 @@ CSFML_API const sfFont* sfText_GetFont(const sfText* text);
/// \return Size of the characters
///
////////////////////////////////////////////////////////////
CSFML_API float sfText_GetSize(const sfText* text);
CSFML_API unsigned int sfText_GetCharacterSize(const sfText* text);
////////////////////////////////////////////////////////////
/// Get the style of a text

View File

@ -33,17 +33,10 @@
////////////////////////////////////////////////////////////
/// Create a new font from a file
////////////////////////////////////////////////////////////
sfFont* sfFont_CreateFromFile(const char* filename, unsigned int charSize, const sfUint32* charset)
sfFont* sfFont_CreateFromFile(const char* filename)
{
sfFont* font = new sfFont;
bool success = false;
if (charset)
success = font->This.LoadFromFile(filename, charSize, charset);
else
success = font->This.LoadFromFile(filename, charSize);
if (!success)
if (!font->This.LoadFromFile(filename))
{
delete font;
font = NULL;
@ -56,17 +49,10 @@ sfFont* sfFont_CreateFromFile(const char* filename, unsigned int charSize, const
////////////////////////////////////////////////////////////
/// Create a new font from a file in memory
////////////////////////////////////////////////////////////
sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes, unsigned int charSize, const sfUint32* charset)
sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes)
{
sfFont* font = new sfFont;
bool success = false;
if (charset)
success = font->This.LoadFromMemory(data, sizeInBytes, charSize, charset);
else
success = font->This.LoadFromMemory(data, sizeInBytes, charSize);
if (!success)
if (!font->This.LoadFromMemory(data, sizeInBytes))
{
delete font;
font = NULL;
@ -86,12 +72,57 @@ void sfFont_Destroy(sfFont* font)
////////////////////////////////////////////////////////////
/// Get the base size of characters in a font;
/// All glyphs dimensions are based on this value
/// Get a glyph in a font
////////////////////////////////////////////////////////////
unsigned int sfFont_GetCharacterSize(const sfFont* font)
sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize)
{
CSFML_CALL_RETURN(font, GetCharacterSize(), 0);
sfGlyph glyph = {0, {0, 0, 0, 0}, {0, 0, 0, 0}};
CSFML_CHECK_RETURN(font, glyph);
sf::Glyph SFMLGlyph = font->This.GetGlyph(codePoint, characterSize);
glyph.Advance = SFMLGlyph.Advance;
glyph.Rectangle.Left = SFMLGlyph.Rectangle.Left;
glyph.Rectangle.Top = SFMLGlyph.Rectangle.Top;
glyph.Rectangle.Right = SFMLGlyph.Rectangle.Right;
glyph.Rectangle.Bottom = SFMLGlyph.Rectangle.Bottom;
glyph.TexCoords.Left = SFMLGlyph.TexCoords.Left;
glyph.TexCoords.Top = SFMLGlyph.TexCoords.Top;
glyph.TexCoords.Right = SFMLGlyph.TexCoords.Right;
glyph.TexCoords.Bottom = SFMLGlyph.TexCoords.Bottom;
return glyph;
}
////////////////////////////////////////////////////////////
/// Get the kerning value corresponding to a given pair of characters in a font
////////////////////////////////////////////////////////////
int sfFont_GetKerning(sfFont* font, sfUint32 first, sfUint32 second, unsigned int characterSize)
{
CSFML_CALL_RETURN(font, GetKerning(first, second, characterSize), 0);
}
////////////////////////////////////////////////////////////
/// Get the line spacing value
////////////////////////////////////////////////////////////
int sfFont_GetLineSpacing(sfFont* font, unsigned int characterSize)
{
CSFML_CALL_RETURN(font, GetLineSpacing(characterSize), 0);
}
////////////////////////////////////////////////////////////
/// Get the image containing the glyphs of a given size in a font
////////////////////////////////////////////////////////////
const sfImage* sfFont_GetImage(sfFont* font, unsigned int characterSize)
{
CSFML_CHECK_RETURN(font, NULL);
*font->Images[characterSize].This = font->This.GetImage(characterSize);
return &font->Images[characterSize];
}

View File

@ -29,6 +29,8 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/ImageStruct.h>
#include <map>
////////////////////////////////////////////////////////////
@ -37,6 +39,7 @@
struct sfFont
{
sf::Font This;
std::map<unsigned int, sfImage> Images;
};

View File

@ -42,9 +42,9 @@ struct sfImage
OwnInstance = true;
}
sfImage(sf::Image* Image)
sfImage(sf::Image* image)
{
This = Image;
This = image;
OwnInstance = false;
}

View File

@ -320,9 +320,9 @@ void sfText_SetFont(sfText* text, const sfFont* font)
////////////////////////////////////////////////////////////
/// Set the size of a string
////////////////////////////////////////////////////////////
void sfText_SetSize(sfText* text, float size)
void sfText_SetCharacterSize(sfText* text, unsigned int size)
{
CSFML_CALL(text, SetSize(size))
CSFML_CALL(text, SetCharacterSize(size))
}
@ -373,9 +373,9 @@ const sfFont* sfText_GetFont(const sfText* text)
////////////////////////////////////////////////////////////
/// Get the size of the characters of a text
////////////////////////////////////////////////////////////
float sfText_GetSize(const sfText* text)
unsigned int sfText_GetCharacterSize(const sfText* text)
{
CSFML_CALL_RETURN(text, GetSize(), 0.f)
CSFML_CALL_RETURN(text, GetCharacterSize(), 0.f)
}

View File

@ -127,7 +127,10 @@ EXPORTS
sfFont_CreateFromFile
sfFont_CreateFromMemory
sfFont_Destroy
sfFont_GetCharacterSize
sfFont_GetGlyph
sfFont_GetKerning
sfFont_GetLineSpacing
sfFont_GetImage
sfFont_GetDefaultFont
sfText_Create
sfText_Destroy
@ -158,12 +161,12 @@ EXPORTS
sfText_SetString
sfText_SetUnicodeString
sfText_SetFont
sfText_SetSize
sfText_SetCharacterSize
sfText_SetStyle
sfText_GetUnicodeString
sfText_GetString
sfText_GetFont
sfText_GetSize
sfText_GetCharacterSize
sfText_GetStyle
sfText_GetCharacterPos
sfText_GetRect

View File

@ -127,7 +127,10 @@ EXPORTS
sfFont_CreateFromFile
sfFont_CreateFromMemory
sfFont_Destroy
sfFont_GetCharacterSize
sfFont_GetGlyph
sfFont_GetKerning
sfFont_GetLineSpacing
sfFont_GetImage
sfFont_GetDefaultFont
sfText_Create
sfText_Destroy
@ -158,12 +161,12 @@ EXPORTS
sfText_SetString
sfText_SetUnicodeString
sfText_SetFont
sfText_SetSize
sfText_SetCharacterSize
sfText_SetStyle
sfText_GetUnicodeString
sfText_GetString
sfText_GetFont
sfText_GetSize
sfText_GetCharacterSize
sfText_GetStyle
sfText_GetCharacterPos
sfText_GetRect

View File

@ -140,8 +140,6 @@
<Unit filename="..\..\src\SFML\Graphics\Color.cpp" />
<Unit filename="..\..\src\SFML\Graphics\Drawable.cpp" />
<Unit filename="..\..\src\SFML\Graphics\Font.cpp" />
<Unit filename="..\..\src\SFML\Graphics\FontLoader.cpp" />
<Unit filename="..\..\src\SFML\Graphics\FontLoader.hpp" />
<Unit filename="..\..\src\SFML\Graphics\GLCheck.cpp" />
<Unit filename="..\..\src\SFML\Graphics\GLCheck.hpp" />
<Unit filename="..\..\src\SFML\Graphics\GLEW\glew.c">

View File

@ -3434,14 +3434,6 @@
RelativePath="..\..\include\SFML\Graphics\Font.hpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.cpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.hpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\GLCheck.cpp"
>

View File

@ -14,6 +14,9 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-main", "sfml-main.vcproj", "{2BD26A09-E1B6-42E2-A0D0-63987B76BB97}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-network", "sfml-network.vcproj", "{823DDC98-42D5-4A38-88CF-9DC06C788AE4}"
ProjectSection(ProjectDependencies) = postProject
{C061A27D-7CA0-4179-9869-672FA04A86A8} = {C061A27D-7CA0-4179-9869-672FA04A86A8}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-system", "sfml-system.vcproj", "{C061A27D-7CA0-4179-9869-672FA04A86A8}"
EndProject

View File

@ -3433,14 +3433,6 @@
RelativePath="..\..\include\SFML\Graphics\Font.hpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.cpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.hpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\GLCheck.cpp"
>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -93,7 +93,7 @@ namespace sample_shader
Sprite entity = new Sprite(new Image("datas/shader/sprite.png"));
// Load the text font
Font font = new Font("datas/shader/arial.ttf", 20);
Font font = new Font("datas/shader/arial.ttf");
// Load the image needed for the wave effect
Image waveImage = new Image("datas/shader/wave.jpg");
@ -135,7 +135,7 @@ namespace sample_shader
Text infoText = new Text();
infoText.Font = font;
infoText.Size = 20;
infoText.Position = new Vector2(5.0F, 510.0F);
infoText.Position = new Vector2(5.0F, 500.0F);
infoText.Color = new Color(250, 100, 30);
infoText.DisplayedString = "Move your mouse to change the shaders' parameters\n" +
"Press numpad 1 to change the background shader\n" +

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security;
using System.IO;
@ -7,6 +8,24 @@ namespace SFML
{
namespace Graphics
{
////////////////////////////////////////////////////////////
/// <summary>
/// Structure describing a glyph (a visual character)
/// </summary>
////////////////////////////////////////////////////////////
[StructLayout(LayoutKind.Sequential)]
public struct Glyph
{
/// <summary>Offset to move horizontically to the next character</summary>
public int Advance;
/// <summary>Bounding rectangle of the glyph, in coordinates relative to the baseline</summary>
public IntRect Rectangle;
/// <summary>Texture coordinates of the glyph inside the font's image</summary>
public FloatRect TexCoords;
}
////////////////////////////////////////////////////////////
/// <summary>
/// Font is the low-level class for loading and
@ -24,47 +43,8 @@ namespace SFML
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Font(string filename) :
this(filename, 30)
base(sfFont_CreateFromFile(filename))
{
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct the font from a file, using custom size
/// </summary>
/// <param name="filename">Font file to load</param>
/// <param name="charSize">Character size</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Font(string filename, uint charSize) :
this(filename, charSize, "")
{
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct the font from a file, using custom size and characters set
/// </summary>
/// <param name="filename">Font file to load</param>
/// <param name="charSize">Character size</param>
/// <param name="charset">Set of characters to generate</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Font(string filename, uint charSize, string charset) :
base(IntPtr.Zero)
{
unsafe
{
IntPtr ptr;
int size;
if (Int32.TryParse(charset, out size))
ptr = new IntPtr(&size);
else
ptr = IntPtr.Zero;
SetThis(sfFont_CreateFromFile(filename, charSize, ptr));
}
if (This == IntPtr.Zero)
throw new LoadingFailedException("font", filename);
}
@ -77,64 +57,73 @@ namespace SFML
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Font(Stream stream) :
this(stream, 30)
{
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct the font from a file in a stream, using custom size
/// </summary>
/// <param name="stream">Stream containing the file contents</param>
/// <param name="charSize">Character size</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Font(Stream stream, uint charSize) :
this(stream, charSize, "")
{
}
////////////////////////////////////////////////////////////
/// <summary>
/// Construct the font from a file in a stream
/// </summary>
/// <param name="stream">Stream containing the file contents</param>
/// <param name="charSize">Character size</param>
/// <param name="charset">Set of characters to generate</param>
/// <exception cref="LoadingFailedException" />
////////////////////////////////////////////////////////////
public Font(Stream stream, uint charSize, string charset) :
base(IntPtr.Zero)
{
unsafe
{
IntPtr ptr;
int size;
if (Int32.TryParse(charset, out size))
ptr = new IntPtr(&size);
else
ptr = IntPtr.Zero;
stream.Position = 0;
byte[] StreamData = new byte[stream.Length];
uint Read = (uint)stream.Read(StreamData, 0, StreamData.Length);
fixed (byte* dataPtr = StreamData)
{
SetThis(sfFont_CreateFromMemory((char*)dataPtr, Read, charSize, ptr));
SetThis(sfFont_CreateFromMemory((char*)dataPtr, Read));
}
}
if (This == IntPtr.Zero)
throw new LoadingFailedException("font");
}
////////////////////////////////////////////////////////////
/// <summary>
/// Base character size
/// Get a glyph in the font
/// </summary>
/// <param name="codePoint">Unicode code point of the character to get</param>
/// <param name="characterSize">Character size</param>
/// <returns>The glyph corresponding to the character</returns>
////////////////////////////////////////////////////////////
public uint CharacterSize
public Glyph GetGlyph(uint codePoint, uint characterSize)
{
get { return sfFont_GetCharacterSize(This); }
return sfFont_GetGlyph(This, codePoint, characterSize);
}
////////////////////////////////////////////////////////////
/// <summary>
/// Get the kerning offset between two glyphs
/// </summary>
/// <param name="first">Unicode code point of the first character</param>
/// <param name="second">Unicode code point of the second character</param>
/// <param name="characterSize">Character size</param>
/// <returns>Kerning offset, in pixels</returns>
////////////////////////////////////////////////////////////
public int GetKerning(uint first, uint second, uint characterSize)
{
return sfFont_GetKerning(This, first, second, characterSize);
}
////////////////////////////////////////////////////////////
/// <summary>
/// Get spacing between two consecutive lines
/// </summary>
/// <param name="characterSize">Character size</param>
/// <returns>Line spacing, in pixels</returns>
////////////////////////////////////////////////////////////
public int GetLineSpacing(uint characterSize)
{
return sfFont_GetLineSpacing(This, characterSize);
}
////////////////////////////////////////////////////////////
/// <summary>
/// Get the image containing the glyphs of a given size
/// </summary>
/// <param name="characterSize">Character size</param>
/// <returns>Image storing the glyphs for the given size</returns>
////////////////////////////////////////////////////////////
public Image GetImage(uint characterSize)
{
myImages[characterSize] = new Image(sfFont_GetImage(This, characterSize));
return myImages[characterSize];
}
////////////////////////////////////////////////////////////
@ -168,6 +157,12 @@ namespace SFML
sfFont_Destroy(This);
if (disposing)
{
foreach (Image image in myImages.Values)
image.Dispose();
}
if (!disposing)
Context.Global.SetActive(false);
}
@ -184,20 +179,30 @@ namespace SFML
{
}
private Dictionary<uint, Image> myImages = new Dictionary<uint, Image>();
private static Font ourDefaultFont = null;
#region Imports
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern IntPtr sfFont_CreateFromFile(string Filename, uint CharSize, IntPtr Charset);
static extern IntPtr sfFont_CreateFromFile(string Filename);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
unsafe static extern IntPtr sfFont_CreateFromMemory(char* Data, uint SizeInBytes, uint CharSize, IntPtr Charset);
unsafe static extern IntPtr sfFont_CreateFromMemory(char* Data, uint SizeInBytes);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern void sfFont_Destroy(IntPtr This);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern uint sfFont_GetCharacterSize(IntPtr This);
static extern Glyph sfFont_GetGlyph(IntPtr This, uint codePoint, uint characterSize);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern int sfFont_GetKerning(IntPtr This, uint first, uint second, uint characterSize);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern int sfFont_GetLineSpacing(IntPtr This, uint characterSize);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern IntPtr sfFont_GetImage(IntPtr This, uint characterSize);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern IntPtr sfFont_GetDefaultFont();

View File

@ -211,10 +211,10 @@ namespace SFML
/// Base size of characters
/// </summary>
////////////////////////////////////////////////////////////
public float Size
public uint Size
{
get {return sfText_GetSize(This);}
set {sfText_SetSize(This, value);}
get {return sfText_GetCharacterSize(This);}
set {sfText_SetCharacterSize(This, value);}
}
////////////////////////////////////////////////////////////
@ -376,7 +376,7 @@ namespace SFML
static extern void sfText_SetFont(IntPtr This, IntPtr Font);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern void sfText_SetSize(IntPtr This, float Size);
static extern void sfText_SetCharacterSize(IntPtr This, uint Size);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern void sfText_SetStyle(IntPtr This, Styles Style);
@ -385,7 +385,7 @@ namespace SFML
static extern string sfText_GetString(IntPtr This);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern float sfText_GetSize(IntPtr This);
static extern uint sfText_GetCharacterSize(IntPtr This);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern Styles sfText_GetStyle(IntPtr This);

View File

@ -36,109 +36,328 @@
#include <SFML/Graphics/Rect.hpp>
#include <map>
#include <string>
#include <vector>
namespace sf
{
namespace priv
{
class FontLoader;
}
////////////////////////////////////////////////////////////
/// Font is the low-level class for loading and
/// manipulating character fonts. This class is meant to
/// be used by sf::Text
/// \brief Class for loading and manipulating character fonts
///
////////////////////////////////////////////////////////////
class SFML_API Font : public Resource<Font>
{
public :
////////////////////////////////////////////////////////////
/// Default constructor
/// \brief Default constructor
///
/// This constructor defines an empty font
///
////////////////////////////////////////////////////////////
Font();
////////////////////////////////////////////////////////////
/// Load the font from a file
/// \brief Copy constructor
///
/// \param filename : Font file to load
/// \param charSize : Size of characters in bitmap - the bigger, the higher quality
/// \param charset : Characters set to generate (by default, contains the ISO-8859-1 printable characters)
///
/// \return True if loading was successful
/// \param copy Instance to copy
///
////////////////////////////////////////////////////////////
bool LoadFromFile(const std::string& filename, unsigned int charSize = 30, String charset = ourDefaultCharset);
Font(const Font& copy);
////////////////////////////////////////////////////////////
/// Load the font from a file in memory
/// \brief Destructor
///
/// \param data : Pointer to the data to load
/// \param sizeInBytes : Size of the data, in bytes
/// \param charSize : Size of characters in bitmap - the bigger, the higher quality
/// \param charset : Characters set to generate (by default, contains the ISO-8859-1 printable characters)
///
/// \return True if loading was successful
/// Cleans up all the internal resources used by the font
///
////////////////////////////////////////////////////////////
bool LoadFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize = 30, String charset = ourDefaultCharset);
~Font();
////////////////////////////////////////////////////////////
/// Get the base size of characters in the font;
/// All glyphs dimensions are based on this value
/// \brief Load the font from a file
///
/// \return Base size of characters
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
/// Note that this function know nothing about the standard
/// fonts installed on the user's system, thus you can't
/// load them directly.
///
/// \param filename Path of the font file to load
///
/// \return True if loading succeeded, false if it failed
///
/// \see LoadFromMemory
///
////////////////////////////////////////////////////////////
unsigned int GetCharacterSize() const;
bool LoadFromFile(const std::string& filename);
////////////////////////////////////////////////////////////
/// Get the description of a glyph (character)
/// given by its unicode value
/// \brief Load the font from a file
///
/// \param codePoint : Unicode value of the character to get
/// The supported font formats are: TrueType, Type 1, CFF,
/// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42.
/// Note that this function know nothing about the standard
/// fonts installed on the user's system, thus you can't
/// load them directly.
///
/// \return Glyph's visual settings, or an invalid glyph if character not found
/// \param data Pointer to the file data in memory
/// \param sizeInBytes Size of the data to load, in bytes
///
/// \return True if loading succeeded, false if it failed
///
/// \see LoadFromFile
///
////////////////////////////////////////////////////////////
const Glyph& GetGlyph(Uint32 codePoint) const;
bool LoadFromMemory(const char* data, std::size_t sizeInBytes);
////////////////////////////////////////////////////////////
/// Get the image containing the rendered characters (glyphs)
/// \brief Retrieve a glyph of the font
///
/// \return Image containing glyphs
/// \param codePoint Unicode code point of the character to get
/// \param characterSize Reference character size
///
/// \return The glyph corresponding to \a codePoint and \a characterSize
///
////////////////////////////////////////////////////////////
const Image& GetImage() const;
const Glyph& GetGlyph(Uint32 codePoint, unsigned int characterSize) const;
////////////////////////////////////////////////////////////
/// Get the SFML default built-in font (Arial)
/// \brief Get the kerning offset of two glyphs
///
/// \return Instance of the default font
/// The kerning is an extra offset (negative) to apply between two
/// glyphs when rendering them, to make the pair look more "natural".
/// For example, the pair "AV" have a special kerning to make them
/// closer than other characters. Most of the glyphs pairs have a
/// kerning offset of zero, though.
///
/// \param first Unicode code point of the first character
/// \param second Unicode code point of the second character
/// \param characterSize Reference character size
///
/// \return Kerning value for \a first and \a second, in pixels
///
////////////////////////////////////////////////////////////
int GetKerning(Uint32 first, Uint32 second, unsigned int characterSize) const;
////////////////////////////////////////////////////////////
/// \brief Get the line spacing
///
/// Line spacing is the vertical offset to apply between two
/// consecutive lines of text.
///
/// \param characterSize Reference character size
///
/// \return Line spacing, in pixels
///
////////////////////////////////////////////////////////////
int GetLineSpacing(unsigned int characterSize) const;
////////////////////////////////////////////////////////////
/// \brief Retrieve the image containing the loaded glyphs of a certain size
///
/// The contents of the returned image changes as more glyphs
/// are requested, thus it is not very relevant. It is mainly
/// used internally by sf::Text.
///
/// \param characterSize Reference character size
///
/// \return Image containing the glyphs of the requested size
///
////////////////////////////////////////////////////////////
const Image& GetImage(unsigned int characterSize) const;
////////////////////////////////////////////////////////////
/// \brief Overload of assignment operator
///
/// \param right Instance to assign
///
/// \return Reference to self
///
////////////////////////////////////////////////////////////
Font& operator =(const Font& right);
////////////////////////////////////////////////////////////
/// \brief Return the default built-in font
///
/// This font is provided for convenience, it is used by
/// sf::Text instances by default. It is provided so that
/// users don't have to provide and load a font file in order
/// to display text on screen.
/// The font used is Arial.
///
/// \return Reference to the built-in default font
///
////////////////////////////////////////////////////////////
static const Font& GetDefaultFont();
private :
friend class priv::FontLoader;
////////////////////////////////////////////////////////////
/// \brief Structure storing a glyph together with its
/// rectangle in the texture
///
////////////////////////////////////////////////////////////
struct GlyphInfo
{
Glyph GlyphDesc;
IntRect TextureRect;
};
////////////////////////////////////////////////////////////
// Static member data
/// \brief Structure defining a row of glyphs
///
////////////////////////////////////////////////////////////
static Uint32 ourDefaultCharset[]; ///< The default charset (all printable ISO-8859-1 characters)
struct Row
{
Row(unsigned int top, unsigned int height) : Width(0), Top(top), Height(height) {}
unsigned int Width; ///< Current width of the row
unsigned int Top; ///< Y position of the row into the texture
unsigned int Height; ///< Height of the row
};
////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////
typedef std::map<Uint32, GlyphInfo> GlyphTable; ///< Table mapping a codepoint to its glyph
////////////////////////////////////////////////////////////
/// \brief Structure defining a page if glyphs
///
////////////////////////////////////////////////////////////
struct Page
{
Page();
GlyphTable Glyphs; ///< Table mapping code points to their corresponding glyph
Image Texture; ///< Image containing the pixels of the glyphs
unsigned int NextRow; ///< Y position of the next new row in the image
std::vector<Row> Rows; ///< List containing the position of all the existing rows
};
////////////////////////////////////////////////////////////
/// \brief Free all the internal resources
///
////////////////////////////////////////////////////////////
void Cleanup();
////////////////////////////////////////////////////////////
/// \brief Load a new glyph and store it in the cache
///
/// \param codePoint Unicode code point of the character to load
/// \param characterSize Reference character size
///
/// \return The glyph corresponding to \a codePoint and \a characterSize
///
////////////////////////////////////////////////////////////
GlyphInfo LoadGlyph(Uint32 codePoint, unsigned int characterSize) const;
////////////////////////////////////////////////////////////
/// \brief Find a suitable rectangle within the texture for a glyph
///
/// \param page Page of glyphs to search in
/// \param width Width of the rectangle
/// \param height Height of the rectangle
///
/// \return Found rectangle within the texture
///
////////////////////////////////////////////////////////////
IntRect FindGlyphRect(Page& page, unsigned int width, unsigned int height) const;
////////////////////////////////////////////////////////////
/// \brief Make sure that the given size is the current one
///
/// \param characterSize Reference character size
///
/// \return True on success, false if any error happened
///
////////////////////////////////////////////////////////////
bool SetCurrentSize(unsigned int characterSize) const;
////////////////////////////////////////////////////////////
// Types
////////////////////////////////////////////////////////////
typedef std::map<unsigned int, Page> PageTable; ///< Table mapping a character size to its page (image)
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
Image myTexture; ///< Texture holding the bitmap font
unsigned int myCharSize; ///< Size of characters in the bitmap font
std::map<Uint32, Glyph> myGlyphs; ///< Rendering settings of each character (glyph)
void* myLibrary; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details)
void* myFace; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details)
int* myRefCount; ///< Reference counter used by implicit sharing
mutable PageTable myPages; ///< Table containing the glyphs pages by character size
mutable std::vector<Uint8> myPixelBuffer; ///< Pixel buffer holding a glyph's pixels before being written to the texture
mutable unsigned int myCurrentSize; ///< Current character size in use
};
} // namespace sf
#endif // SFML_FONT_HPP
////////////////////////////////////////////////////////////
/// \class sf::Font
///
/// Fonts can be loaded from a file or from memory, from
/// the most common types of fonts. See the LoadFromFile()
/// function for the complete list of supported formats.
///
/// Once it is loaded, a sf::Font instance provides three
/// types of informations about the font:
/// \li Global metrics, such as the line spacing
/// \li Per-glyph metrics, such as bounding box or kerning
/// \li Pixel representation of glyphs
///
/// Fonts alone are not very useful: they hold the font data
/// but cannot make anything useful of it. To do so you need to
/// use the sf::Text class, which is able to properly output text
/// with several options such as character size, style, color,
/// position, rotation, etc.
/// This separation allows more flexibility and better performances:
/// indeed a sf::Font is a heavy resource, and any operation on it
/// is slow (often too slow for real-time applications). On the other
/// side, a sf::Text is a lightweight object which can combine the
/// glyphs data and metrics of a sf::Font to display any text on a
/// render target.
/// Note that it is also possible to bind several sf::Text instances
/// to the same sf::Font.
///
/// It is important to note that the sf::Text instance doesn't
/// copy the font that it uses, it only keeps a reference to it.
/// Thus, a sf::Font must not be destructed while it is
/// used by a sf::Text (i.e. never write a function that
/// uses a local sf::Font instance for creating a text).
///
/// Usage example:
/// \code
/// // Declare a new font
/// sf::Font font;
///
/// // Load it from a file
/// if (!font.LoadFromFile("arial.ttf"))
/// {
/// // error...
/// }
///
/// // Create a text which uses our font
/// sf::Text text1;
/// text1.SetFont(font);
/// text1.SetCharacterSize(30);
/// text1.SetStyle(sf::Text::Regular);
///
/// // Create another text using the same font, but with different parameters
/// sf::Text text2;
/// text2.SetFont(font);
/// text2.SetCharacterSize(50);
/// text1.SetStyle(sf::Text::Italic);
/// \endcode
///
/// Apart from loading font files, and passing them to instances
/// of sf::Text, you should normally not have to deal directly
/// with this class. However, it may be useful to access the
/// font metrics or rasterized glyphs for advanced usage.
///
/// \see sf::Text
///
////////////////////////////////////////////////////////////

View File

@ -51,8 +51,8 @@ public :
// Member data
////////////////////////////////////////////////////////////
int Advance; ///< Offset to move horizontically to the next character
IntRect Rectangle; ///< Bounding rectangle of the glyph, in relative coordinates
FloatRect TexCoords; ///< Texture coordinates of the glyph inside the bitmap font
IntRect Rectangle; ///< Bounding rectangle of the glyph, in coordinates relative to the baseline
FloatRect TexCoords; ///< Texture coordinates of the glyph inside the font's image
};
} // namespace sf

View File

@ -203,7 +203,7 @@ public :
/// Warning: for performances reasons, this function doesn't
/// perform any check; thus you're responsible of ensuring that
/// \a rectangle does not exceed the image size, and that
/// \a pixels contain enough elements.
/// \a pixels contains enough elements.
///
/// \param rectangle : Sub-rectangle of the image to update
/// \param pixels : Array of pixels to write to the image

View File

@ -67,10 +67,10 @@ public :
///
/// \param string : Text assigned to the string
/// \param font : Font used to draw the string
/// \param size : Characters size
/// \param characterSize : Base size of characters, in pixels
///
////////////////////////////////////////////////////////////
explicit Text(const String& string, const Font& font = Font::GetDefaultFont(), float size = 30.f);
explicit Text(const String& string, const Font& font = Font::GetDefaultFont(), unsigned int characterSize = 30);
////////////////////////////////////////////////////////////
/// Set the text (from any kind of string)
@ -89,13 +89,13 @@ public :
void SetFont(const Font& font);
////////////////////////////////////////////////////////////
/// Set the size of the string
/// Set the base size for the characters.
/// The default size is 30
///
/// \param size : New size, in pixels
///
////////////////////////////////////////////////////////////
void SetSize(float size);
void SetCharacterSize(unsigned int size);
////////////////////////////////////////////////////////////
/// Set the style of the text
@ -123,12 +123,12 @@ public :
const Font& GetFont() const;
////////////////////////////////////////////////////////////
/// Get the size of the characters
/// Get the base size of characters
///
/// \return Size of the characters
/// \return Size of the characters, in pixels
///
////////////////////////////////////////////////////////////
float GetSize() const;
unsigned int GetCharacterSize() const;
////////////////////////////////////////////////////////////
/// Get the style of the text
@ -148,7 +148,7 @@ public :
/// \return Position of the index-th character (end of string if Index is out of range)
///
////////////////////////////////////////////////////////////
sf::Vector2f GetCharacterPos(std::size_t index) const;
Vector2f GetCharacterPos(std::size_t index) const;
////////////////////////////////////////////////////////////
/// Get the string rectangle on screen
@ -179,7 +179,7 @@ private :
////////////////////////////////////////////////////////////
String myString; ///< String to display
ResourcePtr<Font> myFont; ///< Font used to display the string
float mySize; ///< Size of the characters
unsigned int myCharacterSize; ///< Base size of characters, in pixels
unsigned long myStyle; ///< Text style (see Style enum)
FloatRect myBaseRect; ///< Bounding rectangle of the text in object coordinates
bool myNeedRectUpdate; ///< Does the bounding rect need an update ?

View File

@ -47,7 +47,7 @@ int main()
// Initialize the end text
sf::Text end;
end.SetFont(font);
end.SetSize(60.f);
end.SetCharacterSize(60);
end.Move(150.f, 200.f);
end.SetColor(sf::Color(50, 50, 250));

View File

@ -108,7 +108,7 @@ int main()
// Load the text font
sf::Font font;
if (!font.LoadFromFile("datas/shader/arial.ttf", 20))
if (!font.LoadFromFile("datas/shader/arial.ttf"))
return EXIT_FAILURE;
// Load the image needed for the wave shader
@ -144,7 +144,7 @@ int main()
// Define a string for displaying the description of the current shader
sf::Text shaderStr;
shaderStr.SetFont(font);
shaderStr.SetSize(20);
shaderStr.SetCharacterSize(20);
shaderStr.SetPosition(5.f, 0.f);
shaderStr.SetColor(sf::Color(250, 100, 30));
shaderStr.SetString("Background shader: \"" + backgroundShader.GetName() + "\"\n"
@ -154,8 +154,8 @@ int main()
// Define a string for displaying help
sf::Text infoStr;
infoStr.SetFont(font);
infoStr.SetSize(20);
infoStr.SetPosition(5.f, 510.f);
infoStr.SetCharacterSize(20);
infoStr.SetPosition(5.f, 500.f);
infoStr.SetColor(sf::Color(250, 100, 30));
infoStr.SetString("Move your mouse to change the shaders' parameters\n"
"Press numpad 1/4 to change the background shader\n"

View File

@ -26,133 +26,213 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/FontLoader.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <iostream>
namespace sf
{
////////////////////////////////////////////////////////////
// Static member data
////////////////////////////////////////////////////////////
Uint32 Font::ourDefaultCharset[] =
{
// Printable characters in ASCII range
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E,
// Printable characters in extended ASCII range
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0x2A, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE,
// To make it a valid string
0x00
};
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
Font::Font() :
myCharSize(0)
myLibrary (NULL),
myFace (NULL),
myRefCount (NULL),
myCurrentSize(0)
{
}
////////////////////////////////////////////////////////////
/// Load the font from a file
////////////////////////////////////////////////////////////
bool Font::LoadFromFile(const std::string& filename, unsigned int charSize, String charset)
Font::Font(const Font& copy) :
myLibrary (copy.myLibrary),
myFace (copy.myFace),
myRefCount (copy.myRefCount),
myPages (copy.myPages),
myPixelBuffer(copy.myPixelBuffer),
myCurrentSize(copy.myCurrentSize)
{
// Clear the previous character map
myGlyphs.clear();
// Note: as FreeType doesn't provide functions for copying/cloning,
// we must share all the FreeType pointers
// Always add these special characters
if (std::find(charset.Begin(), charset.End(), L' ') == charset.End()) charset += L' ';
if (std::find(charset.Begin(), charset.End(), L'\n') == charset.End()) charset += L'\n';
if (std::find(charset.Begin(), charset.End(), L'\v') == charset.End()) charset += L'\v';
if (std::find(charset.Begin(), charset.End(), L'\t') == charset.End()) charset += L'\t';
return priv::FontLoader::GetInstance().LoadFontFromFile(filename, charSize, charset, *this);
if (myRefCount)
(*myRefCount)++;
}
////////////////////////////////////////////////////////////
/// Load the font from a file in memory
////////////////////////////////////////////////////////////
bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize, String charset)
Font::~Font()
{
// Clear the previous character map
myGlyphs.clear();
Cleanup();
}
// Check parameters
if (!data || (sizeInBytes == 0))
////////////////////////////////////////////////////////////
bool Font::LoadFromFile(const std::string& filename)
{
std::cerr << "Failed to load font from memory, no data provided" << std::endl;
// Cleanup the previous resources
Cleanup();
// Initialize FreeType
// Note: we initialize FreeType for every font instance in order to avoid having a single
// global manager that would create a lot of issues regarding creation and destruction order.
FT_Library library;
if (FT_Init_FreeType(&library) != 0)
{
std::cerr << "Failed to load font \"" << filename << "\" (failed to initialize FreeType)" << std::endl;
return false;
}
myLibrary = library;
// Load the new font face from the specified file
FT_Face face;
if (FT_New_Face(static_cast<FT_Library>(myLibrary), filename.c_str(), 0, &face) != 0)
{
std::cerr << "Failed to load font \"" << filename << "\" (failed to create the font face)" << std::endl;
return false;
}
// Always add these special characters
if (std::find(charset.Begin(), charset.End(), L' ') == charset.End()) charset += L' ';
if (std::find(charset.Begin(), charset.End(), L'\n') == charset.End()) charset += L'\n';
if (std::find(charset.Begin(), charset.End(), L'\v') == charset.End()) charset += L'\v';
if (std::find(charset.Begin(), charset.End(), L'\t') == charset.End()) charset += L'\t';
// Select the unicode character map
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
{
std::cerr << "Failed to load font \"" << filename << "\" (failed to set the Unicode character set)" << std::endl;
return false;
}
return priv::FontLoader::GetInstance().LoadFontFromMemory(data, sizeInBytes, charSize, charset, *this);
// Store the loaded font in our ugly void* :)
myFace = face;
return true;
}
////////////////////////////////////////////////////////////
/// Get the base size of characters in the font;
/// All glyphs dimensions are based on this value
////////////////////////////////////////////////////////////
unsigned int Font::GetCharacterSize() const
bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes)
{
return myCharSize;
// Cleanup the previous resources
Cleanup();
// Initialize FreeType
// Note: we initialize FreeType for every font instance in order to avoid having a single
// global manager that would create a lot of issues regarding creation and destruction order.
FT_Library library;
if (FT_Init_FreeType(&library) != 0)
{
std::cerr << "Failed to load font from memory (failed to initialize FreeType)" << std::endl;
return false;
}
myLibrary = library;
// Load the new font face from the specified file
FT_Face face;
if (FT_New_Memory_Face(static_cast<FT_Library>(myLibrary), reinterpret_cast<const FT_Byte*>(data), static_cast<FT_Long>(sizeInBytes), 0, &face) != 0)
{
std::cerr << "Failed to load font from memory (failed to create the font face)" << std::endl;
return false;
}
// Select the unicode character map
if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
{
std::cerr << "Failed to load font from memory (failed to set the Unicode character set)" << std::endl;
return false;
}
// Store the loaded font in our ugly void* :)
myFace = face;
return true;
}
////////////////////////////////////////////////////////////
/// Get the description of a glyph (character)
/// given by its unicode value
////////////////////////////////////////////////////////////
const Glyph& Font::GetGlyph(Uint32 codePoint) const
const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize) const
{
std::map<Uint32, Glyph>::const_iterator it = myGlyphs.find(codePoint);
if (it != myGlyphs.end())
// Get the page corresponding to the character size
GlyphTable& glyphs = myPages[characterSize].Glyphs;
// Search the glyph into the cache
GlyphTable::const_iterator it = glyphs.find(codePoint);
if (it != glyphs.end())
{
// Valid glyph
return it->second;
// Found: just return it
return it->second.GlyphDesc;
}
else
{
// Invalid glyph -- return an invalid glyph
static const Glyph invalid;
return invalid;
// Not found: we have to load it
GlyphInfo glyph = LoadGlyph(codePoint, characterSize);
return glyphs.insert(std::make_pair(codePoint, glyph)).first->second.GlyphDesc;
}
}
////////////////////////////////////////////////////////////
/// Get the image containing the rendered characters (glyphs)
////////////////////////////////////////////////////////////
const Image& Font::GetImage() const
int Font::GetKerning(Uint32 first, Uint32 second, unsigned int characterSize) const
{
return myTexture;
FT_Face face = static_cast<FT_Face>(myFace);
if (face && FT_HAS_KERNING(face) && SetCurrentSize(characterSize))
{
// Convert the characters to indices
FT_UInt index1 = FT_Get_Char_Index(face, first);
FT_UInt index2 = FT_Get_Char_Index(face, second);
// Get the kerning vector
FT_Vector kerning;
FT_Get_Kerning(face, index1, index2, FT_KERNING_DEFAULT, &kerning);
// Return the X advance
return kerning.x >> 6;
}
else
{
// Invalid font, or no kerning
return 0;
}
}
////////////////////////////////////////////////////////////
/// Get the SFML default built-in font (Arial)
int Font::GetLineSpacing(unsigned int characterSize) const
{
FT_Face face = static_cast<FT_Face>(myFace);
if (face && SetCurrentSize(characterSize))
{
return (face->size->metrics.height >> 6);
}
else
{
return 0;
}
}
////////////////////////////////////////////////////////////
const Image& Font::GetImage(unsigned int characterSize) const
{
return myPages[characterSize].Texture;
}
////////////////////////////////////////////////////////////
Font& Font::operator =(const Font& right)
{
Font temp(right);
std::swap(myLibrary, temp.myLibrary);
std::swap(myFace, temp.myFace);
std::swap(myPages, temp.myPages);
std::swap(myPixelBuffer, temp.myPixelBuffer);
std::swap(myCurrentSize, temp.myCurrentSize);
return *this;
}
////////////////////////////////////////////////////////////
const Font& Font::GetDefaultFont()
{
@ -167,11 +247,231 @@ const Font& Font::GetDefaultFont()
#include <SFML/Graphics/Arial.hpp>
};
font.LoadFromMemory(data, sizeof(data), 30);
font.LoadFromMemory(data, sizeof(data));
loaded = true;
}
return font;
}
////////////////////////////////////////////////////////////
void Font::Cleanup()
{
// Check if we must destroy the FreeType pointers
if (myRefCount)
{
// Decrease the reference counter
(*myRefCount)--;
// Free the resources only if we are the last owner
if (*myRefCount == 0)
{
// Delete the reference counter
delete myRefCount;
// Destroy the font face
if (myFace)
FT_Done_Face(static_cast<FT_Face>(myFace));
// Close the library
if (myLibrary)
FT_Done_FreeType(static_cast<FT_Library>(myLibrary));
}
}
// Reset members
myLibrary = NULL;
myFace = NULL;
myRefCount = NULL;
myCurrentSize = 0;
myPages.clear();
myPixelBuffer.clear();
}
////////////////////////////////////////////////////////////
Font::GlyphInfo Font::LoadGlyph(Uint32 codePoint, unsigned int characterSize) const
{
// The glyph to return
GlyphInfo glyphInfo;
// First, transform our ugly void* to a FT_Face
FT_Face face = static_cast<FT_Face>(myFace);
if (!face)
return glyphInfo;
// Set the character size
if (!SetCurrentSize(characterSize))
return glyphInfo;
// Load the glyph corresponding to the code point
if (FT_Load_Char(face, codePoint, FT_LOAD_TARGET_NORMAL) != 0)
return glyphInfo;
// Convert the glyph to a bitmap (i.e. rasterize it)
FT_Glyph glyphDesc;
if (FT_Get_Glyph(face->glyph, &glyphDesc) != 0)
return glyphInfo;
FT_Glyph_To_Bitmap(&glyphDesc, FT_RENDER_MODE_NORMAL, 0, 1);
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyphDesc;
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
// Compute the glyph's advance offset
glyphInfo.GlyphDesc.Advance = bitmapGlyph->root.advance.x >> 16;
if ((bitmap.width > 0) && (bitmap.rows > 0))
{
// Leave a small padding around characters, so that filtering doesn't
// pollute them with pixels from neighbours
const unsigned int padding = 1;
// Get the glyphs page corresponding to the character size
Page& page = myPages[characterSize];
// Find a good position for the new glyph into the texture
glyphInfo.TextureRect = FindGlyphRect(page, bitmap.width + 2 * padding, bitmap.rows + 2 * padding);
// Compute the glyph's texture coordinates and bounding box
glyphInfo.GlyphDesc.TexCoords = page.Texture.GetTexCoords(glyphInfo.TextureRect);
glyphInfo.GlyphDesc.Rectangle.Left = bitmapGlyph->left - padding;
glyphInfo.GlyphDesc.Rectangle.Top = -bitmapGlyph->top - padding;
glyphInfo.GlyphDesc.Rectangle.Right = bitmapGlyph->left + bitmap.width + padding;
glyphInfo.GlyphDesc.Rectangle.Bottom = -bitmapGlyph->top + bitmap.rows + padding;
// Extract the glyph's pixels from the bitmap
myPixelBuffer.resize(bitmap.width * bitmap.rows * 4, 255);
const Uint8* pixels = bitmap.buffer;
for (int y = 0; y < bitmap.rows; ++y)
{
for (int x = 0; x < bitmap.width; ++x)
{
// The color channels remain white, just fill the alpha channel
std::size_t index = (x + y * bitmap.width) * 4 + 3;
myPixelBuffer[index] = pixels[x];
// Formula for FT_RENDER_MODE_MONO
// myPixelBuffer[index] = ((pixels[x / 8]) & (1 << (7 - (x % 8)))) ? 255 : 0;
}
pixels += bitmap.pitch;
}
// Write the pixels to the texture
IntRect subrect = glyphInfo.TextureRect;
subrect.Left += padding;
subrect.Top += padding;
subrect.Right -= padding;
subrect.Bottom -= padding;
page.Texture.UpdatePixels(&myPixelBuffer[0], subrect);
}
// Delete the FT glyph
FT_Done_Glyph(glyphDesc);
// Done :)
return glyphInfo;
}
////////////////////////////////////////////////////////////
IntRect Font::FindGlyphRect(Page& page, unsigned int width, unsigned int height) const
{
// Find the line that fits well the glyph
Row* row = NULL;
float bestRatio = 0;
for (std::vector<Row>::iterator it = page.Rows.begin(); it != page.Rows.end() && !row; ++it)
{
float ratio = static_cast<float>(height) / it->Height;
// Ignore rows that are either too small or too high
if ((ratio < 0.7f) || (ratio > 1.f))
continue;
// Check if there's enough horizontal space left in the row
if (width > page.Texture.GetWidth() - it->Width)
continue;
// Make sure that this new row is the best found so far
if (ratio < bestRatio)
continue;
// The current row passed all the tests: we can select it
row = &*it;
bestRatio = ratio;
}
// If we didn't find a matching row, create a new one (10% taller than the glyph)
if (!row)
{
int rowHeight = height + height / 10;
if (page.NextRow + rowHeight >= page.Texture.GetHeight())
{
// Not enough space: resize the texture if possible
unsigned int textureWidth = page.Texture.GetWidth();
unsigned int textureHeight = page.Texture.GetHeight();
if ((textureWidth * 2 <= Image::GetMaximumSize()) && (textureHeight * 2 <= Image::GetMaximumSize()))
{
// Make the texture 2 times bigger
std::size_t size = textureWidth * textureHeight * 4;
std::vector<Uint8> pixels(size);
memcpy(&pixels[0], page.Texture.GetPixelsPtr(), size);
page.Texture.Create(textureWidth * 2, textureHeight * 2, sf::Color(255, 255, 255, 0));
page.Texture.UpdatePixels(&pixels[0], IntRect(0, 0, textureWidth, textureHeight));
// Adjust the texture coordinates of all the glyphs that are stored in this page
for (GlyphTable::iterator it = page.Glyphs.begin(); it != page.Glyphs.end(); ++it)
{
it->second.GlyphDesc.TexCoords = page.Texture.GetTexCoords(it->second.TextureRect);
}
}
else
{
// Oops, we've reached the maximum texture size...
std::cerr << "Failed to add a new character to the font: the maximum image size has been reached" << std::endl;
return IntRect(0, 0, 2, 2);
}
}
// We can now create the new row
page.Rows.push_back(Row(page.NextRow, rowHeight));
page.NextRow += rowHeight;
row = &page.Rows.back();
}
// Find the glyph's rectangle on the selected row
IntRect rect(row->Width, row->Top, row->Width + width, row->Top + height);
// Update the row informations
row->Width += width;
return rect;
}
////////////////////////////////////////////////////////////
bool Font::SetCurrentSize(unsigned int characterSize) const
{
// FT_Set_Pixel_Sizes is an expensive function, so we must call it
// only when necessary to avoid killing performances
if (myCurrentSize != characterSize)
{
myCurrentSize = characterSize;
return FT_Set_Pixel_Sizes(static_cast<FT_Face>(myFace), characterSize, characterSize) == 0;
}
else
{
return true;
}
}
////////////////////////////////////////////////////////////
Font::Page::Page() :
NextRow(0)
{
// Make sure that the texture is initialized by default
Texture.Create(128, 128, Color(255, 255, 255, 0));
}
} // namespace sf

View File

@ -1,671 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
//
// 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.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
//#define SFML_USE_STBTT
#ifndef SFML_USE_STBTT
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/FontLoader.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include FT_GLYPH_H
#include <iostream>
#include <map>
#include <vector>
#include <math.h>
namespace
{
////////////////////////////////////////////////////////////
// Functor to sort glyphs by size
////////////////////////////////////////////////////////////
struct SizeCompare
{
bool operator ()(FT_BitmapGlyph left, FT_BitmapGlyph right) const
{
return left->bitmap.rows < right->bitmap.rows;
}
};
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// Get the unique instance of the class
////////////////////////////////////////////////////////////
FontLoader& FontLoader::GetInstance()
{
static FontLoader instance;
return instance;
}
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
FontLoader::FontLoader()
{
// Initialize FreeType library
FT_Error error = FT_Init_FreeType(&myLibrary);
if (error)
{
std::cerr << "Failed to initialize FreeType library (error code : " << error << ")" << std::endl;
return;
}
}
////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
FontLoader::~FontLoader()
{
// Shutdown FreeType library
if (myLibrary)
FT_Done_FreeType(myLibrary);
}
////////////////////////////////////////////////////////////
/// Load a font from a file
////////////////////////////////////////////////////////////
bool FontLoader::LoadFontFromFile(const std::string& filename, unsigned int charSize, const String& charset, Font& font)
{
// Check if Freetype is correctly initialized
if (!myLibrary)
{
std::cerr << "Failed to load font \"" << filename << "\", FreeType has not been initialized" << std::endl;
return false;
}
// Create a new font face from the specified file
FT_Face face;
FT_Error error = FT_New_Face(myLibrary, filename.c_str(), 0, &face);
if (error)
{
std::cerr << "Failed to load font \"" << filename << "\" (" << GetErrorDesc(error) << ")" << std::endl;
return false;
}
// Create the bitmap font
error = CreateBitmapFont(face, charSize, charset, font);
if (error)
std::cerr << "Failed to load font \"" << filename << "\" (" << GetErrorDesc(error) << ")" << std::endl;
// Delete the font
FT_Done_Face(face);
return error == 0;
}
////////////////////////////////////////////////////////////
/// Load the font from a file in memory
////////////////////////////////////////////////////////////
bool FontLoader::LoadFontFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize, const String& charset, Font& font)
{
// Check if Freetype is correctly initialized
if (!myLibrary)
{
std::cerr << "Failed to load font from memory, FreeType has not been initialized" << std::endl;
return false;
}
// Create a new font face from the specified memory data
FT_Face face;
FT_Error error = FT_New_Memory_Face(myLibrary, reinterpret_cast<const FT_Byte*>(data), static_cast<FT_Long>(sizeInBytes), 0, &face);
if (error)
{
std::cerr << "Failed to load font from memory (" << GetErrorDesc(error) << ")" << std::endl;
return false;
}
// Create the bitmap font
error = CreateBitmapFont(face, charSize, charset, font);
if (error)
std::cerr << "Failed to load font from memory (" << GetErrorDesc(error) << ")" << std::endl;
// Delete the font
FT_Done_Face(face);
return error == 0;
}
////////////////////////////////////////////////////////////
/// Create a bitmap font from a font face and a characters set
////////////////////////////////////////////////////////////
FT_Error FontLoader::CreateBitmapFont(FT_Face face, unsigned int charSize, const String& charset, Font& font)
{
// Let's find how many characters to put in each row to make them fit into a squared texture
unsigned int maxSize = Image::GetMaximumSize();
int nbChars = static_cast<int>(sqrt(static_cast<double>(charset.GetSize())) * 0.75);
// Clamp the character size to make sure we won't create a texture too big
if (nbChars * charSize >= maxSize)
charSize = maxSize / nbChars;
// Initialize the dimensions
unsigned int left = 0;
unsigned int top = 0;
unsigned int texWidth = Image::GetValidSize(charSize * nbChars);
unsigned int texHeight = charSize * nbChars;
std::vector<unsigned int> tops(texWidth, 0);
// Create a pixel buffer for rendering every glyph
std::vector<Uint8> glyphsBuffer(texWidth * texHeight * 4);
// Setup the font size
FT_Error error = FT_Set_Pixel_Sizes(face, charSize, charSize);
if (error)
return error;
// Select the unicode character map
error = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
if (error)
return error;
// Render all glyphs and sort them by size to optimize texture space
typedef std::multimap<FT_BitmapGlyph, Uint32, SizeCompare> GlyphTable;
GlyphTable glyphs;
for (std::size_t i = 0; i < charset.GetSize(); ++i)
{
// Load the glyph corresponding to the current character
error = FT_Load_Char(face, charset[i], FT_LOAD_TARGET_NORMAL);
if (error)
return error;
// Convert the glyph to a bitmap (ie. rasterize it)
FT_Glyph glyph;
error = FT_Get_Glyph(face->glyph, &glyph);
if (error)
return error;
FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
FT_BitmapGlyph bitmapGlyph = (FT_BitmapGlyph)glyph;
// Add it to the sorted table of glyphs
glyphs.insert(std::make_pair(bitmapGlyph, charset[i]));
}
// Leave a small margin around characters, so that filtering doesn't
// pollute them with pixels from neighbours
unsigned int padding = 1;
unsigned int margin = 1;
// Copy the rendered glyphs into the texture
unsigned int maxHeight = 0;
std::map<Uint32, IntRect> coords;
for (GlyphTable::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i)
{
// Get the bitmap of the current glyph
Glyph& curGlyph = font.myGlyphs[i->second];
FT_BitmapGlyph bitmapGlyph = i->first;
FT_Bitmap& bitmap = bitmapGlyph->bitmap;
// Make sure we don't go over the texture width
if (left + bitmap.width + 2 * padding + margin >= texWidth)
left = 0;
// Compute the top coordinate
top = tops[left];
for (unsigned int x = 0; x < bitmap.width + 2 * padding + margin; ++x)
top = std::max(top, tops[left + x]);
// Make sure we don't go over the texture height -- resize it if we need more space
if (top + bitmap.rows + 2 * padding + margin >= texHeight)
{
texHeight *= 2;
glyphsBuffer.resize(texWidth * texHeight * 4);
}
// Store the character's position and size
curGlyph.Rectangle.Left = bitmapGlyph->left - padding;
curGlyph.Rectangle.Top = -bitmapGlyph->top - padding;
curGlyph.Rectangle.Right = bitmapGlyph->left + bitmap.width + padding;
curGlyph.Rectangle.Bottom = -bitmapGlyph->top + bitmap.rows + padding;
curGlyph.Advance = bitmapGlyph->root.advance.x >> 16;
// Texture size may change, so let the texture coordinates be calculated later
coords[i->second] = IntRect(left, top, left + bitmap.width + 2 * padding, top + bitmap.rows + 2 * padding);
// Draw the glyph into our bitmap font
const Uint8* pixels = bitmap.buffer;
for (int y = 0; y < bitmap.rows; ++y)
{
for (int x = 0; x < bitmap.width; ++x)
{
std::size_t index = x + left + padding + (y + top + padding) * texWidth;
glyphsBuffer[index * 4 + 0] = 255;
glyphsBuffer[index * 4 + 1] = 255;
glyphsBuffer[index * 4 + 2] = 255;
glyphsBuffer[index * 4 + 3] = pixels[x];
// Formula for FT_RENDER_MODE_MONO
// glyphsBuffer[index * 4 + 3] = ((pixels[x / 8]) & (1 << (7 - (x % 8)))) ? 255 : 0;
}
pixels += bitmap.pitch;
}
// Update the rendering coordinates
for (unsigned int x = 0; x < bitmap.width + 2 * padding + margin; ++x)
tops[left + x] = top + bitmap.rows + 2 * padding + margin;
left += bitmap.width + 2 * padding + margin;
if (top + bitmap.rows + 2 * padding > maxHeight)
maxHeight = top + bitmap.rows + 2 * padding;
// Delete the glyph
FT_Done_Glyph((FT_Glyph)bitmapGlyph);
}
// Create the font's texture
texHeight = maxHeight;
glyphsBuffer.resize(texWidth * texHeight * 4);
font.myTexture.LoadFromPixels(texWidth, texHeight, &glyphsBuffer[0]);
// Now that the texture is created, we can precompute texture coordinates
for (std::size_t i = 0; i < charset.GetSize(); ++i)
{
Uint32 curChar = charset[i];
font.myGlyphs[curChar].TexCoords = font.myTexture.GetTexCoords(coords[curChar]);
}
// Update the character size (it may have been changed by the function)
font.myCharSize = charSize;
return 0;
}
////////////////////////////////////////////////////////////
/// Get a description from a FT error code
////////////////////////////////////////////////////////////
std::string FontLoader::GetErrorDesc(FT_Error error)
{
switch (error)
{
// Generic errors
case FT_Err_Cannot_Open_Resource : return "cannot open resource";
case FT_Err_Unknown_File_Format : return "unknown file format";
case FT_Err_Invalid_File_Format : return "broken file";
case FT_Err_Invalid_Version : return "invalid FreeType version";
case FT_Err_Lower_Module_Version : return "module version is too low";
case FT_Err_Invalid_Argument : return "invalid argument";
case FT_Err_Unimplemented_Feature : return "unimplemented feature";
case FT_Err_Invalid_Table : return "broken table";
case FT_Err_Invalid_Offset : return "broken offset within table";
// Glyph / character errors
case FT_Err_Invalid_Glyph_Index : return "invalid glyph index";
case FT_Err_Invalid_Character_Code : return "invalid character code";
case FT_Err_Invalid_Glyph_Format : return "unsupported glyph image format";
case FT_Err_Cannot_Render_Glyph : return "cannot render this glyph format";
case FT_Err_Invalid_Outline : return "invalid outline";
case FT_Err_Invalid_Composite : return "invalid composite glyph";
case FT_Err_Too_Many_Hints : return "too many hints";
case FT_Err_Invalid_Pixel_Size : return "invalid pixel size";
// Handle errors
case FT_Err_Invalid_Handle : return "invalid object handle";
case FT_Err_Invalid_Library_Handle : return "invalid library handle";
case FT_Err_Invalid_Driver_Handle : return "invalid module handle";
case FT_Err_Invalid_Face_Handle : return "invalid face handle";
case FT_Err_Invalid_Size_Handle : return "invalid size handle";
case FT_Err_Invalid_Slot_Handle : return "invalid glyph slot handle";
case FT_Err_Invalid_CharMap_Handle : return "invalid charmap handle";
case FT_Err_Invalid_Cache_Handle : return "invalid cache manager handle";
case FT_Err_Invalid_Stream_Handle : return "invalid stream handle";
// Driver errors
case FT_Err_Too_Many_Drivers : return "too many modules";
case FT_Err_Too_Many_Extensions : return "too many extensions";
// Memory errors
case FT_Err_Out_Of_Memory : return "out of memory";
case FT_Err_Unlisted_Object : return "unlisted object";
// Stream errors
case FT_Err_Cannot_Open_Stream : return "cannot open stream";
case FT_Err_Invalid_Stream_Seek : return "invalid stream seek";
case FT_Err_Invalid_Stream_Skip : return "invalid stream skip";
case FT_Err_Invalid_Stream_Read : return "invalid stream read";
case FT_Err_Invalid_Stream_Operation : return "invalid stream operation";
case FT_Err_Invalid_Frame_Operation : return "invalid frame operation";
case FT_Err_Nested_Frame_Access : return "nested frame access";
case FT_Err_Invalid_Frame_Read : return "invalid frame read";
// Raster errors
case FT_Err_Raster_Uninitialized : return "raster uninitialized";
case FT_Err_Raster_Corrupted : return "raster corrupted";
case FT_Err_Raster_Overflow : return "raster overflow";
case FT_Err_Raster_Negative_Height : return "negative height while rastering";
// Cache errors
case FT_Err_Too_Many_Caches : return "too many registered caches";
// TrueType and SFNT errors
case FT_Err_Invalid_Opcode : return "invalid opcode";
case FT_Err_Too_Few_Arguments : return "too few arguments";
case FT_Err_Stack_Overflow : return "stack overflow";
case FT_Err_Code_Overflow : return "code overflow";
case FT_Err_Bad_Argument : return "bad argument";
case FT_Err_Divide_By_Zero : return "division by zero";
case FT_Err_Invalid_Reference : return "invalid reference";
case FT_Err_Debug_OpCode : return "found debug opcode";
case FT_Err_ENDF_In_Exec_Stream : return "found ENDF opcode in execution stream";
case FT_Err_Nested_DEFS : return "nested DEFS";
case FT_Err_Invalid_CodeRange : return "invalid code range";
case FT_Err_Execution_Too_Long : return "execution context too long";
case FT_Err_Too_Many_Function_Defs : return "too many function definitions";
case FT_Err_Too_Many_Instruction_Defs : return "too many instruction definitions";
case FT_Err_Table_Missing : return "SFNT font table missing";
case FT_Err_Horiz_Header_Missing : return "horizontal header (hhea) table missing";
case FT_Err_Locations_Missing : return "locations (loca) table missing";
case FT_Err_Name_Table_Missing : return "name table missing";
case FT_Err_CMap_Table_Missing : return "character map (cmap) table missing";
case FT_Err_Hmtx_Table_Missing : return "horizontal metrics (hmtx) table missing";
case FT_Err_Post_Table_Missing : return "PostScript (post) table missing";
case FT_Err_Invalid_Horiz_Metrics : return "invalid horizontal metrics";
case FT_Err_Invalid_CharMap_Format : return "invalid character map (cmap) format";
case FT_Err_Invalid_PPem : return "invalid ppem value";
case FT_Err_Invalid_Vert_Metrics : return "invalid vertical metrics";
case FT_Err_Could_Not_Find_Context : return "could not find context";
case FT_Err_Invalid_Post_Table_Format : return "invalid PostScript (post) table format";
case FT_Err_Invalid_Post_Table : return "invalid PostScript (post) table";
// CCF, CID and Type 1 errors
case FT_Err_Syntax_Error : return "opcode syntax error";
case FT_Err_Stack_Underflow : return "argument stack underflow";
case FT_Err_Ignore : return "ignore";
// BDF errors
case FT_Err_Missing_Startfont_Field : return "`STARTFONT' field missing";
case FT_Err_Missing_Font_Field : return "`FONT' field missing";
case FT_Err_Missing_Size_Field : return "`SIZE' field missing";
case FT_Err_Missing_Chars_Field : return "`CHARS' field missing";
case FT_Err_Missing_Startchar_Field : return "`STARTCHAR' field missing";
case FT_Err_Missing_Encoding_Field : return "`ENCODING' field missing";
case FT_Err_Missing_Bbx_Field : return "`BBX' field missing";
}
return "unknown error";
}
} // namespace priv
} // namespace sf
#else
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/FontLoader.hpp>
#include <SFML/Graphics/Color.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#define STB_TRUETYPE_IMPLEMENTATION
#include <SFML/Graphics/stb_truetype/stb_truetype.h>
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <math.h>
namespace
{
////////////////////////////////////////////////////////////
// Functor to sort glyphs by size
////////////////////////////////////////////////////////////
struct SizeCompare
{
bool operator ()(const sf::Glyph& left, const sf::Glyph& right) const
{
return left.Rectangle.GetSize().y < right.Rectangle.GetSize().y;
}
};
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// Get the unique instance of the class
////////////////////////////////////////////////////////////
FontLoader& FontLoader::GetInstance()
{
static FontLoader instance;
return instance;
}
////////////////////////////////////////////////////////////
/// Default constructor
////////////////////////////////////////////////////////////
FontLoader::FontLoader()
{
}
////////////////////////////////////////////////////////////
/// Destructor
////////////////////////////////////////////////////////////
FontLoader::~FontLoader()
{
}
////////////////////////////////////////////////////////////
/// Load a font from a file
////////////////////////////////////////////////////////////
bool FontLoader::LoadFontFromFile(const std::string& filename, unsigned int charSize, const String& charset, Font& font)
{
// Get the contents of the font file
std::ifstream file(filename.c_str(), std::ios_base::binary);
if (!file)
return false;
file.seekg(0, std::ios::end);
std::size_t length = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> data(length);
file.read(&data[0], static_cast<std::streamsize>(length));
// Load from memory
return LoadFontFromMemory(&data[0], data.size(), charSize, charset, font);
}
////////////////////////////////////////////////////////////
/// Load the font from a file in memory
////////////////////////////////////////////////////////////
bool FontLoader::LoadFontFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize, const String& charset, Font& font)
{
// Let's find how many characters to put in each row to make them fit into a squared texture
unsigned int maxSize = Image::GetMaximumSize();
int nbChars = static_cast<int>(sqrt(static_cast<double>(charset.GetSize())) * 0.75);
// Clamp the character size to make sure we won't create a texture too big
if (nbChars * charSize >= maxSize)
charSize = maxSize / nbChars;
// Initialize the dimensions
unsigned int left = 0;
unsigned int top = 0;
unsigned int texWidth = Image::GetValidSize(charSize * nbChars);
unsigned int texHeight = charSize * nbChars;
std::vector<unsigned int> tops(texWidth, 0);
// Create a pixel buffer for rendering every glyph
std::vector<Uint8> glyphsBuffer(texWidth * texHeight * 4);
// Load the font
stbtt_fontinfo info;
int success = stbtt_InitFont(&info, reinterpret_cast<const unsigned char*>(data), 0);
if (!success)
return false;
// Compute the global scale to apply to match the character size
float scale = stbtt_ScaleForPixelHeight(&info, static_cast<float>(charSize));
// Render all glyphs and sort them by size to optimize texture space
typedef std::multimap<Glyph, Uint32, SizeCompare> GlyphTable;
GlyphTable glyphs;
for (std::size_t i = 0; i < charset.GetSize(); ++i)
{
// Load the glyph corresponding to the current character
int index = stbtt_FindGlyphIndex(&info, static_cast<int>(charset[i]));
// Extract the glyph parameters (bounding box, horizontal advance)
Glyph glyph;
stbtt_GetGlyphHMetrics(&info, index, &glyph.Advance, NULL);
stbtt_GetGlyphBitmapBox(&info, index, scale, scale, &glyph.Rectangle.Left, &glyph.Rectangle.Top, &glyph.Rectangle.Right, &glyph.Rectangle.Bottom);
// Apply the global scale to the horizontal advance
glyph.Advance = static_cast<int>(glyph.Advance * scale);
// Add it to the sorted table of glyphs
glyphs.insert(std::make_pair(glyph, charset[i]));
}
// Leave a small margin around characters, so that filtering doesn't
// pollute them with pixels from neighbours
unsigned int padding = 1;
unsigned int margin = 1;
// Copy the rendered glyphs into the texture
unsigned int maxHeight = 0;
std::map<Uint32, IntRect> coords;
for (GlyphTable::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i)
{
// Get the bitmap of the current glyph
Glyph& curGlyph = font.myGlyphs[i->second];
const Glyph& bitmapGlyph = i->first;
const Vector2i& glyphSize = bitmapGlyph.Rectangle.GetSize();
// Make sure we don't go over the texture width
if (left + glyphSize.x + 2 * padding + margin >= texWidth)
left = 0;
// Compute the top coordinate
top = tops[left];
for (unsigned int x = 0; x < glyphSize.x + 2 * padding + margin; ++x)
top = std::max(top, tops[left + x]);
// Make sure we don't go over the texture height -- resize it if we need more space
if (top + glyphSize.x + 2 * padding + margin >= texHeight)
{
texHeight *= 2;
glyphsBuffer.resize(texWidth * texHeight * 4);
}
// Store the character's position and size
curGlyph.Rectangle.Left = bitmapGlyph.Rectangle.Left - padding;
curGlyph.Rectangle.Top = bitmapGlyph.Rectangle.Top - padding;
curGlyph.Rectangle.Right = bitmapGlyph.Rectangle.Right + padding;
curGlyph.Rectangle.Bottom = bitmapGlyph.Rectangle.Bottom + padding;
curGlyph.Advance = bitmapGlyph.Advance;
// Texture size may change, so let the texture coordinates be calculated later
coords[i->second] = IntRect(left, top, left + glyphSize.x + 2 * padding, top + glyphSize.y + 2 * padding);
// Draw the glyph into our bitmap font
int width, height;
unsigned char* bitmap = stbtt_GetCodepointBitmap(&info, scale, scale, i->second, &width, &height, NULL, NULL);
unsigned char* pixels = bitmap;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
std::size_t index = x + left + padding + (y + top + padding) * texWidth;
glyphsBuffer[index * 4 + 0] = 255;
glyphsBuffer[index * 4 + 1] = 255;
glyphsBuffer[index * 4 + 2] = 255;
glyphsBuffer[index * 4 + 3] = pixels[x];
}
pixels += width;
}
// Update the rendering coordinates
for (unsigned int x = 0; x < width + 2 * padding + margin; ++x)
tops[left + x] = top + height + 2 * padding + margin;
left += width + 2 * padding + margin;
if (top + height + 2 * padding > maxHeight)
maxHeight = top + height + 2 * padding;
// Delete the bitmap
stbtt_FreeBitmap(bitmap, NULL);
}
// Create the font's texture
texHeight = maxHeight;
glyphsBuffer.resize(texWidth * texHeight * 4);
font.myTexture.LoadFromPixels(texWidth, texHeight, &glyphsBuffer[0]);
// Now that the texture is created, we can precompute texture coordinates
for (std::size_t i = 0; i < charset.GetSize(); ++i)
{
Uint32 curChar = charset[i];
font.myGlyphs[curChar].TexCoords = font.myTexture.GetTexCoords(coords[curChar]);
}
// Update the character size (it may have been changed by the function)
font.myCharSize = charSize;
return 0;
}
////////////////////////////////////////////////////////////
/// Create a bitmap font from a font face and a characters set
////////////////////////////////////////////////////////////
FT_Error FontLoader::CreateBitmapFont(FT_Face face, unsigned int charSize, const String& charset, Font& font)
{
return 0;
}
////////////////////////////////////////////////////////////
/// Get a description from a FT error code
////////////////////////////////////////////////////////////
std::string FontLoader::GetErrorDesc(FT_Error error)
{
return "";
}
} // namespace priv
} // namespace sf
#endif

View File

@ -1,132 +0,0 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2009 Laurent Gomila (laurent.gom@gmail.com)
//
// 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.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_FONTLOADER_HPP
#define SFML_FONTLOADER_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/NonCopyable.hpp>
#include <SFML/System/String.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <string>
namespace sf
{
class Font;
namespace priv
{
////////////////////////////////////////////////////////////
/// FontLoader loads and saves character fonts
////////////////////////////////////////////////////////////
class FontLoader : NonCopyable
{
public :
////////////////////////////////////////////////////////////
/// Get the unique instance of the class
///
/// \return Reference to the FontLoader instance
///
////////////////////////////////////////////////////////////
static FontLoader& GetInstance();
////////////////////////////////////////////////////////////
/// Load a font from a file
///
/// \param filename : Path of the font file to load
/// \param charSize : Size of characters in bitmap - the bigger, the higher quality
/// \param charset : Characters set to generate
/// \param font : Font object to fill up
///
/// \return True if loading was successful
///
////////////////////////////////////////////////////////////
bool LoadFontFromFile(const std::string& filename, unsigned int charSize, const String& charset, Font& font);
////////////////////////////////////////////////////////////
/// Load the font from a file in memory
///
/// \param data : Pointer to the data to load
/// \param sizeInBytes : Size of the data, in bytes
/// \param charSize : Size of characters in bitmap - the bigger, the higher quality
/// \param charset : Characters set to generate
/// \param font : Font object to fill up
///
/// \return True if loading was successful
///
////////////////////////////////////////////////////////////
bool LoadFontFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize, const String& charset, Font& font);
private :
////////////////////////////////////////////////////////////
/// Default constructor
///
////////////////////////////////////////////////////////////
FontLoader();
////////////////////////////////////////////////////////////
/// Destructor
///
////////////////////////////////////////////////////////////
~FontLoader();
////////////////////////////////////////////////////////////
/// Create a bitmap font from a font face and a characters set
///
/// \param face : Font face containing the loaded font
/// \param charSize : Size of characters in bitmap
/// \param charset : Characters set to generate
/// \param font : Font object to fill up
///
////////////////////////////////////////////////////////////
FT_Error CreateBitmapFont(FT_Face face, unsigned int charSize, const String& charset, Font& font);
////////////////////////////////////////////////////////////
/// Get a description from a FT error code
///
/// \param error : FreeType error code
///
/// \return Error description
///
////////////////////////////////////////////////////////////
static std::string GetErrorDesc(FT_Error error);
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
FT_Library myLibrary; ///< Handle to the Freetype library
};
} // namespace priv
} // namespace sf
#endif // SFML_FONTLOADER_HPP

View File

@ -28,7 +28,6 @@
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <iostream>

View File

@ -37,7 +37,7 @@ namespace sf
////////////////////////////////////////////////////////////
Text::Text() :
myFont (&Font::GetDefaultFont()),
mySize (30.f),
myCharacterSize (30),
myStyle (Regular),
myNeedRectUpdate(true)
{
@ -48,9 +48,9 @@ myNeedRectUpdate(true)
////////////////////////////////////////////////////////////
/// Construct the string from any kind of text
////////////////////////////////////////////////////////////
Text::Text(const String& string, const Font& font, float size) :
Text::Text(const String& string, const Font& font, unsigned int characterSize) :
myFont (&font),
mySize (size),
myCharacterSize (characterSize),
myStyle (Regular),
myNeedRectUpdate(true)
{
@ -82,14 +82,14 @@ void Text::SetFont(const Font& font)
////////////////////////////////////////////////////////////
/// Set the size of the string
/// Set the base size for the characters.
////////////////////////////////////////////////////////////
void Text::SetSize(float size)
void Text::SetCharacterSize(unsigned int size)
{
if (mySize != size)
if (myCharacterSize != size)
{
myNeedRectUpdate = true;
mySize = size;
myCharacterSize = size;
}
}
@ -127,11 +127,11 @@ const Font& Text::GetFont() const
////////////////////////////////////////////////////////////
/// Get the size of the characters
/// Get the base size of characters
////////////////////////////////////////////////////////////
float Text::GetSize() const
unsigned int Text::GetCharacterSize() const
{
return mySize;
return myCharacterSize;
}
@ -149,36 +149,42 @@ unsigned long Text::GetStyle() const
/// in coordinates relative to the string
/// (note : translation, center, rotation and scale are not applied)
////////////////////////////////////////////////////////////
sf::Vector2f Text::GetCharacterPos(std::size_t index) const
Vector2f Text::GetCharacterPos(std::size_t index) const
{
// Make sure that we have a valid font
if (!myFont)
return Vector2f(0, 0);
// Adjust the index if it's out of range
if (index > myString.GetSize())
index = myString.GetSize();
// The final size is based on the text size
float factor = mySize / myFont->GetCharacterSize();
float advanceY = mySize;
// We'll need this a lot
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize).Advance);
// Compute the position
sf::Vector2f position;
Uint32 prevChar = 0;
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
for (std::size_t i = 0; i < index; ++i)
{
// Get the current character and its corresponding glyph
Uint32 curChar = myString[i];
const Glyph& curGlyph = myFont->GetGlyph(curChar);
float advanceX = curGlyph.Advance * factor;
// Apply the kerning offset
position.x += static_cast<float>(myFont->GetKerning(prevChar, curChar, myCharacterSize));
prevChar = curChar;
// Handle special characters
switch (curChar)
{
// Handle special characters
case L' ' : position.x += advanceX; break;
case L'\t' : position.x += advanceX * 4; break;
case L'\v' : position.y += advanceY * 4; break;
case L'\n' : position.y += advanceY; position.x = 0; break;
// Regular character : just add its advance value
default : position.x += advanceX; break;
case L' ' : position.x += space; continue;
case L'\t' : position.x += space * 4; continue;
case L'\v' : position.y += lineSpacing * 4; continue;
case L'\n' : position.y += lineSpacing; position.x = 0; continue;
}
// For regular characters, add the advance offset of the glyph
position.x += static_cast<float>(myFont->GetGlyph(curChar, myCharacterSize).Advance);
}
return position;
@ -204,24 +210,22 @@ FloatRect Text::GetRect() const
////////////////////////////////////////////////////////////
/// /see sfDrawable::Render
/// /see Drawable::Render
////////////////////////////////////////////////////////////
void Text::Render(RenderTarget&, RenderQueue& queue) const
{
// No text, no rendering :)
if (myString.IsEmpty())
// No text or not font: nothing to render
if (!myFont || myString.IsEmpty())
return;
// Set the scaling factor to get the actual size
float charSize = static_cast<float>(myFont->GetCharacterSize());
float factor = mySize / charSize;
// Bind the font texture
queue.SetTexture(&myFont->GetImage());
queue.SetTexture(&myFont->GetImage(myCharacterSize));
// Initialize the rendering coordinates
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize).Advance);
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
float x = 0.f;
float y = charSize;
float y = static_cast<float>(myCharacterSize);
// Holds the lines to draw later, for underlined style
std::vector<float> underlineCoords;
@ -232,15 +236,15 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
// Draw one quad for each character
unsigned int index = 0;
Uint32 prevChar = 0;
queue.BeginBatch();
for (std::size_t i = 0; i < myString.GetSize(); ++i)
{
// Get the current character and its corresponding glyph
Uint32 curChar = myString[i];
const Glyph& curGlyph = myFont->GetGlyph(curChar);
int advance = curGlyph.Advance;
const IntRect& rect = curGlyph.Rectangle;
const FloatRect& coord = curGlyph.TexCoords;
// Apply the kerning offset
x += static_cast<float>(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
@ -253,17 +257,23 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
// Handle special characters
switch (curChar)
{
case L' ' : x += advance; continue;
case L'\n' : y += charSize; x = 0; continue;
case L'\t' : x += advance * 4; continue;
case L'\v' : y += charSize * 4; continue;
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(factor * (x + rect.Left - italicCoeff * rect.Top), factor * (y + rect.Top), coord.Left, coord.Top);
queue.AddVertex(factor * (x + rect.Left - italicCoeff * rect.Bottom), factor * (y + rect.Bottom), coord.Left, coord.Bottom);
queue.AddVertex(factor * (x + rect.Right - italicCoeff * rect.Bottom), factor * (y + rect.Bottom), coord.Right, coord.Bottom);
queue.AddVertex(factor * (x + rect.Right - italicCoeff * rect.Top), factor * (y + rect.Top), coord.Right, coord.Top);
queue.AddVertex(x + rect.Left - italicCoeff * rect.Top, y + rect.Top, coord.Left, coord.Top);
queue.AddVertex(x + rect.Left - italicCoeff * rect.Bottom, y + rect.Bottom, coord.Left, coord.Bottom);
queue.AddVertex(x + rect.Right - italicCoeff * rect.Bottom, y + rect.Bottom, coord.Right, coord.Bottom);
queue.AddVertex(x + rect.Right - italicCoeff * rect.Top, y + rect.Top, coord.Right, coord.Top);
queue.AddTriangle(index + 0, index + 1, index + 3);
queue.AddTriangle(index + 3, index + 1, index + 2);
@ -277,7 +287,7 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
// slightly offseted, to simulate a higher weight
if (myStyle & Bold)
{
float offset = mySize * 0.02f;
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};
@ -285,32 +295,38 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
{
index = 0;
x = 0.f;
y = charSize;
y = static_cast<float>(myCharacterSize);
Uint32 prevChar = 0;
queue.BeginBatch();
for (std::size_t i = 0; i < myString.GetSize(); ++i)
{
// Get the current character and its corresponding glyph
Uint32 curChar = myString[i];
const Glyph& curGlyph = myFont->GetGlyph(curChar);
int advance = curGlyph.Advance;
const IntRect& rect = curGlyph.Rectangle;
const FloatRect& coord = curGlyph.TexCoords;
// Apply the kerning offset
x += static_cast<float>(myFont->GetKerning(prevChar, curChar, myCharacterSize));
prevChar = curChar;
// Handle special characters
switch (curChar)
{
case L' ' : x += advance; continue;
case L'\n' : y += charSize; x = 0; continue;
case L'\t' : x += advance * 4; continue;
case L'\v' : y += charSize * 4; continue;
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(factor * (x + offsetsX[j] + rect.Left - italicCoeff * rect.Top), factor * (y + offsetsY[j] + rect.Top), coord.Left, coord.Top);
queue.AddVertex(factor * (x + offsetsX[j] + rect.Left - italicCoeff * rect.Bottom), factor * (y + offsetsY[j] + rect.Bottom), coord.Left, coord.Bottom);
queue.AddVertex(factor * (x + offsetsX[j] + rect.Right - italicCoeff * rect.Bottom), factor * (y + offsetsY[j] + rect.Bottom), coord.Right, coord.Bottom);
queue.AddVertex(factor * (x + offsetsX[j] + rect.Right - italicCoeff * rect.Top), factor * (y + offsetsY[j] + rect.Top), coord.Right, coord.Top);
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);
@ -338,10 +354,10 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
queue.BeginBatch();
for (std::size_t i = 0; i < underlineCoords.size(); i += 2)
{
queue.AddVertex(factor * (0), factor * (underlineCoords[i + 1]));
queue.AddVertex(factor * (0), factor * (underlineCoords[i + 1] + thickness));
queue.AddVertex(factor * (underlineCoords[i]), factor * (underlineCoords[i + 1] + thickness));
queue.AddVertex(factor * (underlineCoords[i]), factor * (underlineCoords[i + 1]));
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);
@ -356,41 +372,51 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const
////////////////////////////////////////////////////////////
void Text::RecomputeRect()
{
// Reset the "need update" state
// Reset the previous states
myNeedRectUpdate = false;
// No text, empty box :)
if (myString.IsEmpty())
{
myBaseRect = FloatRect(0, 0, 0, 0);
// No text or not font: empty box
if (!myFont || myString.IsEmpty())
return;
}
// Initial values
float charSize = static_cast<float>(myCharacterSize);
float space = static_cast<float>(myFont->GetGlyph(L' ', myCharacterSize).Advance);
float lineSpacing = static_cast<float>(myFont->GetLineSpacing(myCharacterSize));
float curWidth = 0;
float curHeight = 0;
float width = 0;
float height = 0;
float factor = mySize / myFont->GetCharacterSize();
Uint32 prevChar = 0;
// Go through each character
for (std::size_t i = 0; i < myString.GetSize(); ++i)
{
// Get the current character and its corresponding glyph
Uint32 curChar = myString[i];
const Glyph& curGlyph = myFont->GetGlyph(curChar);
float advance = curGlyph.Advance * factor;
const IntRect& rect = curGlyph.Rectangle;
// Apply the kerning offset
curWidth += static_cast<float>(myFont->GetKerning(prevChar, curChar, myCharacterSize));
prevChar = curChar;
// Handle special characters
switch (curChar)
{
case L' ' : curWidth += advance; continue;
case L'\t' : curWidth += advance * 4; continue;
case L'\v' : height += mySize * 4; curHeight = 0; continue;
case L' ' :
curWidth += space;
continue;
case L'\t' :
curWidth += space * 4;
continue;
case L'\v' :
height += lineSpacing * 4;
curHeight = 0;
continue;
case L'\n' :
height += mySize;
height += lineSpacing;
curHeight = 0;
if (curWidth > width)
width = curWidth;
@ -398,11 +424,14 @@ void Text::RecomputeRect()
continue;
}
// Extract the current glyph's description
const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize);
// Advance to the next character
curWidth += advance;
curWidth += static_cast<float>(curGlyph.Advance);
// Update the maximum height
float charHeight = (myFont->GetCharacterSize() + rect.Bottom) * factor;
float charHeight = charSize + curGlyph.Rectangle.Bottom;
if (charHeight > curHeight)
curHeight = charHeight;
}
@ -415,21 +444,21 @@ void Text::RecomputeRect()
// Add a slight width / height if we're using the bold style
if (myStyle & Bold)
{
width += 1 * factor;
height += 1 * factor;
width += 1.f;
height += 1.f;
}
// Add a slight width if we're using the italic style
if (myStyle & Italic)
{
width += 0.208f * mySize;
width += 0.208f * charSize;
}
// Add a slight height if we're using the underlined style
if (myStyle & Underlined)
{
if (curHeight < mySize + 4 * factor)
height += 4 * factor;
if (curHeight < charSize + 4.f)
height += 4.f;
}
// Finally update the rectangle

File diff suppressed because it is too large Load Diff

View File

@ -244,10 +244,6 @@ Socket::Status SocketUDP::Send(Packet& packet, const IPAddress& address, unsigne
////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Receive(Packet& packet, IPAddress& address, unsigned short& port)
{
// This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
// So if a packet is split into more than one chunk, nobody knows what could happen...
// Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it.
// We start by getting the size of the incoming packet
Uint32 packetSize = 0;
std::size_t received = 0;