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 nudsfml.graphics.font; 97 98 import bindbc.sfml.graphics; 99 100 import std.string; 101 102 import nudsfml.graphics.texture; 103 import nudsfml.graphics.glyph; 104 import nudsfml.system.inputstream; 105 //import nudsfml.system.err; 106 107 /** 108 * Class for loading and manipulating character fonts. 109 */ 110 class Font 111 { 112 113 /// Holds various information about a font. 114 struct Info 115 { 116 /// The font family. 117 const(char)[] family; 118 } 119 120 package sfFont* sfPtr; 121 private Info m_info; 122 private Texture[int] textures; 123 124 //keeps an instance of the C++ stream stored if used 125 private fontStream m_stream; 126 127 /** 128 * Default constructor. 129 * 130 * Defines an empty font. 131 */ 132 this() { 133 sfPtr = null;//sfFont_construct(); 134 } 135 136 package this(sfFont* newFont){ 137 sfPtr = newFont; 138 } 139 140 /// Destructor. 141 ~this() { 142 import nudsfml.system.config; 143 mixin(destructorOutput); 144 if(sfPtr != null) { 145 sfFont_destroy(sfPtr); 146 } 147 } 148 149 /** 150 * Load the font from a file. 151 * 152 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, 153 * X11 PCF, Windows FNT, BDF, PFR and Type 42. Note that this function know 154 * nothing about the standard fonts installed on the user's system, thus you 155 * can't load them directly. 156 * 157 * DSFML cannot preload all the font data in this function, so the file has 158 * to remain accessible until the Font object loads a new font or is 159 * destroyed. 160 * 161 * Params: 162 * filename = Path of the font file to load 163 * 164 * Returns: true if loading succeeded, false if it failed. 165 */ 166 bool loadFromFile(const(char)[] filename){ 167 if (sfPtr !is null) { 168 sfFont_destroy(sfPtr); 169 } 170 sfPtr = sfFont_createFromFile(filename.toStringz); 171 return sfPtr !is null; 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 if (sfPtr !is null) { 191 sfFont_destroy(sfPtr); 192 } 193 sfPtr = sfFont_createFromMemory(data.ptr, data.length); 194 return sfPtr !is null; 195 } 196 197 /** 198 * Load the font from a custom stream. 199 * 200 * The supported font formats are: TrueType, Type 1, CFF, OpenType, SFNT, 201 * X11 PCF, Windows FNT, BDF, PFR and Type 42. 202 * 203 * DSFML cannot preload all the font data in this function, so the contents 204 * of stream have to remain valid as long as the font is used. 205 * 206 * Params: 207 * stream = Source stream to read from 208 * 209 * Returns: true if loading succeeded, false if it failed. 210 */ 211 /*bool loadFromStream(InputStream stream) 212 { 213 m_stream = new fontStream(stream); 214 return sfFont_loadFromStream(sfPtr, m_stream); 215 }*/ 216 217 ref const(Info) getInfo() const { 218 return m_info; 219 } 220 221 /** 222 * Retrieve a glyph of the font. 223 * 224 * Params: 225 * codePoint = Unicode code point of the character ot get 226 * characterSize = Reference character size 227 * bold = Retrieve the bold version or the regular one? 228 * outlineThickness = Thickness of outline (when != 0 the glyph will not be filled) 229 * 230 * Returns: The glyph corresponding to codePoint and characterSize. 231 */ 232 Glyph getGlyph(dchar codePoint, uint characterSize, bool bold, float outlineThickness = 0) const{ 233 int b = bold ? 1 : 0; 234 Glyph temp = cast(Glyph)sfFont_getGlyph(sfPtr, cast(uint)codePoint, characterSize, b, outlineThickness);; 235 return temp; 236 } 237 238 /** 239 * Get the kerning offset of two glyphs. 240 * 241 * The kerning is an extra offset (negative) to apply between two glyphs 242 * when rendering them, to make the pair look more "natural". For example, 243 * the pair "AV" have a special kerning to make them closer than other 244 * characters. Most of the glyphs pairs have a kerning offset of zero, 245 * though. 246 * 247 * Params: 248 * first = Unicode code point of the first character 249 * second = Unicode code point of the second character 250 * characterSize = Reference character size 251 * 252 * Returns: Kerning value for first and second, in pixels. 253 */ 254 float getKerning (dchar first, dchar second, uint characterSize) const 255 { 256 sfFont * f = cast(sfFont*)sfPtr; 257 return sfFont_getKerning(f, cast(uint)first, cast(uint)second, characterSize); 258 } 259 260 /** 261 * Get the line spacing. 262 * 263 * The spacing is the vertical offset to apply between consecutive lines of 264 * text. 265 * 266 * Params: 267 * characterSize = Reference character size 268 * 269 * Returns: Line spacing, in pixels. 270 */ 271 float getLineSpacing (uint characterSize) const 272 { 273 sfFont * f = cast(sfFont*)sfPtr; 274 return sfFont_getLineSpacing(f, characterSize); 275 } 276 277 /** 278 * Get the position of the underline. 279 * 280 * Underline position is the vertical offset to apply between the baseline 281 * and the underline. 282 * 283 * Params: 284 * characterSize = Reference character size 285 * 286 * Returns: Underline position, in pixels. 287 */ 288 float getUnderlinePosition (uint characterSize) const 289 { 290 sfFont * f = cast(sfFont*)sfPtr; 291 return sfFont_getUnderlinePosition(f, characterSize); 292 } 293 294 /** 295 * Get the thickness of the underline. 296 * 297 * Underline thickness is the vertical size of the underline. 298 * 299 * Params: 300 * characterSize = Reference character size 301 * 302 * Returns: Underline thickness, in pixels. 303 */ 304 float getUnderlineThickness (uint characterSize) const 305 { 306 return sfFont_getUnderlineThickness(sfPtr, characterSize); 307 } 308 309 /** 310 * Retrieve the texture containing the loaded glyphs of a certain size. 311 * 312 * The contents of the returned texture changes as more glyphs are 313 * requested, thus it is not very relevant. It is mainly used internally by 314 * Text. 315 * 316 * Params: 317 * characterSize = Reference character size 318 * 319 * Returns: Texture containing the glyphs of the requested size. 320 */ 321 const(Texture) getTexture (uint characterSize){ 322 import std.stdio; 323 Texture ret; // = textures.get(characterSize, null); 324 325 sfTexture* p = cast(sfTexture*)sfFont_getTexture(sfPtr, characterSize); 326 ret = new Texture(p); 327 328 return ret; 329 } 330 331 /** 332 * Performs a deep copy on the font. 333 * 334 * Returns: The duplicated font. 335 */ 336 @property 337 Font dup() const 338 { 339 return new Font(sfFont_copy(sfPtr)); 340 } 341 } 342 343 unittest { 344 version(DSFML_Unittest_Graphics) { 345 import std.stdio; 346 import nudsfml.graphics; 347 import nudsfml.window; 348 349 import nudsfml.graphics.text; 350 351 writeln("Unitest for Font"); 352 353 auto font = new Font(); 354 assert(font.loadFromFile("data/CamingoCode-Regular.ttf")); 355 356 Text text; 357 text = new Text("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789{}", font); 358 text.position = Vector2f(10, 300); 359 360 RenderWindow win = new RenderWindow(VideoMode(800, 600), "Font Test"); 361 362 Clock clock = new Clock(); 363 while(win.isOpen){ 364 Event event; 365 while(win.pollEvent(event)){ 366 if(event.type == Event.Type.Closed) 367 win.close(); 368 } 369 370 if(clock.getElapsedTime().asSeconds() > 1.0f){ 371 win.close(); 372 } 373 374 win.clear(); 375 win.draw(text); 376 win.display(); 377 } 378 379 380 //draw text or something 381 382 writeln(); 383 } 384 } 385 386 387 //private: 388 private extern(C++) interface fontInputStream { 389 long read(void* data, long size); 390 391 long seek(long position); 392 393 long tell(); 394 395 long getSize(); 396 } 397 398 399 private class fontStream:fontInputStream { 400 private InputStream myStream; 401 402 this(InputStream stream) { 403 myStream = stream; 404 } 405 406 extern(C++)long read(void* data, long size) { 407 return myStream.read(data[0..cast(size_t)size]); 408 } 409 410 extern(C++)long seek(long position) { 411 return myStream.seek(position); 412 } 413 414 extern(C++)long tell() { 415 return myStream.tell(); 416 } 417 418 extern(C++)long getSize(){ 419 return myStream.getSize(); 420 } 421 }