1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2017 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 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 */ 24 25 /** 26 * 27 * Fonts can be loaded from a file, from memory or from a custom stream, and 28 * supports the most common types of fonts. See the `loadFromFile` function for 29 * the complete list of supported formats. 30 * 31 * Once it is loaded, a $(U Font) instance provides three types of information 32 * about the font: 33 * $(UL 34 * $(LI Global metrics, such as the line spacing) 35 * $(LI Per-glyph metrics, such as bounding box or kerning) 36 * $(LI Pixel representation of glyphs)) 37 * 38 * $(PARA 39 * Fonts alone are not very useful: they hold the font data but cannot make 40 * anything useful of it. To do so you need to use the $(TEXT_LINK) class, which 41 * is able to properly output text with several options such as character size, 42 * style, color, position, rotation, etc. 43 * This separation allows more flexibility and better performances: indeed a 44 & $(U Font) is a heavy resource, and any operation on it is slow (often too 45 * slow for real-time applications). On the other side, a $(TEXT_LINK) is a 46 * lightweight object which can combine the glyphs data and metrics of a 47 * $(U Font) to display any text on a render target. 48 * Note that it is also possible to bind several $(TEXT_LINK) instances to the 49 * same $(U Font). 50 * 51 * It is important to note that the $(TEXT_LINK) instance doesn't copy the font 52 * that it uses, it only keeps a reference to it. Thus, a $(U Font) must not be 53 * destructed while it is used by a $(TEXT_LINK).) 54 * 55 * Example: 56 * --- 57 * // Declare a new font 58 * auto font = new Font(); 59 * 60 * // Load it from a file 61 * if (!font.loadFromFile("arial.ttf")) 62 * { 63 * // error... 64 * } 65 * 66 * // Create a text which uses our font 67 * auto text1 = new Text(); 68 * text1.setFont(font); 69 * text1.setCharacterSize(30); 70 * text1.setStyle(Text.Style.Regular); 71 * 72 * // Create another text using the same font, but with different parameters 73 * auto text2 = new Text(); 74 * text2.setFont(font); 75 * text2.setCharacterSize(50); 76 * text2.setStyle(Text.Style.Italic); 77 * --- 78 * 79 * $(PARA Apart from loading font files, and passing them to instances of 80 * $(TEXT_LINK), you should normally not have to deal directly with this class. 81 * However, it may be useful to access the font metrics or rasterized glyphs for 82 * advanced usage. 83 * 84 * Note that if the font is a bitmap font, it is not scalable, thus not all 85 * requested sizes will be available to use. This needs to be taken into 86 * consideration when using $(TEXT_LINK). 87 * If you need to display text of a certain size, make sure the corresponding 88 * bitmap font that supports that size is used.) 89 * 90 * See_Also: 91 * $(TEXT_LINK) 92 */ 93 module dsfml.graphics.font; 94 95 import dsfml.graphics.texture; 96 import dsfml.graphics.glyph; 97 import dsfml.system.inputstream; 98 import dsfml.system.err; 99 100 /** 101 * Class for loading and manipulating character fonts. 102 */ 103 class Font 104 { 105 106 /// Holds various information about a font. 107 struct Info 108 { 109 /// The font family. 110 const(char)[] family; 111 } 112 113 package sfFont* sfPtr; 114 private Info m_info; 115 private Texture fontTexture; 116 //keeps an instance of the C++ stream stored if used 117 private fontStream m_stream; 118 119 /** 120 * Default constructor. 121 * 122 * Defines an empty font. 123 */ 124 this() 125 { 126 sfPtr = sfFont_construct(); 127 fontTexture = new Texture(sfFont_getTexturePtr(sfPtr)); 128 } 129 130 package this(sfFont* newFont) 131 { 132 sfPtr = newFont; 133 fontTexture = new Texture(sfFont_getTexturePtr(sfPtr)); 134 } 135 136 /// Destructor. 137 ~this() 138 { 139 import dsfml.system.config; 140 mixin(destructorOutput); 141 sfFont_destroy(sfPtr); 142 } 143 144 /** 145 * Load the font from a file. 146 * 147 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, 148 * X11 PCF, Windows FNT, BDF, PFR and Type 42. Note that this function know 149 * nothing about the standard fonts installed on the user's system, thus you 150 * can't load them directly. 151 * 152 * DSFML cannot preload all the font data in this function, so the file has 153 * to remain accessible until the Font object loads a new font or is 154 * destroyed. 155 * 156 * Params: 157 * filename = Path of the font file to load 158 * 159 * Returns: true if loading succeeded, false if it failed. 160 */ 161 bool loadFromFile(const(char)[] filename) 162 { 163 import dsfml.system..string; 164 165 bool ret = sfFont_loadFromFile(sfPtr, filename.ptr, filename.length); 166 if(!ret) 167 { 168 err.write(dsfml.system..string.toString(sfErr_getOutput())); 169 } 170 171 return ret; 172 } 173 174 /** 175 * Load the font from a file in memory. 176 * 177 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, 178 * X11 PCF, Windows FNT, BDF, PFR and Type 42. 179 * 180 * DSFML cannot preload all the font data in this function, so the buffer 181 * pointed by data has to remain valid until the Font object loads a new 182 * font or is destroyed. 183 * 184 * Params: 185 * data = data holding the font file 186 * 187 * Returns: true if loading succeeded, false if it failed. 188 */ 189 bool loadFromMemory(const(void)[] data) 190 { 191 import dsfml.system..string; 192 193 bool ret = sfFont_loadFromMemory(sfPtr, data.ptr, data.length); 194 if(!ret) 195 { 196 err.write(dsfml.system..string.toString(sfErr_getOutput())); 197 } 198 199 return ret; 200 } 201 202 /** 203 * Load the font from a custom stream. 204 * 205 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, 206 * X11 PCF, Windows FNT, BDF, PFR and Type 42. 207 * 208 * DSFML cannot preload all the font data in this function, so the contents 209 * of stream have to remain valid as long as the font is used. 210 * 211 * Params: 212 * stream = Source stream to read from 213 * 214 * Returns: true if loading succeeded, false if it failed. 215 */ 216 bool loadFromStream(InputStream stream) 217 { 218 import dsfml.system..string; 219 220 m_stream = new fontStream(stream); 221 222 bool ret = sfFont_loadFromStream(sfPtr, m_stream); 223 224 if(!ret) 225 { 226 err.write(dsfml.system..string.toString(sfErr_getOutput())); 227 } 228 229 return ret; 230 } 231 232 ref const(Info) getInfo() 233 { 234 return m_info; 235 } 236 237 /** 238 * Retrieve a glyph of the font. 239 * 240 * Params: 241 * codePoint = Unicode code point of the character ot get 242 * characterSize = Reference character size 243 * bold = Retrieve the bold version or the regular one? 244 * 245 * Returns: The glyph corresponding to codePoint and characterSize. 246 */ 247 Glyph getGlyph(dchar codePoint, uint characterSize, bool bold) const 248 { 249 Glyph temp; 250 251 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); 252 253 return temp; 254 } 255 256 /** 257 * Get the kerning offset of two glyphs. 258 * 259 * The kerning is an extra offset (negative) to apply between two glyphs 260 * when rendering them, to make the pair look more "natural". For example, 261 * the pair "AV" have a special kerning to make them closer than other 262 * characters. Most of the glyphs pairs have a kerning offset of zero, 263 * though. 264 * 265 * Params: 266 * first = Unicode code point of the first character 267 * second = Unicode code point of the second character 268 * characterSize = Reference character size 269 * 270 * Returns: Kerning value for first and second, in pixels. 271 */ 272 float getKerning (dchar first, dchar second, uint characterSize) const 273 { 274 return sfFont_getKerning(sfPtr, cast(uint)first, cast(uint)second, characterSize); 275 } 276 277 /** 278 * Get the line spacing. 279 * 280 * The spacing is the vertical offset to apply between consecutive lines of 281 * text. 282 * 283 * Params: 284 * characterSize = Reference character size 285 * 286 * Returns: Line spacing, in pixels. 287 */ 288 float getLineSpacing (uint characterSize) const 289 { 290 return sfFont_getLineSpacing(sfPtr, characterSize); 291 } 292 293 /** 294 * Get the position of the underline. 295 * 296 * Underline position is the vertical offset to apply between the baseline 297 * and the underline. 298 * 299 * Params: 300 * characterSize = Reference character size 301 * 302 * Returns: Underline position, in pixels. 303 */ 304 float getUnderlinePosition (uint characterSize) const 305 { 306 return sfFont_getUnderlinePosition(sfPtr, characterSize); 307 } 308 309 /** 310 * Get the thickness of the underline. 311 * 312 * Underline thickness is the vertical size of the underline. 313 * 314 * Params: 315 * characterSize = Reference character size 316 * 317 * Returns: Underline thickness, in pixels. 318 */ 319 float getUnderlineThickness (uint characterSize) const 320 { 321 return sfFont_getUnderlineThickness(sfPtr, characterSize); 322 } 323 324 /** 325 * Retrieve the texture containing the loaded glyphs of a certain size. 326 * 327 * The contents of the returned texture changes as more glyphs are 328 * requested, thus it is not very relevant. It is mainly used internally by 329 * Text. 330 * 331 * Params: 332 * characterSize = Reference character size 333 * 334 * Returns: Texture containing the glyphs of the requested size. 335 */ 336 const(Texture) getTexture (uint characterSize) const 337 { 338 //ToDo: cache texture somehow? 339 340 import std.stdio; 341 342 sfFont_updateTexture(sfPtr, characterSize); 343 344 return fontTexture; 345 } 346 347 /** 348 * Performs a deep copy on the font. 349 * 350 * Returns: The duplicated font. 351 */ 352 @property 353 Font dup() const 354 { 355 return new Font(sfFont_copy(sfPtr)); 356 } 357 } 358 359 unittest 360 { 361 version(DSFML_Unittest_Graphics) 362 { 363 import std.stdio; 364 365 import dsfml.graphics.text; 366 367 writeln("Unitest for Font"); 368 369 auto font = new Font(); 370 assert(font.loadFromFile("res/Warenhaus-Standard.ttf")); 371 372 Text text; 373 text = new Text("Sample String", font); 374 375 376 //draw text or something 377 378 writeln(); 379 } 380 } 381 382 383 private: 384 private extern(C++) interface fontInputStream 385 { 386 long read(void* data, long size); 387 388 long seek(long position); 389 390 long tell(); 391 392 long getSize(); 393 } 394 395 396 private class fontStream:fontInputStream 397 { 398 private InputStream myStream; 399 400 this(InputStream stream) 401 { 402 myStream = stream; 403 } 404 405 extern(C++)long read(void* data, long size) 406 { 407 return myStream.read(data[0..cast(size_t)size]); 408 } 409 410 extern(C++)long seek(long position) 411 { 412 return myStream.seek(position); 413 } 414 415 extern(C++)long tell() 416 { 417 return myStream.tell(); 418 } 419 420 extern(C++)long getSize() 421 { 422 return myStream.getSize(); 423 } 424 } 425 426 427 428 package extern(C) struct sfFont; 429 430 private extern(C): 431 432 sfFont* sfFont_construct(); 433 434 //Create a new font from a file 435 bool sfFont_loadFromFile(sfFont* font, const(char)* filename, size_t length); 436 437 438 //Create a new image font a file in memory 439 bool sfFont_loadFromMemory(sfFont* font, const(void)* data, size_t sizeInBytes); 440 441 442 //Create a new image font a custom stream 443 bool sfFont_loadFromStream(sfFont* font, fontInputStream stream); 444 445 446 // Copy an existing font 447 sfFont* sfFont_copy(const sfFont* font); 448 449 450 //Destroy an existing font 451 void sfFont_destroy(sfFont* font); 452 453 454 //Get a glyph in a font 455 void sfFont_getGlyph(const(sfFont)* font, uint codePoint, int characterSize, bool bold, float* glyphAdvance, float* glyphBoundsLeft, float* glyphBoundsTop, float* glyphBoundsWidth, float* glyphBoundsHeight, int* glyphTextRectLeft, int* glyphTextRectTop, int* glyphTextRectWidth, int* glyphTextRectHeight); 456 457 458 //Get the kerning value corresponding to a given pair of characters in a font 459 float sfFont_getKerning(const(sfFont)* font, uint first, uint second, uint characterSize); 460 461 462 //Get the line spacing value 463 float sfFont_getLineSpacing(const(sfFont)* font, uint characterSize); 464 465 //Get the position of the underline 466 float sfFont_getUnderlinePosition (const(sfFont)* font, uint characterSize); 467 468 //Get the thickness of the underline 469 float sfFont_getUnderlineThickness (const(sfFont)* font, uint characterSize); 470 471 472 //Get the texture pointer for a particular font 473 sfTexture* sfFont_getTexturePtr(const(sfFont)* font); 474 475 sfTexture* sfFont_getTexture(const(sfFont)* font, uint characterSize); 476 477 //Update the internal texture associated with the font 478 void sfFont_updateTexture(const(sfFont)* font, uint characterSize); 479 480 const(char)* sfErr_getOutput();