1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Text drawing routines.
12 *
13 * By Shawn Hargreaves.
14 *
15 * textout_justify() by Seymour Shlien.
16 *
17 * Laurence Withers added the textout_ex() function family.
18 *
19 * See readme.txt for copyright information.
20 */
21
22
23 #include <math.h>
24 #include <ctype.h>
25 #include "allegro5/allegro.h"
26
27 #include "allegro5/allegro_font.h"
28 #include "allegro5/internal/aintern_dtor.h"
29 #include "allegro5/internal/aintern_font.h"
30 #include "allegro5/internal/aintern_system.h"
31
32 /* If you call this, you're probably making a mistake. */
33 /*
34 #define strlen(s) __are_you_sure__
35 */
36 /* Removed the above define since some compilers seem to use some
37 * preprocessor magic when calling strcmp() that inserts a call to strlen.
38 * There might be a better way to do this.
39 */
40
41
42
43 /* Text usually looks best when aligned to pixels -
44 * but if x is 0.5 it may very well end up at an integer
45 * position if the current transformation scales by 2 or
46 * translated x by 0.5. So we simply apply the transformation,
47 * round to nearest integer, and backtransform that.
48 */
align_to_integer_pixel_inner(ALLEGRO_TRANSFORM const * fwd,ALLEGRO_TRANSFORM const * inv,float * x,float * y)49 static void align_to_integer_pixel_inner(
50 ALLEGRO_TRANSFORM const *fwd,
51 ALLEGRO_TRANSFORM const *inv,
52 float *x, float *y)
53 {
54 al_transform_coordinates(fwd, x, y);
55 *x = floorf(*x + 0.5f);
56 *y = floorf(*y + 0.5f);
57 al_transform_coordinates(inv, x, y);
58 }
59
align_to_integer_pixel(float * x,float * y)60 static void align_to_integer_pixel(float *x, float *y)
61 {
62 ALLEGRO_TRANSFORM const *fwd;
63 ALLEGRO_TRANSFORM inv;
64
65 fwd = al_get_current_transform();
66 al_copy_transform(&inv, fwd);
67 al_invert_transform(&inv);
68 align_to_integer_pixel_inner(fwd, &inv, x, y);
69 }
70
71
72
73 /* Function: al_draw_ustr
74 */
al_draw_ustr(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x,float y,int flags,const ALLEGRO_USTR * ustr)75 void al_draw_ustr(const ALLEGRO_FONT *font,
76 ALLEGRO_COLOR color, float x, float y, int flags,
77 const ALLEGRO_USTR *ustr)
78 {
79 ASSERT(font);
80 ASSERT(ustr);
81
82 if (flags & ALLEGRO_ALIGN_CENTRE) {
83 /* Use integer division to avoid introducing a fractional
84 * component to an integer x value.
85 */
86 x -= font->vtable->text_length(font, ustr) / 2;
87 }
88 else if (flags & ALLEGRO_ALIGN_RIGHT) {
89 x -= font->vtable->text_length(font, ustr);
90 }
91
92 if (flags & ALLEGRO_ALIGN_INTEGER)
93 align_to_integer_pixel(&x, &y);
94
95 font->vtable->render(font, color, ustr, x, y);
96 }
97
98
99
100 /* Function: al_draw_text
101 */
al_draw_text(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x,float y,int flags,char const * text)102 void al_draw_text(const ALLEGRO_FONT *font,
103 ALLEGRO_COLOR color, float x, float y, int flags,
104 char const *text)
105 {
106 ALLEGRO_USTR_INFO info;
107 ASSERT(text);
108 al_draw_ustr(font, color, x, y, flags, al_ref_cstr(&info, text));
109 }
110
111
112
113 /* Function: al_draw_justified_ustr
114 */
al_draw_justified_ustr(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x1,float x2,float y,float diff,int flags,const ALLEGRO_USTR * ustr)115 void al_draw_justified_ustr(const ALLEGRO_FONT *font,
116 ALLEGRO_COLOR color, float x1, float x2,
117 float y, float diff, int flags, const ALLEGRO_USTR *ustr)
118 {
119 const char *whitespace = " \t\n\r";
120 ALLEGRO_USTR_INFO word_info;
121 const ALLEGRO_USTR *word;
122 int pos1, pos2;
123 int minlen;
124 int num_words;
125 int space;
126 float fleft, finc;
127 int advance;
128 ALLEGRO_TRANSFORM const *fwd = NULL;
129 ALLEGRO_TRANSFORM inv;
130
131 ASSERT(font);
132
133 /* count words and measure min length (without spaces) */
134 num_words = 0;
135 minlen = 0;
136 pos1 = 0;
137 for (;;) {
138 pos1 = al_ustr_find_cset_cstr(ustr, pos1, whitespace);
139 if (pos1 == -1)
140 break;
141 pos2 = al_ustr_find_set_cstr(ustr, pos1, whitespace);
142 if (pos2 == -1)
143 pos2 = al_ustr_size(ustr);
144
145 word = al_ref_ustr(&word_info, ustr, pos1, pos2);
146 minlen += font->vtable->text_length(font, word);
147 num_words++;
148
149 pos1 = pos2;
150 }
151
152 /* amount of room for space between words */
153 space = x2 - x1 - minlen;
154
155 if ((space <= 0) || (space > diff) || (num_words < 2)) {
156 /* can't justify */
157 if (flags & ALLEGRO_ALIGN_INTEGER)
158 align_to_integer_pixel(&x1, &y);
159 font->vtable->render(font, color, ustr, x1, y);
160 return;
161 }
162
163 /* distribute space left evenly between words */
164 fleft = (float)x1;
165 finc = (float)space / (float)(num_words-1);
166 pos1 = 0;
167
168 if (flags & ALLEGRO_ALIGN_INTEGER) {
169 fwd = al_get_current_transform();
170 al_copy_transform(&inv, fwd);
171 al_invert_transform(&inv);
172 }
173
174 for (;;) {
175 pos1 = al_ustr_find_cset_cstr(ustr, pos1, whitespace);
176 if (pos1 == -1)
177 break;
178 pos2 = al_ustr_find_set_cstr(ustr, pos1, whitespace);
179 if (pos2 == -1)
180 pos2 = al_ustr_size(ustr);
181
182 word = al_ref_ustr(&word_info, ustr, pos1, pos2);
183 if (flags & ALLEGRO_ALIGN_INTEGER) {
184 float drawx = fleft;
185 float drawy = y;
186 align_to_integer_pixel_inner(fwd, &inv, &drawx, &drawy);
187 advance = font->vtable->render(font, color, word, drawx, drawy);
188 }
189 else {
190 advance = font->vtable->render(font, color, word, fleft, y);
191 }
192 fleft += advance + finc;
193 pos1 = pos2;
194 }
195 }
196
197
198 /* Function: al_draw_justified_text
199 */
al_draw_justified_text(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x1,float x2,float y,float diff,int flags,const char * text)200 void al_draw_justified_text(const ALLEGRO_FONT *font,
201 ALLEGRO_COLOR color, float x1, float x2,
202 float y, float diff, int flags, const char *text)
203 {
204 ALLEGRO_USTR_INFO info;
205 ASSERT(text);
206 al_draw_justified_ustr(font, color, x1, x2, y, diff, flags,
207 al_ref_cstr(&info, text));
208 }
209
210
211 /* Function: al_draw_textf
212 */
al_draw_textf(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x,float y,int flags,const char * format,...)213 void al_draw_textf(const ALLEGRO_FONT *font, ALLEGRO_COLOR color,
214 float x, float y, int flags,
215 const char *format, ...)
216 {
217 ALLEGRO_USTR *buf;
218 va_list ap;
219 const char *s;
220 ASSERT(font);
221 ASSERT(format);
222
223 /* Fast path for common case. */
224 if (0 == strcmp(format, "%s")) {
225 va_start(ap, format);
226 s = va_arg(ap, const char *);
227 al_draw_text(font, color, x, y, flags, s);
228 va_end(ap);
229 return;
230 }
231
232 va_start(ap, format);
233 buf = al_ustr_new("");
234 al_ustr_vappendf(buf, format, ap);
235 va_end(ap);
236
237 al_draw_text(font, color, x, y, flags, al_cstr(buf));
238
239 al_ustr_free(buf);
240 }
241
242
243
244 /* Function: al_draw_justified_textf
245 */
al_draw_justified_textf(const ALLEGRO_FONT * f,ALLEGRO_COLOR color,float x1,float x2,float y,float diff,int flags,const char * format,...)246 void al_draw_justified_textf(const ALLEGRO_FONT *f,
247 ALLEGRO_COLOR color, float x1, float x2, float y,
248 float diff, int flags, const char *format, ...)
249 {
250 ALLEGRO_USTR *buf;
251 va_list ap;
252 ASSERT(f);
253 ASSERT(format);
254
255 va_start(ap, format);
256 buf = al_ustr_new("");
257 al_ustr_vappendf(buf, format, ap);
258 va_end(ap);
259
260 al_draw_justified_text(f, color, x1, x2, y, diff, flags,
261 al_cstr(buf));
262
263 al_ustr_free(buf);
264 }
265
266
267
268 /* Function: al_get_ustr_width
269 */
al_get_ustr_width(const ALLEGRO_FONT * f,ALLEGRO_USTR const * ustr)270 int al_get_ustr_width(const ALLEGRO_FONT *f, ALLEGRO_USTR const *ustr)
271 {
272 ASSERT(f);
273 ASSERT(ustr);
274
275 return f->vtable->text_length(f, ustr);
276 }
277
278
279
280 /* Function: al_get_text_width
281 */
al_get_text_width(const ALLEGRO_FONT * f,const char * str)282 int al_get_text_width(const ALLEGRO_FONT *f, const char *str)
283 {
284 ALLEGRO_USTR_INFO str_info;
285 const ALLEGRO_USTR *ustr;
286 ASSERT(f);
287 ASSERT(str);
288
289 ustr = al_ref_cstr(&str_info, str);
290
291 return f->vtable->text_length(f, ustr);
292 }
293
294
295
296 /* Function: al_get_font_line_height
297 */
al_get_font_line_height(const ALLEGRO_FONT * f)298 int al_get_font_line_height(const ALLEGRO_FONT *f)
299 {
300 ASSERT(f);
301 return f->vtable->font_height(f);
302 }
303
304
305
306 /* Function: al_get_font_ascent
307 */
al_get_font_ascent(const ALLEGRO_FONT * f)308 int al_get_font_ascent(const ALLEGRO_FONT *f)
309 {
310 ASSERT(f);
311 return f->vtable->font_ascent(f);
312 }
313
314
315
316 /* Function: al_get_font_descent
317 */
al_get_font_descent(const ALLEGRO_FONT * f)318 int al_get_font_descent(const ALLEGRO_FONT *f)
319 {
320 ASSERT(f);
321 return f->vtable->font_descent(f);
322 }
323
324
325
326 /* Function: al_get_ustr_dimensions
327 */
al_get_ustr_dimensions(const ALLEGRO_FONT * f,ALLEGRO_USTR const * ustr,int * bbx,int * bby,int * bbw,int * bbh)328 void al_get_ustr_dimensions(const ALLEGRO_FONT *f,
329 ALLEGRO_USTR const *ustr,
330 int *bbx, int *bby, int *bbw, int *bbh)
331 {
332 ASSERT(f);
333 ASSERT(ustr);
334 f->vtable->get_text_dimensions(f, ustr, bbx, bby,
335 bbw, bbh);
336 }
337
338
339
340 /* Function: al_get_text_dimensions
341 */
al_get_text_dimensions(const ALLEGRO_FONT * f,char const * text,int * bbx,int * bby,int * bbw,int * bbh)342 void al_get_text_dimensions(const ALLEGRO_FONT *f,
343 char const *text,
344 int *bbx, int *bby, int *bbw, int *bbh)
345 {
346 ALLEGRO_USTR_INFO info;
347 ASSERT(f);
348 ASSERT(text);
349
350 f->vtable->get_text_dimensions(f, al_ref_cstr(&info, text), bbx, bby,
351 bbw, bbh);
352 }
353
354
355
356 /* Function: al_destroy_font
357 */
al_destroy_font(ALLEGRO_FONT * f)358 void al_destroy_font(ALLEGRO_FONT *f)
359 {
360 if (!f)
361 return;
362
363 _al_unregister_destructor(_al_dtor_list, f->dtor_item);
364
365 f->vtable->destroy(f);
366 }
367
368
369 /* Function: al_get_font_ranges
370 */
al_get_font_ranges(ALLEGRO_FONT * f,int ranges_count,int * ranges)371 int al_get_font_ranges(ALLEGRO_FONT *f, int ranges_count, int *ranges)
372 {
373 return f->vtable->get_font_ranges(f, ranges_count, ranges);
374 }
375
376 /* Function: al_draw_glyph
377 */
al_draw_glyph(const ALLEGRO_FONT * f,ALLEGRO_COLOR color,float x,float y,int codepoint)378 void al_draw_glyph(const ALLEGRO_FONT *f, ALLEGRO_COLOR color, float x, float y,
379 int codepoint)
380 {
381 f->vtable->render_char(f, color, codepoint, x, y);
382 };
383
384 /* Function: al_get_glyph_width
385 */
al_get_glyph_width(const ALLEGRO_FONT * f,int codepoint)386 int al_get_glyph_width(const ALLEGRO_FONT *f, int codepoint)
387 {
388 return f->vtable->char_length(f, codepoint);
389 }
390
391 /* Function: al_get_glyph_dimensions
392 */
al_get_glyph_dimensions(const ALLEGRO_FONT * f,int codepoint,int * bbx,int * bby,int * bbw,int * bbh)393 bool al_get_glyph_dimensions(const ALLEGRO_FONT *f,
394 int codepoint, int *bbx, int *bby, int *bbw, int *bbh)
395 {
396 return f->vtable->get_glyph_dimensions(f, codepoint, bbx, bby, bbw, bbh);
397 }
398
399 /* Function: al_get_glyph_advance
400 */
al_get_glyph_advance(const ALLEGRO_FONT * f,int codepoint1,int codepoint2)401 int al_get_glyph_advance(const ALLEGRO_FONT *f, int codepoint1, int codepoint2)
402 {
403 return f->vtable->get_glyph_advance(f, codepoint1, codepoint2);
404 }
405
406 /* Function: al_get_glyph
407 */
al_get_glyph(const ALLEGRO_FONT * f,int prev_codepoint,int codepoint,ALLEGRO_GLYPH * glyph)408 bool al_get_glyph(const ALLEGRO_FONT *f, int prev_codepoint, int codepoint, ALLEGRO_GLYPH *glyph)
409 {
410 return f->vtable->get_glyph(f, prev_codepoint, codepoint, glyph);
411 };
412
413
414 /* This helper function helps splitting an ustr in several delimited parts.
415 * It returns an ustr that refers to the next part of the string that
416 * is delimited by the delimiters in delimiter.
417 * Returns NULL at the end of the string.
418 * Pos is updated to byte index of character after the delimiter or
419 * to the end of the string.
420 */
ustr_split_next(const ALLEGRO_USTR * ustr,ALLEGRO_USTR_INFO * info,int * pos,const char * delimiter)421 static const ALLEGRO_USTR *ustr_split_next(const ALLEGRO_USTR *ustr,
422 ALLEGRO_USTR_INFO *info, int *pos, const char *delimiter)
423 {
424 const ALLEGRO_USTR *result;
425 int end, size;
426
427 size = al_ustr_size(ustr);
428 if (*pos >= size) {
429 return NULL;
430 }
431
432 end = al_ustr_find_set_cstr(ustr, *pos, delimiter);
433 if (end == -1)
434 end = size;
435
436 result = al_ref_ustr(info, ustr, *pos, end);
437 /* Set pos to character AFTER delimiter */
438 al_ustr_next(ustr, &end);
439 (*pos) = end;
440 return result;
441 }
442
443
444
445 /* This returns the next "soft" line of text from ustr
446 * that will fit in max_with using the font font, starting at pos *pos.
447 * These are "soft" lines because they are broken up if needed at a space
448 * or tab character.
449 * This function updates pos if needed, and returns the next "soft" line,
450 * or NULL if no more soft lines.
451 * The soft line will not include the trailing space where the
452 * line was split, but pos will be set to point to after that trailing
453 * space so iteration can continue easily.
454 */
get_next_soft_line(const ALLEGRO_USTR * ustr,ALLEGRO_USTR_INFO * info,int * pos,const ALLEGRO_FONT * font,float max_width)455 static const ALLEGRO_USTR *get_next_soft_line(const ALLEGRO_USTR *ustr,
456 ALLEGRO_USTR_INFO *info, int *pos,
457 const ALLEGRO_FONT *font, float max_width)
458 {
459 const ALLEGRO_USTR *result = NULL;
460 const char *whitespace = " \t";
461 int old_end = 0;
462 int end = 0;
463 int size = al_ustr_size(ustr);
464 bool first_word = true;
465
466 if (*pos >= size) {
467 return NULL;
468 }
469
470 end = *pos;
471 old_end = end;
472 do {
473 /* On to the next word. */
474 end = al_ustr_find_set_cstr(ustr, end, whitespace);
475 if (end < 0)
476 end = size;
477
478 /* Reference to the line that is being built. */
479 result = al_ref_ustr(info, ustr, *pos, end);
480
481 /* Check if the line is too long. If it is, return a soft line. */
482 if (al_get_ustr_width(font, result) > max_width) {
483 /* Corner case: a single word may not even fit the line.
484 * In that case, return the word/line anyway as the "soft line",
485 * the user can set a clip rectangle to cut it. */
486
487 if (first_word) {
488 /* Set pos to character AFTER end to allow easy iteration. */
489 al_ustr_next(ustr, &end);
490 *pos = end;
491 return result;
492 }
493 else {
494 /* Not first word, return old end position without the new word */
495 result = al_ref_ustr(info, ustr, *pos, old_end);
496 /* Set pos to character AFTER end to allow easy iteration. */
497 al_ustr_next(ustr, &old_end);
498 *pos = old_end;
499 return result;
500 }
501 }
502 first_word = false;
503 old_end = end;
504 /* Skip the character at end which normally is whitespace. */
505 al_ustr_next(ustr, &end);
506 } while (end < size);
507
508 /* If we get here the whole ustr will fit.*/
509 result = al_ref_ustr(info, ustr, *pos, size);
510 *pos = size;
511 return result;
512 }
513
514
515 /* Function: al_do_multiline_ustr
516 */
al_do_multiline_ustr(const ALLEGRO_FONT * font,float max_width,const ALLEGRO_USTR * ustr,bool (* cb)(int line_num,const ALLEGRO_USTR * line,void * extra),void * extra)517 void al_do_multiline_ustr(const ALLEGRO_FONT *font, float max_width,
518 const ALLEGRO_USTR *ustr,
519 bool (*cb)(int line_num, const ALLEGRO_USTR * line, void *extra),
520 void *extra)
521 {
522 const char *linebreak = "\n";
523 const ALLEGRO_USTR *hard_line, *soft_line;
524 ALLEGRO_USTR_INFO hard_line_info, soft_line_info;
525 int hard_line_pos = 0, soft_line_pos = 0;
526 int line_num = 0;
527 bool proceed;
528
529 /* For every "hard" line separated by a newline character... */
530 hard_line = ustr_split_next(ustr, &hard_line_info, &hard_line_pos,
531 linebreak);
532 while (hard_line) {
533 /* For every "soft" line in the "hard" line... */
534 soft_line_pos = 0;
535 soft_line =
536 get_next_soft_line(hard_line, &soft_line_info, &soft_line_pos, font,
537 max_width);
538 /* No soft line here because it's an empty hard line. */
539 if (!soft_line) {
540 /* Call the callback with empty string to indicate an empty line. */
541 proceed = cb(line_num, al_ustr_empty_string(), extra);
542 if (!proceed) return;
543 line_num ++;
544 }
545 while(soft_line) {
546 /* Call the callback on the next soft line. */
547 proceed = cb(line_num, soft_line, extra);
548 if (!proceed) return;
549 line_num++;
550
551 soft_line = get_next_soft_line(hard_line, &soft_line_info,
552 &soft_line_pos, font, max_width);
553 }
554 hard_line = ustr_split_next(ustr, &hard_line_info, &hard_line_pos,
555 linebreak);
556 }
557 }
558
559
560
561 /* Helper struct for al_do_multiline_text. */
562 typedef struct DO_MULTILINE_TEXT_EXTRA {
563 bool (*callback)(int line_num, const char *line, int size, void *extra);
564 void *extra;
565 } DO_MULTILINE_TEXT_EXTRA;
566
567
568
569 /* The functions do_multiline_text_cb is the helper callback
570 * that "adapts" al_do_multiline_ustr to al_do_multiline_text.
571 */
do_multiline_text_cb(int line_num,const ALLEGRO_USTR * line,void * extra)572 static bool do_multiline_text_cb(int line_num, const ALLEGRO_USTR *line,
573 void *extra) {
574 DO_MULTILINE_TEXT_EXTRA *s = extra;
575
576 return s->callback(line_num, al_cstr(line), al_ustr_size(line), s->extra);
577 }
578
579
580
581 /* Function: al_do_multiline_text
582 */
al_do_multiline_text(const ALLEGRO_FONT * font,float max_width,const char * text,bool (* cb)(int line_num,const char * line,int size,void * extra),void * extra)583 void al_do_multiline_text(const ALLEGRO_FONT *font,
584 float max_width, const char *text,
585 bool (*cb)(int line_num, const char *line, int size, void *extra),
586 void *extra)
587 {
588 ALLEGRO_USTR_INFO info;
589 DO_MULTILINE_TEXT_EXTRA extra2;
590 ASSERT(font);
591 ASSERT(text);
592
593 extra2.callback = cb;
594 extra2.extra = extra;
595 al_do_multiline_ustr(font, max_width, al_ref_cstr(&info, text),
596 do_multiline_text_cb, &extra2);
597 }
598
599
600
601 /* Helper struct for al_draw_multiline_ustr. */
602 typedef struct DRAW_MULTILINE_USTR_EXTRA {
603 const ALLEGRO_FONT *font;
604 ALLEGRO_COLOR color;
605 float x;
606 float y;
607 float line_height;
608 int flags;
609 } DRAW_MULTILINE_USTR_EXTRA;
610
611
612
613 /* The function draw_multiline_ustr_cb is the helper callback
614 * that implements the actual drawing for al_draw_multiline_ustr.
615 */
draw_multiline_ustr_cb(int line_num,const ALLEGRO_USTR * line,void * extra)616 static bool draw_multiline_ustr_cb(int line_num, const ALLEGRO_USTR *line,
617 void *extra) {
618 DRAW_MULTILINE_USTR_EXTRA *s = extra;
619 float y;
620
621 y = s->y + (s->line_height * line_num);
622 al_draw_ustr(s->font, s->color, s->x, y, s->flags, line);
623 return true;
624 }
625
626
627
628 /* Function: al_draw_multiline_ustr
629 */
al_draw_multiline_ustr(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x,float y,float max_width,float line_height,int flags,const ALLEGRO_USTR * ustr)630 void al_draw_multiline_ustr(const ALLEGRO_FONT *font,
631 ALLEGRO_COLOR color, float x, float y, float max_width, float line_height,
632 int flags, const ALLEGRO_USTR *ustr)
633 {
634 DRAW_MULTILINE_USTR_EXTRA extra;
635 ASSERT(font);
636 ASSERT(ustr);
637
638 extra.font = font;
639 extra.color = color;
640 extra.x = x;
641 extra.y = y;
642 if (line_height < 1) {
643 extra.line_height = al_get_font_line_height(font);
644 }
645 else {
646 extra.line_height = line_height;
647 }
648 extra.flags = flags;
649
650 al_do_multiline_ustr(font, max_width, ustr, draw_multiline_ustr_cb, &extra);
651 }
652
653
654
655 /* Function: al_draw_multiline_text
656 */
al_draw_multiline_text(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x,float y,float max_width,float line_height,int flags,const char * text)657 void al_draw_multiline_text(const ALLEGRO_FONT *font,
658 ALLEGRO_COLOR color, float x, float y, float max_width, float line_height,
659 int flags, const char *text)
660 {
661 ALLEGRO_USTR_INFO info;
662 ASSERT(font);
663 ASSERT(text);
664
665 al_draw_multiline_ustr(font, color, x, y, max_width, line_height, flags,
666 al_ref_cstr(&info, text));
667 }
668
669
670
671 /* Function: al_draw_multiline_textf
672 */
al_draw_multiline_textf(const ALLEGRO_FONT * font,ALLEGRO_COLOR color,float x,float y,float max_width,float line_height,int flags,const char * format,...)673 void al_draw_multiline_textf(const ALLEGRO_FONT *font,
674 ALLEGRO_COLOR color, float x, float y, float max_width, float line_height,
675 int flags, const char *format, ...)
676 {
677 ALLEGRO_USTR *buf;
678 va_list ap;
679 ASSERT(font);
680 ASSERT(format);
681
682 va_start(ap, format);
683 buf = al_ustr_new("");
684 al_ustr_vappendf(buf, format, ap);
685 va_end(ap);
686
687 al_draw_multiline_ustr(font, color, x, y, max_width, line_height, flags,
688 buf);
689
690 al_ustr_free(buf);
691 }
692
693
694 /* Function: al_set_fallback_font
695 */
al_set_fallback_font(ALLEGRO_FONT * font,ALLEGRO_FONT * fallback)696 void al_set_fallback_font(ALLEGRO_FONT *font, ALLEGRO_FONT *fallback)
697 {
698 font->fallback = fallback;
699 }
700
701 /* Function: al_get_fallback_font
702 */
al_get_fallback_font(ALLEGRO_FONT * font)703 ALLEGRO_FONT *al_get_fallback_font(ALLEGRO_FONT *font)
704 {
705 return font->fallback;
706 }
707
708
709 /* vim: set sts=3 sw=3 et: */
710