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