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