diff --git a/CSFML/build/VC2008/csfml-graphics.vcproj b/CSFML/build/VC2008/csfml-graphics.vcproj index d7d16c7c..09bfd5c0 100644 --- a/CSFML/build/VC2008/csfml-graphics.vcproj +++ b/CSFML/build/VC2008/csfml-graphics.vcproj @@ -232,6 +232,10 @@ RelativePath="..\..\src\SFML\Graphics\FontStruct.h" > + + diff --git a/CSFML/include/SFML/Graphics/Font.h b/CSFML/include/SFML/Graphics/Font.h index 16f76636..685da11f 100644 --- a/CSFML/include/SFML/Graphics/Font.h +++ b/CSFML/include/SFML/Graphics/Font.h @@ -36,26 +36,22 @@ /// Create a new font from a file /// /// \param filename : Path of the font file to load -/// \param charSize : Size of characters in bitmap - the bigger, the higher quality -/// \param charset : Characters set to generate (just pass NULL to get the default charset) /// /// \return A new sfFont object, or NULL if it failed /// //////////////////////////////////////////////////////////// -CSFML_API sfFont* sfFont_CreateFromFile(const char* filename, unsigned int charSize, const sfUint32* charset); +CSFML_API sfFont* sfFont_CreateFromFile(const char* filename); //////////////////////////////////////////////////////////// /// Create a new image font a file in memory /// /// \param data : Pointer to the file data in memory /// \param sizeInBytes : Size of the data to load, in bytes -/// \param charSize : Size of characters in bitmap - the bigger, the higher quality -/// \param charset : Characters set to generate (just pass NULL to get the default charset) /// /// \return A new sfFont object, or NULL if it failed /// //////////////////////////////////////////////////////////// -CSFML_API sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes, unsigned int charSize, const sfUint32* charset); +CSFML_API sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes); //////////////////////////////////////////////////////////// /// Destroy an existing font @@ -66,15 +62,52 @@ CSFML_API sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes, CSFML_API void sfFont_Destroy(sfFont* font); //////////////////////////////////////////////////////////// -/// Get the base size of characters in a font; -/// All glyphs dimensions are based on this value +/// Get a glyph in a font /// -/// \param font : Font object +/// \param font : Source font +/// \param codePoint : Unicode code point of the character to get +/// \param characterSize : Character size, in pixels /// -/// \return Base size of characters +/// \return The corresponding glyph /// //////////////////////////////////////////////////////////// -CSFML_API unsigned int sfFont_GetCharacterSize(const sfFont* font); +CSFML_API sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize); + +//////////////////////////////////////////////////////////// +/// Get the kerning value corresponding to a given pair of characters in a font +/// +/// \param font : Source font +/// \param first : Unicode code point of the first character +/// \param second : Unicode code point of the second character +/// \param characterSize : Character size, in pixels +/// +/// \return Kerning offset, in pixels +/// +//////////////////////////////////////////////////////////// +CSFML_API int sfFont_GetKerning(sfFont* font, sfUint32 first, sfUint32 second, unsigned int characterSize); + +//////////////////////////////////////////////////////////// +/// Get the line spacing value +/// +/// \param font : Source font +/// \param codePoint : Unicode code point of the character to get +/// \param characterSize : Character size, in pixels +/// +/// \return Line spacing, in pixels +/// +//////////////////////////////////////////////////////////// +CSFML_API int sfFont_GetLineSpacing(sfFont* font, unsigned int characterSize); + +//////////////////////////////////////////////////////////// +/// Get the image containing the glyphs of a given size in a font +/// +/// \param font : Source font +/// \param characterSize : Character size, in pixels +/// +/// \return Read-only pointer to the image +/// +//////////////////////////////////////////////////////////// +CSFML_API const sfImage* sfFont_GetImage(sfFont* font, unsigned int characterSize); //////////////////////////////////////////////////////////// /// Get the built-in default font (Arial) diff --git a/CSFML/include/SFML/Graphics/Text.h b/CSFML/include/SFML/Graphics/Text.h index 5c367402..a30fdb0a 100644 --- a/CSFML/include/SFML/Graphics/Text.h +++ b/CSFML/include/SFML/Graphics/Text.h @@ -336,7 +336,7 @@ CSFML_API void sfText_SetFont(sfText* text, const sfFont* font); /// \param size : New size, in pixels /// //////////////////////////////////////////////////////////// -CSFML_API void sfText_SetSize(sfText* text, float size); +CSFML_API void sfText_SetCharacterSize(sfText* text, unsigned int size); //////////////////////////////////////////////////////////// /// Set the style of a text @@ -385,7 +385,7 @@ CSFML_API const sfFont* sfText_GetFont(const sfText* text); /// \return Size of the characters /// //////////////////////////////////////////////////////////// -CSFML_API float sfText_GetSize(const sfText* text); +CSFML_API unsigned int sfText_GetCharacterSize(const sfText* text); //////////////////////////////////////////////////////////// /// Get the style of a text diff --git a/CSFML/src/SFML/Graphics/Font.cpp b/CSFML/src/SFML/Graphics/Font.cpp index 8e2b2207..e66395a1 100644 --- a/CSFML/src/SFML/Graphics/Font.cpp +++ b/CSFML/src/SFML/Graphics/Font.cpp @@ -33,17 +33,10 @@ //////////////////////////////////////////////////////////// /// Create a new font from a file //////////////////////////////////////////////////////////// -sfFont* sfFont_CreateFromFile(const char* filename, unsigned int charSize, const sfUint32* charset) +sfFont* sfFont_CreateFromFile(const char* filename) { sfFont* font = new sfFont; - - bool success = false; - if (charset) - success = font->This.LoadFromFile(filename, charSize, charset); - else - success = font->This.LoadFromFile(filename, charSize); - - if (!success) + if (!font->This.LoadFromFile(filename)) { delete font; font = NULL; @@ -56,17 +49,10 @@ sfFont* sfFont_CreateFromFile(const char* filename, unsigned int charSize, const //////////////////////////////////////////////////////////// /// Create a new font from a file in memory //////////////////////////////////////////////////////////// -sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes, unsigned int charSize, const sfUint32* charset) +sfFont* sfFont_CreateFromMemory(const char* data, size_t sizeInBytes) { sfFont* font = new sfFont; - - bool success = false; - if (charset) - success = font->This.LoadFromMemory(data, sizeInBytes, charSize, charset); - else - success = font->This.LoadFromMemory(data, sizeInBytes, charSize); - - if (!success) + if (!font->This.LoadFromMemory(data, sizeInBytes)) { delete font; font = NULL; @@ -86,12 +72,57 @@ void sfFont_Destroy(sfFont* font) //////////////////////////////////////////////////////////// -/// Get the base size of characters in a font; -/// All glyphs dimensions are based on this value +/// Get a glyph in a font //////////////////////////////////////////////////////////// -unsigned int sfFont_GetCharacterSize(const sfFont* font) +sfGlyph sfFont_GetGlyph(sfFont* font, sfUint32 codePoint, unsigned int characterSize) { - CSFML_CALL_RETURN(font, GetCharacterSize(), 0); + sfGlyph glyph = {0, {0, 0, 0, 0}, {0, 0, 0, 0}}; + CSFML_CHECK_RETURN(font, glyph); + + sf::Glyph SFMLGlyph = font->This.GetGlyph(codePoint, characterSize); + + glyph.Advance = SFMLGlyph.Advance; + glyph.Rectangle.Left = SFMLGlyph.Rectangle.Left; + glyph.Rectangle.Top = SFMLGlyph.Rectangle.Top; + glyph.Rectangle.Right = SFMLGlyph.Rectangle.Right; + glyph.Rectangle.Bottom = SFMLGlyph.Rectangle.Bottom; + glyph.TexCoords.Left = SFMLGlyph.TexCoords.Left; + glyph.TexCoords.Top = SFMLGlyph.TexCoords.Top; + glyph.TexCoords.Right = SFMLGlyph.TexCoords.Right; + glyph.TexCoords.Bottom = SFMLGlyph.TexCoords.Bottom; + + return glyph; +} + + +//////////////////////////////////////////////////////////// +/// Get the kerning value corresponding to a given pair of characters in a font +//////////////////////////////////////////////////////////// +int sfFont_GetKerning(sfFont* font, sfUint32 first, sfUint32 second, unsigned int characterSize) +{ + CSFML_CALL_RETURN(font, GetKerning(first, second, characterSize), 0); +} + + +//////////////////////////////////////////////////////////// +/// Get the line spacing value +//////////////////////////////////////////////////////////// +int sfFont_GetLineSpacing(sfFont* font, unsigned int characterSize) +{ + CSFML_CALL_RETURN(font, GetLineSpacing(characterSize), 0); +} + + +//////////////////////////////////////////////////////////// +/// Get the image containing the glyphs of a given size in a font +//////////////////////////////////////////////////////////// +const sfImage* sfFont_GetImage(sfFont* font, unsigned int characterSize) +{ + CSFML_CHECK_RETURN(font, NULL); + + *font->Images[characterSize].This = font->This.GetImage(characterSize); + + return &font->Images[characterSize]; } diff --git a/CSFML/src/SFML/Graphics/FontStruct.h b/CSFML/src/SFML/Graphics/FontStruct.h index 08a31f17..019ea773 100644 --- a/CSFML/src/SFML/Graphics/FontStruct.h +++ b/CSFML/src/SFML/Graphics/FontStruct.h @@ -29,6 +29,8 @@ // Headers //////////////////////////////////////////////////////////// #include +#include +#include //////////////////////////////////////////////////////////// @@ -37,6 +39,7 @@ struct sfFont { sf::Font This; + std::map Images; }; diff --git a/CSFML/src/SFML/Graphics/ImageStruct.h b/CSFML/src/SFML/Graphics/ImageStruct.h index 1edc6530..c6289430 100644 --- a/CSFML/src/SFML/Graphics/ImageStruct.h +++ b/CSFML/src/SFML/Graphics/ImageStruct.h @@ -42,9 +42,9 @@ struct sfImage OwnInstance = true; } - sfImage(sf::Image* Image) + sfImage(sf::Image* image) { - This = Image; + This = image; OwnInstance = false; } diff --git a/CSFML/src/SFML/Graphics/Text.cpp b/CSFML/src/SFML/Graphics/Text.cpp index 7f8bb9c7..f3ffb77b 100644 --- a/CSFML/src/SFML/Graphics/Text.cpp +++ b/CSFML/src/SFML/Graphics/Text.cpp @@ -320,9 +320,9 @@ void sfText_SetFont(sfText* text, const sfFont* font) //////////////////////////////////////////////////////////// /// Set the size of a string //////////////////////////////////////////////////////////// -void sfText_SetSize(sfText* text, float size) +void sfText_SetCharacterSize(sfText* text, unsigned int size) { - CSFML_CALL(text, SetSize(size)) + CSFML_CALL(text, SetCharacterSize(size)) } @@ -373,9 +373,9 @@ const sfFont* sfText_GetFont(const sfText* text) //////////////////////////////////////////////////////////// /// Get the size of the characters of a text //////////////////////////////////////////////////////////// -float sfText_GetSize(const sfText* text) +unsigned int sfText_GetCharacterSize(const sfText* text) { - CSFML_CALL_RETURN(text, GetSize(), 0.f) + CSFML_CALL_RETURN(text, GetCharacterSize(), 0.f) } diff --git a/CSFML/src/SFML/Graphics/csfml-graphics-d.def b/CSFML/src/SFML/Graphics/csfml-graphics-d.def index f0643776..84b63511 100644 --- a/CSFML/src/SFML/Graphics/csfml-graphics-d.def +++ b/CSFML/src/SFML/Graphics/csfml-graphics-d.def @@ -127,7 +127,10 @@ EXPORTS sfFont_CreateFromFile sfFont_CreateFromMemory sfFont_Destroy - sfFont_GetCharacterSize + sfFont_GetGlyph + sfFont_GetKerning + sfFont_GetLineSpacing + sfFont_GetImage sfFont_GetDefaultFont sfText_Create sfText_Destroy @@ -158,12 +161,12 @@ EXPORTS sfText_SetString sfText_SetUnicodeString sfText_SetFont - sfText_SetSize + sfText_SetCharacterSize sfText_SetStyle sfText_GetUnicodeString sfText_GetString sfText_GetFont - sfText_GetSize + sfText_GetCharacterSize sfText_GetStyle sfText_GetCharacterPos sfText_GetRect diff --git a/CSFML/src/SFML/Graphics/csfml-graphics.def b/CSFML/src/SFML/Graphics/csfml-graphics.def index 049adbba..cb01bf35 100644 --- a/CSFML/src/SFML/Graphics/csfml-graphics.def +++ b/CSFML/src/SFML/Graphics/csfml-graphics.def @@ -127,7 +127,10 @@ EXPORTS sfFont_CreateFromFile sfFont_CreateFromMemory sfFont_Destroy - sfFont_GetCharacterSize + sfFont_GetGlyph + sfFont_GetKerning + sfFont_GetLineSpacing + sfFont_GetImage sfFont_GetDefaultFont sfText_Create sfText_Destroy @@ -158,12 +161,12 @@ EXPORTS sfText_SetString sfText_SetUnicodeString sfText_SetFont - sfText_SetSize + sfText_SetCharacterSize sfText_SetStyle sfText_GetUnicodeString sfText_GetString sfText_GetFont - sfText_GetSize + sfText_GetCharacterSize sfText_GetStyle sfText_GetCharacterPos sfText_GetRect diff --git a/build/codeblocks/sfml-graphics.cbp b/build/codeblocks/sfml-graphics.cbp index f07b6e71..a9b2275a 100644 --- a/build/codeblocks/sfml-graphics.cbp +++ b/build/codeblocks/sfml-graphics.cbp @@ -140,8 +140,6 @@ - - diff --git a/build/vc2005/sfml-graphics.vcproj b/build/vc2005/sfml-graphics.vcproj index 0e3c9095..d8d041fb 100644 --- a/build/vc2005/sfml-graphics.vcproj +++ b/build/vc2005/sfml-graphics.vcproj @@ -3434,14 +3434,6 @@ RelativePath="..\..\include\SFML\Graphics\Font.hpp" > - - - - diff --git a/build/vc2008/SFML.sln b/build/vc2008/SFML.sln index 8442ed71..fa803a74 100644 --- a/build/vc2008/SFML.sln +++ b/build/vc2008/SFML.sln @@ -14,6 +14,9 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-main", "sfml-main.vcproj", "{2BD26A09-E1B6-42E2-A0D0-63987B76BB97}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-network", "sfml-network.vcproj", "{823DDC98-42D5-4A38-88CF-9DC06C788AE4}" + ProjectSection(ProjectDependencies) = postProject + {C061A27D-7CA0-4179-9869-672FA04A86A8} = {C061A27D-7CA0-4179-9869-672FA04A86A8} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sfml-system", "sfml-system.vcproj", "{C061A27D-7CA0-4179-9869-672FA04A86A8}" EndProject diff --git a/build/vc2008/sfml-graphics.vcproj b/build/vc2008/sfml-graphics.vcproj index feb22c5e..1954e795 100644 --- a/build/vc2008/sfml-graphics.vcproj +++ b/build/vc2008/sfml-graphics.vcproj @@ -3433,14 +3433,6 @@ RelativePath="..\..\include\SFML\Graphics\Font.hpp" > - - - - diff --git a/dotnet/extlibs/csfml-audio.dll b/dotnet/extlibs/csfml-audio.dll index cd78f3c7..2e2ffb2c 100644 Binary files a/dotnet/extlibs/csfml-audio.dll and b/dotnet/extlibs/csfml-audio.dll differ diff --git a/dotnet/extlibs/csfml-graphics.dll b/dotnet/extlibs/csfml-graphics.dll index 6337dc10..496f2b87 100644 Binary files a/dotnet/extlibs/csfml-graphics.dll and b/dotnet/extlibs/csfml-graphics.dll differ diff --git a/dotnet/extlibs/csfml-window.dll b/dotnet/extlibs/csfml-window.dll index b45310ae..556dbca0 100644 Binary files a/dotnet/extlibs/csfml-window.dll and b/dotnet/extlibs/csfml-window.dll differ diff --git a/dotnet/samples/shader/Shader.cs b/dotnet/samples/shader/Shader.cs index a8a765a2..3ded018b 100644 --- a/dotnet/samples/shader/Shader.cs +++ b/dotnet/samples/shader/Shader.cs @@ -93,7 +93,7 @@ namespace sample_shader Sprite entity = new Sprite(new Image("datas/shader/sprite.png")); // Load the text font - Font font = new Font("datas/shader/arial.ttf", 20); + Font font = new Font("datas/shader/arial.ttf"); // Load the image needed for the wave effect Image waveImage = new Image("datas/shader/wave.jpg"); @@ -135,7 +135,7 @@ namespace sample_shader Text infoText = new Text(); infoText.Font = font; infoText.Size = 20; - infoText.Position = new Vector2(5.0F, 510.0F); + infoText.Position = new Vector2(5.0F, 500.0F); infoText.Color = new Color(250, 100, 30); infoText.DisplayedString = "Move your mouse to change the shaders' parameters\n" + "Press numpad 1 to change the background shader\n" + diff --git a/dotnet/src/Graphics/Font.cs b/dotnet/src/Graphics/Font.cs index 273d2d6c..91ffb66c 100644 --- a/dotnet/src/Graphics/Font.cs +++ b/dotnet/src/Graphics/Font.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Security; using System.IO; @@ -7,6 +8,24 @@ namespace SFML { namespace Graphics { + //////////////////////////////////////////////////////////// + /// + /// Structure describing a glyph (a visual character) + /// + //////////////////////////////////////////////////////////// + [StructLayout(LayoutKind.Sequential)] + public struct Glyph + { + /// Offset to move horizontically to the next character + public int Advance; + + /// Bounding rectangle of the glyph, in coordinates relative to the baseline + public IntRect Rectangle; + + /// Texture coordinates of the glyph inside the font's image + public FloatRect TexCoords; + } + //////////////////////////////////////////////////////////// /// /// Font is the low-level class for loading and @@ -24,47 +43,8 @@ namespace SFML /// //////////////////////////////////////////////////////////// public Font(string filename) : - this(filename, 30) + base(sfFont_CreateFromFile(filename)) { - } - - //////////////////////////////////////////////////////////// - /// - /// Construct the font from a file, using custom size - /// - /// Font file to load - /// Character size - /// - //////////////////////////////////////////////////////////// - public Font(string filename, uint charSize) : - this(filename, charSize, "") - { - } - - //////////////////////////////////////////////////////////// - /// - /// Construct the font from a file, using custom size and characters set - /// - /// Font file to load - /// Character size - /// Set of characters to generate - /// - //////////////////////////////////////////////////////////// - public Font(string filename, uint charSize, string charset) : - base(IntPtr.Zero) - { - unsafe - { - IntPtr ptr; - int size; - if (Int32.TryParse(charset, out size)) - ptr = new IntPtr(&size); - else - ptr = IntPtr.Zero; - - SetThis(sfFont_CreateFromFile(filename, charSize, ptr)); - } - if (This == IntPtr.Zero) throw new LoadingFailedException("font", filename); } @@ -77,64 +57,73 @@ namespace SFML /// //////////////////////////////////////////////////////////// public Font(Stream stream) : - this(stream, 30) - { - } - - //////////////////////////////////////////////////////////// - /// - /// Construct the font from a file in a stream, using custom size - /// - /// Stream containing the file contents - /// Character size - /// - //////////////////////////////////////////////////////////// - public Font(Stream stream, uint charSize) : - this(stream, charSize, "") - { - } - - //////////////////////////////////////////////////////////// - /// - /// Construct the font from a file in a stream - /// - /// Stream containing the file contents - /// Character size - /// Set of characters to generate - /// - //////////////////////////////////////////////////////////// - public Font(Stream stream, uint charSize, string charset) : base(IntPtr.Zero) { unsafe { - IntPtr ptr; - int size; - if (Int32.TryParse(charset, out size)) - ptr = new IntPtr(&size); - else - ptr = IntPtr.Zero; - stream.Position = 0; byte[] StreamData = new byte[stream.Length]; uint Read = (uint)stream.Read(StreamData, 0, StreamData.Length); fixed (byte* dataPtr = StreamData) { - SetThis(sfFont_CreateFromMemory((char*)dataPtr, Read, charSize, ptr)); + SetThis(sfFont_CreateFromMemory((char*)dataPtr, Read)); } } + if (This == IntPtr.Zero) throw new LoadingFailedException("font"); } //////////////////////////////////////////////////////////// /// - /// Base character size + /// Get a glyph in the font /// + /// Unicode code point of the character to get + /// Character size + /// The glyph corresponding to the character //////////////////////////////////////////////////////////// - public uint CharacterSize + public Glyph GetGlyph(uint codePoint, uint characterSize) { - get { return sfFont_GetCharacterSize(This); } + return sfFont_GetGlyph(This, codePoint, characterSize); + } + + //////////////////////////////////////////////////////////// + /// + /// Get the kerning offset between two glyphs + /// + /// Unicode code point of the first character + /// Unicode code point of the second character + /// Character size + /// Kerning offset, in pixels + //////////////////////////////////////////////////////////// + public int GetKerning(uint first, uint second, uint characterSize) + { + return sfFont_GetKerning(This, first, second, characterSize); + } + + //////////////////////////////////////////////////////////// + /// + /// Get spacing between two consecutive lines + /// + /// Character size + /// Line spacing, in pixels + //////////////////////////////////////////////////////////// + public int GetLineSpacing(uint characterSize) + { + return sfFont_GetLineSpacing(This, characterSize); + } + + //////////////////////////////////////////////////////////// + /// + /// Get the image containing the glyphs of a given size + /// + /// Character size + /// Image storing the glyphs for the given size + //////////////////////////////////////////////////////////// + public Image GetImage(uint characterSize) + { + myImages[characterSize] = new Image(sfFont_GetImage(This, characterSize)); + return myImages[characterSize]; } //////////////////////////////////////////////////////////// @@ -168,6 +157,12 @@ namespace SFML sfFont_Destroy(This); + if (disposing) + { + foreach (Image image in myImages.Values) + image.Dispose(); + } + if (!disposing) Context.Global.SetActive(false); } @@ -184,20 +179,30 @@ namespace SFML { } + private Dictionary myImages = new Dictionary(); private static Font ourDefaultFont = null; #region Imports [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] - static extern IntPtr sfFont_CreateFromFile(string Filename, uint CharSize, IntPtr Charset); + static extern IntPtr sfFont_CreateFromFile(string Filename); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] - unsafe static extern IntPtr sfFont_CreateFromMemory(char* Data, uint SizeInBytes, uint CharSize, IntPtr Charset); + unsafe static extern IntPtr sfFont_CreateFromMemory(char* Data, uint SizeInBytes); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] static extern void sfFont_Destroy(IntPtr This); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] - static extern uint sfFont_GetCharacterSize(IntPtr This); + static extern Glyph sfFont_GetGlyph(IntPtr This, uint codePoint, uint characterSize); + + [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] + static extern int sfFont_GetKerning(IntPtr This, uint first, uint second, uint characterSize); + + [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] + static extern int sfFont_GetLineSpacing(IntPtr This, uint characterSize); + + [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] + static extern IntPtr sfFont_GetImage(IntPtr This, uint characterSize); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] static extern IntPtr sfFont_GetDefaultFont(); diff --git a/dotnet/src/Graphics/Text.cs b/dotnet/src/Graphics/Text.cs index e686d394..42ed4b23 100644 --- a/dotnet/src/Graphics/Text.cs +++ b/dotnet/src/Graphics/Text.cs @@ -211,10 +211,10 @@ namespace SFML /// Base size of characters /// //////////////////////////////////////////////////////////// - public float Size + public uint Size { - get {return sfText_GetSize(This);} - set {sfText_SetSize(This, value);} + get {return sfText_GetCharacterSize(This);} + set {sfText_SetCharacterSize(This, value);} } //////////////////////////////////////////////////////////// @@ -376,7 +376,7 @@ namespace SFML static extern void sfText_SetFont(IntPtr This, IntPtr Font); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] - static extern void sfText_SetSize(IntPtr This, float Size); + static extern void sfText_SetCharacterSize(IntPtr This, uint Size); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] static extern void sfText_SetStyle(IntPtr This, Styles Style); @@ -385,7 +385,7 @@ namespace SFML static extern string sfText_GetString(IntPtr This); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] - static extern float sfText_GetSize(IntPtr This); + static extern uint sfText_GetCharacterSize(IntPtr This); [DllImport("csfml-graphics"), SuppressUnmanagedCodeSecurity] static extern Styles sfText_GetStyle(IntPtr This); diff --git a/include/SFML/Graphics/Font.hpp b/include/SFML/Graphics/Font.hpp index 318209d4..de3798b8 100644 --- a/include/SFML/Graphics/Font.hpp +++ b/include/SFML/Graphics/Font.hpp @@ -36,109 +36,328 @@ #include #include #include +#include namespace sf { -namespace priv -{ -class FontLoader; -} - //////////////////////////////////////////////////////////// -/// Font is the low-level class for loading and -/// manipulating character fonts. This class is meant to -/// be used by sf::Text +/// \brief Class for loading and manipulating character fonts +/// //////////////////////////////////////////////////////////// class SFML_API Font : public Resource { public : //////////////////////////////////////////////////////////// - /// Default constructor + /// \brief Default constructor + /// + /// This constructor defines an empty font /// //////////////////////////////////////////////////////////// Font(); //////////////////////////////////////////////////////////// - /// Load the font from a file + /// \brief Copy constructor /// - /// \param filename : Font file to load - /// \param charSize : Size of characters in bitmap - the bigger, the higher quality - /// \param charset : Characters set to generate (by default, contains the ISO-8859-1 printable characters) - /// - /// \return True if loading was successful + /// \param copy Instance to copy /// //////////////////////////////////////////////////////////// - bool LoadFromFile(const std::string& filename, unsigned int charSize = 30, String charset = ourDefaultCharset); + Font(const Font& copy); //////////////////////////////////////////////////////////// - /// Load the font from a file in memory + /// \brief Destructor /// - /// \param data : Pointer to the data to load - /// \param sizeInBytes : Size of the data, in bytes - /// \param charSize : Size of characters in bitmap - the bigger, the higher quality - /// \param charset : Characters set to generate (by default, contains the ISO-8859-1 printable characters) - /// - /// \return True if loading was successful + /// Cleans up all the internal resources used by the font /// //////////////////////////////////////////////////////////// - bool LoadFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize = 30, String charset = ourDefaultCharset); + ~Font(); //////////////////////////////////////////////////////////// - /// Get the base size of characters in the font; - /// All glyphs dimensions are based on this value + /// \brief Load the font from a file /// - /// \return Base size of characters + /// The supported font formats are: TrueType, Type 1, CFF, + /// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. + /// Note that this function know nothing about the standard + /// fonts installed on the user's system, thus you can't + /// load them directly. + /// + /// \param filename Path of the font file to load + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see LoadFromMemory /// //////////////////////////////////////////////////////////// - unsigned int GetCharacterSize() const; + bool LoadFromFile(const std::string& filename); //////////////////////////////////////////////////////////// - /// Get the description of a glyph (character) - /// given by its unicode value + /// \brief Load the font from a file /// - /// \param codePoint : Unicode value of the character to get + /// The supported font formats are: TrueType, Type 1, CFF, + /// OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. + /// Note that this function know nothing about the standard + /// fonts installed on the user's system, thus you can't + /// load them directly. /// - /// \return Glyph's visual settings, or an invalid glyph if character not found + /// \param data Pointer to the file data in memory + /// \param sizeInBytes Size of the data to load, in bytes + /// + /// \return True if loading succeeded, false if it failed + /// + /// \see LoadFromFile /// //////////////////////////////////////////////////////////// - const Glyph& GetGlyph(Uint32 codePoint) const; + bool LoadFromMemory(const char* data, std::size_t sizeInBytes); //////////////////////////////////////////////////////////// - /// Get the image containing the rendered characters (glyphs) + /// \brief Retrieve a glyph of the font /// - /// \return Image containing glyphs + /// \param codePoint Unicode code point of the character to get + /// \param characterSize Reference character size + /// + /// \return The glyph corresponding to \a codePoint and \a characterSize /// //////////////////////////////////////////////////////////// - const Image& GetImage() const; + const Glyph& GetGlyph(Uint32 codePoint, unsigned int characterSize) const; //////////////////////////////////////////////////////////// - /// Get the SFML default built-in font (Arial) + /// \brief Get the kerning offset of two glyphs /// - /// \return Instance of the default font + /// The kerning is an extra offset (negative) to apply between two + /// glyphs when rendering them, to make the pair look more "natural". + /// For example, the pair "AV" have a special kerning to make them + /// closer than other characters. Most of the glyphs pairs have a + /// kerning offset of zero, though. + /// + /// \param first Unicode code point of the first character + /// \param second Unicode code point of the second character + /// \param characterSize Reference character size + /// + /// \return Kerning value for \a first and \a second, in pixels + /// + //////////////////////////////////////////////////////////// + int GetKerning(Uint32 first, Uint32 second, unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Get the line spacing + /// + /// Line spacing is the vertical offset to apply between two + /// consecutive lines of text. + /// + /// \param characterSize Reference character size + /// + /// \return Line spacing, in pixels + /// + //////////////////////////////////////////////////////////// + int GetLineSpacing(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Retrieve the image containing the loaded glyphs of a certain size + /// + /// The contents of the returned image changes as more glyphs + /// are requested, thus it is not very relevant. It is mainly + /// used internally by sf::Text. + /// + /// \param characterSize Reference character size + /// + /// \return Image containing the glyphs of the requested size + /// + //////////////////////////////////////////////////////////// + const Image& GetImage(unsigned int characterSize) const; + + //////////////////////////////////////////////////////////// + /// \brief Overload of assignment operator + /// + /// \param right Instance to assign + /// + /// \return Reference to self + /// + //////////////////////////////////////////////////////////// + Font& operator =(const Font& right); + + //////////////////////////////////////////////////////////// + /// \brief Return the default built-in font + /// + /// This font is provided for convenience, it is used by + /// sf::Text instances by default. It is provided so that + /// users don't have to provide and load a font file in order + /// to display text on screen. + /// The font used is Arial. + /// + /// \return Reference to the built-in default font /// //////////////////////////////////////////////////////////// static const Font& GetDefaultFont(); private : - friend class priv::FontLoader; + //////////////////////////////////////////////////////////// + /// \brief Structure storing a glyph together with its + /// rectangle in the texture + /// + //////////////////////////////////////////////////////////// + struct GlyphInfo + { + Glyph GlyphDesc; + IntRect TextureRect; + }; //////////////////////////////////////////////////////////// - // Static member data + /// \brief Structure defining a row of glyphs + /// //////////////////////////////////////////////////////////// - static Uint32 ourDefaultCharset[]; ///< The default charset (all printable ISO-8859-1 characters) + struct Row + { + Row(unsigned int top, unsigned int height) : Width(0), Top(top), Height(height) {} + + unsigned int Width; ///< Current width of the row + unsigned int Top; ///< Y position of the row into the texture + unsigned int Height; ///< Height of the row + }; + + //////////////////////////////////////////////////////////// + // Types + //////////////////////////////////////////////////////////// + typedef std::map 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 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 PageTable; ///< Table mapping a character size to its page (image) //////////////////////////////////////////////////////////// // Member data //////////////////////////////////////////////////////////// - Image myTexture; ///< Texture holding the bitmap font - unsigned int myCharSize; ///< Size of characters in the bitmap font - std::map myGlyphs; ///< Rendering settings of each character (glyph) + void* myLibrary; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details) + void* myFace; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details) + int* myRefCount; ///< Reference counter used by implicit sharing + mutable PageTable myPages; ///< Table containing the glyphs pages by character size + mutable std::vector myPixelBuffer; ///< Pixel buffer holding a glyph's pixels before being written to the texture + mutable unsigned int myCurrentSize; ///< Current character size in use }; } // namespace sf #endif // SFML_FONT_HPP + + +//////////////////////////////////////////////////////////// +/// \class sf::Font +/// +/// Fonts can be loaded from a file or from memory, from +/// the most common types of fonts. See the LoadFromFile() +/// function for the complete list of supported formats. +/// +/// Once it is loaded, a sf::Font instance provides three +/// types of informations about the font: +/// \li Global metrics, such as the line spacing +/// \li Per-glyph metrics, such as bounding box or kerning +/// \li Pixel representation of glyphs +/// +/// Fonts alone are not very useful: they hold the font data +/// but cannot make anything useful of it. To do so you need to +/// use the sf::Text class, which is able to properly output text +/// with several options such as character size, style, color, +/// position, rotation, etc. +/// This separation allows more flexibility and better performances: +/// indeed a sf::Font is a heavy resource, and any operation on it +/// is slow (often too slow for real-time applications). On the other +/// side, a sf::Text is a lightweight object which can combine the +/// glyphs data and metrics of a sf::Font to display any text on a +/// render target. +/// Note that it is also possible to bind several sf::Text instances +/// to the same sf::Font. +/// +/// It is important to note that the sf::Text instance doesn't +/// copy the font that it uses, it only keeps a reference to it. +/// Thus, a sf::Font must not be destructed while it is +/// used by a sf::Text (i.e. never write a function that +/// uses a local sf::Font instance for creating a text). +/// +/// Usage example: +/// \code +/// // Declare a new font +/// sf::Font font; +/// +/// // Load it from a file +/// if (!font.LoadFromFile("arial.ttf")) +/// { +/// // error... +/// } +/// +/// // Create a text which uses our font +/// sf::Text text1; +/// text1.SetFont(font); +/// text1.SetCharacterSize(30); +/// text1.SetStyle(sf::Text::Regular); +/// +/// // Create another text using the same font, but with different parameters +/// sf::Text text2; +/// text2.SetFont(font); +/// text2.SetCharacterSize(50); +/// text1.SetStyle(sf::Text::Italic); +/// \endcode +/// +/// Apart from loading font files, and passing them to instances +/// of sf::Text, you should normally not have to deal directly +/// with this class. However, it may be useful to access the +/// font metrics or rasterized glyphs for advanced usage. +/// +/// \see sf::Text +/// +//////////////////////////////////////////////////////////// diff --git a/include/SFML/Graphics/Glyph.hpp b/include/SFML/Graphics/Glyph.hpp index ec1b8869..1b6168a3 100644 --- a/include/SFML/Graphics/Glyph.hpp +++ b/include/SFML/Graphics/Glyph.hpp @@ -51,8 +51,8 @@ public : // Member data //////////////////////////////////////////////////////////// int Advance; ///< Offset to move horizontically to the next character - IntRect Rectangle; ///< Bounding rectangle of the glyph, in relative coordinates - FloatRect TexCoords; ///< Texture coordinates of the glyph inside the bitmap font + IntRect Rectangle; ///< Bounding rectangle of the glyph, in coordinates relative to the baseline + FloatRect TexCoords; ///< Texture coordinates of the glyph inside the font's image }; } // namespace sf diff --git a/include/SFML/Graphics/Image.hpp b/include/SFML/Graphics/Image.hpp index 77f5e15d..907fdf13 100644 --- a/include/SFML/Graphics/Image.hpp +++ b/include/SFML/Graphics/Image.hpp @@ -203,7 +203,7 @@ public : /// Warning: for performances reasons, this function doesn't /// perform any check; thus you're responsible of ensuring that /// \a rectangle does not exceed the image size, and that - /// \a pixels contain enough elements. + /// \a pixels contains enough elements. /// /// \param rectangle : Sub-rectangle of the image to update /// \param pixels : Array of pixels to write to the image diff --git a/include/SFML/Graphics/Text.hpp b/include/SFML/Graphics/Text.hpp index 8a865f94..5524428f 100644 --- a/include/SFML/Graphics/Text.hpp +++ b/include/SFML/Graphics/Text.hpp @@ -65,12 +65,12 @@ public : //////////////////////////////////////////////////////////// /// Construct the string from any kind of text /// - /// \param string : Text assigned to the string - /// \param font : Font used to draw the string - /// \param size : Characters size + /// \param string : Text assigned to the string + /// \param font : Font used to draw the string + /// \param characterSize : Base size of characters, in pixels /// //////////////////////////////////////////////////////////// - explicit Text(const String& string, const Font& font = Font::GetDefaultFont(), float size = 30.f); + explicit Text(const String& string, const Font& font = Font::GetDefaultFont(), unsigned int characterSize = 30); //////////////////////////////////////////////////////////// /// Set the text (from any kind of string) @@ -89,13 +89,13 @@ public : void SetFont(const Font& font); //////////////////////////////////////////////////////////// - /// Set the size of the string + /// Set the base size for the characters. /// The default size is 30 /// /// \param size : New size, in pixels /// //////////////////////////////////////////////////////////// - void SetSize(float size); + void SetCharacterSize(unsigned int size); //////////////////////////////////////////////////////////// /// Set the style of the text @@ -123,12 +123,12 @@ public : const Font& GetFont() const; //////////////////////////////////////////////////////////// - /// Get the size of the characters + /// Get the base size of characters /// - /// \return Size of the characters + /// \return Size of the characters, in pixels /// //////////////////////////////////////////////////////////// - float GetSize() const; + unsigned int GetCharacterSize() const; //////////////////////////////////////////////////////////// /// Get the style of the text @@ -148,7 +148,7 @@ public : /// \return Position of the index-th character (end of string if Index is out of range) /// //////////////////////////////////////////////////////////// - sf::Vector2f GetCharacterPos(std::size_t index) const; + Vector2f GetCharacterPos(std::size_t index) const; //////////////////////////////////////////////////////////// /// Get the string rectangle on screen @@ -179,7 +179,7 @@ private : //////////////////////////////////////////////////////////// String myString; ///< String to display ResourcePtr myFont; ///< Font used to display the string - float mySize; ///< Size of the characters + unsigned int myCharacterSize; ///< Base size of characters, in pixels unsigned long myStyle; ///< Text style (see Style enum) FloatRect myBaseRect; ///< Bounding rectangle of the text in object coordinates bool myNeedRectUpdate; ///< Does the bounding rect need an update ? diff --git a/samples/pong/Pong.cpp b/samples/pong/Pong.cpp index 192a6820..e1db79b1 100644 --- a/samples/pong/Pong.cpp +++ b/samples/pong/Pong.cpp @@ -47,7 +47,7 @@ int main() // Initialize the end text sf::Text end; end.SetFont(font); - end.SetSize(60.f); + end.SetCharacterSize(60); end.Move(150.f, 200.f); end.SetColor(sf::Color(50, 50, 250)); diff --git a/samples/shader/Shader.cpp b/samples/shader/Shader.cpp index 8d102082..45ba013b 100644 --- a/samples/shader/Shader.cpp +++ b/samples/shader/Shader.cpp @@ -108,7 +108,7 @@ int main() // Load the text font sf::Font font; - if (!font.LoadFromFile("datas/shader/arial.ttf", 20)) + if (!font.LoadFromFile("datas/shader/arial.ttf")) return EXIT_FAILURE; // Load the image needed for the wave shader @@ -144,7 +144,7 @@ int main() // Define a string for displaying the description of the current shader sf::Text shaderStr; shaderStr.SetFont(font); - shaderStr.SetSize(20); + shaderStr.SetCharacterSize(20); shaderStr.SetPosition(5.f, 0.f); shaderStr.SetColor(sf::Color(250, 100, 30)); shaderStr.SetString("Background shader: \"" + backgroundShader.GetName() + "\"\n" @@ -154,8 +154,8 @@ int main() // Define a string for displaying help sf::Text infoStr; infoStr.SetFont(font); - infoStr.SetSize(20); - infoStr.SetPosition(5.f, 510.f); + infoStr.SetCharacterSize(20); + infoStr.SetPosition(5.f, 500.f); infoStr.SetColor(sf::Color(250, 100, 30)); infoStr.SetString("Move your mouse to change the shaders' parameters\n" "Press numpad 1/4 to change the background shader\n" diff --git a/src/SFML/Graphics/Font.cpp b/src/SFML/Graphics/Font.cpp index ab6455be..cdf15494 100644 --- a/src/SFML/Graphics/Font.cpp +++ b/src/SFML/Graphics/Font.cpp @@ -26,133 +26,213 @@ // Headers //////////////////////////////////////////////////////////// #include -#include +#include +#include FT_FREETYPE_H +#include FT_GLYPH_H #include namespace sf { //////////////////////////////////////////////////////////// -// Static member data -//////////////////////////////////////////////////////////// -Uint32 Font::ourDefaultCharset[] = -{ - // Printable characters in ASCII range - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, - - // Printable characters in extended ASCII range - 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0x2A, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, - 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, - - // To make it a valid string - 0x00 -}; - - -//////////////////////////////////////////////////////////// -/// Default constructor -//////////////////////////////////////////////////////////// Font::Font() : -myCharSize(0) +myLibrary (NULL), +myFace (NULL), +myRefCount (NULL), +myCurrentSize(0) { } //////////////////////////////////////////////////////////// -/// Load the font from a file -//////////////////////////////////////////////////////////// -bool Font::LoadFromFile(const std::string& filename, unsigned int charSize, String charset) +Font::Font(const Font& copy) : +myLibrary (copy.myLibrary), +myFace (copy.myFace), +myRefCount (copy.myRefCount), +myPages (copy.myPages), +myPixelBuffer(copy.myPixelBuffer), +myCurrentSize(copy.myCurrentSize) { - // Clear the previous character map - myGlyphs.clear(); + // Note: as FreeType doesn't provide functions for copying/cloning, + // we must share all the FreeType pointers - // Always add these special characters - if (std::find(charset.Begin(), charset.End(), L' ') == charset.End()) charset += L' '; - if (std::find(charset.Begin(), charset.End(), L'\n') == charset.End()) charset += L'\n'; - if (std::find(charset.Begin(), charset.End(), L'\v') == charset.End()) charset += L'\v'; - if (std::find(charset.Begin(), charset.End(), L'\t') == charset.End()) charset += L'\t'; - - return priv::FontLoader::GetInstance().LoadFontFromFile(filename, charSize, charset, *this); + if (myRefCount) + (*myRefCount)++; } //////////////////////////////////////////////////////////// -/// Load the font from a file in memory -//////////////////////////////////////////////////////////// -bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes, unsigned int charSize, String charset) +Font::~Font() { - // Clear the previous character map - myGlyphs.clear(); + Cleanup(); +} - // Check parameters - if (!data || (sizeInBytes == 0)) + +//////////////////////////////////////////////////////////// +bool Font::LoadFromFile(const std::string& filename) +{ + // 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, no data provided" << std::endl; + 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(myLibrary), filename.c_str(), 0, &face) != 0) + { + std::cerr << "Failed to load font \"" << filename << "\" (failed to create the font face)" << std::endl; return false; } - // Always add these special characters - if (std::find(charset.Begin(), charset.End(), L' ') == charset.End()) charset += L' '; - if (std::find(charset.Begin(), charset.End(), L'\n') == charset.End()) charset += L'\n'; - if (std::find(charset.Begin(), charset.End(), L'\v') == charset.End()) charset += L'\v'; - if (std::find(charset.Begin(), charset.End(), L'\t') == charset.End()) charset += L'\t'; - - return priv::FontLoader::GetInstance().LoadFontFromMemory(data, sizeInBytes, charSize, charset, *this); -} - - -//////////////////////////////////////////////////////////// -/// Get the base size of characters in the font; -/// All glyphs dimensions are based on this value -//////////////////////////////////////////////////////////// -unsigned int Font::GetCharacterSize() const -{ - return myCharSize; -} - - -//////////////////////////////////////////////////////////// -/// Get the description of a glyph (character) -/// given by its unicode value -//////////////////////////////////////////////////////////// -const Glyph& Font::GetGlyph(Uint32 codePoint) const -{ - std::map::const_iterator it = myGlyphs.find(codePoint); - if (it != myGlyphs.end()) + // Select the unicode character map + if (FT_Select_Charmap(face, FT_ENCODING_UNICODE) != 0) { - // Valid glyph - return it->second; + std::cerr << "Failed to load font \"" << filename << "\" (failed to set the Unicode character set)" << std::endl; + return false; + } + + // Store the loaded font in our ugly void* :) + myFace = face; + + return true; +} + + +//////////////////////////////////////////////////////////// +bool Font::LoadFromMemory(const char* data, std::size_t sizeInBytes) +{ + // 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(myLibrary), reinterpret_cast(data), static_cast(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; +} + + +//////////////////////////////////////////////////////////// +const Glyph& Font::GetGlyph(Uint32 codePoint, unsigned int characterSize) const +{ + // Get the page corresponding to the character size + GlyphTable& glyphs = myPages[characterSize].Glyphs; + + // Search the glyph into the cache + GlyphTable::const_iterator it = glyphs.find(codePoint); + if (it != glyphs.end()) + { + // Found: just return it + return it->second.GlyphDesc; } else { - // Invalid glyph -- return an invalid glyph - static const Glyph invalid; - return invalid; + // Not found: we have to load it + GlyphInfo glyph = LoadGlyph(codePoint, characterSize); + return glyphs.insert(std::make_pair(codePoint, glyph)).first->second.GlyphDesc; } } //////////////////////////////////////////////////////////// -/// Get the image containing the rendered characters (glyphs) -//////////////////////////////////////////////////////////// -const Image& Font::GetImage() const +int Font::GetKerning(Uint32 first, Uint32 second, unsigned int characterSize) const { - return myTexture; + FT_Face face = static_cast(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(myFace); + + if (face && SetCurrentSize(characterSize)) + { + return (face->size->metrics.height >> 6); + } + else + { + return 0; + } +} + + +//////////////////////////////////////////////////////////// +const Image& Font::GetImage(unsigned int characterSize) const +{ + return myPages[characterSize].Texture; +} + + +//////////////////////////////////////////////////////////// +Font& Font::operator =(const Font& right) +{ + Font temp(right); + + std::swap(myLibrary, temp.myLibrary); + std::swap(myFace, temp.myFace); + std::swap(myPages, temp.myPages); + std::swap(myPixelBuffer, temp.myPixelBuffer); + std::swap(myCurrentSize, temp.myCurrentSize); + + return *this; +} + + //////////////////////////////////////////////////////////// const Font& Font::GetDefaultFont() { @@ -167,11 +247,231 @@ const Font& Font::GetDefaultFont() #include }; - font.LoadFromMemory(data, sizeof(data), 30); + font.LoadFromMemory(data, sizeof(data)); loaded = true; } return font; } + +//////////////////////////////////////////////////////////// +void Font::Cleanup() +{ + // Check if we must destroy the FreeType pointers + if (myRefCount) + { + // Decrease the reference counter + (*myRefCount)--; + + // Free the resources only if we are the last owner + if (*myRefCount == 0) + { + // Delete the reference counter + delete myRefCount; + + // Destroy the font face + if (myFace) + FT_Done_Face(static_cast(myFace)); + + // Close the library + if (myLibrary) + FT_Done_FreeType(static_cast(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(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::iterator it = page.Rows.begin(); it != page.Rows.end() && !row; ++it) + { + float ratio = static_cast(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 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(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 diff --git a/src/SFML/Graphics/FontLoader.cpp b/src/SFML/Graphics/FontLoader.cpp deleted file mode 100644 index 97802e18..00000000 --- a/src/SFML/Graphics/FontLoader.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include FT_GLYPH_H -#include -#include -#include -#include - - -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(data), static_cast(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(sqrt(static_cast(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 tops(texWidth, 0); - - // Create a pixel buffer for rendering every glyph - std::vector 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 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 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 -#include -#include -#include -#include -#define STB_TRUETYPE_IMPLEMENTATION -#include -#include -#include -#include -#include -#include - - -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 data(length); - file.read(&data[0], static_cast(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(sqrt(static_cast(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 tops(texWidth, 0); - - // Create a pixel buffer for rendering every glyph - std::vector glyphsBuffer(texWidth * texHeight * 4); - - // Load the font - stbtt_fontinfo info; - int success = stbtt_InitFont(&info, reinterpret_cast(data), 0); - if (!success) - return false; - - // Compute the global scale to apply to match the character size - float scale = stbtt_ScaleForPixelHeight(&info, static_cast(charSize)); - - // Render all glyphs and sort them by size to optimize texture space - typedef std::multimap 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(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(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 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 diff --git a/src/SFML/Graphics/FontLoader.hpp b/src/SFML/Graphics/FontLoader.hpp deleted file mode 100644 index f3dad3bf..00000000 --- a/src/SFML/Graphics/FontLoader.hpp +++ /dev/null @@ -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 -#include -#include -#include FT_FREETYPE_H -#include - - -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 diff --git a/src/SFML/Graphics/RenderWindow.cpp b/src/SFML/Graphics/RenderWindow.cpp index 10e645c6..6e5bd3c0 100644 --- a/src/SFML/Graphics/RenderWindow.cpp +++ b/src/SFML/Graphics/RenderWindow.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include diff --git a/src/SFML/Graphics/Text.cpp b/src/SFML/Graphics/Text.cpp index 567b5bdd..a17626e3 100644 --- a/src/SFML/Graphics/Text.cpp +++ b/src/SFML/Graphics/Text.cpp @@ -37,7 +37,7 @@ namespace sf //////////////////////////////////////////////////////////// Text::Text() : myFont (&Font::GetDefaultFont()), -mySize (30.f), +myCharacterSize (30), myStyle (Regular), myNeedRectUpdate(true) { @@ -48,9 +48,9 @@ myNeedRectUpdate(true) //////////////////////////////////////////////////////////// /// Construct the string from any kind of text //////////////////////////////////////////////////////////// -Text::Text(const String& string, const Font& font, float size) : +Text::Text(const String& string, const Font& font, unsigned int characterSize) : myFont (&font), -mySize (size), +myCharacterSize (characterSize), myStyle (Regular), myNeedRectUpdate(true) { @@ -82,14 +82,14 @@ void Text::SetFont(const Font& font) //////////////////////////////////////////////////////////// -/// Set the size of the string +/// Set the base size for the characters. //////////////////////////////////////////////////////////// -void Text::SetSize(float size) +void Text::SetCharacterSize(unsigned int size) { - if (mySize != size) + if (myCharacterSize != size) { myNeedRectUpdate = true; - mySize = size; + myCharacterSize = size; } } @@ -127,11 +127,11 @@ const Font& Text::GetFont() const //////////////////////////////////////////////////////////// -/// Get the size of the characters +/// Get the base size of characters //////////////////////////////////////////////////////////// -float Text::GetSize() const +unsigned int Text::GetCharacterSize() const { - return mySize; + return myCharacterSize; } @@ -149,36 +149,42 @@ unsigned long Text::GetStyle() const /// in coordinates relative to the string /// (note : translation, center, rotation and scale are not applied) //////////////////////////////////////////////////////////// -sf::Vector2f Text::GetCharacterPos(std::size_t index) const +Vector2f Text::GetCharacterPos(std::size_t index) const { + // Make sure that we have a valid font + if (!myFont) + return Vector2f(0, 0); + // Adjust the index if it's out of range if (index > myString.GetSize()) index = myString.GetSize(); - // The final size is based on the text size - float factor = mySize / myFont->GetCharacterSize(); - float advanceY = mySize; + // We'll need this a lot + float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize).Advance); // Compute the position sf::Vector2f position; + Uint32 prevChar = 0; + float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); for (std::size_t i = 0; i < index; ++i) { - // Get the current character and its corresponding glyph - Uint32 curChar = myString[i]; - const Glyph& curGlyph = myFont->GetGlyph(curChar); - float advanceX = curGlyph.Advance * factor; + Uint32 curChar = myString[i]; + // Apply the kerning offset + position.x += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize)); + prevChar = curChar; + + // Handle special characters switch (curChar) { - // Handle special characters - case L' ' : position.x += advanceX; break; - case L'\t' : position.x += advanceX * 4; break; - case L'\v' : position.y += advanceY * 4; break; - case L'\n' : position.y += advanceY; position.x = 0; break; - - // Regular character : just add its advance value - default : position.x += advanceX; break; + case L' ' : position.x += space; continue; + case L'\t' : position.x += space * 4; continue; + case L'\v' : position.y += lineSpacing * 4; continue; + case L'\n' : position.y += lineSpacing; position.x = 0; continue; } + + // For regular characters, add the advance offset of the glyph + position.x += static_cast(myFont->GetGlyph(curChar, myCharacterSize).Advance); } return position; @@ -204,24 +210,22 @@ FloatRect Text::GetRect() const //////////////////////////////////////////////////////////// -/// /see sfDrawable::Render +/// /see Drawable::Render //////////////////////////////////////////////////////////// void Text::Render(RenderTarget&, RenderQueue& queue) const { - // No text, no rendering :) - if (myString.IsEmpty()) + // No text or not font: nothing to render + if (!myFont || myString.IsEmpty()) return; - // Set the scaling factor to get the actual size - float charSize = static_cast(myFont->GetCharacterSize()); - float factor = mySize / charSize; - // Bind the font texture - queue.SetTexture(&myFont->GetImage()); + queue.SetTexture(&myFont->GetImage(myCharacterSize)); // Initialize the rendering coordinates + float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize).Advance); + float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); float x = 0.f; - float y = charSize; + float y = static_cast(myCharacterSize); // Holds the lines to draw later, for underlined style std::vector underlineCoords; @@ -232,15 +236,15 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const // Draw one quad for each character unsigned int index = 0; + Uint32 prevChar = 0; queue.BeginBatch(); for (std::size_t i = 0; i < myString.GetSize(); ++i) { - // Get the current character and its corresponding glyph - Uint32 curChar = myString[i]; - const Glyph& curGlyph = myFont->GetGlyph(curChar); - int advance = curGlyph.Advance; - const IntRect& rect = curGlyph.Rectangle; - const FloatRect& coord = curGlyph.TexCoords; + Uint32 curChar = myString[i]; + + // Apply the kerning offset + x += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize)); + prevChar = curChar; // If we're using the underlined style and there's a new line, // we keep track of the previous line to draw it later @@ -253,17 +257,23 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const // Handle special characters switch (curChar) { - case L' ' : x += advance; continue; - case L'\n' : y += charSize; x = 0; continue; - case L'\t' : x += advance * 4; continue; - case L'\v' : y += charSize * 4; continue; + case L' ' : x += space; continue; + case L'\t' : x += space * 4; continue; + case L'\n' : y += lineSpacing; x = 0; continue; + case L'\v' : y += lineSpacing * 4; continue; } + // Extract the current glyph's description + const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize); + int advance = curGlyph.Advance; + const IntRect& rect = curGlyph.Rectangle; + const FloatRect& coord = curGlyph.TexCoords; + // Draw a textured quad for the current character - queue.AddVertex(factor * (x + rect.Left - italicCoeff * rect.Top), factor * (y + rect.Top), coord.Left, coord.Top); - queue.AddVertex(factor * (x + rect.Left - italicCoeff * rect.Bottom), factor * (y + rect.Bottom), coord.Left, coord.Bottom); - queue.AddVertex(factor * (x + rect.Right - italicCoeff * rect.Bottom), factor * (y + rect.Bottom), coord.Right, coord.Bottom); - queue.AddVertex(factor * (x + rect.Right - italicCoeff * rect.Top), factor * (y + rect.Top), coord.Right, coord.Top); + queue.AddVertex(x + rect.Left - italicCoeff * rect.Top, y + rect.Top, coord.Left, coord.Top); + queue.AddVertex(x + rect.Left - italicCoeff * rect.Bottom, y + rect.Bottom, coord.Left, coord.Bottom); + queue.AddVertex(x + rect.Right - italicCoeff * rect.Bottom, y + rect.Bottom, coord.Right, coord.Bottom); + queue.AddVertex(x + rect.Right - italicCoeff * rect.Top, y + rect.Top, coord.Right, coord.Top); queue.AddTriangle(index + 0, index + 1, index + 3); queue.AddTriangle(index + 3, index + 1, index + 2); @@ -277,7 +287,7 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const // slightly offseted, to simulate a higher weight if (myStyle & Bold) { - float offset = mySize * 0.02f; + float offset = myCharacterSize * 0.02f; static const float offsetsX[] = {-offset, offset, 0.f, 0.f}; static const float offsetsY[] = {0.f, 0.f, -offset, offset}; @@ -285,32 +295,38 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const { index = 0; x = 0.f; - y = charSize; + y = static_cast(myCharacterSize); + Uint32 prevChar = 0; queue.BeginBatch(); for (std::size_t i = 0; i < myString.GetSize(); ++i) { - // Get the current character and its corresponding glyph - Uint32 curChar = myString[i]; - const Glyph& curGlyph = myFont->GetGlyph(curChar); - int advance = curGlyph.Advance; - const IntRect& rect = curGlyph.Rectangle; - const FloatRect& coord = curGlyph.TexCoords; + Uint32 curChar = myString[i]; + + // Apply the kerning offset + x += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize)); + prevChar = curChar; // Handle special characters switch (curChar) { - case L' ' : x += advance; continue; - case L'\n' : y += charSize; x = 0; continue; - case L'\t' : x += advance * 4; continue; - case L'\v' : y += charSize * 4; continue; + case L' ' : x += space; continue; + case L'\t' : x += space * 4; continue; + case L'\n' : y += lineSpacing; x = 0; continue; + case L'\v' : y += lineSpacing * 4; continue; } + // Extract the current glyph's description + const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize); + int advance = curGlyph.Advance; + const IntRect& rect = curGlyph.Rectangle; + const FloatRect& coord = curGlyph.TexCoords; + // Draw a textured quad for the current character - queue.AddVertex(factor * (x + offsetsX[j] + rect.Left - italicCoeff * rect.Top), factor * (y + offsetsY[j] + rect.Top), coord.Left, coord.Top); - queue.AddVertex(factor * (x + offsetsX[j] + rect.Left - italicCoeff * rect.Bottom), factor * (y + offsetsY[j] + rect.Bottom), coord.Left, coord.Bottom); - queue.AddVertex(factor * (x + offsetsX[j] + rect.Right - italicCoeff * rect.Bottom), factor * (y + offsetsY[j] + rect.Bottom), coord.Right, coord.Bottom); - queue.AddVertex(factor * (x + offsetsX[j] + rect.Right - italicCoeff * rect.Top), factor * (y + offsetsY[j] + rect.Top), coord.Right, coord.Top); + queue.AddVertex(x + offsetsX[j] + rect.Left - italicCoeff * rect.Top, y + offsetsY[j] + rect.Top, coord.Left, coord.Top); + queue.AddVertex(x + offsetsX[j] + rect.Left - italicCoeff * rect.Bottom, y + offsetsY[j] + rect.Bottom, coord.Left, coord.Bottom); + queue.AddVertex(x + offsetsX[j] + rect.Right - italicCoeff * rect.Bottom, y + offsetsY[j] + rect.Bottom, coord.Right, coord.Bottom); + queue.AddVertex(x + offsetsX[j] + rect.Right - italicCoeff * rect.Top, y + offsetsY[j] + rect.Top, coord.Right, coord.Top); queue.AddTriangle(index + 0, index + 1, index + 3); queue.AddTriangle(index + 3, index + 1, index + 2); @@ -338,10 +354,10 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const queue.BeginBatch(); for (std::size_t i = 0; i < underlineCoords.size(); i += 2) { - queue.AddVertex(factor * (0), factor * (underlineCoords[i + 1])); - queue.AddVertex(factor * (0), factor * (underlineCoords[i + 1] + thickness)); - queue.AddVertex(factor * (underlineCoords[i]), factor * (underlineCoords[i + 1] + thickness)); - queue.AddVertex(factor * (underlineCoords[i]), factor * (underlineCoords[i + 1])); + queue.AddVertex(0, underlineCoords[i + 1]); + queue.AddVertex(0, underlineCoords[i + 1] + thickness); + queue.AddVertex(underlineCoords[i], underlineCoords[i + 1] + thickness); + queue.AddVertex(underlineCoords[i], underlineCoords[i + 1]); queue.AddTriangle(index + 0, index + 1, index + 3); queue.AddTriangle(index + 3, index + 1, index + 2); @@ -356,41 +372,51 @@ void Text::Render(RenderTarget&, RenderQueue& queue) const //////////////////////////////////////////////////////////// void Text::RecomputeRect() { - // Reset the "need update" state + // Reset the previous states myNeedRectUpdate = false; + myBaseRect = FloatRect(0, 0, 0, 0); - // No text, empty box :) - if (myString.IsEmpty()) - { - myBaseRect = FloatRect(0, 0, 0, 0); + // No text or not font: empty box + if (!myFont || myString.IsEmpty()) return; - } // Initial values - float curWidth = 0; - float curHeight = 0; - float width = 0; - float height = 0; - float factor = mySize / myFont->GetCharacterSize(); + float charSize = static_cast(myCharacterSize); + float space = static_cast(myFont->GetGlyph(L' ', myCharacterSize).Advance); + float lineSpacing = static_cast(myFont->GetLineSpacing(myCharacterSize)); + float curWidth = 0; + float curHeight = 0; + float width = 0; + float height = 0; + Uint32 prevChar = 0; // Go through each character for (std::size_t i = 0; i < myString.GetSize(); ++i) { - // Get the current character and its corresponding glyph - Uint32 curChar = myString[i]; - const Glyph& curGlyph = myFont->GetGlyph(curChar); - float advance = curGlyph.Advance * factor; - const IntRect& rect = curGlyph.Rectangle; + Uint32 curChar = myString[i]; + + // Apply the kerning offset + curWidth += static_cast(myFont->GetKerning(prevChar, curChar, myCharacterSize)); + prevChar = curChar; // Handle special characters switch (curChar) { - case L' ' : curWidth += advance; continue; - case L'\t' : curWidth += advance * 4; continue; - case L'\v' : height += mySize * 4; curHeight = 0; continue; + case L' ' : + curWidth += space; + continue; + + case L'\t' : + curWidth += space * 4; + continue; + + case L'\v' : + height += lineSpacing * 4; + curHeight = 0; + continue; case L'\n' : - height += mySize; + height += lineSpacing; curHeight = 0; if (curWidth > width) width = curWidth; @@ -398,11 +424,14 @@ void Text::RecomputeRect() continue; } + // Extract the current glyph's description + const Glyph& curGlyph = myFont->GetGlyph(curChar, myCharacterSize); + // Advance to the next character - curWidth += advance; + curWidth += static_cast(curGlyph.Advance); // Update the maximum height - float charHeight = (myFont->GetCharacterSize() + rect.Bottom) * factor; + float charHeight = charSize + curGlyph.Rectangle.Bottom; if (charHeight > curHeight) curHeight = charHeight; } @@ -415,21 +444,21 @@ void Text::RecomputeRect() // Add a slight width / height if we're using the bold style if (myStyle & Bold) { - width += 1 * factor; - height += 1 * factor; + width += 1.f; + height += 1.f; } // Add a slight width if we're using the italic style if (myStyle & Italic) { - width += 0.208f * mySize; + width += 0.208f * charSize; } // Add a slight height if we're using the underlined style if (myStyle & Underlined) { - if (curHeight < mySize + 4 * factor) - height += 4 * factor; + if (curHeight < charSize + 4.f) + height += 4.f; } // Finally update the rectangle diff --git a/src/SFML/Graphics/stb_truetype/stb_truetype.h b/src/SFML/Graphics/stb_truetype/stb_truetype.h deleted file mode 100644 index f9e7fe56..00000000 --- a/src/SFML/Graphics/stb_truetype/stb_truetype.h +++ /dev/null @@ -1,1807 +0,0 @@ -// stb_truetype.h - v0.3 - public domain - 2009 Sean Barrett / RAD Game Tools -// -// This library processes TrueType files: -// parse files -// extract glyph metrics -// extract glyph shapes -// render glyphs to one-channel bitmaps with antialiasing (box filter) -// -// Todo: -// non-MS cmaps -// crashproof on bad data -// hinting -// subpixel positioning when rendering bitmap -// cleartype-style AA -// -// ADDITIONAL CONTRIBUTORS -// -// Mikko Mononen: compound shape support, more cmap formats -// -// VERSIONS -// -// 0.3 (2009-06-24) cmap fmt=12, compound shapes (MM) -// userdata, malloc-from-userdata, non-zero fill (STB) -// 0.2 (2009-03-11) Fix unsigned/signed char warnings -// 0.1 (2009-03-09) First public release -// -// USAGE -// -// Include this file in whatever places neeed to refer to it. In ONE C/C++ -// file, write: -// #define STB_TRUETYPE_IMPLEMENTATION -// before the #include of this file. This expands out the actual -// implementation into that C/C++ file. -// -// Look at the header-file sections below for the API, but here's a quick skim: -// -// Simple 3D API (don't ship this, but it's fine for tools and quick start, -// and you can cut and paste from it to move to more advanced) -// stbtt_BakeFontBitmap() -- bake a font to a bitmap for use as texture -// stbtt_GetBakedQuad() -- compute quad to draw for a given char -// -// "Load" a font file from a memory buffer (you have to keep the buffer loaded) -// stbtt_InitFont() -// stbtt_GetFontOffsetForIndex() -- use for TTC font collections -// -// Render a unicode codepoint to a bitmap -// stbtt_GetCodepointBitmap() -- allocates and returns a bitmap -// stbtt_MakeCodepointBitmap() -- renders into bitmap you provide -// stbtt_GetCodepointBitmapBox() -- how big the bitmap must be -// -// Character advance/positioning -// stbtt_GetCodepointHMetrics() -// stbtt_GetFontVMetrics() -// -// NOTES -// -// The system uses the raw data found in the .ttf file without changing it -// and without building auxiliary data structures. This is a bit inefficient -// on little-endian systems (the data is big-endian), but assuming you're -// caching the bitmaps or glyph shapes this shouldn't be a big deal. -// -// It appears to be very hard to programmatically determine what font a -// given file is in a general way. I provide an API for this, but I don't -// recommend it. -// -// -// SOURCE STATISTICS (based on v0.3, 1800 LOC) -// -// Documentation & header file 350 LOC \___ 500 LOC documentation -// Sample code 140 LOC / -// Truetype parsing 580 LOC ---- 600 LOC TrueType -// Software rasterization 240 LOC \ . -// Curve tesselation 120 LOC \__ 500 LOC Bitmap creation -// Bitmap management 70 LOC / -// Baked bitmap interface 70 LOC / -// Font name matching & access 150 LOC ---- 150 -// C runtime library abstraction 60 LOC ---- 60 - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// SAMPLE PROGRAMS -//// -// -// Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless -// -#if 0 -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -char ttf_buffer[1<<20]; -unsigned char temp_bitmap[512*512]; - -stbtt_chardata cdata[96]; // ASCII 32..126 is 95 glyphs -GLstbtt_uint ftex; - -void my_stbtt_initfont(void) -{ - fread(ttf_buffer, 1, 1<<20, fopen("c:/windows/fonts/times.ttf", "rb")); - stbtt_BakeFontBitmap(data,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits! - // can free ttf_buffer at this point - glGenTextures(1, &ftex); - glBindTexture(GL_TEXTURE_2D, ftex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap); - // can free temp_bitmap at this point - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); -} - -void my_stbtt_print(float x, float y, char *text) -{ - // assume orthographic projection with units = screen pixels, origin at top left - glBindTexture(GL_TEXTURE_2D, ftex); - glBegin(GL_QUADS); - while (*text) { - if (*text >= 32 && *text < 128) { - stbtt_aligned_quad q; - stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl,0=old d3d - glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0); - glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0); - glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1); - glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1); - } - ++text; - } - glEnd(); -} -#endif -// -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program (this compiles): get a single bitmap, print as ASCII art -// -#if 0 -#include -#define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation -#include "stb_truetype.h" - -char ttf_buffer[1<<25]; - -int main(int argc, char **argv) -{ - stbtt_fontinfo font; - unsigned char *bitmap; - int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20); - - fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/arialbd.ttf", "rb")); - - stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); - bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0); - - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) - putchar(" .:ioVM@"[bitmap[j*w+i]>>5]); - putchar('\n'); - } - return 0; -} -#endif -// -// Output: -// -// .ii. -// @@@@@@. -// V@Mio@@o -// :i. V@V -// :oM@@M -// :@@@MM@M -// @@o o@M -// :@@. M@M -// @@@o@@@@ -// :M@@V:@@. -// -////////////////////////////////////////////////////////////////////////////// -// -// Complete program: print "Hello World!" banner, with bugs -// -#if 0 -int main(int arg, char **argv) -{ - unsigned char screen[20][79]; - int i,j, pos=0; - float scale; - char *text = "Heljo World!"; - - fread(buffer, 1, 1000000, fopen("c:/windows/fonts/arialbd.ttf", "rb")); - stbtt_InitFont(&font, buffer, 0); - - scale = stbtt_ScaleForPixelHeight(&font, 16); - memset(screen, 0, sizeof(screen)); - - while (*text) { - int advance,lsb,x0,y0,x1,y1, newpos, baseline=13; - stbtt_GetCodepointHMetrics(&font, *text, &advance, &lsb); - stbtt_GetCodepointBitmapBox(&font, *text, scale,scale, &x0,&y0,&x1,&y1); - newpos = pos + (int) (lsb * scale) + x0; - stbtt_MakeCodepointBitmap(&font, &screen[baseline + y0][newpos], x1-x0,y1-y0, 79, scale,scale, *text); - // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong - // because this API is really for baking character bitmaps into textures - pos += (int) (advance * scale); - ++text; - } - - for (j=0; j < 20; ++j) { - for (i=0; i < 79; ++i) - putchar(" .:ioVM@"[screen[j][i]>>5]); - putchar('\n'); - } - - return 0; -} -#endif - - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -//// -//// INTEGRATION WITH RUNTIME LIBRARIES -//// - -#ifdef STB_TRUETYPE_IMPLEMENTATION - // #define your own (u)stbtt_int8/16/32 before including to override this - #ifndef stbtt_uint8 - typedef unsigned char stbtt_uint8; - typedef signed char stbtt_int8; - typedef unsigned short stbtt_uint16; - typedef signed short stbtt_int16; - typedef unsigned int stbtt_uint32; - typedef signed int stbtt_int32; - #endif - - typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1]; - typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1]; - - // #define your own STBTT_sort() to override this to avoid qsort - #ifndef STBTT_sort - #include - #define STBTT_sort(data,num_items,item_size,compare_func) qsort(data,num_items,item_size,compare_func) - #endif - - // #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h - #ifndef STBTT_ifloor - #include - #define STBTT_ifloor(x) ((int) floor(x)) - #define STBTT_iceil(x) ((int) ceil(x)) - #endif - - // #define your own functions "STBTT_malloc" / "STBTT_free" to avoid malloc.h - #ifndef STBTT_malloc - #include - #define STBTT_malloc(x,u) malloc(x) - #define STBTT_free(x,u) free(x) - #endif - - #ifndef STBTT_assert - #include - #define STBTT_assert(x) assert(x) - #endif - - #ifndef STBTT_strlen - #include - #define STBTT_strlen(x) strlen(x) - #endif - - #ifndef STBTT_memcpy - #include - #define STBTT_memcpy memcpy - #define STBTT_memset memset - #endif -#endif - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// INTERFACE -//// -//// - -#ifndef __STB_INCLUDE_STB_TRUETYPE_H__ -#define __STB_INCLUDE_STB_TRUETYPE_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -////////////////////////////////////////////////////////////////////////////// -// -// TEXTURE BAKING API -// -// If you use this API, you only have to call two functions ever. -// - -typedef struct -{ - unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap - float xoff,yoff,xadvance; -} stbtt_bakedchar; - -extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata); // you allocate this, it's num_chars long -// if return is positive, the first unused row of the bitmap -// if return is negative, returns the negative of the number of characters that fit -// if return is 0, no characters fit and no rows were used -// This uses a very crappy packing. - -typedef struct -{ - float x0,y0,s0,t0; // top-left - float x1,y1,s1,t1; // bottom-right -} stbtt_aligned_quad; - -extern void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, // same data as above - int char_index, // character to display - float *xpos, float *ypos, // pointers to current position in screen pixel space - stbtt_aligned_quad *q, // output: quad to draw - int opengl_fillrule); // true if opengl fill rule; false if DX9 or earlier -// Call GetBakedQuad with char_index = 'character - first_char', and it -// creates the quad you need to draw and advances the current position. -// It's inefficient; you might want to c&p it and optimize it. - - -////////////////////////////////////////////////////////////////////////////// -// -// FONT LOADING -// -// - -extern int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index); -// Each .ttf file may have more than one font. Each has a sequential index -// number starting from 0. Call this function to get the font offset for a -// given index; it returns -1 if the index is out of range. A regular .ttf -// file will only define one font and it always be at offset 0, so it will -// return '0' for index 0, and -1 for all other indices. You can just skip -// this step if you know it's that kind of font. - - -// The following structure is defined publically so you can declare one on -// the stack or as a global or etc. -typedef struct -{ - void *userdata; - unsigned char *data; // pointer to .ttf file - int fontstart; // offset of start of font - - int numGlyphs; // number of glyphs, needed for range checking - - int loca,head,glyf,hhea,hmtx; // table locations as offset from start of .ttf - int index_map; // a cmap mapping for our chosen character encoding - int indexToLocFormat; // format needed to map from glyph index to glyph -} stbtt_fontinfo; - -extern int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset); -// Given an offset into the file that defines a font, this function builds -// the necessary cached info for the rest of the system. You must allocate -// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't -// need to do anything special to free it, because the contents are a pure -// cache with no additional data structures. Returns 0 on failure. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER TO GLYPH-INDEX CONVERSIOn - -int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint); -// If you're going to perform multiple operations on the same character -// and you want a speed-up, call this function with the character you're -// going to process, then use glyph-based functions instead of the -// codepoint-based functions. - - -////////////////////////////////////////////////////////////////////////////// -// -// CHARACTER PROPERTIES -// - -extern float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels); -// computes a scale factor to produce a font whose "height" is 'pixels' tall. -// Height is measured as the distance from the highest ascender to the lowest -// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics -// and computing: -// scale = pixels / (ascent - descent) -// so if you prefer to measure height by the ascent only, use a similar calculation. - -extern void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap); -// ascent is the coordinate above the baseline the font extends; descent -// is the coordinate below the baseline the font extends (i.e. it is typically negative) -// lineGap is the spacing between one row's descent and the next row's ascent... -// so you should advance the vertical position by "*ascent - *descent + *lineGap" -// these are expressed in unscaled coordinates - -extern void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing); -// leftSideBearing is the offset from the current horizontal position to the left edge of the character -// advanceWidth is the offset from the current horizontal position to the next horizontal position -// these are expressed in unscaled coordinates - -extern int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2); -// an additional amount to add to the 'advance' value between ch1 and ch2 -// @TODO; for now always returns 0! - -extern int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1); -// Gets the bounding box of the visible part of the glyph, in unscaled coordinates - -extern void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing); -extern int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2); -extern int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1); -// as above, but takes one or more glyph indices for greater efficiency - - -////////////////////////////////////////////////////////////////////////////// -// -// GLYPH SHAPES (you probably don't need these, but they have to go before -// the bitmaps for C declaration-order reasons) -// - -#ifndef STBTT_vmove // you can predefine these to use different values (but why?) - enum { - STBTT_vmove=1, - STBTT_vline, - STBTT_vcurve - }; -#endif - -#ifndef stbtt_vertex // you can predefine this to use different values - // (we share this with other code at RAD) - #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file - typedef struct - { - stbtt_vertex_type x,y,cx,cy; - unsigned char type,padding; - } stbtt_vertex; -#endif - -extern int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices); -extern int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices); -// returns # of vertices and fills *vertices with the pointer to them -// these are expressed in "unscaled" coordinates - -extern void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices); -// frees the data allocated above - -////////////////////////////////////////////////////////////////////////////// -// -// BITMAP RENDERING -// - -extern void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata); -// frees the bitmap allocated below - -extern unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff); -// allocates a large-enough single-channel 8bpp bitmap and renders the -// specified character/glyph at the specified scale into it, with -// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). -// *width & *height are filled out with the width & height of the bitmap, -// which is stored left-to-right, top-to-bottom. -// -// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap - -extern void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint); -// the same as above, but you pass in storage for the bitmap in the form -// of 'output', with row spacing of 'out_stride' bytes. the bitmap is -// clipped to out_w/out_h bytes. call the next function to get the -// height and width and positioning info - -extern void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -// get the bbox of the bitmap centered around the glyph origin; so the -// bitmap width is ix1-ix0, height is iy1-iy0, and location to place -// the bitmap top left is (leftSideBearing*scale,iy0). -// (Note that the bitmap uses y-increases-down, but the shape uses -// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) - -extern unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff); -extern void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); -extern void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph); - -//extern void stbtt_get_true_bbox(stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1); - -// @TODO: don't expose this structure -typedef struct -{ - int w,h,stride; - unsigned char *pixels; -} stbtt__bitmap; - -extern void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata); - -////////////////////////////////////////////////////////////////////////////// -// -// Finding the right font... -// -// You should really just solve this offline, keep your own tables -// of what font is what, and don't try to get it out of the .ttf file. -// That's because getting it out of the .ttf file is really hard, because -// the names in the file can appear in many possible encodings, in many -// possible languages, and e.g. if you need a case-insensitive comparison, -// the details of that depend on the encoding & language in a complex way -// (actually underspecified in truetype, but also gigantic). -// -// But you can use the provided functions in two possible ways: -// stbtt_FindMatchingFont() will use *case-sensitive* comparisons on -// unicode-encoded names to try to find the font you want; -// you can run this before calling stbtt_InitFont() -// -// stbtt_GetFontNameString() lets you get any of the various strings -// from the file yourself and do your own comparisons on them. -// You have to have called stbtt_InitFont() first. - - -extern int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags); -// returns the offset (not index) of the font that matches, or -1 if none -// if you use STBTT_MACSTYLE_DONTCARE, use a font name like "Arial Bold". -// if you use any other flag, use a font name like "Arial"; this checks -// the 'macStyle' header field; i don't know if fonts set this consistently -#define STBTT_MACSTYLE_DONTCARE 0 -#define STBTT_MACSTYLE_BOLD 1 -#define STBTT_MACSTYLE_ITALIC 2 -#define STBTT_MACSTYLE_UNDERSCORE 4 -#define STBTT_MACSTYLE_NONE 8 // <= not same as 0, this makes us check the bitfield is 0 - -extern int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2); -// returns 1/0 whether the first string interpreted as utf8 is identical to -// the second string interpreted as big-endian utf16... useful for strings from next func - -extern char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID); -// returns the string (which may be big-endian double byte, e.g. for unicode) -// and puts the length in bytes in *length. -// -// some of the values for the IDs are below; for more see the truetype spec: -// http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html -// http://www.microsoft.com/typography/otspec/name.htm - -enum { // platformID - STBTT_PLATFORM_ID_UNICODE =0, - STBTT_PLATFORM_ID_MAC =1, - STBTT_PLATFORM_ID_ISO =2, - STBTT_PLATFORM_ID_MICROSOFT =3 -}; - -enum { // encodingID for STBTT_PLATFORM_ID_UNICODE - STBTT_UNICODE_EID_UNICODE_1_0 =0, - STBTT_UNICODE_EID_UNICODE_1_1 =1, - STBTT_UNICODE_EID_ISO_10646 =2, - STBTT_UNICODE_EID_UNICODE_2_0_BMP=3, - STBTT_UNICODE_EID_UNICODE_2_0_FULL=4, -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT - STBTT_MS_EID_SYMBOL =0, - STBTT_MS_EID_UNICODE_BMP =1, - STBTT_MS_EID_SHIFTJIS =2, - STBTT_MS_EID_UNICODE_FULL =10, -}; - -enum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes - STBTT_MAC_EID_ROMAN =0, STBTT_MAC_EID_ARABIC =4, - STBTT_MAC_EID_JAPANESE =1, STBTT_MAC_EID_HEBREW =5, - STBTT_MAC_EID_CHINESE_TRAD =2, STBTT_MAC_EID_GREEK =6, - STBTT_MAC_EID_KOREAN =3, STBTT_MAC_EID_RUSSIAN =7, -}; - -enum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... - // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs - STBTT_MS_LANG_ENGLISH =0x0409, STBTT_MS_LANG_ITALIAN =0x0410, - STBTT_MS_LANG_CHINESE =0x0804, STBTT_MS_LANG_JAPANESE =0x0411, - STBTT_MS_LANG_DUTCH =0x0413, STBTT_MS_LANG_KOREAN =0x0412, - STBTT_MS_LANG_FRENCH =0x040c, STBTT_MS_LANG_RUSSIAN =0x0419, - STBTT_MS_LANG_GERMAN =0x0407, STBTT_MS_LANG_SPANISH =0x0409, - STBTT_MS_LANG_HEBREW =0x040d, STBTT_MS_LANG_SWEDISH =0x041D, -}; - -enum { // languageID for STBTT_PLATFORM_ID_MAC - STBTT_MAC_LANG_ENGLISH =0 , STBTT_MAC_LANG_JAPANESE =11, - STBTT_MAC_LANG_ARABIC =12, STBTT_MAC_LANG_KOREAN =23, - STBTT_MAC_LANG_DUTCH =4 , STBTT_MAC_LANG_RUSSIAN =32, - STBTT_MAC_LANG_FRENCH =1 , STBTT_MAC_LANG_SPANISH =6 , - STBTT_MAC_LANG_GERMAN =2 , STBTT_MAC_LANG_SWEDISH =5 , - STBTT_MAC_LANG_HEBREW =10, STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33, - STBTT_MAC_LANG_ITALIAN =3 , STBTT_MAC_LANG_CHINESE_TRAD =19, -}; - -#ifdef __cplusplus -} -#endif - -#endif // __STB_INCLUDE_STB_TRUETYPE_H__ - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -//// -//// IMPLEMENTATION -//// -//// - -#ifdef STB_TRUETYPE_IMPLEMENTATION - -////////////////////////////////////////////////////////////////////////// -// -// accessors to parse data from file -// - -// on platforms that don't allow misaligned reads, if we want to allow -// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE - -#define ttBYTE(p) (* (stbtt_uint8 *) (p)) -#define ttCHAR(p) (* (stbtt_int8 *) (p)) -#define ttFixed(p) ttLONG(p) - -#if defined(STB_TRUETYPE_BIGENDIAN) && !defined(ALLOW_UNALIGNED_TRUETYPE) - - #define ttUSHORT(p) (* (stbtt_uint16 *) (p)) - #define ttSHORT(p) (* (stbtt_int16 *) (p)) - #define ttULONG(p) (* (stbtt_uint32 *) (p)) - #define ttLONG(p) (* (stbtt_int32 *) (p)) - -#else - - stbtt_uint16 ttUSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; } - stbtt_int16 ttSHORT(const stbtt_uint8 *p) { return p[0]*256 + p[1]; } - stbtt_uint32 ttULONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - stbtt_int32 ttLONG(const stbtt_uint8 *p) { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; } - -#endif - -#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3)) -#define stbtt_tag(p,str) stbtt_tag4(p,str[0],str[1],str[2],str[3]) - -static int stbtt__isfont(const stbtt_uint8 *font) -{ - // check the version number - if (stbtt_tag(font, "1")) return 1; // TrueType 1 - if (stbtt_tag(font, "typ1")) return 1; // TrueType with type 1 font -- we don't support this! - if (stbtt_tag(font, "OTTO")) return 1; // OpenType with CFF - if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0 - return 0; -} - -// @OPTIMIZE: binary search -static stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, char *tag) -{ - stbtt_int32 num_tables = ttUSHORT(data+fontstart+4); - stbtt_uint32 tabledir = fontstart + 12; - stbtt_int32 i; - for (i=0; i < num_tables; ++i) { - stbtt_uint32 loc = tabledir + 16*i; - if (stbtt_tag(data+loc+0, tag)) - return ttULONG(data+loc+8); - } - return 0; -} - -int stbtt_GetFontOffsetForIndex(const unsigned char *font_collection, int index) -{ - // if it's just a font, there's only one valid index - if (stbtt__isfont(font_collection)) - return index == 0 ? 0 : -1; - - // check if it's a TTC - if (stbtt_tag(font_collection, "ttcf")) { - // version 1? - if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) { - stbtt_int32 n = ttLONG(font_collection+8); - if (index >= n) - return -1; - return ttULONG(font_collection+12+index*14); - } - } - return -1; -} - -int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data2, int fontstart) -{ - stbtt_uint8 *data = (stbtt_uint8 *) data2; - stbtt_uint32 cmap, t; - stbtt_int32 i,numTables; - - info->data = data; - info->fontstart = fontstart; - - cmap = stbtt__find_table(data, fontstart, "cmap"); - info->loca = stbtt__find_table(data, fontstart, "loca"); - info->head = stbtt__find_table(data, fontstart, "head"); - info->glyf = stbtt__find_table(data, fontstart, "glyf"); - info->hhea = stbtt__find_table(data, fontstart, "hhea"); - info->hmtx = stbtt__find_table(data, fontstart, "hmtx"); - if (!cmap || !info->loca || !info->head || !info->glyf || !info->hhea || !info->hmtx) - return 0; - - t = stbtt__find_table(data, fontstart, "maxp"); - if (t) - info->numGlyphs = ttUSHORT(data+t+4); - else - info->numGlyphs = 0xffff; - - // find a cmap encoding table we understand *now* to avoid searching - // later. (todo: could make this installable) - // the same regardless of glyph. - numTables = ttUSHORT(data + cmap + 2); - info->index_map = 0; - for (i=0; i < numTables; ++i) { - stbtt_uint32 encoding_record = cmap + 4 + 8 * i; - // find an encoding we understand: - switch(ttUSHORT(data+encoding_record)) { - case STBTT_PLATFORM_ID_MICROSOFT: - switch (ttUSHORT(data+encoding_record+2)) { - case STBTT_MS_EID_UNICODE_BMP: - case STBTT_MS_EID_UNICODE_FULL: - // MS/Unicode - info->index_map = cmap + ttULONG(data+encoding_record+4); - break; - } - break; - } - } - if (info->index_map == 0) - return 0; - - info->indexToLocFormat = ttUSHORT(data+info->head + 50); - return 1; -} - -int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint) -{ - stbtt_uint8 *data = info->data; - stbtt_uint32 index_map = info->index_map; - - stbtt_uint16 format = ttUSHORT(data + index_map + 0); - if (format == 0) { // apple byte encoding - stbtt_int32 bytes = ttUSHORT(data + index_map + 2); - if (unicode_codepoint < bytes-6) - return ttBYTE(data + index_map + 6 + unicode_codepoint); - return 0; - } else if (format == 6) { - stbtt_uint32 first = ttUSHORT(data + index_map + 6); - stbtt_uint32 count = ttUSHORT(data + index_map + 8); - if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count) - return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2); - return 0; - } else if (format == 2) { - STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean - return 0; - } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges - stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1; - stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1; - stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10); - stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1; - stbtt_uint16 item, offset, start, end; - - // do a binary search of the segments - stbtt_uint32 endCount = index_map + 14; - stbtt_uint32 search = endCount; - - if (unicode_codepoint > 0xffff) - return 0; - - // they lie from endCount .. endCount + segCount - // but searchRange is the nearest power of two, so... - if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2)) - search += rangeShift*2; - - // now decrement to bias correctly to find smallest - search -= 2; - while (entrySelector) { - stbtt_uint16 start, end; - searchRange >>= 1; - start = ttUSHORT(data + search + 2 + segcount*2 + 2); - end = ttUSHORT(data + search + 2); - start = ttUSHORT(data + search + searchRange*2 + segcount*2 + 2); - end = ttUSHORT(data + search + searchRange*2); - if (unicode_codepoint > end) - search += searchRange*2; - --entrySelector; - } - search += 2; - - item = (stbtt_uint16) ((search - endCount) >> 1); - - STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item)); - start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item); - end = ttUSHORT(data + index_map + 14 + 2 + 2*item); - if (unicode_codepoint < start) - return 0; - - offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item); - if (offset == 0) - return unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item); - - return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item); - } else if (format == 12) { - stbtt_uint16 ngroups = ttUSHORT(data+index_map+6); - stbtt_int32 low,high; - stbtt_uint16 g = 0; - low = 0; high = (stbtt_int32)ngroups; - // Binary search the right group. - while (low <= high) { - stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high - stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12); - stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4); - if ((stbtt_uint32) unicode_codepoint < start_char) - high = mid-1; - else if ((stbtt_uint32) unicode_codepoint > end_char) - low = mid+1; - else { - stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8); - return start_glyph + unicode_codepoint-start_char; - } - } - return 0; // not found - } - // @TODO - STBTT_assert(0); - return 0; -} - -int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices) -{ - return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices); -} - -static void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int16 x, stbtt_int16 y, stbtt_int16 cx, stbtt_int16 cy) -{ - v->type = type; - v->x = x; - v->y = y; - v->cx = cx; - v->cy = cy; -} - -static int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index) -{ - int g1,g2; - - if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range - if (info->indexToLocFormat >= 2) return -1; // unknown index->glyph map format - - if (info->indexToLocFormat == 0) { - g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2; - g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2; - } else { - g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4); - g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4); - } - - return g1==g2 ? -1 : g1; // if length is 0, return -1 -} - -int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1) -{ - int g = stbtt__GetGlyfOffset(info, glyph_index); - if (g < 0) return 0; - - if (x0) *x0 = ttSHORT(info->data + g + 2); - if (y0) *y0 = ttSHORT(info->data + g + 4); - if (x1) *x1 = ttSHORT(info->data + g + 6); - if (y1) *y1 = ttSHORT(info->data + g + 8); - return 1; -} - -int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1) -{ - return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1); -} - -int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices) -{ - stbtt_int16 numberOfContours; - stbtt_uint8 *endPtsOfContours; - stbtt_uint8 *data = info->data; - stbtt_vertex *vertices=0; - int num_vertices=0; - int g = stbtt__GetGlyfOffset(info, glyph_index); - - *pvertices = NULL; - - if (g < 0) return 0; - - numberOfContours = ttSHORT(data + g); - - if (numberOfContours > 0) { - stbtt_uint8 flags=0,flagcount; - stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off; - stbtt_int16 x,y,cx,cy,sx,sy; - stbtt_uint8 *points; - endPtsOfContours = (data + g + 10); - ins = ttUSHORT(data + g + 10 + numberOfContours * 2); - points = data + g + 10 + numberOfContours * 2 + 2 + ins; - - n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2); - - m = n + numberOfContours; // a loose bound on how many vertices we might need - vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata); - if (vertices == 0) - return 0; - - next_move = 0; - flagcount=0; - - // in first pass, we load uninterpreted data into the allocated array - // above, shifted to the end of the array so we won't overwrite it when - // we create our final data starting from the front - - off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated - - // first load flags - - for (i=0; i < n; ++i) { - if (flagcount == 0) { - flags = *points++; - if (flags & 8) - flagcount = *points++; - } else - --flagcount; - vertices[off+i].type = flags; - } - - // now load x coordinates - x=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 2) { - stbtt_int16 dx = *points++; - x += (flags & 16) ? dx : -dx; // ??? - } else { - if (!(flags & 16)) { - x = x + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].x = x; - } - - // now load y coordinates - y=0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - if (flags & 4) { - stbtt_int16 dy = *points++; - y += (flags & 32) ? dy : -dy; // ??? - } else { - if (!(flags & 32)) { - y = y + (stbtt_int16) (points[0]*256 + points[1]); - points += 2; - } - } - vertices[off+i].y = y; - } - - // now convert them to our format - num_vertices=0; - sx = sy = cx = cy = 0; - for (i=0; i < n; ++i) { - flags = vertices[off+i].type; - x = (stbtt_int16) vertices[off+i].x; - y = (stbtt_int16) vertices[off+i].y; - if (next_move == i) { - // when we get to the end, we have to close the shape explicitly - if (i != 0) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - - // now start the new one - stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,x,y,0,0); - next_move = 1 + ttUSHORT(endPtsOfContours+j*2); - ++j; - was_off = 0; - sx = x; - sy = y; - } else { - if (!(flags & 1)) { // if it's a curve - if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy); - cx = x; - cy = y; - was_off = 1; - } else { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0); - was_off = 0; - } - } - } - if (i != 0) { - if (was_off) - stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy); - else - stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0); - } - } else if (numberOfContours == -1) { - // Compound shapes. - int more = 1; - stbtt_uint8 *comp = data + g + 10; - num_vertices = 0; - vertices = 0; - while (more) { - stbtt_uint16 flags, gidx; - int comp_num_verts = 0, i; - stbtt_vertex *comp_verts = 0, *tmp = 0; - float mtx[6] = {1,0,0,1,0,0}, m, n; - - flags = ttSHORT(comp); comp+=2; - gidx = ttSHORT(comp); comp+=2; - - if (flags & 2) { // XY values - if (flags & 1) { // shorts - mtx[4] = ttSHORT(comp); comp+=2; - mtx[5] = ttSHORT(comp); comp+=2; - } else { - mtx[4] = ttCHAR(comp); comp+=1; - mtx[5] = ttCHAR(comp); comp+=1; - } - } - else { - // @TODO handle matching point - STBTT_assert(0); - } - if (flags & (1<<3)) { // WE_HAVE_A_SCALE - mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = mtx[2] = 0; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO - mtx[0] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[1] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[2] = ttSHORT(comp)/16384.0f; comp+=2; - mtx[3] = ttSHORT(comp)/16384.0f; comp+=2; - } - - // Find transformation scales. - m = (float) sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]); - n = (float) sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]); - - // Get indexed glyph. - comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts); - if (comp_num_verts > 0) { - // Transform vertices. - for (i = 0; i < comp_num_verts; ++i) { - stbtt_vertex* v = &comp_verts[i]; - stbtt_vertex_type x,y; - x=v->x; y=v->y; - v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - x=v->cx; y=v->cy; - v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4])); - v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5])); - } - // Append vertices. - tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata); - if (!tmp) { - if (vertices) STBTT_free(vertices, info->userdata); - if (comp_verts) STBTT_free(comp_verts, info->userdata); - return 0; - } - if (num_vertices > 0) memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex)); - memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex)); - if (vertices) STBTT_free(vertices, info->userdata); - vertices = tmp; - STBTT_free(comp_verts, info->userdata); - num_vertices += comp_num_verts; - } - // More components ? - more = flags & (1<<5); - } - } else if (numberOfContours < 0) { - // @TODO other compound variations? - STBTT_assert(0); - } else { - // numberOfCounters == 0, do nothing - } - - *pvertices = vertices; - return num_vertices; -} - -void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing) -{ - stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34); - if (glyph_index < numOfLongHorMetrics) { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*glyph_index); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2); - } else { - if (advanceWidth) *advanceWidth = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1)); - if (leftSideBearing) *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics)); - } -} - -int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2) -{ - return 0; -} - -int stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2) -{ - return 0; -} - -void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing) -{ - stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing); -} - -void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap) -{ - if (ascent ) *ascent = ttSHORT(info->data+info->hhea + 4); - if (descent) *descent = ttSHORT(info->data+info->hhea + 6); - if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8); -} - -float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height) -{ - int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6); - return (float) height / fheight; -} - -void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v) -{ - STBTT_free(v, info->userdata); -} - -////////////////////////////////////////////////////////////////////////////// -// -// antialiasing software rasterizer -// - -void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - int x0,y0,x1,y1; - if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) - x0=y0=x1=y1=0; // e.g. space character - // now move to integral bboxes (treating pixels as little squares, what pixels get touched)? - if (ix0) *ix0 = STBTT_ifloor(x0 * scale_x); - if (iy0) *iy0 = -STBTT_iceil (y1 * scale_y); - if (ix1) *ix1 = STBTT_iceil (x1 * scale_x); - if (iy1) *iy1 = -STBTT_ifloor(y0 * scale_y); -} - -void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1) -{ - stbtt_GetGlyphBitmapBox(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y, ix0,iy0,ix1,iy1); -} - -typedef struct stbtt__edge { - float x0,y0, x1,y1; - int invert; -} stbtt__edge; - -typedef struct stbtt__active_edge -{ - int x,dx; - float ey; - struct stbtt__active_edge *next; - int valid; -} stbtt__active_edge; - -#define FIXSHIFT 10 -#define FIX (1 << FIXSHIFT) -#define FIXMASK (FIX-1) - -static stbtt__active_edge *new_active(stbtt__edge *e, int off_x, float start_point, void *userdata) -{ - stbtt__active_edge *z = (stbtt__active_edge *) STBTT_malloc(sizeof(*z), userdata); // @TODO: make a pool of these!!! - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); - STBTT_assert(e->y0 <= start_point); - if (!z) return z; - // round dx down to avoid going too far - if (dxdy < 0) - z->dx = -STBTT_ifloor(FIX * -dxdy); - else - z->dx = STBTT_ifloor(FIX * dxdy); - z->x = STBTT_ifloor(FIX * (e->x0 + dxdy * (start_point - e->y0))); - z->x -= off_x * FIX; - z->ey = e->y1; - z->next = 0; - z->valid = e->invert ? 1 : -1; - return z; -} - -// note: this routine clips fills that extend off the edges... ideally this -// wouldn't happen, but it could happen if the truetype glyph bounding boxes -// are wrong, or if the user supplies a too-small bitmap -static void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight) -{ - // non-zero winding fill - int x0=0, w=0; - - while (e) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->valid; - } else { - int x1 = e->x; w += e->valid; - // if we went to zero, we need to draw - if (w == 0) { - int i = x0 >> FIXSHIFT; - int j = x1 >> FIXSHIFT; - - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] = scanline[i] + (stbtt_uint8) (((FIX - (x0 & FIXMASK)) * max_weight) >> FIXSHIFT); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & FIXMASK) * max_weight) >> FIXSHIFT); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] = scanline[i] + (stbtt_uint8) max_weight; - } - } - } - } - - e = e->next; - } -} - -static void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata) -{ - stbtt__active_edge *active = NULL; - int y,j=0; - int max_weight = (255 / vsubsample); // weight per vertical scanline - int s; // vertical subsample index - unsigned char scanline_data[512], *scanline; - - if (result->w > 512) - scanline = (unsigned char *) STBTT_malloc(result->w, userdata); - else - scanline = scanline_data; - - y = off_y * vsubsample; - e[n].y0 = (off_y + result->h) * (float) vsubsample + 1; - - while (j < result->h) { - STBTT_memset(scanline, 0, result->w); - for (s=0; s < vsubsample; ++s) { - // find center of pixel for this scanline - float scan_y = y + 0.5f; - stbtt__active_edge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - stbtt__active_edge * z = *step; - if (z->ey <= scan_y) { - *step = z->next; // delete from list - STBTT_assert(z->valid); - z->valid = 0; - STBTT_free(z, userdata); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for(;;) { - int changed=0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - stbtt__active_edge *t = *step; - stbtt__active_edge *q = t->next; - - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e->y0 <= scan_y) { - if (e->y1 > scan_y) { - stbtt__active_edge *z = new_active(e, off_x, scan_y, userdata); - // find insertion point - if (active == NULL) - active = z; - else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - stbtt__active_edge *p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - ++e; - } - - // now process all active edges in XOR fashion - if (active) - stbtt__fill_active_edges(scanline, result->w, active, max_weight); - - ++y; - } - STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w); - ++j; - } - - while (active) { - stbtt__active_edge *z = active; - active = active->next; - STBTT_free(z, userdata); - } - - if (scanline != scanline_data) - STBTT_free(scanline, userdata); -} - -static int stbtt__edge_compare(const void *p, const void *q) -{ - stbtt__edge *a = (stbtt__edge *) p; - stbtt__edge *b = (stbtt__edge *) q; - - if (a->y0 < b->y0) return -1; - if (a->y0 > b->y0) return 1; - return 0; -} - -typedef struct -{ - float x,y; -} stbtt__point; - -static void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, int off_x, int off_y, int invert, void *userdata) -{ - float y_scale_inv = invert ? -scale_y : scale_y; - stbtt__edge *e; - int n,i,j,k,m; - int vsubsample = result->h < 8 ? 15 : 5; - // vsubsample should divide 255 evenly; otherwise we won't reach full opacity - - // now we have to blow out the windings into explicit edge lists - n = 0; - for (i=0; i < windings; ++i) - n += wcount[i]; - - e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel - if (e == 0) return; - n = 0; - - m=0; - for (i=0; i < windings; ++i) { - stbtt__point *p = pts + m; - m += wcount[i]; - j = wcount[i]-1; - for (k=0; k < wcount[i]; j=k++) { - int a=k,b=j; - // skip the edge if horizontal - if (p[j].y == p[k].y) - continue; - // add edge from j to k to the list - e[n].invert = 0; - if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) { - e[n].invert = 1; - a=j,b=k; - } - e[n].x0 = p[a].x * scale_x; - e[n].y0 = p[a].y * y_scale_inv * vsubsample; - e[n].x1 = p[b].x * scale_x; - e[n].y1 = p[b].y * y_scale_inv * vsubsample; - ++n; - } - } - - // now sort the edges by their highest point (should snap to integer, and then by x) - STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); - - // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule - stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata); - - STBTT_free(e, userdata); -} - -static void stbtt__add_point(stbtt__point *points, int n, float x, float y) -{ - if (!points) return; // during first pass, it's unallocated - points[n].x = x; - points[n].y = y; -} - -// tesselate until threshhold p is happy... @TODO warped to compensate for non-linear stretching -static int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n) -{ - // midpoint - float mx = (x0 + 2*x1 + x2)/4; - float my = (y0 + 2*y1 + y2)/4; - // versus directly drawn line - float dx = (x0+x2)/2 - mx; - float dy = (y0+y2)/2 - my; - if (n > 16) // 65536 segments on one curve better be enough! - return 1; - if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA - stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1); - stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1); - } else { - stbtt__add_point(points, *num_points,x2,y2); - *num_points = *num_points+1; - } - return 1; -} - -// returns number of contours -stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata) -{ - stbtt__point *points=0; - int num_points=0; - - float objspace_flatness_squared = objspace_flatness * objspace_flatness; - int i,n=0,start=0, pass; - - // count how many "moves" there are to get the contour count - for (i=0; i < num_verts; ++i) - if (vertices[i].type == STBTT_vmove) - ++n; - - *num_contours = n; - if (n == 0) return 0; - - *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata); - - if (*contour_lengths == 0) { - *num_contours = 0; - return 0; - } - - // make two passes through the points so we don't need to realloc - for (pass=0; pass < 2; ++pass) { - float x=0,y=0; - if (pass == 1) { - points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata); - if (points == NULL) goto error; - } - num_points = 0; - n= -1; - for (i=0; i < num_verts; ++i) { - switch (vertices[i].type) { - case STBTT_vmove: - // start the next contour - if (n >= 0) - (*contour_lengths)[n] = num_points - start; - ++n; - start = num_points; - - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x,y); - break; - case STBTT_vline: - x = vertices[i].x, y = vertices[i].y; - stbtt__add_point(points, num_points++, x, y); - break; - case STBTT_vcurve: - stbtt__tesselate_curve(points, &num_points, x,y, - vertices[i].cx, vertices[i].cy, - vertices[i].x, vertices[i].y, - objspace_flatness_squared, 0); - x = vertices[i].x, y = vertices[i].y; - break; - } - } - (*contour_lengths)[n] = num_points - start; - } - - return points; -error: - STBTT_free(points, userdata); - STBTT_free(*contour_lengths, userdata); - *contour_lengths = 0; - *num_contours = 0; - return NULL; -} - -void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, int x_off, int y_off, int invert, void *userdata) -{ - float scale = scale_x > scale_y ? scale_y : scale_x; - int winding_count, *winding_lengths; - stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata); - if (windings) { - stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, x_off, y_off, invert, userdata); - STBTT_free(winding_lengths, userdata); - STBTT_free(windings, userdata); - } -} - -void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata) -{ - STBTT_free(bitmap, userdata); -} - -unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff) -{ - int ix0,iy0,ix1,iy1; - stbtt__bitmap gbm; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - - if (scale_x == 0) scale_x = scale_y; - if (scale_y == 0) { - if (scale_x == 0) return NULL; - scale_y = scale_x; - } - - stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,&ix1,&iy1); - - // now we get the size - gbm.w = (ix1 - ix0); - gbm.h = (iy1 - iy0); - gbm.pixels = NULL; // in case we error - - if (width ) *width = gbm.w; - if (height) *height = gbm.h; - if (xoff ) *xoff = ix0; - if (yoff ) *yoff = iy0; - - if (gbm.w && gbm.h) { - gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata); - if (gbm.pixels) { - gbm.stride = gbm.w; - - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0, iy0, 1, info->userdata); - } - } - STBTT_free(vertices, info->userdata); - return gbm.pixels; -} - -void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph) -{ - int ix0,iy0; - stbtt_vertex *vertices; - int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices); - stbtt__bitmap gbm; - - stbtt_GetGlyphBitmapBox(info, glyph, scale_x, scale_y, &ix0,&iy0,0,0); - gbm.pixels = output; - gbm.w = out_w; - gbm.h = out_h; - gbm.stride = out_stride; - - if (gbm.w && gbm.h) - stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, ix0,iy0, 1, info->userdata); - - STBTT_free(vertices, info->userdata); -} - -unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff) -{ - return stbtt_GetGlyphBitmap(info, scale_x, scale_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff); -} - -void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint) -{ - stbtt_MakeGlyphBitmap(info, output, out_w, out_h, out_stride, scale_x, scale_y, stbtt_FindGlyphIndex(info,codepoint)); -} - -////////////////////////////////////////////////////////////////////////////// -// -// bitmap baking -// -// This is SUPER-SHITTY packing to keep source code small - -extern int stbtt_BakeFontBitmap(const unsigned char *data, int offset, // font location (use offset=0 for plain .ttf) - float pixel_height, // height of font in pixels - unsigned char *pixels, int pw, int ph, // bitmap to be filled in - int first_char, int num_chars, // characters to bake - stbtt_bakedchar *chardata) -{ - float scale; - int x,y,bottom_y, i; - stbtt_fontinfo f; - stbtt_InitFont(&f, data, offset); - STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels - x=y=1; - bottom_y = 1; - - scale = stbtt_ScaleForPixelHeight(&f, pixel_height); - - for (i=0; i < num_chars; ++i) { - int advance, lsb, x0,y0,x1,y1,gw,gh; - int g = stbtt_FindGlyphIndex(&f, first_char + i); - stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb); - stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1); - gw = x1-x0; - gh = y1-y0; - if (x + gw + 1 >= pw) - y = bottom_y, x = 1; // advance to next row - if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row - return -i; - STBTT_assert(x+gw < pw); - STBTT_assert(y+gh < ph); - stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g); - chardata[i].x0 = (stbtt_int16) x; - chardata[i].y0 = (stbtt_int16) y; - chardata[i].x1 = (stbtt_int16) (x + gw); - chardata[i].y1 = (stbtt_int16) (y + gh); - chardata[i].xadvance = scale * advance; - chardata[i].xoff = (float) x0; - chardata[i].yoff = (float) y0; - x = x + gw + 2; - if (y+gh+2 > bottom_y) - bottom_y = y+gh+2; - } - return bottom_y; -} - -void stbtt_GetBakedQuad(stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule) -{ - float d3d_bias = opengl_fillrule ? 0 : -0.5f; - float ipw = 1.0f / pw, iph = 1.0f / ph; - stbtt_bakedchar *b = chardata + char_index; - int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5); - int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5); - - q->x0 = round_x + d3d_bias; - q->y0 = round_y + d3d_bias; - q->x1 = round_x + b->x1 - b->x0 + d3d_bias; - q->y1 = round_y + b->y1 - b->y0 + d3d_bias; - - q->s0 = b->x0 * ipw; - q->t0 = b->y0 * ipw; - q->s1 = b->x1 * iph; - q->t1 = b->y1 * iph; - - *xpos += b->xadvance; -} - -////////////////////////////////////////////////////////////////////////////// -// -// font name matching -- recommended not to use this -// - -// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string -static stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2) -{ - stbtt_int32 i=0; - - // convert utf16 to utf8 and compare the results while converting - while (len2) { - stbtt_uint16 ch = s2[0]*256 + s2[1]; - if (ch < 0x80) { - if (i >= len1) return -1; - if (s1[i++] != ch) return -1; - } else if (ch < 0x800) { - if (i+1 >= len1) return -1; - if (s1[i++] != 0xc0 + (ch >> 6)) return -1; - if (s1[i++] != 0x80 + (ch & 0x3f)) return -1; - } else if (ch >= 0xd800 && ch < 0xdc00) { - stbtt_uint32 c; - stbtt_uint16 ch2 = s2[2]*256 + s2[3]; - if (i+3 >= len1) return -1; - c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000; - if (s1[i++] != 0xf0 + (c >> 18)) return -1; - if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((c ) & 0x3f)) return -1; - s2 += 2; // plus another 2 below - len2 -= 2; - } else if (ch >= 0xdc00 && ch < 0xe000) { - return -1; - } else { - if (i+2 >= len1) return -1; - if (s1[i++] != 0xe0 + (ch >> 12)) return -1; - if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1; - if (s1[i++] != 0x80 + ((ch ) & 0x3f)) return -1; - } - s2 += 2; - len2 -= 2; - } - return i; -} - -int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2) -{ - return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2); -} - -// returns results in whatever encoding you request... but note that 2-byte encodings -// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare -char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID) -{ - stbtt_int32 i,count,stringOffset; - stbtt_uint8 *fc = font->data; - stbtt_uint32 offset = font->fontstart; - stbtt_uint32 nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return NULL; - - count = ttUSHORT(fc+nm+2); - stringOffset = nm + ttUSHORT(fc+nm+4); - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2) - && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) { - *length = ttUSHORT(fc+loc+8); - return (char *) (fc+stringOffset+ttUSHORT(fc+loc+10)); - } - } - return NULL; -} - -static int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id) -{ - stbtt_int32 i; - stbtt_int32 count = ttUSHORT(fc+nm+2); - stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4); - - for (i=0; i < count; ++i) { - stbtt_uint32 loc = nm + 6 + 12 * i; - stbtt_int32 id = ttUSHORT(fc+loc+6); - if (id == target_id) { - // find the encoding - stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4); - - // is this a Unicode encoding? - if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) { - stbtt_int32 slen = ttUSHORT(fc+loc+8), off = ttUSHORT(fc+loc+10); - - // check if there's a prefix match - stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen); - if (matchlen >= 0) { - // check for target_id+1 immediately following, with same encoding & language - if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) { - stbtt_int32 slen = ttUSHORT(fc+loc+12+8), off = ttUSHORT(fc+loc+12+10); - if (slen == 0) { - if (matchlen == nlen) - return 1; - } else if (matchlen < nlen && name[matchlen] == ' ') { - ++matchlen; - if (stbtt_CompareUTF8toUTF16_bigendian((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen)) - return 1; - } - } else { - // if nothing immediately following - if (matchlen == nlen) - return 1; - } - } - } - - // @TODO handle other encodings - } - } - return 0; -} - -static int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags) -{ - stbtt_int32 nlen = STBTT_strlen((char *) name); - stbtt_uint32 nm,hd; - if (!stbtt__isfont(fc+offset)) return 0; - - // check italics/bold/underline flags in macStyle... - if (flags) { - hd = stbtt__find_table(fc, offset, "head"); - if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0; - } - - nm = stbtt__find_table(fc, offset, "name"); - if (!nm) return 0; - - if (flags) { - // if we checked the macStyle flags, then just check the family and ignore the subfamily - if (stbtt__matchpair(fc, nm, name, nlen, 16, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, -1)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } else { - if (stbtt__matchpair(fc, nm, name, nlen, 16, 17)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 1, 2)) return 1; - if (stbtt__matchpair(fc, nm, name, nlen, 3, -1)) return 1; - } - - return 0; -} - -int stbtt_FindMatchingFont(const unsigned char *font_collection, const char *name_utf8, stbtt_int32 flags) -{ - stbtt_int32 i; - for (i=0;;++i) { - stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i); - if (off < 0) return off; - if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags)) - return off; - } -} - -#endif // STB_TRUETYPE_IMPLEMENTATION diff --git a/src/SFML/Network/SocketUDP.cpp b/src/SFML/Network/SocketUDP.cpp index cda58288..ee99ac30 100644 --- a/src/SFML/Network/SocketUDP.cpp +++ b/src/SFML/Network/SocketUDP.cpp @@ -244,10 +244,6 @@ Socket::Status SocketUDP::Send(Packet& packet, const IPAddress& address, unsigne //////////////////////////////////////////////////////////// Socket::Status SocketUDP::Receive(Packet& packet, IPAddress& address, unsigned short& port) { - // This is not safe at all, as data can be lost, duplicated, or arrive in a different order. - // So if a packet is split into more than one chunk, nobody knows what could happen... - // Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it. - // We start by getting the size of the incoming packet Uint32 packetSize = 0; std::size_t received = 0;