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