1 /* 2 DSFML - The Simple and Fast Multimedia Library for D 3 4 Copyright (c) 2013 - 2015 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 6 This software is provided 'as-is', without any express or implied warranty. 7 In no event will the authors be held liable for any damages arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, including commercial applications, 10 and to alter it and redistribute it freely, subject to the following restrictions: 11 12 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. 13 If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 14 15 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 16 17 3. This notice may not be removed or altered from any source distribution 18 */ 19 20 module dsfml.graphics.font; 21 22 import dsfml.graphics.texture; 23 import dsfml.graphics.glyph; 24 import dsfml.system.inputstream; 25 import dsfml.system.err; 26 27 /++ 28 + Class for loading and manipulating character fonts. 29 + 30 + Fonts can be loaded from a file, from memory or from a custom stream, and supports the most common types of fonts. 31 + 32 + See the loadFromFile function for the complete list of supported formats. 33 + 34 + Once it is loaded, a Font instance provides three types of information about the font: 35 + - Global metrics, such as the line spacing 36 + - Per-glyph metrics, such as bounding box or kerning 37 + - Pixel representation of glyphs 38 + 39 + Authors: Laurent Gomila, Jeremy DeHaan 40 + See_Also: http://sfml-dev.org/documentation/2.0/classsf_1_1Font.php#details 41 +/ 42 class Font 43 { 44 package sfFont* sfPtr; 45 46 private Texture fontTexture; 47 private fontStream m_stream;//keeps an instance of the C++ stream stored if used 48 49 /// Defines an empty font 50 this() 51 { 52 sfPtr = sfFont_construct(); 53 fontTexture = new Texture(sfFont_getTexturePtr(sfPtr)); 54 } 55 56 package this(sfFont* newFont) 57 { 58 sfPtr = newFont; 59 fontTexture = new Texture(sfFont_getTexturePtr(sfPtr)); 60 } 61 62 ~this() 63 { 64 import dsfml.system.config; 65 mixin(destructorOutput); 66 sfFont_destroy(sfPtr); 67 } 68 69 /** 70 * Load the font from a file. 71 * 72 * 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. 73 * 74 * Params: 75 * filename = Path of the font file to load 76 * 77 * Returns: True if loading succeeded, false if it failed. 78 */ 79 bool loadFromFile(string filename) 80 { 81 import dsfml.system..string; 82 83 bool ret = sfFont_loadFromFile(sfPtr, toStringz(filename)); 84 if(!ret) 85 { 86 err.write(dsfml.system..string.toString(sfErr_getOutput())); 87 } 88 89 return ret; 90 } 91 92 /** 93 * Load the font from a file in memory. 94 * 95 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. Warning: SFML cannot preload all the font data in this function, so the buffer pointed by data has to remain valid as long as the font is used. 96 * 97 * Params: 98 * data = data holding the font file 99 * 100 * Returns: True if loading succeeded, false if it failed. 101 */ 102 bool loadFromMemory(const(void)[] data) 103 { 104 import dsfml.system..string; 105 106 bool ret = sfFont_loadFromMemory(sfPtr, data.ptr, data.length); 107 if(!ret) 108 { 109 err.write(dsfml.system..string.toString(sfErr_getOutput())); 110 } 111 112 return ret; 113 } 114 115 /** 116 * Load the font from a custom stream. 117 * 118 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, X11 PCF, Windows FNT, BDF, PFR and Type 42. Warning: SFML cannot preload all the font data in this function, so the contents of stream have to remain valid as long as the font is used. 119 * 120 * Params: 121 * stream = Source stream to read from 122 * 123 * Returns: True if loading succeeded, false if it failed. 124 */ 125 bool loadFromStream(InputStream stream) 126 { 127 import dsfml.system..string; 128 129 m_stream = new fontStream(stream); 130 131 bool ret = sfFont_loadFromStream(sfPtr, m_stream); 132 133 if(!ret) 134 { 135 err.write(dsfml.system..string.toString(sfErr_getOutput())); 136 } 137 138 return ret; 139 } 140 141 /** 142 * Retrieve a glyph of the font. 143 * 144 * Params: 145 * codePoint = Unicode code point of the character ot get 146 * characterSize = Reference character size 147 * bols = Retrieve the bold version or the regular one? 148 * 149 * Returns: The glyph corresponding to codePoint and characterSize 150 */ 151 Glyph getGlyph(dchar codePoint, uint characterSize, bool bold) const 152 { 153 Glyph temp; 154 155 sfFont_getGlyph(sfPtr, cast(uint)codePoint, characterSize,bold,&temp.advance,&temp.bounds.left,&temp.bounds.top,&temp.bounds.width,&temp.bounds.height,&temp.textureRect.left,&temp.textureRect.top,&temp.textureRect.width,&temp.textureRect.height); 156 157 return temp; 158 } 159 160 /** 161 * Get the kerning offset of two glyphs. 162 * 163 * 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. 164 * 165 * Params: 166 * first = Unicode code point of the first character 167 * second = Unicode code point of the second character 168 * characterSize = Reference character size 169 * 170 * Returns: Kerning value for first and second, in pixels 171 */ 172 int getKerning (dchar first, dchar second, uint characterSize) const 173 { 174 return sfFont_getKerning(sfPtr, cast(uint)first, cast(uint)second, characterSize); 175 } 176 177 /** 178 * Get the line spacing. 179 * 180 * The spacing is the vertical offset to apply between consecutive lines of text. 181 * 182 * Params: 183 * characterSize = Reference character size 184 * 185 * Returns: Line spacing, in pixels 186 */ 187 int getLineSpacing (uint characterSize) const 188 { 189 return sfFont_getLineSpacing(sfPtr, characterSize); 190 } 191 192 /** 193 * Retrieve the texture containing the loaded glyphs of a certain size. 194 * 195 * The contents of the returned texture changes as more glyphs are requested, thus it is not very relevant. It is mainly used internally by Text. 196 * 197 * Params: 198 * characterSize = Reference character size 199 * 200 * Returns: Texture containing the glyphs of the requested size 201 */ 202 const(Texture) getTexture (uint characterSize) const 203 { 204 //ToDo: cache texture somehow? 205 //Possible: cache last size used using sound method(mutable instance storage) 206 207 import std.stdio; 208 209 //writeln("Updating Texture"); 210 211 sfFont_updateTexture(sfPtr, characterSize); 212 213 //fontTexture.sfPtr = sfFont_getTexture(sfPtr, characterSize); 214 215 // writeln("returning texture"); 216 return fontTexture; 217 } 218 219 /** 220 * Performs a deep copy on the font. 221 * 222 * Returns: The duplicated font. 223 */ 224 @property 225 Font dup() const 226 { 227 return new Font(sfFont_copy(sfPtr)); 228 } 229 230 } 231 232 unittest 233 { 234 version(DSFML_Unittest_Graphics) 235 { 236 import std.stdio; 237 238 import dsfml.graphics.text; 239 240 writeln("Unitest for Font"); 241 242 auto font = new Font(); 243 assert(font.loadFromFile("res/Warenhaus-Standard.ttf")); 244 245 Text text; 246 text = new Text("Sample String", font); 247 248 249 //draw text or something 250 251 writeln(); 252 } 253 } 254 255 256 private: 257 private extern(C++) interface fontInputStream 258 { 259 long read(void* data, long size); 260 261 long seek(long position); 262 263 long tell(); 264 265 long getSize(); 266 } 267 268 269 private class fontStream:fontInputStream 270 { 271 private InputStream myStream; 272 273 this(InputStream stream) 274 { 275 myStream = stream; 276 } 277 278 extern(C++)long read(void* data, long size) 279 { 280 return myStream.read(data[0..cast(size_t)size]); 281 } 282 283 extern(C++)long seek(long position) 284 { 285 return myStream.seek(position); 286 } 287 288 extern(C++)long tell() 289 { 290 return myStream.tell(); 291 } 292 293 extern(C++)long getSize() 294 { 295 return myStream.getSize(); 296 } 297 } 298 299 300 301 package extern(C) struct sfFont; 302 303 private extern(C): 304 305 sfFont* sfFont_construct(); 306 307 //Create a new font from a file 308 bool sfFont_loadFromFile(sfFont* font, const(char)* filename); 309 310 311 //Create a new image font a file in memory 312 bool sfFont_loadFromMemory(sfFont* font, const(void)* data, size_t sizeInBytes); 313 314 315 //Create a new image font a custom stream 316 bool sfFont_loadFromStream(sfFont* font, fontInputStream stream); 317 318 319 // Copy an existing font 320 sfFont* sfFont_copy(const sfFont* font); 321 322 323 //Destroy an existing font 324 void sfFont_destroy(sfFont* font); 325 326 327 //Get a glyph in a font 328 void sfFont_getGlyph(const(sfFont)* font, uint codePoint, int characterSize, bool bold, int* glyphAdvance, int* glyphBoundsLeft, int* glyphBoundsTop, int* glyphBoundsWidth, int* glyphBoundsHeight, int* glyphTextRectLeft, int* glyphTextRectTop, int* glyphTextRectWidth, int* glyphTextRectHeight); 329 330 331 //Get the kerning value corresponding to a given pair of characters in a font 332 int sfFont_getKerning(const(sfFont)* font, uint first, uint second, uint characterSize); 333 334 335 //Get the line spacing value 336 int sfFont_getLineSpacing(const(sfFont)* font, uint characterSize); 337 338 339 //Get the texture pointer for a particular font 340 sfTexture* sfFont_getTexturePtr(const(sfFont)* font); 341 342 sfTexture* sfFont_getTexture(const(sfFont)* font, uint characterSize); 343 344 //Update the internal texture associated with the font 345 void sfFont_updateTexture(const(sfFont)* font, uint characterSize); 346 347 348 349 const(char)* sfErr_getOutput();