1 /* Public domain */
2
3 #ifndef _AGAR_GUI_TEXT_H_
4 #define _AGAR_GUI_TEXT_H_
5
6 #include <agar/gui/surface.h>
7 #include <agar/gui/drv.h>
8
9 #include <agar/gui/begin.h>
10
11 #define AG_GLYPH_NBUCKETS 1024 /* Buckets for glyph cache table */
12 #define AG_TEXT_STATES_MAX 128 /* Maximum number of saved text states */
13
14 struct ag_window;
15 struct ag_button;
16
17 enum ag_text_justify {
18 AG_TEXT_LEFT,
19 AG_TEXT_CENTER,
20 AG_TEXT_RIGHT
21 };
22 enum ag_text_valign {
23 AG_TEXT_TOP,
24 AG_TEXT_MIDDLE,
25 AG_TEXT_BOTTOM
26 };
27 enum ag_text_msg_title {
28 AG_MSG_ERROR,
29 AG_MSG_WARNING,
30 AG_MSG_INFO
31 };
32
33 struct ag_font;
34
35 /* Font specification (may be obtained from fontconfig) */
36 enum ag_font_type {
37 AG_FONT_VECTOR, /* Vectorial font */
38 AG_FONT_BITMAP /* Raw glyph pixmaps */
39 };
40 enum ag_font_spec_source {
41 AG_FONT_SOURCE_FILE, /* Load from file */
42 AG_FONT_SOURCE_MEMORY /* Read from memory */
43 };
44 typedef struct ag_font_spec {
45 enum ag_font_type type;
46 enum ag_font_spec_source sourceType;
47 union {
48 char file[AG_PATHNAME_MAX]; /* Font file */
49 struct {
50 const Uint8 *data; /* Memory region */
51 size_t size;
52 } mem;
53 } source;
54 int index; /* Font index */
55 double size; /* Font size */
56 struct { /* Transform matrix */
57 double xx, xy;
58 double yx, yy;
59 } matrix;
60 } AG_FontSpec;
61
62 /* Cached glyph surface/texture information. */
63 typedef struct ag_glyph {
64 struct ag_font *font; /* Font face */
65 AG_Color color; /* Glyph color */
66 Uint32 ch; /* Unicode character */
67 AG_Surface *su; /* Rendered surface */
68 int advance; /* Pixel advance */
69 Uint texture; /* Cached texture (driver-specific) */
70 AG_TexCoord texcoords; /* Texture coordinates */
71 AG_SLIST_ENTRY(ag_glyph) glyphs;
72 } AG_Glyph;
73
74 /* Loaded font */
75 typedef struct ag_font {
76 struct ag_object obj;
77 AG_FontSpec spec; /* Input font specification */
78 Uint flags;
79 #define AG_FONT_BOLD 0x01 /* Render as bold */
80 #define AG_FONT_ITALIC 0x02 /* Render as italic */
81 #define AG_FONT_UNDERLINE 0x04 /* Render with underline */
82 #define AG_FONT_UPPERCASE 0x08 /* Force uppercase display */
83 int height; /* Body size in pixels */
84 int ascent; /* Ascent (relative to baseline) */
85 int descent; /* Descent (relative to baseline) */
86 int lineskip; /* Multiline y-increment */
87 void *ttf; /* TTF object */
88 char bspec[32]; /* Bitmap font specification */
89 AG_Surface **bglyphs; /* Bitmap glyphs */
90 Uint nglyphs; /* Bitmap glyph count */
91 Uint32 c0, c1; /* Bitmap glyph range */
92 Uint nRefs; /* Reference count */
93 AG_TAILQ_ENTRY(ag_font) fonts;
94 } AG_Font;
95
96 /*
97 * State variables for text rendering.
98 * SYNC: AG_TextStateCompare()
99 */
100 typedef struct ag_text_state {
101 AG_Font *font; /* Font face */
102 AG_Color color; /* Foreground text color */
103 AG_Color colorBG; /* Background color */
104 enum ag_text_justify justify; /* Justification mode */
105 enum ag_text_valign valign; /* Vertical alignment mode */
106 int tabWd; /* Width of \t in pixels */
107 } AG_TextState;
108
109 /* Description of font stored in data segment. */
110 typedef struct ag_static_font {
111 const char *name; /* Identifier */
112 enum ag_font_type type; /* Type of font */
113 Uint32 size; /* Size in bytes */
114 const Uint8 *data; /* Font data */
115 AG_Font *font; /* Initialized font structure */
116 } AG_StaticFont;
117
118 /* Measures of rendered text. */
119 typedef struct ag_text_metrics {
120 int w, h; /* Dimensions in pixels */
121 Uint *wLines; /* Width of each line */
122 Uint nLines; /* Total line count */
123 } AG_TextMetrics;
124
125 typedef struct ag_glyph_cache {
126 AG_SLIST_HEAD_(ag_glyph) glyphs;
127 } AG_GlyphCache;
128
129 __BEGIN_DECLS
130 extern AG_ObjectClass agFontClass;
131 extern AG_Font *agDefaultFont;
132 extern int agTextFontHeight;
133 extern int agTextFontAscent;
134 extern int agTextFontDescent;
135 extern int agTextFontLineSkip;
136 extern int agFreetypeInited;
137 extern int agRTL;
138 extern int agGlyphGC;
139 extern AG_TextState *agTextState;
140 extern AG_Mutex agTextLock;
141 extern AG_StaticFont *agBuiltinFonts[];
142 extern const int agBuiltinFontCount;
143
144 int AG_InitTextSubsystem(void);
145 void AG_DestroyTextSubsystem(void);
146
147 void AG_TextParseFontSpec(const char *);
148 AG_Font *AG_FetchFont(const char *, int, int);
149 void AG_UnusedFont(AG_Font *);
150 void AG_SetDefaultFont(AG_Font *);
151 void AG_SetRTL(int);
152
153 void AG_PushTextState(void);
154 void AG_PopTextState(void);
155 AG_Font *AG_TextFontLookup(const char *, int, Uint);
156 AG_Font *AG_TextFontPts(int);
157 AG_Font *AG_TextFontPct(int);
158
159 void AG_TextSize(const char *, int *, int *);
160 void AG_TextSizeMulti(const char *, int *, int *, Uint **, Uint *);
161 void AG_TextSizeUCS4(const Uint32 *, int *, int *);
162 void AG_TextSizeMultiUCS4(const Uint32 *, int *, int *, Uint **, Uint *);
163
164 AG_Surface *AG_TextRenderf(const char *, ...);
165 AG_Surface *AG_TextRenderUCS4(const Uint32 *);
166
167 void AG_TextMsgS(enum ag_text_msg_title, const char *);
168 void AG_TextMsg(enum ag_text_msg_title, const char *, ...)
169 FORMAT_ATTRIBUTE(printf,2,3)
170 NONNULL_ATTRIBUTE(2);
171
172 void AG_TextTmsgS(enum ag_text_msg_title, Uint32, const char *);
173 void AG_TextTmsg(enum ag_text_msg_title, Uint32, const char *, ...)
174 FORMAT_ATTRIBUTE(printf,3,4)
175 NONNULL_ATTRIBUTE(3);
176
177 void AG_TextInfoS(const char *, const char *);
178 void AG_TextInfo(const char *, const char *, ...)
179 FORMAT_ATTRIBUTE(printf,2,3)
180 NONNULL_ATTRIBUTE(2);
181
182 void AG_TextWarningS(const char *, const char *);
183 void AG_TextWarning(const char *, const char *, ...)
184 FORMAT_ATTRIBUTE(printf,2,3)
185 NONNULL_ATTRIBUTE(2);
186
187 void AG_TextErrorS(const char *);
188 void AG_TextError(const char *, ...)
189 FORMAT_ATTRIBUTE(printf,1,2)
190 NONNULL_ATTRIBUTE(1);
191
192 void AG_TextEditFloat(double *, double, double, const char *,
193 const char *, ...)
194 FORMAT_ATTRIBUTE(printf,5,6)
195 NONNULL_ATTRIBUTE(5);
196 void AG_TextEditString(char *, size_t, const char *, ...)
197 FORMAT_ATTRIBUTE(printf,3,4)
198 NONNULL_ATTRIBUTE(3);
199 struct ag_window *AG_TextPromptOptions(struct ag_button **, Uint, const char *, ...);
200
201 void AG_TextInitGlyphCache(AG_Driver *);
202 void AG_TextClearGlyphCache(AG_Driver *);
203 void AG_TextDestroyGlyphCache(AG_Driver *);
204 AG_Glyph *AG_TextRenderGlyphMiss(AG_Driver *, Uint32);
205
206 void AG_TextAlign(int *, int *, int, int, int, int, int, int, int,
207 int, enum ag_text_justify, enum ag_text_valign);
208
209 #define AG_TextMsgFromError() \
210 AG_TextMsgS(AG_MSG_ERROR, AG_GetError())
211
212 /* Compare two text states. */
213 static __inline__ int
AG_TextStateCompare(const AG_TextState * s1,const AG_TextState * s2)214 AG_TextStateCompare(const AG_TextState *s1, const AG_TextState *s2)
215 {
216 if (s1->font == s2->font &&
217 AG_ColorCompare(s1->color,s2->color) == 0 &&
218 AG_ColorCompare(s1->colorBG,s2->colorBG) == 0 &&
219 s1->justify == s2->justify &&
220 s1->valign == s2->valign &&
221 s1->tabWd == s2->tabWd) {
222 return (0);
223 }
224 return (1);
225 }
226
227 /*
228 * Return the offset in pixels needed to align text based on the current
229 * justification mode.
230 */
231 static __inline__ int
AG_TextJustifyOffset(int w,int wLine)232 AG_TextJustifyOffset(int w, int wLine)
233 {
234 switch (agTextState->justify) {
235 case AG_TEXT_LEFT: return (0);
236 case AG_TEXT_CENTER: return (w/2 - wLine/2);
237 case AG_TEXT_RIGHT: return (w - wLine);
238 }
239 return (0);
240 }
241
242 /*
243 * Return the offset in pixels needed to align text based on the current
244 * vertical alignment mode.
245 */
246 static __inline__ int
AG_TextValignOffset(int h,int hLine)247 AG_TextValignOffset(int h, int hLine)
248 {
249 switch (agTextState->valign) {
250 case AG_TEXT_TOP: return (0);
251 case AG_TEXT_MIDDLE: return (h/2 - hLine/2);
252 case AG_TEXT_BOTTOM: return (h - hLine);
253 }
254 return (0);
255 }
256
257 /*
258 * Allocate a transparent surface and render text from a C string.
259 * The string may contain UTF-8 sequences.
260 */
261 static __inline__ AG_Surface *
AG_TextRender(const char * text)262 AG_TextRender(const char *text)
263 {
264 Uint32 *ucs;
265 AG_Surface *su;
266
267 if ((ucs = AG_ImportUnicode("UTF-8", text, NULL, NULL)) != NULL) {
268 su = AG_TextRenderUCS4(ucs);
269 AG_Free(ucs);
270 return (su);
271 }
272 return (NULL);
273 }
274
275 /*
276 * Lookup/insert a glyph in the glyph cache.
277 * Must be called from GUI rendering context.
278 */
279 static __inline__ AG_Glyph *
AG_TextRenderGlyph(AG_Driver * drv,Uint32 ch)280 AG_TextRenderGlyph(AG_Driver *drv, Uint32 ch)
281 {
282 AG_Glyph *gl;
283 Uint h = (Uint)(ch % AG_GLYPH_NBUCKETS);
284
285 AG_SLIST_FOREACH(gl, &drv->glyphCache[h].glyphs, glyphs) {
286 if (ch == gl->ch &&
287 agTextState->font == gl->font &&
288 AG_ColorCompare(agTextState->color,gl->color) == 0)
289 break;
290 }
291 if (gl == NULL) {
292 gl = AG_TextRenderGlyphMiss(drv, ch);
293 AG_SLIST_INSERT_HEAD(&drv->glyphCache[h].glyphs, gl, glyphs);
294 }
295 return (gl);
296 }
297
298
299 /* Set active text color. */
300 static __inline__ void
AG_TextColor(AG_Color C)301 AG_TextColor(AG_Color C)
302 {
303 AG_MutexLock(&agTextLock);
304 agTextState->color = C;
305 AG_MutexUnlock(&agTextLock);
306 }
307 static __inline__ void
AG_TextColorRGB(Uint8 r,Uint8 g,Uint8 b)308 AG_TextColorRGB(Uint8 r, Uint8 g, Uint8 b)
309 {
310 AG_MutexLock(&agTextLock);
311 agTextState->color = AG_ColorRGB(r,g,b);
312 AG_MutexUnlock(&agTextLock);
313 }
314 static __inline__ void
AG_TextColorRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)315 AG_TextColorRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
316 {
317 AG_MutexLock(&agTextLock);
318 agTextState->color = AG_ColorRGBA(r,g,b,a);
319 AG_MutexUnlock(&agTextLock);
320 }
321
322 /* Set text color from 0xRRGGBBAA format. */
323 static __inline__ void
AG_TextColorHex(Uint32 c)324 AG_TextColorHex(Uint32 c)
325 {
326 AG_MutexLock(&agTextLock);
327 agTextState->color = AG_ColorHex(c);
328 AG_MutexUnlock(&agTextLock);
329 }
330
331 /* Set active text background color. */
332 static __inline__ void
AG_TextBGColor(AG_Color C)333 AG_TextBGColor(AG_Color C)
334 {
335 AG_MutexLock(&agTextLock);
336 agTextState->colorBG = C;
337 AG_MutexUnlock(&agTextLock);
338 }
339 static __inline__ void
AG_TextBGColorRGB(Uint8 r,Uint8 g,Uint8 b)340 AG_TextBGColorRGB(Uint8 r, Uint8 g, Uint8 b)
341 {
342 AG_MutexLock(&agTextLock);
343 agTextState->colorBG = AG_ColorRGB(r,g,b);
344 AG_MutexUnlock(&agTextLock);
345 }
346 static __inline__ void
AG_TextBGColorRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)347 AG_TextBGColorRGBA(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
348 {
349 AG_MutexLock(&agTextLock);
350 agTextState->colorBG = AG_ColorRGBA(r,g,b,a);
351 AG_MutexUnlock(&agTextLock);
352 }
353
354 /* Set text BG color from 0xRRGGBBAA format. */
355 static __inline__ void
AG_TextBGColorHex(Uint32 c)356 AG_TextBGColorHex(Uint32 c)
357 {
358 AG_MutexLock(&agTextLock);
359 agTextState->colorBG = AG_ColorHex(c);
360 AG_MutexUnlock(&agTextLock);
361 }
362
363 /* Select a specific font face to use in rendering text. */
364 static __inline__ void
AG_TextFont(AG_Font * font)365 AG_TextFont(AG_Font *font)
366 {
367 AG_MutexLock(&agTextLock);
368 agTextState->font = font;
369 AG_MutexUnlock(&agTextLock);
370 }
371
372 /* Select the justification mode to use in rendering text. */
373 static __inline__ void
AG_TextJustify(enum ag_text_justify mode)374 AG_TextJustify(enum ag_text_justify mode)
375 {
376 AG_MutexLock(&agTextLock);
377 agTextState->justify = mode;
378 AG_MutexUnlock(&agTextLock);
379 }
380
381 /* Select the vertical alignment mode to use in rendering text. */
382 static __inline__ void
AG_TextValign(enum ag_text_valign mode)383 AG_TextValign(enum ag_text_valign mode)
384 {
385 AG_MutexLock(&agTextLock);
386 agTextState->valign = mode;
387 AG_MutexUnlock(&agTextLock);
388 }
389
390 /* Select the tab width in pixels for rendering text. */
391 static __inline__ void
AG_TextTabWidth(int px)392 AG_TextTabWidth(int px)
393 {
394 AG_MutexLock(&agTextLock);
395 agTextState->tabWd = px;
396 AG_MutexUnlock(&agTextLock);
397 }
398
399 #ifdef AG_LEGACY
400 #define AG_TextFormat AG_TextRenderf
401
402 static __inline__ void
AG_TextColor32(Uint32 px)403 AG_TextColor32(Uint32 px)
404 {
405 AG_Color C;
406
407 C = AG_GetColorRGB(px, agSurfaceFmt);
408 AG_MutexLock(&agTextLock);
409 agTextState->color = C;
410 AG_MutexUnlock(&agTextLock);
411 }
412 #endif /* AG_LEGACY */
413
414 __END_DECLS
415
416 #include <agar/gui/close.h>
417 #endif /* _AGAR_GUI_TEXT_H_ */
418