1 /* This code is (C) AllegroGL contributors, and double licensed under
2 * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3 */
4 /** \file aglf.c
5 * \brief Text output and font support in OpenGL.
6 */
7
8 #include <math.h>
9 #include <string.h>
10 #include <stdio.h>
11
12 #include "allegro.h"
13
14 #include "alleggl.h"
15 #include "allglint.h"
16
17 #ifdef ALLEGRO_MACOSX
18 #include <OpenGL/glu.h>
19 #else
20 #include <GL/glu.h>
21 #endif
22
23 #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGROGL_GENERIC_DRIVER
24 #include <xalleg.h>
25 #include <GL/glx.h>
26 #endif
27
28 #define PREFIX_E "agl-font ERROR: "
29
30
31
32 static int aglf_font_generation_mode = AGL_FONT_POLYGONS;
33
34
35 /* find_range:
36 * Searches a font for a specific character.
37 */
find_range(AL_CONST FONT_AGL_DATA * f,int c)38 static AL_CONST FONT_AGL_DATA *find_range(AL_CONST FONT_AGL_DATA *f, int c) {
39
40 while (f) {
41 if ((c >= f->start) && (c < f->end))
42 return f;
43
44 f = f->next;
45 }
46
47 return NULL;
48 }
49
50
51
52 /* allegro_gl_printf(FONT *f, float x, float y, float z, int color,
53 char *format, ...) */
54 /** Equivalent to:
55 * <pre>
56 * r = getr(color);
57 * g = getg(color);
58 * b = getb(color);
59 * a = geta(color);
60 * glColor4f(r, g, b, a);
61 * allegro_gl_printf_ex(f, x, y, z,
62 * format, ...);
63 * </pre>
64 *
65 * Note that the current primary color is not preserved.
66 */
allegro_gl_printf(AL_CONST FONT * f,float x,float y,float z,int color,AL_CONST char * format,...)67 int allegro_gl_printf(AL_CONST FONT *f, float x, float y, float z, int color,
68 AL_CONST char *format, ...) {
69
70 #define BUF_SIZE 1024
71 char buf[BUF_SIZE];
72 va_list ap;
73
74 if (!__allegro_gl_valid_context)
75 return 0;
76
77 /* Get the string */
78 va_start(ap, format);
79 uvszprintf(buf, BUF_SIZE, format, ap);
80 va_end(ap);
81
82 #undef BUF_SIZE
83
84 /* Set color */
85 {
86 GLubyte c[4];
87 c[0] = (GLubyte)getr(color);
88 c[1] = (GLubyte)getg(color);
89 c[2] = (GLubyte)getb(color);
90 c[3] = (__allegro_gl_use_alpha && bitmap_color_depth(screen) == 32)
91 ? (GLubyte)geta(color) : 255;
92
93 glColor4ubv(c);
94 }
95
96 return allegro_gl_printf_ex(f, x, y, z, buf);
97 }
98
99
100
101 /* allegro_gl_printf_ex(FONT *f, float x, float y, float z,
102 * char *format, ...)
103 */
104 /** Prints a formatted string (printf style) on the screen.
105 *
106 * \param f Which font to use.
107 * \param x,y,z Coordinates to print at. They specify the top-left
108 * corner of the text position.
109 * \param format The format string (see printf() for details)
110 *
111 * For bitmap fonts, the raster position is set to (x,y),
112 * 'z' is ignored.
113 * The current modelview matrix applies to this code so you may want to
114 * use glLoadIdentity() beforehand. On the other hand, you can use the
115 * modelview matrix to apply transformations to the text. This will only work
116 * with textured or vector (outline) fonts.
117 * This function only accepts AllegroGL formated fonts, as converted by
118 * allegro_gl_convert_allegro_font(), or loaded by
119 * allegro_gl_load_system_font() or allegro_gl_load_system_font_ex().
120 *
121 * Texturing must be enabled for this function to work with
122 * #AGL_FONT_TYPE_TEXTURED fonts.
123 *
124 * Remember to use <code>glEnable(GL_TEXTURE_2D)</code> to enable texturing.
125 *
126 * The resulting size may not be what you expect. For bitmaped fonts,
127 * there is nothing you can do about this appart changing the font itself.
128 * Textured and Vector fonts are more flexible, in that you can use
129 * glScale to adjust the size of the characters.
130 *
131 * If you need to draw the text without the black backround, we suggest
132 * you set up a proper blending mode prior to drawing the text, such as:
133 * <pre>
134 * glEnable(GL_BLEND);
135 * glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR);
136 * </pre>
137 *
138 * If you want to emulate the Allegro drawing mode (no blending at all),
139 * then you should use the folowing code instead:
140 *
141 * <pre>
142 * glDisable(GL_DEPTH_TEST);
143 * glEnable(GL_BLEND);
144 *
145 * glBlendFunc(GL_DST_COLOR, GL_ZERO);
146 * allegro_gl_printf();
147 *
148 * glBlendFunc(GL_ONE, GL_ONE);
149 * allegro_gl_printf(); // Same as the one above!
150 *
151 * glEnable(GL_DEPTH_TEST);
152 * </pre>
153 *
154 * Have a look at NeHe's Tutorial #20 for details on this technique.
155 * http://nehe.gamedev.net/
156 *
157 * The most flexible way to use fonts, though, is to use alpha textures
158 * based on a greyscale font. Set the texture format to
159 * <code>GL_ALPHA4</code> or <code>GL_ALPHA8</code> before creating the
160 * (textured) font. Then you can set the colour and blend modes like so:
161 *
162 * <pre>
163 * glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
164 * allegro_gl_printf_ex(my_font, x, y, z, "Hi!")
165 * </pre>
166 *
167 * \return The number of characters printed.
168 */
allegro_gl_printf_ex(AL_CONST FONT * f,float x,float y,float z,AL_CONST char * format,...)169 int allegro_gl_printf_ex(AL_CONST FONT *f, float x, float y, float z,
170 AL_CONST char *format, ...) {
171 #define BUF_SIZE 1024
172 char buf[BUF_SIZE];
173 va_list ap;
174
175 AL_CONST FONT_AGL_DATA *range = NULL;
176 int c, pos = 0;
177 int count = 0;
178 AL_CONST FONT_AGL_DATA *d;
179 GLint vert_order, cull_mode;
180 GLint matrix_mode;
181
182 int restore_rasterpos = 0;
183 GLuint old_texture_bind = 0;
184 GLfloat old_raster_pos[4];
185
186
187 if (!__allegro_gl_valid_context)
188 return 0;
189
190 /* Check arguments */
191 if (!format || !f) {
192 TRACE(PREFIX_E "agl_printf: Null parameter\n");
193 return 0;
194 }
195
196 if (f->vtable != font_vtable_agl) {
197 TRACE(PREFIX_E "agl_printf: Font parameter isn't of the AGL "
198 "type.\n");
199 return 0;
200 }
201
202 d = (AL_CONST FONT_AGL_DATA*)f->data;
203
204 /* Get the string */
205 va_start(ap, format);
206 uvszprintf(buf, BUF_SIZE, format, ap);
207 va_end(ap);
208
209 #undef BUF_SIZE
210
211 glGetIntegerv(GL_MATRIX_MODE, &matrix_mode);
212 glGetIntegerv(GL_FRONT_FACE, &vert_order);
213 glGetIntegerv(GL_CULL_FACE_MODE, &cull_mode);
214
215 glMatrixMode(GL_MODELVIEW);
216 glPushMatrix();
217
218 glFrontFace(GL_CW);
219 glCullFace(GL_BACK);
220
221 { GLint temp;
222 glGetIntegerv(GL_TEXTURE_BINDING_2D, &temp);
223 old_texture_bind = (GLuint)temp;
224 }
225
226 if (d->type == AGL_FONT_TYPE_BITMAP) {
227 glTranslatef(0, 0, -1);
228 glBindTexture(GL_TEXTURE_2D, 0);
229
230 glGetFloatv(GL_CURRENT_RASTER_POSITION, old_raster_pos);
231 glRasterPos2f(x, y);
232 restore_rasterpos = 1;
233 }
234 else if (d->type == AGL_FONT_TYPE_OUTLINE) {
235 glTranslatef(x, y, z);
236 glBindTexture(GL_TEXTURE_2D, 0);
237 }
238 else if (d->type == AGL_FONT_TYPE_TEXTURED) {
239 glTranslatef(x, y, z);
240 }
241
242
243 while ((c = ugetc(buf + pos)) != 0) {
244
245 pos += ucwidth(c);
246
247 if ((!range) || (c < range->start) || (c >= range->end)) {
248 /* search for a suitable character range */
249 range = find_range(d, c);
250
251 if (!range) {
252 range = find_range(d, (c = '^'));
253
254 if (!range)
255 continue;
256 }
257 }
258
259 /* Set up texture */
260 if (d->type == AGL_FONT_TYPE_TEXTURED) {
261 glBindTexture(GL_TEXTURE_2D, range->texture);
262 }
263
264 /* draw the character */
265 c -= range->start;
266 c += range->list_base;
267
268 glCallList(c);
269
270 count++;
271 }
272
273 glPopMatrix();
274
275 glMatrixMode(matrix_mode);
276 glFrontFace(vert_order);
277 glCullFace(cull_mode);
278
279 glBindTexture(GL_TEXTURE_2D, old_texture_bind);
280
281 if (restore_rasterpos) {
282 glRasterPos4fv(old_raster_pos);
283 }
284
285 return count;
286 }
287
288
289
290 #ifndef ALLEGROGL_GENERIC_DRIVER
291 #ifdef ALLEGRO_WINDOWS
292
win_load_system_font(char * name,int type,int style,int w,int h,float depth,int start,int end)293 static FONT *win_load_system_font(char *name, int type, int style, int w, int h, float depth, int start, int end) {
294
295 HFONT hFont;
296
297 FONT_AGL_DATA *data;
298 FONT *ret;
299
300 ret = malloc(sizeof(FONT));
301 if (!ret) {
302 TRACE(PREFIX_E "win_load_system_font: Ran out of memory "
303 "while allocating %i bytes\n", sizeof(FONT));
304 return NULL;
305 }
306 data = malloc(sizeof(FONT_AGL_DATA));
307 if (!data) {
308 free(ret);
309 TRACE(PREFIX_E "win_load_system_font: Ran out of memory "
310 "while allocating %i bytes\n", sizeof(FONT_AGL_DATA));
311 return NULL;
312 }
313 ret->vtable = font_vtable_agl;
314 ret->data = data;
315
316 data->list_base = glGenLists(end - start);
317 data->start = start;
318 data->end = end;
319 data->next = NULL;
320 data->is_free_chunk = 0;
321
322 if (type == AGL_FONT_TYPE_BITMAP || type == AGL_FONT_TYPE_DONT_CARE) {
323
324 HDC dc;
325
326 hFont = CreateFont( -h, w,
327 0, 0,
328 (style & AGL_FONT_STYLE_BOLD) ? FW_BOLD
329 : ((style & AGL_FONT_STYLE_BLACK) ? FW_BLACK : FW_NORMAL),
330 ((style & AGL_FONT_STYLE_ITALIC) ? TRUE : FALSE),
331 ((style & AGL_FONT_STYLE_UNDERLINE) ? TRUE : FALSE),
332 ((style & AGL_FONT_STYLE_STRIKEOUT) ? TRUE : FALSE),
333 ANSI_CHARSET,
334 OUT_TT_PRECIS,
335 CLIP_DEFAULT_PRECIS,
336 (style & AGL_FONT_STYLE_ANTI_ALIASED) ? ANTIALIASED_QUALITY
337 : DEFAULT_QUALITY,
338 FF_DONTCARE | DEFAULT_PITCH,
339 name);
340
341 dc = GetDC(win_get_window());
342
343 SelectObject(dc, hFont);
344
345 wglUseFontBitmaps(dc, start, end - start, data->list_base);
346 data->type = AGL_FONT_TYPE_BITMAP;
347 data->data = NULL;
348 }
349 else if (type == AGL_FONT_TYPE_OUTLINE) {
350 HDC dc;
351
352 GLYPHMETRICSFLOAT *gmf;
353 gmf = malloc(sizeof(GLYPHMETRICSFLOAT) * (end - start));
354 memset(gmf, 0, sizeof(GLYPHMETRICSFLOAT) * (end - start));
355
356 hFont = CreateFont( -h, w,
357 0, 0,
358 (style & AGL_FONT_STYLE_BOLD) ? FW_BOLD
359 : ((style & AGL_FONT_STYLE_BLACK) ? FW_BLACK : FW_NORMAL),
360 ((style & AGL_FONT_STYLE_ITALIC) ? TRUE : FALSE),
361 ((style & AGL_FONT_STYLE_UNDERLINE) ? TRUE : FALSE),
362 ((style & AGL_FONT_STYLE_STRIKEOUT) ? TRUE : FALSE),
363 ANSI_CHARSET,
364 OUT_TT_PRECIS,
365 CLIP_DEFAULT_PRECIS,
366 (style & AGL_FONT_STYLE_ANTI_ALIASED) ? ANTIALIASED_QUALITY
367 : DEFAULT_QUALITY,
368 FF_DONTCARE | DEFAULT_PITCH,
369 name);
370
371 dc = GetDC(win_get_window());
372
373 SelectObject(dc, hFont);
374 wglUseFontOutlines(dc, start, end - start, data->list_base,
375 0.0, depth, (aglf_font_generation_mode == AGL_FONT_POLYGONS)
376 ? WGL_FONT_POLYGONS : WGL_FONT_LINES, gmf);
377
378 data->type = AGL_FONT_TYPE_OUTLINE;
379 data->data = gmf;
380 }
381
382 return ret;
383 }
384 #endif
385
386
387
388 #ifdef ALLEGRO_WITH_XWINDOWS
x_load_system_font(char * name,int type,int style,int w,int h,float depth,int start,int end)389 static FONT *x_load_system_font(char *name, int type, int style, int w, int h,
390 float depth, int start, int end) {
391 FONT_AGL_DATA *data;
392 FONT *ret;
393 XFontStruct *xfont;
394
395 ret = malloc(sizeof(FONT));
396 if (!ret) {
397 TRACE(PREFIX_E "x_load_system_font: Ran out of memory "
398 "while allocating %zi bytes\n", sizeof(FONT));
399 return NULL;
400 }
401 data = malloc(sizeof(FONT_AGL_DATA));
402 if (!data) {
403 free(ret);
404 TRACE(PREFIX_E "x_load_system_font: Ran out of memory "
405 "while allocating %zi bytes\n", sizeof(FONT_AGL_DATA));
406 return NULL;
407 }
408 ret->vtable = font_vtable_agl;
409 ret->data = data;
410
411 data->list_base = glGenLists(end - start);
412 data->start = start;
413 data->end = end;
414 data->next = NULL;
415 data->is_free_chunk = 0;
416
417 if (type == AGL_FONT_TYPE_BITMAP || type == AGL_FONT_TYPE_DONT_CARE) {
418 char buf[256], major_type[256], minor_type[2];
419
420 usprintf(major_type, "medium");
421 if (style & AGL_FONT_STYLE_BOLD)
422 usprintf(major_type, "bold");
423 minor_type[0] = (style & AGL_FONT_STYLE_ITALIC) ? 'i' : 'r';
424 minor_type[1] = '\0';
425
426 usprintf(buf, "-*-%s-%s-%s-normal-*-%i-*-*-*-*-*-*-*", name,
427 major_type, minor_type, h);
428 /* Load the font */
429 xfont = XLoadQueryFont(_xwin.display, buf);
430 if (!xfont) {
431 free(ret);
432 free(data);
433 TRACE(PREFIX_E "x_load_system_font: Failed to load "
434 "%s\n", buf);
435 return NULL;
436 }
437 glXUseXFont(xfont->fid, start, end - start, data->list_base);
438 data->type = AGL_FONT_TYPE_BITMAP;
439 data->data = NULL;
440 XFreeFont(_xwin.display, xfont);
441 }
442 else {
443 /* Not Yet Implemented */
444 return NULL;
445 }
446
447 return ret;
448 }
449 #endif
450 #endif /* ALLEGROGL_GENERIC_DRIVER */
451
452
453
454 /* void allegro_gl_set_font_generation_mode(int mode) */
455 /** Set the font generation mode for system fonts.
456 *
457 * \b Note: This function is deprecated and will be removed
458 * in a future version.
459 *
460 * \param mode Can be either #AGL_FONT_POLYGONS or #AGL_FONT_LINES.
461 * for creating polygonal or line characters.
462 * Default is #AGL_FONT_POLYGONS.
463 *
464 * Subsequent calls to allegro_gl_load_system_font() and
465 * allegro_gl_load_system_font_ex() may be affected by this function.
466 *
467 * \deprecated
468 */
allegro_gl_set_font_generation_mode(int mode)469 void allegro_gl_set_font_generation_mode(int mode) {
470 aglf_font_generation_mode = mode;
471 return;
472 }
473
474
475
476 /* FONT *allegro_gl_load_system_font(char *name, int style, int w, int h) */
477 /** Short hand for aglf_load_system_font_ex(name, #AGL_FONT_TYPE_OUTLINE,
478 * style, w, h, 0.0f, 32, 256)
479 *
480 * \b Note: This function is deprecated and will be removed
481 * in a future version.
482 *
483 * \deprecated
484 */
allegro_gl_load_system_font(char * name,int style,int w,int h)485 FONT *allegro_gl_load_system_font(char *name, int style, int w, int h) {
486
487 return allegro_gl_load_system_font_ex(name, AGL_FONT_TYPE_OUTLINE,
488 style, w, h, 0.0f, 32, 256);
489 }
490
491
492
493 /* FONT *allegro_gl_load_system_font_ex(char *name, int type, int style,
494 int w, int h, float depth, int start, int end) */
495 /** Loads a system font.
496 *
497 * \b Note: This function is deprecated and will be removed
498 * in a future version.
499 *
500 * \param name The name of the system font ("Courrier" or "Arial"
501 * for example)
502 * \param type The font type to generate (#AGL_FONT_TYPE_DONT_CARE,
503 * #AGL_FONT_TYPE_BITMAP, #AGL_FONT_TYPE_OUTLINE)
504 * \param style The text decorations of the font to create
505 * (#AGL_FONT_STYLE_ITALIC, etc - can be or'ed together)
506 * \param w,h The size of the font characters that will be created.
507 * \param depth The z-depth of the font. 0.0f is flat, 1.0f is very
508 * thick
509 * \param start,end The range of characters to create from 'start'
510 * (included) to 'end' (excluded) in UTF-8 format
511 * (ANSI only on Windows).
512 *
513 * \note
514 * - In #AGL_FONT_TYPE_OUTLINE type, some system fonts seem to be unresponsive
515 * to the size paramaters (w and h). You cannot depend on either a system
516 * font being present, or the font being what you expect - it is possible to
517 * have two fonts with the same name but with different graphic data.
518 * - BITMAP fonts have no depth.
519 * - The width and height parameters are also system dependent, and may or
520 * may not work with the selected font.
521 *
522 * \return The loaded font, or NULL on error.
523 *
524 * \deprecated
525 */
allegro_gl_load_system_font_ex(char * name,int type,int style,int w,int h,float depth,int start,int end)526 FONT *allegro_gl_load_system_font_ex(char *name, int type, int style,
527 int w, int h, float depth, int start, int end) {
528
529 FONT *ret = NULL;
530
531 if (!__allegro_gl_valid_context)
532 return NULL;
533
534 if (!name) {
535 TRACE(PREFIX_E "load_system_font: Nameless font\n");
536 return NULL;
537 }
538
539 /* Load a system font */
540
541 #ifndef ALLEGROGL_GENERIC_DRIVER
542 #ifdef ALLEGRO_WINDOWS
543 ret = win_load_system_font(name, type, style, w, h, depth, start, end);
544 #elif defined ALLEGRO_UNIX
545 XLOCK();
546 ret = x_load_system_font(name, type, style, w, h, depth, start, end);
547 XUNLOCK();
548 #else
549 /* Other platform */
550 #endif
551 #endif
552
553 return ret;
554 }
555
556
557
558 /** void allegro_gl_destroy_font(FONT *usefont) */
559 /** Destroys the font.
560 *
561 * \param f The AGL font to be destroyed.
562 *
563 * The allocated memory is freed, as well as any display list, or texture
564 * objects it uses.
565 *
566 * You cannot use that font anymore after calling this function.
567 * It's safe to call this function with a NULL pointer; a note will be
568 * placed in allegro.log if DEBUGMODE was defined.
569 *
570 * If NULL is passed as the font to destroy, then this function returns
571 * immediately.
572 */
allegro_gl_destroy_font(FONT * f)573 void allegro_gl_destroy_font(FONT *f) {
574
575 FONT_AGL_DATA *data;
576
577 if (!f) {
578 return;
579 }
580 if (f->vtable != font_vtable_agl) {
581 TRACE(PREFIX_E "destroy_font: Font is not of AGL type\n");
582 return;
583 }
584
585 data = f->data;
586
587 if (!data) {
588 TRACE(PREFIX_E "destroy_font: Font is inconsistent\n");
589 return;
590 }
591
592 /* Iterate through every segment of the font */
593 while (data) {
594 FONT_AGL_DATA *datanext;
595
596 /* Release all resources taken up by this font */
597 if (data->type == AGL_FONT_TYPE_BITMAP
598 || data->type == AGL_FONT_TYPE_OUTLINE
599 || data->type == AGL_FONT_TYPE_TEXTURED) {
600
601 if (__allegro_gl_valid_context) {
602 if (data->list_base)
603 glDeleteLists(data->list_base, data->end - data->start);
604 if (data->texture)
605 glDeleteTextures(1, &data->texture);
606 }
607 }
608 if (data->type == AGL_FONT_TYPE_OUTLINE) {
609 if (data->data)
610 free(data->data);
611 }
612 else if (data->type == AGL_FONT_TYPE_TEXTURED) {
613 if (data->data)
614 destroy_bitmap(data->data);
615 if (data->glyph_coords)
616 free(data->glyph_coords);
617 }
618 else if (data->type == AGL_FONT_TYPE_BITMAP) {
619 if (data->data) {
620 int i;
621 FONT_GLYPH **gl = data->data;
622 for (i = 0; i < data->end - data->start; i++) {
623 if (gl[i])
624 free(gl[i]);
625 }
626 free(gl);
627 }
628 }
629 datanext = data->next;
630
631 if (data->is_free_chunk)
632 free(data);
633
634 data = datanext;
635 }
636 free(f->data);
637
638 if (f != font)
639 free(f);
640
641 return;
642 }
643
644
645
646 /* size_t allegro_gl_list_font_textures(FONT *f, GLuint *ids, size_t max_num_id) */
647 /** List the texture ID of all textures forming the specified font.
648 *
649 * The font specified must be an AllegroGL font.
650 *
651 * If ids is not NULL, then the ID numbers of all textures used by the font
652 * are written to the GLuint array pointed by ids. The size of that array
653 * is specified by the max_num_id parameter. This function will never write
654 * more than 'max_num_id' values in the ids array.
655 *
656 * If f is NULL, then zero is returned and the ids array is never touched.
657 *
658 * If the font does not contain any textures (because it is a bitmap or outline
659 * font, for example), then zero is returned.
660 *
661 * \return Number of texture IDs that make up this font.
662 *
663 * Here are two examples of the use of this function:
664 *
665 * <pre>
666 * int num_ids = allegro_gl_list_font_textures(font, NULL, 0);
667 *
668 * GLuint *id = malloc(sizeof(GLuint) * num_ids);
669 *
670 * if (!id) {
671 * //handle error
672 * }
673 *
674 * allegro_gl_list_font_textures(font, id, num_ids);
675 *
676 * for (i = 0; i < num_ids; i++) {
677 * glBindTexture(GL_TEXTURE_2D, id[i]);
678 * // Use this texture
679 * }
680 *
681 * free(id);
682 * </pre>
683 *
684 * <pre>
685 * GLint id[10]; // Reserve a safe number
686 * GLint num_ids = allegro_gl_list_font_textures(font, id, 10);
687 * </pre>
688 */
allegro_gl_list_font_textures(FONT * f,GLuint * ids,size_t max_num_id)689 size_t allegro_gl_list_font_textures(FONT *f, GLuint *ids, size_t max_num_id) {
690
691 size_t num_ids = 0;
692 FONT_AGL_DATA *data;
693
694 if (!f) {
695 return 0;
696 }
697 if (f->vtable != font_vtable_agl) {
698 TRACE(PREFIX_E "list_font_textures: Font is not of AGL type\n");
699 return 0;
700 }
701
702 data = f->data;
703
704 if (!data) {
705 TRACE(PREFIX_E "list_font_textures: Font is inconsistent\n");
706 return 0;
707 }
708
709 if (!__allegro_gl_valid_context) {
710 return 0;
711 }
712
713 /* Iterate through all font segments */
714 while (data) {
715 if (data->texture) {
716 /* Add the texture ID in the array, if it's not NULL and if there
717 * is room.
718 */
719 if (ids && num_ids < max_num_id) {
720 ids[num_ids] = data->texture;
721 }
722 num_ids++;
723 }
724
725 data = data->next;
726 }
727
728 return num_ids;
729 }
730
731