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" RelativePath="..\..\src\SFML\Graphics\FontStruct.h"
> >
</File> </File>
<File
RelativePath="..\..\include\SFML\Graphics\Glyph.h"
>
</File>
<File <File
RelativePath="..\..\src\SFML\Graphics\Image.cpp" RelativePath="..\..\src\SFML\Graphics\Image.cpp"
> >

View File

@ -36,26 +36,22 @@
/// Create a new font from a file /// Create a new font from a file
/// ///
/// \param filename : Path of the font file to load /// \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 /// \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 /// Create a new image font a file in memory
/// ///
/// \param data : Pointer to the file data in memory /// \param data : Pointer to the file data in memory
/// \param sizeInBytes : Size of the data to load, in bytes /// \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 /// \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 /// 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); CSFML_API void sfFont_Destroy(sfFont* font);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Get the base size of characters in a font; /// Get a glyph in a font
/// All glyphs dimensions are based on this value
/// ///
/// \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) /// 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 /// \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 /// Set the style of a text
@ -385,7 +385,7 @@ CSFML_API const sfFont* sfText_GetFont(const sfText* text);
/// \return Size of the characters /// \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 /// Get the style of a text

View File

@ -33,17 +33,10 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Create a new font from a file /// 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; sfFont* font = new sfFont;
if (!font->This.LoadFromFile(filename))
bool success = false;
if (charset)
success = font->This.LoadFromFile(filename, charSize, charset);
else
success = font->This.LoadFromFile(filename, charSize);
if (!success)
{ {
delete font; delete font;
font = NULL; 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 /// 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; sfFont* font = new sfFont;
if (!font->This.LoadFromMemory(data, sizeInBytes))
bool success = false;
if (charset)
success = font->This.LoadFromMemory(data, sizeInBytes, charSize, charset);
else
success = font->This.LoadFromMemory(data, sizeInBytes, charSize);
if (!success)
{ {
delete font; delete font;
font = NULL; font = NULL;
@ -86,12 +72,57 @@ void sfFont_Destroy(sfFont* font)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Get the base size of characters in a font; /// Get a glyph in a font
/// All glyphs dimensions are based on this value
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
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 // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Graphics/Font.hpp> #include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/ImageStruct.h>
#include <map>
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -37,6 +39,7 @@
struct sfFont struct sfFont
{ {
sf::Font This; sf::Font This;
std::map<unsigned int, sfImage> Images;
}; };

View File

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

View File

@ -320,9 +320,9 @@ void sfText_SetFont(sfText* text, const sfFont* font)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Set the size of a string /// 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 /// 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_CreateFromFile
sfFont_CreateFromMemory sfFont_CreateFromMemory
sfFont_Destroy sfFont_Destroy
sfFont_GetCharacterSize sfFont_GetGlyph
sfFont_GetKerning
sfFont_GetLineSpacing
sfFont_GetImage
sfFont_GetDefaultFont sfFont_GetDefaultFont
sfText_Create sfText_Create
sfText_Destroy sfText_Destroy
@ -158,12 +161,12 @@ EXPORTS
sfText_SetString sfText_SetString
sfText_SetUnicodeString sfText_SetUnicodeString
sfText_SetFont sfText_SetFont
sfText_SetSize sfText_SetCharacterSize
sfText_SetStyle sfText_SetStyle
sfText_GetUnicodeString sfText_GetUnicodeString
sfText_GetString sfText_GetString
sfText_GetFont sfText_GetFont
sfText_GetSize sfText_GetCharacterSize
sfText_GetStyle sfText_GetStyle
sfText_GetCharacterPos sfText_GetCharacterPos
sfText_GetRect sfText_GetRect

View File

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

View File

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

View File

@ -3434,14 +3434,6 @@
RelativePath="..\..\include\SFML\Graphics\Font.hpp" RelativePath="..\..\include\SFML\Graphics\Font.hpp"
> >
</File> </File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.cpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.hpp"
>
</File>
<File <File
RelativePath="..\..\src\SFML\Graphics\GLCheck.cpp" 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}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-main", "sfml-main.vcproj", "{2BD26A09-E1B6-42E2-A0D0-63987B76BB97}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-network", "sfml-network.vcproj", "{823DDC98-42D5-4A38-88CF-9DC06C788AE4}" 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 EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-system", "sfml-system.vcproj", "{C061A27D-7CA0-4179-9869-672FA04A86A8}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-system", "sfml-system.vcproj", "{C061A27D-7CA0-4179-9869-672FA04A86A8}"
EndProject EndProject

View File

@ -3433,14 +3433,6 @@
RelativePath="..\..\include\SFML\Graphics\Font.hpp" RelativePath="..\..\include\SFML\Graphics\Font.hpp"
> >
</File> </File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.cpp"
>
</File>
<File
RelativePath="..\..\src\SFML\Graphics\FontLoader.hpp"
>
</File>
<File <File
RelativePath="..\..\src\SFML\Graphics\GLCheck.cpp" 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")); Sprite entity = new Sprite(new Image("datas/shader/sprite.png"));
// Load the text font // 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 // Load the image needed for the wave effect
Image waveImage = new Image("datas/shader/wave.jpg"); Image waveImage = new Image("datas/shader/wave.jpg");
@ -135,7 +135,7 @@ namespace sample_shader
Text infoText = new Text(); Text infoText = new Text();
infoText.Font = font; infoText.Font = font;
infoText.Size = 20; 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.Color = new Color(250, 100, 30);
infoText.DisplayedString = "Move your mouse to change the shaders' parameters\n" + infoText.DisplayedString = "Move your mouse to change the shaders' parameters\n" +
"Press numpad 1 to change the background shader\n" + "Press numpad 1 to change the background shader\n" +

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security; using System.Security;
using System.IO; using System.IO;
@ -7,6 +8,24 @@ namespace SFML
{ {
namespace Graphics 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> /// <summary>
/// Font is the low-level class for loading and /// Font is the low-level class for loading and
@ -24,47 +43,8 @@ namespace SFML
/// <exception cref="LoadingFailedException" /> /// <exception cref="LoadingFailedException" />
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
public Font(string filename) : 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) if (This == IntPtr.Zero)
throw new LoadingFailedException("font", filename); throw new LoadingFailedException("font", filename);
} }
@ -77,64 +57,73 @@ namespace SFML
/// <exception cref="LoadingFailedException" /> /// <exception cref="LoadingFailedException" />
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
public Font(Stream stream) : 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) base(IntPtr.Zero)
{ {
unsafe unsafe
{ {
IntPtr ptr;
int size;
if (Int32.TryParse(charset, out size))
ptr = new IntPtr(&size);
else
ptr = IntPtr.Zero;
stream.Position = 0; stream.Position = 0;
byte[] StreamData = new byte[stream.Length]; byte[] StreamData = new byte[stream.Length];
uint Read = (uint)stream.Read(StreamData, 0, StreamData.Length); uint Read = (uint)stream.Read(StreamData, 0, StreamData.Length);
fixed (byte* dataPtr = StreamData) fixed (byte* dataPtr = StreamData)
{ {
SetThis(sfFont_CreateFromMemory((char*)dataPtr, Read, charSize, ptr)); SetThis(sfFont_CreateFromMemory((char*)dataPtr, Read));
} }
} }
if (This == IntPtr.Zero) if (This == IntPtr.Zero)
throw new LoadingFailedException("font"); throw new LoadingFailedException("font");
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// <summary> /// <summary>
/// Base character size /// Get a glyph in the font
/// </summary> /// </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); sfFont_Destroy(This);
if (disposing)
{
foreach (Image image in myImages.Values)
image.Dispose();
}
if (!disposing) if (!disposing)
Context.Global.SetActive(false); Context.Global.SetActive(false);
} }
@ -184,20 +179,30 @@ namespace SFML
{ {
} }
private Dictionary<uint, Image> myImages = new Dictionary<uint, Image>();
private static Font ourDefaultFont = null; private static Font ourDefaultFont = null;
#region Imports #region Imports
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] [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] [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] [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern void sfFont_Destroy(IntPtr This); static extern void sfFont_Destroy(IntPtr This);
[DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] [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] [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity]
static extern IntPtr sfFont_GetDefaultFont(); static extern IntPtr sfFont_GetDefaultFont();

View File

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

View File

@ -36,109 +36,328 @@
#include <SFML/Graphics/Rect.hpp> #include <SFML/Graphics/Rect.hpp>
#include <map> #include <map>
#include <string> #include <string>
#include <vector>
namespace sf namespace sf
{ {
namespace priv
{
class FontLoader;
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Font is the low-level class for loading and /// \brief Class for loading and manipulating character fonts
/// manipulating character fonts. This class is meant to ///
/// be used by sf::Text
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
class SFML_API Font : public Resource<Font> class SFML_API Font : public Resource<Font>
{ {
public : public :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Default constructor /// \brief Default constructor
///
/// This constructor defines an empty font
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Font(); Font();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Load the font from a file /// \brief Copy constructor
/// ///
/// \param filename : Font file to load /// \param copy Instance to copy
/// \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
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
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 /// Cleans up all the internal resources used by the font
/// \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
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
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; /// \brief Load the font from a file
/// All glyphs dimensions are based on this value
/// ///
/// \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) /// \brief Load the font from a file
/// given by its unicode value
/// ///
/// \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(); static const Font& GetDefaultFont();
private : 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 // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Image myTexture; ///< Texture holding the bitmap font void* myLibrary; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details)
unsigned int myCharSize; ///< Size of characters in the bitmap font void* myFace; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details)
std::map<Uint32, Glyph> myGlyphs; ///< Rendering settings of each character (glyph) 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 } // namespace sf
#endif // SFML_FONT_HPP #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 // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
int Advance; ///< Offset to move horizontically to the next character int Advance; ///< Offset to move horizontically to the next character
IntRect Rectangle; ///< Bounding rectangle of the glyph, in relative coordinates IntRect Rectangle; ///< Bounding rectangle of the glyph, in coordinates relative to the baseline
FloatRect TexCoords; ///< Texture coordinates of the glyph inside the bitmap font FloatRect TexCoords; ///< Texture coordinates of the glyph inside the font's image
}; };
} // namespace sf } // namespace sf

View File

@ -203,7 +203,7 @@ public :
/// Warning: for performances reasons, this function doesn't /// Warning: for performances reasons, this function doesn't
/// perform any check; thus you're responsible of ensuring that /// perform any check; thus you're responsible of ensuring that
/// \a rectangle does not exceed the image size, and 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 rectangle : Sub-rectangle of the image to update
/// \param pixels : Array of pixels to write to the image /// \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 string : Text assigned to the string
/// \param font : Font used to draw 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) /// Set the text (from any kind of string)
@ -89,13 +89,13 @@ public :
void SetFont(const Font& font); void SetFont(const Font& font);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Set the size of the string /// Set the base size for the characters.
/// The default size is 30 /// The default size is 30
/// ///
/// \param size : New size, in pixels /// \param size : New size, in pixels
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void SetSize(float size); void SetCharacterSize(unsigned int size);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Set the style of the text /// Set the style of the text
@ -123,12 +123,12 @@ public :
const Font& GetFont() const; 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 /// 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) /// \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 /// Get the string rectangle on screen
@ -179,7 +179,7 @@ private :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
String myString; ///< String to display String myString; ///< String to display
ResourcePtr<Font> myFont; ///< Font used to display the string 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) unsigned long myStyle; ///< Text style (see Style enum)
FloatRect myBaseRect; ///< Bounding rectangle of the text in object coordinates FloatRect myBaseRect; ///< Bounding rectangle of the text in object coordinates
bool myNeedRectUpdate; ///< Does the bounding rect need an update ? bool myNeedRectUpdate; ///< Does the bounding rect need an update ?

View File

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

View File

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

View File

@ -26,133 +26,213 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Graphics/Font.hpp> #include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/FontLoader.hpp> #include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include <iostream> #include <iostream>
namespace sf 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() : Font::Font() :
myCharSize(0) myLibrary (NULL),
myFace (NULL),
myRefCount (NULL),
myCurrentSize(0)
{ {
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Load the font from a file Font::Font(const Font& copy) :
//////////////////////////////////////////////////////////// myLibrary (copy.myLibrary),
bool Font::LoadFromFile(const std::string& filename, unsigned int charSize, String charset) myFace (copy.myFace),
myRefCount (copy.myRefCount),
myPages (copy.myPages),
myPixelBuffer(copy.myPixelBuffer),
myCurrentSize(copy.myCurrentSize)
{ {
// Clear the previous character map // Note: as FreeType doesn't provide functions for copying/cloning,
myGlyphs.clear(); // we must share all the FreeType pointers
// Always add these special characters if (myRefCount)
if (std::find(charset.Begin(), charset.End(), L' ') == charset.End()) charset += L' '; (*myRefCount)++;
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);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Load the font from a file in memory Font::~Font()
////////////////////////////////////////////////////////////
bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize, String charset)
{ {
// Clear the previous character map Cleanup();
myGlyphs.clear(); }
// 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; return false;
} }
// Always add these special characters // Select the unicode character map
if (std::find(charset.Begin(), charset.End(), L' ') == charset.End()) charset += L' '; if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0)
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'; std::cerr << "Failed to load font \"" << filename << "\" (failed to set the Unicode character set)" << std::endl;
if (std::find(charset.Begin(), charset.End(), L'\t') == charset.End()) charset += L'\t'; 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; bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes)
/// All glyphs dimensions are based on this value
////////////////////////////////////////////////////////////
unsigned int Font::GetCharacterSize() const
{ {
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) const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize) const
/// given by its unicode value
////////////////////////////////////////////////////////////
const Glyph& Font::GetGlyph(Uint32 codePoint) const
{ {
std::map<Uint32, Glyph>::const_iterator it = myGlyphs.find(codePoint); // Get the page corresponding to the character size
if (it != myGlyphs.end()) GlyphTable& glyphs = myPages[characterSize].Glyphs;
// Search the glyph into the cache
GlyphTable::const_iterator it = glyphs.find(codePoint);
if (it != glyphs.end())
{ {
// Valid glyph // Found: just return it
return it->second; return it->second.GlyphDesc;
} }
else else
{ {
// Invalid glyph -- return an invalid glyph // Not found: we have to load it
static const Glyph invalid; GlyphInfo glyph = LoadGlyph(codePoint, characterSize);
return invalid; return glyphs.insert(std::make_pair(codePoint, glyph)).first->second.GlyphDesc;
} }
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// Get the image containing the rendered characters (glyphs) int Font::GetKerning(Uint32 first, Uint32 second, unsigned int characterSize) const
////////////////////////////////////////////////////////////
const Image& Font::GetImage() 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() const Font& Font::GetDefaultFont()
{ {
@ -167,11 +247,231 @@ const Font& Font::GetDefaultFont()
#include <SFML/Graphics/Arial.hpp> #include <SFML/Graphics/Arial.hpp>
}; };
font.LoadFromMemory(data, sizeof(data), 30); font.LoadFromMemory(data, sizeof(data));
loaded = true; loaded = true;
} }
return font; 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 } // 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/RenderWindow.hpp>
#include <SFML/Graphics/Drawable.hpp> #include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Image.hpp> #include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/GLCheck.hpp>
#include <iostream> #include <iostream>

View File

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