1 module gfm.sdl2.sdlttf; 2 3 import std.string; 4 5 import derelict.sdl2.sdl, 6 derelict.sdl2.ttf, 7 derelict.util.exception; 8 9 import std.logger; 10 11 import gfm.core.text, 12 gfm.math.vector, 13 gfm.sdl2.sdl, 14 gfm.sdl2.surface; 15 16 /// SDL_ttf library wrapper. 17 final class SDLTTF 18 { 19 public 20 { 21 /// Loads the SDL_ttf library. 22 /// Throws: $(D SDL2Exception) on error. 23 this(SDL2 sdl2) 24 { 25 _sdl2 = sdl2; // force loading of SDL first 26 _logger = sdl2._logger; 27 _SDLTTFInitialized = false; 28 29 try 30 { 31 DerelictSDL2ttf.load(); 32 } 33 catch(DerelictException e) 34 { 35 throw new SDL2Exception(e.msg); 36 } 37 38 int res = TTF_Init(); 39 if (res != 0) 40 throwSDL2TTFException("TTF_Init"); 41 42 _logger.infof("SDL_ttf: initialized."); 43 _SDLTTFInitialized = true; 44 } 45 46 /// Releases the SDL_ttf library. 47 void close() 48 { 49 if (_SDLTTFInitialized) 50 { 51 _SDLTTFInitialized = false; 52 TTF_Quit(); 53 } 54 55 DerelictSDL2ttf.unload(); 56 } 57 58 ~this() 59 { 60 close(); 61 } 62 } 63 64 private 65 { 66 Logger _logger; 67 SDL2 _sdl2; 68 bool _SDLTTFInitialized; 69 70 void throwSDL2TTFException(string callThatFailed) 71 { 72 string message = format("%s failed: %s", callThatFailed, getErrorString()); 73 throw new SDL2Exception(message); 74 } 75 76 string getErrorString() 77 { 78 return sanitizeUTF8(TTF_GetError(), _logger, "SDL_TTF error string"); 79 } 80 } 81 } 82 83 /// SDL_ttf loaded font wrapper. 84 final class SDLFont 85 { 86 public 87 { 88 /// Loads a font from a file. 89 /// Params: 90 /// ptSize = font size in 72 dpi ("This basically translates to pixel height" says the doc). 91 /// Throws: $(D SDL2Exception) on error. 92 this(SDLTTF sdlttf, string filename, int ptSize) 93 { 94 _sdlttf = sdlttf; 95 _font = TTF_OpenFont(toStringz(filename), ptSize); 96 if (_font is null) 97 _sdlttf.throwSDL2TTFException("TTF_OpenFont"); 98 } 99 100 ~this() 101 { 102 close(); 103 } 104 105 /// Releases the SDL resource. 106 void close() 107 { 108 if (_font !is null) 109 { 110 TTF_CloseFont(_font); 111 _font = null; 112 } 113 } 114 115 /// Returns: Font style. 116 int style() 117 { 118 return TTF_GetFontStyle(_font); 119 } 120 121 /// Set font style. 122 int setStyle(int newStyle) 123 { 124 if (newStyle != TTF_GetFontStyle(_font)) 125 TTF_SetFontStyle(_font, newStyle); 126 return newStyle; 127 } 128 129 /// Returns: Font hinting. 130 int hinting() 131 { 132 return TTF_GetFontHinting(_font); 133 } 134 135 /// Set font hinting. 136 int setHinting(int newHinting) 137 { 138 if (newHinting != TTF_GetFontHinting(_font)) 139 TTF_SetFontHinting(_font, newHinting); 140 return newHinting; 141 } 142 143 /// Returns: Font outline. 144 int outline() 145 { 146 return TTF_GetFontOutline(_font); 147 } 148 149 /// Set font outline. 150 int setOutline(int newOutline) 151 { 152 if (newOutline != TTF_GetFontOutline(_font)) 153 TTF_SetFontOutline(_font, newOutline); 154 return newOutline; 155 } 156 157 /// Returns: true if kerning is enabled. 158 bool getKerning() 159 { 160 return TTF_GetFontKerning(_font) != 0; 161 } 162 163 /// Enables/Disables font kerning. 164 bool setKerning(bool enabled) 165 { 166 TTF_SetFontKerning(_font, enabled ? 1 : 0); 167 return enabled; 168 } 169 170 /// Returns: Maximum height of a glyph in pixels. 171 int height() 172 { 173 return TTF_FontAscent(_font); 174 } 175 176 /// Returns: Height above baseline in pixels. 177 int ascent() 178 { 179 return TTF_FontAscent(_font); 180 } 181 182 /// Returns: Height below baseline. 183 int descent() 184 { 185 return TTF_FontDescent(_font); 186 } 187 188 /// Returns: Line skip, the recommended pixel interval between two lines. 189 int lineSkip() 190 { 191 return TTF_FontLineSkip(_font); 192 } 193 194 /// Returns: Size of text in pixels if rendered with this font. 195 vec2i measureText(string text) 196 { 197 int w, h; 198 TTF_SizeUTF8(_font, toStringz(text), &w, &h); 199 return vec2i(w, h); 200 } 201 202 /// Create a 32-bit ARGB surface and render the given text at high quality, 203 /// using alpha blending to dither the font with the given color. 204 /// Throws: $(D SDL2Exception) on error. 205 SDL2Surface renderTextBlended(string text, SDL_Color color) 206 { 207 return checkedSurface(TTF_RenderUTF8_Blended(_font, toStringz(text), color)); 208 } 209 210 /// Create an 8-bit palettized surface and render the given text at fast 211 /// quality with the given font and color. 212 /// Throws: $(D SDL2Exception) on error. 213 SDL2Surface renderTextSolid(string text, SDL_Color color) 214 { 215 return checkedSurface(TTF_RenderUTF8_Solid(_font, toStringz(text), color)); 216 } 217 218 /// Create an 8-bit palettized surface and render the given text at high 219 /// quality with the given font and colors. 220 /// Throws: $(D SDL2Exception) on error. 221 SDL2Surface renderTextShaded(string text, SDL_Color fg, SDL_Color bg) 222 { 223 return checkedSurface(TTF_RenderUTF8_Shaded(_font, toStringz(text), fg, bg)); 224 } 225 } 226 227 private 228 { 229 SDLTTF _sdlttf; 230 TTF_Font *_font; 231 232 SDL2Surface checkedSurface(SDL_Surface* s) 233 { 234 if (s is null) 235 _sdlttf.throwSDL2TTFException("TTF_Render"); 236 return new SDL2Surface(_sdlttf._sdl2, s, SDL2Surface.Owned.YES); 237 } 238 } 239 }