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