AllegroGL: fontconv.c Source File

AllegroGL 0.4.4

- Main Page
- Related Pages
- Modules
- Files

- File List
- Globals

fontconv.c
Go to the documentation of this file.
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 */
13 #include <math.h>
14 #include <string.h>
15 #include <stdio.h>
16
17 #include <allegro.h>
18 #include <allegro/internal/aintern.h>
19
20 #include "alleggl.h"
21 #include "allglint.h"
22
23 #ifdef ALLEGRO_MACOSX
24 #include <OpenGL/glu.h>
25 #else
26 #include <GL/glu.h>
27 #endif
28
29 #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGROGL_GENERIC_DRIVER
30 #include <xalleg.h>
31 #include <GL/glx.h>
32 #endif
33
34 #define PREFIX_I "agl-font INFO: "
35 #define PREFIX_W "agl-font WARNING: "
36 #define PREFIX_E "agl-font ERROR: "
37
38
39 /* Number of pixels between characters in a textured font.
40 */
41 #define FONT_CHARACTER_SPACING 2
42
43 /* Uncomment to have the font generator dump screenshots of the textures it
44 * generates.
45 */
46 /* #define SAVE_FONT_SCREENSHOT */
47
48
49 static int agl_get_font_height(AL_CONST FONT *f);
50 static int agl_char_length(const FONT *f, int ch);
51 static int agl_text_length(const FONT *f, const char *str);
52
53 static int agl_get_font_ranges(FONT *f);
54 static int agl_get_font_range_begin(FONT *f, int range);
55 static int agl_get_font_range_end(FONT *f, int range);
56 static FONT *agl_extract_font_range(FONT *f, int start, int end);
57 static FONT *agl_merge_fonts(FONT *f1, FONT *f2);
58
59 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0)
60 static int agl_transpose_font(FONT *f, int drange);
61 #endif
62
63
64 FONT_VTABLE _agl_font_vtable = {
65 agl_get_font_height,
66 agl_char_length,
67 agl_text_length,
68 NULL, /* render_char */
69 NULL, /* render */
70 allegro_gl_destroy_font,
71 agl_get_font_ranges,
72 agl_get_font_range_begin,
73 agl_get_font_range_end,
74 agl_extract_font_range,
75 agl_merge_fonts,
76 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0)
77 agl_transpose_font
78 #endif
79 };
80
81
82 FONT_VTABLE *font_vtable_agl = &_agl_font_vtable;
83
84 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
85 void *src, int *height);
86 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA **dest, FONT *f,
87 void *src, int *height, float scale, GLint format);
88 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format, int has_alpha);
89 static int aglf_check_texture(BITMAP *bmp, GLint format, int has_alpha);
90 static BITMAP* look_for_texture(int beg, int end, AGL_GLYPH *glyphs,
91 int max_w, int max_h, int total_area,
92 GLint format, int has_alpha);
93
94
95
96 union mixed_ptr {
97 FONT_MONO_DATA* mf;
98 FONT_COLOR_DATA* cf;
99 void *ptr;
100 };
101
102
103 /* Stores info about a texture size */
104 typedef struct texture_size {
105 int w, h;
106 } texture_size;
107
108
109
110 static int agl_get_font_height(AL_CONST FONT *f) {
111 return f->height;
112 }
113
114
115 /* iroundf:
116 * Round float to nearest integer, away from zero.
117 */
118 static int iroundf(float v) {
119 float f = floor(v);
120 float c = ceil(v);
121
122 if (v >= 0) {
123 /* distance to ceil smaller than distance to floor */
124 if ((c - v) < (v - f))
125 return (int)c;
126 else
127 return (int)f;
128 }
129 else {
130 /* distance to ceil smaller than distance to floor */
131 if ((c - v) < (v - f))
132 return (int)f;
133 else
134 return (int)c;
135 }
136 }
137
138
139
140 /* agl_char_length_fractional:
141 * Returns the width, in fractional pixels of the given character.
142 */
143 static float agl_char_length_fractional(const FONT *f, int ch) {
144 FONT_AGL_DATA *fad = f->data;
145
146 if (fad->type == AGL_FONT_TYPE_TEXTURED) {
147 while (fad) {
148 if (ch >= fad->start && ch < fad->end) {
149 AGL_GLYPH *coords = &(fad->glyph_coords[ch - fad->start]);
150 return (coords->offset_x + coords->w + coords->offset_w)
151 / fabs(fad->scale);
152 }
153
154 fad = fad->next;
155 }
156 }
157 else if (fad->type == AGL_FONT_TYPE_BITMAP) {
158 while (fad) {
159 if (ch >= fad->start && ch < fad->end) {
160 FONT_GLYPH **gl = fad->data;
161 return gl[ch - fad->start]->w;
162 }
163
164 fad = fad->next;
165 }
166 }
167
168 /* if we don't find the character, then search for the missing
169 * glyph, but don't get stuck in a loop. */
170 if (ch != allegro_404_char)
171 return agl_char_length_fractional(f, allegro_404_char);
172
173 return 0;
174 }
175
176
177
178 /* agl_char_length:
179 * font vtable entry
180 * Returns the width, in pixels of the given character.
181 */
182 static int agl_char_length(const FONT *f, int ch) {
183 return iroundf(agl_char_length_fractional(f, ch));
184 }
185
186
187
188 /* agl_text_length:
189 * font vtable entry
190 * Returns the length, in pixels, of a string as rendered in a font.
191 */
192 static int agl_text_length(const FONT *f, const char *str) {
193 int ch = 0;
194 float l = 0;
195 const char *p = str;
196 ASSERT(f);
197 ASSERT(str);
198
199 while ( (ch = ugetxc(&p)) ) {
200 l += agl_char_length_fractional(f, ch);
201 }
202
203 return iroundf(l);
204 }
205
206
207
208 /* agl_get_font_ranges:
209 * font vtable entry
210 * Returns the number of character ranges in a font, or -1 if that information
211 * is not available.
212 */
213 static int agl_get_font_ranges(FONT *f) {
214 FONT_AGL_DATA *fad;
215 int ranges = 0;
216
217 if (!f)
218 return 0;
219
220 fad = (FONT_AGL_DATA*)(f->data);
221
222 while (fad) {
223 FONT_AGL_DATA *next = fad->next;
224
225 ranges++;
226 if (!next)
227 return ranges;
228 fad = next;
229 }
230
231 return -1;
232 }
233
234
235
236 /* agl_get_font_range_begin:
237 * font vtable entry
238 * Get first character for font.
239 */
240 static int agl_get_font_range_begin(FONT *f, int range) {
241 FONT_AGL_DATA *fad;
242 int n = 0;
243
244 if (!f || !f->data)
245 return -1;
246
247 if (range < 0)
248 range = 0;
249
250 fad = (FONT_AGL_DATA*)(f->data);
251 while (fad && n <= range) {
252 FONT_AGL_DATA *next = fad->next;
253
254 if (!next || range == n)
255 return fad->start;
256 fad = next;
257 n++;
258 }
259
260 return -1;
261 }
262
263
264
265 /* agl_get_font_range_end:
266 * font vtable entry
267 * Get last character for font range.
268 */
269 static int agl_get_font_range_end(FONT *f, int range) {
270 FONT_AGL_DATA* fad = 0;
271 int n = 0;
272
273 if (!f || !f->data)
274 return -1;
275
276 fad = (FONT_AGL_DATA*)(f->data);
277
278 while (fad && (n <= range || range == -1)) {
279 FONT_AGL_DATA *next = fad->next;
280 if (!next || range == n)
281 return fad->end - 1;
282 fad = next;
283 n++;
284 }
285
286 return -1;
287 }
288
289
290
291 /* Creates a call lists from given glyph coords. Returns list base.*/
292 static int create_textured_font_call_lists(AGL_GLYPH *coords, int max, BITMAP *bmp,
293 float scale, int *height) {
294 GLuint list;
295 int i;
296
297 int rev = scale < 0 ? 1 : 0;
298 scale = fabs(scale);
299
300 list = glGenLists(max);
301
302 for (i = 0; i < max; i++) {
303 /* Coords of glyph in texture (texture coords) */
304 float tx = (float)coords[i].x / bmp->w;
305 float ty = 1.0 - (float)coords[i].y / bmp->h;
306 /* Size of glyph in texture (texture coords) */
307 float dtx = (float)(coords[i].w) / bmp->w;
308 float dty = (float)(coords[i].h) / bmp->h;
309
310 /* Offset to apply to glyph (output coords) */
311 float xoffs = (float)coords[i].offset_x / scale;
312 float yoffs = (float)coords[i].offset_y / scale;
313 /* Size of rendered glyph (output coords) */
314 float woffs = (float)coords[i].w / scale;
315 float hoffs = (float)coords[i].h / scale;
316
317 /* Size of overall screen character including dead space */
318 float sizew = (float)(coords[i].offset_x + coords[i].w
319 + coords[i].offset_w) / scale;
320 int sizeh = iroundf((coords[i].offset_y + coords[i].h
321 + coords[i].offset_h) / scale);
322
323 if ((*height) < sizeh)
324 *height = sizeh;
325
326 if (rev) {
327 hoffs = -hoffs;
328 yoffs = -yoffs;
329 }
330
331 glNewList(list + i, GL_COMPILE);
332
333 glBegin(GL_QUADS);
334 glTexCoord2f(tx, ty);
335 glVertex2f(xoffs, -yoffs);
336
337 glTexCoord2f(tx + dtx, ty);
338 glVertex2f(xoffs + woffs, -yoffs);
339
340 glTexCoord2f(tx + dtx, ty - dty);
341 glVertex2f(xoffs + woffs, -yoffs - hoffs);
342
343 glTexCoord2f(tx, ty - dty);
344 glVertex2f(xoffs, -yoffs - hoffs);
345 glEnd();
346
347 glTranslatef(sizew, 0, 0);
348
349 glEndList();
350 }
351
352 return list;
353 }
354
355
356
357 /* copy_glyph_range:
358 * Copies part of glyph range.
359 */
360 static FONT_AGL_DATA* copy_glyph_range(FONT_AGL_DATA *fad, int start, int end,
361 int *height) {
362 int i, count, w = 0, h = 0;
363 AGL_GLYPH *coords;
364 BITMAP *bmp, *srcbmp;
365 FONT_AGL_DATA *newfad = NULL;
366
367 if (fad->type != AGL_FONT_TYPE_TEXTURED)
368 return NULL;
369
370 count = end - start;
371
372 coords = malloc(count * sizeof (AGL_GLYPH));
373
374 /* for now, just copy glyph coords of the range */
375 for (i = 0; i < count; i++) {
376 coords[i] = fad->glyph_coords[start - fad->start + i];
377 coords[i].glyph_num = i;
378 }
379
380 /* calculate the width of the glyphs and find the max height */
381 for (i = 0; i < count; i++) {
382 int hh = coords[i].h + coords[i].offset_y + coords[i].offset_h;
383 if (h < hh)
384 h = hh;
385 w += coords[i].w + coords[i].offset_w + coords[i].offset_x;
386 }
387
388 srcbmp = (BITMAP*)fad->data;
389
390 /* allocate a new bitmap to hold new glyphs */
391 w = __allegro_gl_make_power_of_2(w);
392 h = __allegro_gl_make_power_of_2(h);
393 bmp = create_bitmap_ex(bitmap_color_depth(srcbmp), w, h);
394 if (!bmp) {
395 TRACE(PREFIX_E "copy_glyph_range: Unable to create bitmap of size"
396 "%ix%i pixels!\n", w, h);
397 free(coords);
398 return NULL;
399 }
400
401 if (__allegro_gl_get_num_channels(fad->format) == 4) {
402 clear_to_color(bmp, bitmap_mask_color(bmp));
403 }
404 else {
405 clear_bitmap(bmp);
406 }
407
408 /* blit every glyph from the range to the new bitmap */
409 w = 0;
410 for (i = 0; i < count; i++) {
411 int ch = start - fad->start + i;
412 int ww = coords[i].w + coords[i].offset_w + coords[i].offset_x;
413 blit(srcbmp, bmp, fad->glyph_coords[ch].x, 0, w, 0, ww, bmp->h);
414 /* fix new glyphs coords while here */
415 coords[i].x = w;
416 w += ww;
417 }
418
419 newfad = malloc(sizeof(struct FONT_AGL_DATA));
420
421 newfad->type = AGL_FONT_TYPE_TEXTURED;
422 newfad->is_free_chunk = 0;
423 newfad->scale = fad->scale;
424 newfad->format = fad->format;
425 newfad->has_alpha = fad->has_alpha;
426 newfad->start = start;
427 newfad->end = end;
428 newfad->data = bmp;
429 newfad->glyph_coords = coords;
430 newfad->next = NULL;
431 newfad->list_base = create_textured_font_call_lists(coords, count, bmp,
432 newfad->scale, height);
433 newfad->texture = aglf_upload_texture(bmp, newfad->format, newfad->has_alpha);
434
435 return newfad;
436 }
437
438
439
440 /* agl_extract_font_range:
441 * font vtable entry
442 * Extracts a glyph range from a given font and makes a new font of it.
443 */
444 static FONT *agl_extract_font_range(FONT *f, int start, int end) {
445 FONT *retval = NULL;
446 FONT_AGL_DATA *fad, *next, *newfad = NULL;
447 int count;
448
449 if (!f)
450 return NULL;
451
452 /* check if range boundaries make sense */
453 if (start == -1 && end == -1) {
454 }
455 else if (start == -1 && end > agl_get_font_range_begin(f, -1)) {
456 }
457 else if (end == -1 && start <= agl_get_font_range_end(f, -1)) {
458 }
459 else if (start <= end && start != -1 && end != -1) {
460 }
461 else
462 return NULL;
463
464 fad = (FONT_AGL_DATA*)f->data;
465
466 /* only textured fonts are supported */
467 if (fad->type != AGL_FONT_TYPE_TEXTURED)
468 return NULL;
469
470 /* anticipate invalid range values */
471 start = MAX(start, agl_get_font_range_begin(f, -1));
472 if (end > -1) {
473 end = MIN(end, agl_get_font_range_end(f, -1));
474 }
475 else {
476 end = agl_get_font_range_end(f, -1);
477 }
478 end++;
479
480 retval = malloc(sizeof (struct FONT));
481 retval->height = 0;
482 retval->vtable = font_vtable_agl;
483
484 next = fad;
485 count = end - start;
486
487 while (next) {
488 /* find the range that is covered by the requested range
489 * check if the requested and processed ranges at least overlap
490 * or if the requested range wraps processed range.
491 */
492 if ((start >= next->start && start < next->end)
493 || (end <= next->end && end > next->start)
494 || (start < next->start && end > next->end)) {
495 int local_start, local_end;
496
497 /* extract the overlapping range */
498 local_start = MAX(next->start, start);
499 local_end = MIN(next->end, end);
500
501 if (newfad) {
502 newfad->next = copy_glyph_range(next, local_start, local_end,
503 &(retval->height));
504 newfad = newfad->next;
505 newfad->is_free_chunk = TRUE;
506 }
507 else {
508 newfad = copy_glyph_range(next, local_start, local_end,
509 &(retval->height));
510 retval->data = newfad;
511 }
512 }
513
514 next = next->next;
515 }
516
517 return retval;
518 }
519
520
521
522 /* agl_merge_fonts:
523 * font vtable entry
524 * Merges f2 with f1 and returns a new font.
525 */
526 static FONT *agl_merge_fonts(FONT *f1, FONT *f2) {
527 FONT *retval;
528 FONT_AGL_DATA *fad1, *fad2, *fad = NULL;
529 int phony = 0;
530
531 if (!f1 || !f2)
532 return NULL;
533
534 fad1 = (FONT_AGL_DATA*)f1->data;
535 fad2 = (FONT_AGL_DATA*)f2->data;
536
537 /* fonts must be textured and of the same format */
538 if (fad1->type != AGL_FONT_TYPE_TEXTURED ||
539 fad2->type != AGL_FONT_TYPE_TEXTURED)
540 return NULL;
541
542 if (fad1->format != fad2->format)
543 return NULL;
544
545 /* alloc output font */
546 retval = malloc(sizeof(struct FONT));
547 retval->vtable = font_vtable_agl;
548 retval->height = MAX(f1->height, f2->height);
549
550 while (fad1 || fad2) {
551 if (fad1 && (!fad2 || fad1->start < fad2->start)) {
552 if (fad) {
553 fad->next = copy_glyph_range(fad1, fad1->start, fad1->end,
554 &phony);
555 fad = fad->next;
556 fad->is_free_chunk = TRUE;
557 }
558 else {
559 fad = copy_glyph_range(fad1, fad1->start, fad1->end, &phony);
560 retval->data = fad;
561 }
562 fad1 = fad1->next;
563 }
564 else {
565 if (fad) {
566 fad->next = copy_glyph_range(fad2, fad2->start, fad2->end,
567 &phony);
568 fad = fad->next;
569 fad->is_free_chunk = TRUE;
570 }
571 else {
572 fad = copy_glyph_range(fad2, fad2->start, fad2->end, &phony);
573 retval->data = fad;
574 }
575 fad2 = fad2->next;
576 }
577 }
578
579 return retval;
580 }
581
582
583
584 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0)
585 /* agl_transpose_font:
586 * font vtable entry
587 * Transposes characters in a font.
588 */
589 static int agl_transpose_font(FONT *f, int drange) {
590 FONT_AGL_DATA* fad = 0;
591
592 if (!f)
593 return -1;
594
595 fad = (FONT_AGL_DATA*)(f->data);
596
597 while(fad) {
598 FONT_AGL_DATA* next = fad->next;
599 fad->start += drange;
600 fad->end += drange;
601 fad = next;
602 }
603
604 return 0;
605 }
606 #endif
607
608
609
610 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */
623 FONT *allegro_gl_convert_allegro_font(FONT *f, int type, float scale) {
624 GLint format = allegro_gl_get_texture_format(NULL);
625 return allegro_gl_convert_allegro_font_ex(f, type, scale, format);
626 }
627
628
629
630 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */
688 FONT *allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale,
689 GLint format) {
690 int max = 0, height = 0;
691 int i;
692 FONT *dest;
693 FONT_AGL_DATA *destdata;
694 int has_alpha = 0;
695
696 union {
697 FONT_MONO_DATA* mf;
698 FONT_COLOR_DATA* cf;
699 void *ptr;
700 } dat;
701
702 if (!__allegro_gl_valid_context) {
703 return NULL;
704 }
705
706 if (!f) {
707 TRACE(PREFIX_E "convert_allegro_font: Null source\n");
708 return NULL;
709 }
710
711 /* Make sure it's an Allegro font - we don't want any surprises */
712 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
713 if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color && f->vtable != font_vtable_trans) {
714 #else
715 if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color) {
716 #endif
717 TRACE(PREFIX_I "convert_allegro_font: Source font is not "
718 "in Allegro format\n");
719 return NULL;
720 }
721
722 /* No vector fonts allowed as destination */
723 if (type == AGL_FONT_TYPE_OUTLINE) {
724 /* Can't convert bitmap to vector font */
725 TRACE(PREFIX_I "convert_allegro_font: Unable to convert a "
726 "pixmap font to a vector font.\n");
727 return NULL;
728 }
729
730 /* Make sure the scaling factor is appropreate */
731 if (fabs(scale) < 0.001) {
732 TRACE(PREFIX_W "convert_allegro_font: Scaling factor might be "
733 "too small: %f\n", scale);
734 }
735
736 /* Count number of ranges */
737 max = get_font_ranges(f);
738
739 /* There should really be an API for this */
740 dest = (FONT*)malloc(sizeof(FONT));
741 if (!dest) {
742 TRACE(PREFIX_E "convert_allegro_font: Ran out of memory "
743 "while allocating %i bytes\n", (int)sizeof(FONT));
744 return NULL;
745 }
746 destdata = (FONT_AGL_DATA*)malloc(sizeof(FONT_AGL_DATA) * max);
747 if (!destdata) {
748 TRACE(PREFIX_E "convert_allegro_font: Ran out of memory "
749 "while allocating %i bytes\n", (int)sizeof(FONT_AGL_DATA) * max);
750 return NULL;
751 }
752 memset(destdata, 0, sizeof(FONT_AGL_DATA) * max);
753
754 /* Construct the linked list */
755 for (i = 0; i < max - 1; i++) {
756 destdata[i].next = &destdata[i + 1];
757 }
758 destdata[max - 1].next = NULL;
759
760 /* Set up the font */
761 dest->data = destdata;
762 dest->vtable = font_vtable_agl;
763 dest->height = 0;
764
765 destdata->type = type;
766
767 if (type == AGL_FONT_TYPE_DONT_CARE) {
768 destdata->type = AGL_FONT_TYPE_TEXTURED;
769 }
770
771 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
772 has_alpha = (f->vtable == font_vtable_trans);
773 #endif
774
775 /* Convert each range */
776 dat.ptr = f->data;
777
778 while (dat.ptr) {
779
780 destdata->has_alpha = has_alpha;
781
782 if (type == AGL_FONT_TYPE_BITMAP) {
783 aglf_convert_allegro_font_to_bitmap(destdata, f, dat.ptr, &height);
784 }
785 else if (type == AGL_FONT_TYPE_TEXTURED) {
786 aglf_convert_allegro_font_to_texture(&destdata, f, dat.ptr, &height,
787 scale, format);
788 }
789
790 if (height > dest->height) {
791 dest->height = height;
792 }
793
794 dat.ptr = (is_mono_font(f) ? (void*)dat.mf->next : (void*)dat.cf->next);
795
796 destdata = destdata->next;
797 }
798
799 return dest;
800 }
801
802
803
804 /* QSort helper for sorting glyphs according to width,
805 * then height - largest first.
806 */
807 static int sort_glyphs(const void *c1, const void *c2) {
808 AGL_GLYPH *g1 = (AGL_GLYPH*)c1;
809 AGL_GLYPH *g2 = (AGL_GLYPH*)c2;
810
811 if (g1->w < g2->w) {
812 return 1;
813 }
814 else if (g1->w == g2->w) {
815 return -g1->h + g2->h;
816 }
817 else {
818 return -1;
819 }
820 }
821
822
823
824 /* QSort helper for unsorting glyphs.
825 */
826 static int unsort_glyphs(const void *c1, const void *c2) {
827 AGL_GLYPH *g1 = (AGL_GLYPH*)c1;
828 AGL_GLYPH *g2 = (AGL_GLYPH*)c2;
829
830 return g1->glyph_num - g2->glyph_num;
831 }
832
833
834
835 /* QSort helper for sorting textures by area.
836 */
837 static int sort_textures(const void *c1, const void *c2) {
838 texture_size *t1 = (texture_size*)c1;
839 texture_size *t2 = (texture_size*)c2;
840
841 return t1->w * t1->h - t2->w * t2->h;
842 }
843
844
845
846 #ifdef SAVE_FONT_SCREENSHOT
847 static void save_shot(BITMAP *bmp) {
848
849 int i;
850 char name[128];
851
852 for (i = 0; i < 1000; i++) {
853 /* TGA, in case it is a truecolor font with alpha */
854 sprintf(name, "fonttest_%02i.tga", i);
855 if (!exists(name)) {
856 save_tga(name, bmp, NULL);
857 break;
858 }
859 }
860 }
861 #endif
862
863
864
865 /* Helper function. This will try to place all the glyphs in the bitmap the
866 * best way it can
867 */
868 static int aglf_sort_out_glyphs(BITMAP *bmp, AGL_GLYPH *glyphs, const int beg,
869 const int end) {
870
871 int i, j;
872 int last_line = 0;
873 int last_x = 0;
874
875 /* We now try to make all the glyphs fit on the bitmap */
876 for (i = 0; i < end - beg; i++) {
877 int collide = FALSE;
878
879 /* Place glyphs on last_line */
880 glyphs[i].x = last_x;
881 glyphs[i].y = last_line;
882
883 /* Check for collision */
884
885 for (j = 0; j < i; j++) {
886 if ((glyphs[i].x >= glyphs[j].x + glyphs[j].w)
887 || (glyphs[i].y >= glyphs[j].y + glyphs[j].h)
888 || (glyphs[j].x >= glyphs[i].x + glyphs[i].w)
889 || (glyphs[j].y >= glyphs[i].y + glyphs[i].h)) {
890 continue;
891 }
892 last_x = glyphs[j].x + glyphs[j].w;
893 glyphs[i].x = last_x;
894 j = 0;
895 }
896
897 if ((last_x + glyphs[i].w > bmp->w)
898 || (last_line + glyphs[i].h > bmp->h)) {
899 collide = TRUE;
900 }
901
902 if (collide) {
903 /* If there was a collision, we need to find the sprite with
904 * the smallest height that is still grater than last_line.
905 * We also need to redo this glyph.
906 */
907 int min_line = bmp->h + 1;
908 int min_glyph = -1;
909
910 for (j = 0; j < i; j++) {
911 if ( glyphs[j].y + glyphs[j].h < min_line
912 && glyphs[j].y + glyphs[j].h
913 > last_line - FONT_CHARACTER_SPACING) {
914
915 min_line = glyphs[j].y + glyphs[j].h
916 + FONT_CHARACTER_SPACING;
917 min_glyph = j;
918 }
919 }
920 /* If it can't possibly all fit, failure */
921 if (min_glyph == -1) {
922 TRACE(PREFIX_I "sort_out_glyphs: Unable to fit all glyphs into "
923 "the texture.\n");
924 return FALSE;
925 }
926 /* Otherwise, start over at the top of that glyph */
927 last_x = glyphs[min_glyph].x;
928 last_line = min_line;
929
930 /* Redo this glyph */
931 i--;
932 }
933 else {
934 last_x += glyphs[i].w + FONT_CHARACTER_SPACING;
935 }
936 }
937
938 /* All ok */
939 return TRUE;
940 }
941
942
943
944 static int split_font(FONT *f, void *source, void **dest1, void **dest2) {
945
946 union mixed_ptr range1, range2, src;
947 int colored;
948 int i;
949
950 (*dest1) = NULL;
951 (*dest2) = NULL;
952 src.ptr = source;
953
954 colored = (is_mono_font(f) ? FALSE : TRUE);
955
956 /* Allocate the ranges that we need */
957 range1.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA)
958 : sizeof(FONT_MONO_DATA));
959 if (!range1.ptr) {
960 TRACE(PREFIX_E "split_font() - Ran out of memory while "
961 "trying ot allocate %i bytes.\n",
962 colored ? (int)sizeof(FONT_COLOR_DATA)
963 : (int)sizeof(FONT_MONO_DATA));
964 return FALSE;
965 }
966
967 range2.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA)
968 : sizeof(FONT_MONO_DATA));
969 if (!range2.ptr) {
970 TRACE(PREFIX_E "split_font() - Ran out of memory while "
971 "trying to allocate %i bytes.\n",
972 colored ? (int)sizeof(FONT_COLOR_DATA)
973 : (int)sizeof(FONT_MONO_DATA));
974 free(range1.ptr);
975 return FALSE;
976 }
977
978 (*dest1) = range1.ptr;
979 (*dest2) = range2.ptr;
980
981 /* Now we split up the range */
982 if (colored) {
983 /* Half the range */
984 int mid = src.cf->begin + (src.cf->end - src.cf->begin) / 2;
985
986 range1.cf->begin = src.cf->begin;
987 range1.cf->end = mid;
988 range2.cf->begin = mid;
989 range2.cf->end = src.cf->end;
990
991 range1.cf->next = NULL;
992 range2.cf->next = NULL;
993
994 /* Split up the bitmaps */
995 range1.cf->bitmaps = malloc(sizeof(BITMAP*)
996 * (range1.cf->end - range1.cf->begin));
997 if (!range1.cf->bitmaps) {
998 TRACE(PREFIX_E "split_font() - Ran out of memory "
999 "while trying to allocate %i bytes.\n",
1000 (int)sizeof(BITMAP*) * (range1.cf->end - range1.cf->begin));
1001 free(range1.ptr);
1002 free(range2.ptr);
1003 return FALSE;
1004 }
1005
1006 range2.cf->bitmaps = malloc(sizeof(BITMAP*)
1007 * (range2.cf->end - range2.cf->begin));
1008 if (!range2.cf->bitmaps) {
1009 TRACE(PREFIX_E "split_font() - Ran out of memory "
1010 "while trying to allocate %i bytes.\n",
1011 (int)sizeof(BITMAP*) * (range2.cf->end - range2.cf->begin));
1012 free(range1.cf->bitmaps);
1013 free(range1.ptr);
1014 free(range2.ptr);
1015 return FALSE;
1016 }
1017
1018
1019 for (i = 0; i < (range1.cf->end - range1.cf->begin); i++) {
1020 range1.cf->bitmaps[i] = src.cf->bitmaps[i];
1021 }
1022 for (i = 0; i < (range2.cf->end - range2.cf->begin); i++) {
1023 range2.cf->bitmaps[i] =
1024 src.cf->bitmaps[i + range2.cf->begin - range1.cf->begin];
1025 }
1026 }
1027 else {
1028 /* Half the range */
1029 int mid = src.mf->begin + (src.mf->end - src.mf->begin) / 2;
1030
1031 range1.mf->begin = src.mf->begin;
1032 range1.mf->end = mid;
1033 range2.mf->begin = mid;
1034 range2.mf->end = src.mf->end;
1035
1036 range1.mf->next = NULL;
1037 range2.mf->next = NULL;
1038
1039 /* Split up the bitmaps */
1040 range1.mf->glyphs = malloc(sizeof(FONT_GLYPH*)
1041 * (range1.mf->end - range1.mf->begin));
1042 if (!range1.mf->glyphs) {
1043 TRACE(PREFIX_E "split_font() - Ran out of memory "
1044 "while trying to allocate %i bytes.\n",
1045 (int)sizeof(FONT_GLYPH*) * (range1.mf->end - range1.mf->begin));
1046 free(range1.ptr);
1047 free(range2.ptr);
1048 return FALSE;
1049 }
1050
1051 range2.mf->glyphs = malloc(sizeof(FONT_GLYPH*)
1052 * (range2.mf->end - range2.mf->begin));
1053 if (!range2.mf->glyphs) {
1054 TRACE(PREFIX_E "split_font() - Ran out of memory "
1055 "while trying to allocate %i bytes.\n",
1056 (int)sizeof(FONT_GLYPH*) * (range2.mf->end - range2.mf->begin));
1057 free(range1.mf->glyphs);
1058 free(range1.ptr);
1059 free(range2.ptr);
1060 return FALSE;
1061 }
1062
1063 for (i = 0; i < (range1.mf->end - range1.mf->begin); i++) {
1064 range1.mf->glyphs[i] = src.mf->glyphs[i];
1065 }
1066 for (i = 0; i < (range2.mf->end - range2.mf->begin); i++) {
1067 range2.mf->glyphs[i] =
1068 src.mf->glyphs[i + range2.mf->begin - range1.mf->begin];
1069 }
1070 }
1071
1072 return TRUE;
1073 }
1074
1075
1076
1077 /* Destroys a split font */
1078 static void destroy_split_font(FONT *f, union mixed_ptr range1,
1079 union mixed_ptr range2) {
1080
1081 if (!is_mono_font(f)) {
1082 free(range1.cf->bitmaps);
1083 free(range2.cf->bitmaps);
1084 }
1085 else {
1086 free(range1.mf->glyphs);
1087 free(range2.mf->glyphs);
1088 }
1089
1090 free(range1.ptr);
1091 free(range2.ptr);
1092
1093 return;
1094 }
1095
1096
1097
1098 static int do_crop_font_range(FONT *f, AGL_GLYPH *glyphs, int beg, int end) {
1099
1100 int i, j, k;
1101 int max = end - beg;
1102 char buf[32];
1103
1104 /* Allocate a temp bitmap to work with */
1105 BITMAP *temp = create_bitmap(32, 32);
1106
1107 if (!temp) {
1108 TRACE(PREFIX_E "crop_font_range - Unable to create "
1109 "bitmap of size: %ix%i!\n", 32, 32);
1110 goto error;
1111 }
1112
1113 /* Crop glyphs */
1114 for (i = 0; i < max; i++) {
1115 int used = 0;
1116
1117 if (glyphs[i].w > temp->w || glyphs[i].h > temp->h) {
1118 int old_w = temp->w, old_h = temp->h;
1119 destroy_bitmap(temp);
1120 temp = create_bitmap(old_w * 2, old_h * 2);
1121 if (!temp) {
1122 TRACE(PREFIX_E "crop_font_range - Unable to "
1123 "create bitmap of size: %ix%i!\n", old_w * 2, old_h * 2);
1124 goto error;
1125 }
1126 }
1127 clear_bitmap(temp);
1128
1129 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
1130
1131 textout_ex(temp, f, buf, 0, 0,
1132 makecol_depth(bitmap_color_depth(temp), 255, 255, 255), 0);
1133
1134 /* Crop top */
1135 for (j = 0; j < glyphs[i].h; j++) {
1136 used = 0;
1137
1138 for (k = 0; k < glyphs[i].w; k++) {
1139 if (getpixel(temp, k, j)) {
1140 used = 1;
1141 glyphs[i].offset_y += j;
1142 glyphs[i].h -= j;
1143 break;
1144 }
1145 }
1146 if (used)
1147 break;
1148 }
1149
1150 /* If just the top crop killed our glyph, then skip it entirely */
1151 if (!used) {
1152 TRACE(PREFIX_I "crop_font_range: skipping glyph %i\n", i);
1153 glyphs[i].offset_y = 0;
1154 glyphs[i].offset_h = glyphs[i].h - 1;
1155 glyphs[i].offset_w = glyphs[i].w - 2;
1156 glyphs[i].h = 1;
1157 glyphs[i].w = 1;
1158 continue;
1159 }
1160
1161 /* Crop bottom */
1162 j = glyphs[i].h + glyphs[i].offset_y - 1;
1163 for ( /* above */; j >= glyphs[i].offset_y; j--) {
1164 used = 0;
1165
1166 for (k = 0; k < glyphs[i].w; k++) {
1167 if (getpixel(temp, k, j)) {
1168 used = 1;
1169 glyphs[i].offset_h +=
1170 glyphs[i].h + glyphs[i].offset_y - j - 2;
1171 glyphs[i].h -= glyphs[i].h + glyphs[i].offset_y - j - 1;
1172 break;
1173 }
1174 }
1175 if (used)
1176 break;
1177 }
1178
1179 /* Crop Left */
1180 for (j = 0; j < glyphs[i].w; j++) {
1181 used = 0;
1182
1183 k = MAX(glyphs[i].offset_y - 1, 0);
1184 for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
1185 if (getpixel(temp, j, k)) {
1186 used = 1;
1187 glyphs[i].offset_x += j;
1188 glyphs[i].w -= j;
1189 break;
1190 }
1191 }
1192 if (used)
1193 break;
1194 }
1195
1196 /* Crop Right */
1197 j = glyphs[i].w + glyphs[i].offset_x - 1;
1198 for (/* above */; j >= glyphs[i].offset_x; j--) {
1199 used = 0;
1200
1201 k = MAX(glyphs[i].offset_y - 1, 0);
1202 for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
1203 if (getpixel(temp, j, k)) {
1204 used = 1;
1205 glyphs[i].offset_w +=
1206 glyphs[i].w + glyphs[i].offset_x - 1 - j;
1207 glyphs[i].w -= glyphs[i].w + glyphs[i].offset_x - j - 1;
1208 break;
1209 }
1210 }
1211 if (used)
1212 break;
1213 }
1214 #ifdef LOGLEVEL
1215 TRACE(PREFIX_I "crop_font_range: Glyph %i (%c) offs: x: %i y: %i, "
1216 "w: %i h: %i, offs: w: %i h: %i\n", i, i + beg,
1217 glyphs[i].offset_x, glyphs[i].offset_y, glyphs[i].w, glyphs[i].h,
1218 glyphs[i].offset_w, glyphs[i].offset_h);
1219 #endif
1220 }
1221
1222 destroy_bitmap(temp);
1223
1224 return TRUE;
1225
1226 error:
1227 if (temp) {
1228 destroy_bitmap(temp);
1229 }
1230
1231 return FALSE;
1232 }
1233
1234
1235
1236 /* Crops a font over a particular range */
1237 static int crop_font_range(FONT *f, void *src, int beg, int end,
1238 AGL_GLYPH *glyphs,
1239 int *net_area, int *gross_area,
1240 int *max_w, int *max_h) {
1241
1242 int i;
1243 int crop = 1;
1244 int max = end - beg;
1245 int ret = TRUE;
1246
1247 union mixed_ptr dat;
1248 dat.ptr = src;
1249
1250 /* Disable cropping for trucolor fonts. */
1251 if (is_color_font(f)) {
1252 FONT_COLOR_DATA *fcd = f->data;
1253 if (bitmap_color_depth(fcd->bitmaps[0]) != 8) {
1254 crop = 0;
1255 }
1256 }
1257
1258 /* Load default sizes */
1259 for (i = 0; i < max; i++) {
1260 glyphs[i].glyph_num = i;
1261
1262 if (is_mono_font(f)) {
1263 glyphs[i].w = dat.mf->glyphs[i]->w + 1;
1264 glyphs[i].h = dat.mf->glyphs[i]->h + 1;
1265 } else {
1266 glyphs[i].w = dat.cf->bitmaps[i]->w + 1;
1267 glyphs[i].h = dat.cf->bitmaps[i]->h + 1;
1268 }
1269 glyphs[i].offset_w = -1;
1270 glyphs[i].offset_h = -1;
1271
1272 /* Not placed yet */
1273 glyphs[i].x = -1;
1274 }
1275
1276 if (crop) {
1277 ret = do_crop_font_range(f, glyphs, beg, end);
1278 }
1279
1280 (*gross_area) = 0;
1281 (*net_area) = 0;
1282 (*max_w) = 0;
1283 (*max_h) = 0;
1284
1285 /* Find max w and h, total area covered by the bitmaps, and number of
1286 * glyphs
1287 */
1288 for (i = 0; i < max; i++) {
1289 if (glyphs[i].w > *max_w) (*max_w) = glyphs[i].w;
1290 if (glyphs[i].h > *max_h) (*max_h) = glyphs[i].h;
1291 (*net_area) += glyphs[i].w * glyphs[i].h;
1292 (*gross_area) += (glyphs[i].w + FONT_CHARACTER_SPACING)
1293 * (glyphs[i].h + FONT_CHARACTER_SPACING);
1294 }
1295 return ret;
1296
1297 }
1298
1299
1300
1301 /* Tries to find a texture that will fit the font
1302 */
1303 static BITMAP* look_for_texture(int beg, int end, AGL_GLYPH *glyphs,
1304 int max_w, int max_h, int total_area, GLint format, int has_alpha) {
1305
1306 BITMAP *bmp = NULL;
1307 int i, j;
1308
1309 /* Max texture size (1 << n) */
1310 /* XXX <rohannessian> We should use ARB_np2 if we can
1311 *
1312 * Other note: w*h shouldn't exceed 31 bits; otherwise, we get funny
1313 * behavior on 32-bit architectures. Limit texture sizes to 32k*32k
1314 * (30 bits).
1315 */
1316 #define MIN_TEXTURE_SIZE 2
1317 #define NUM_TEXTURE_SIZE 13
1318 texture_size texture_sizes[NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE];
1319
1320 /* Set up texture sizes */
1321 for (i = 0; i < NUM_TEXTURE_SIZE; i++) {
1322 for (j = 0; j < NUM_TEXTURE_SIZE; j++) {
1323 texture_sizes[j + i * NUM_TEXTURE_SIZE].w =
1324 1 << (j + MIN_TEXTURE_SIZE);
1325 texture_sizes[j + i * NUM_TEXTURE_SIZE].h =
1326 1 << (i + MIN_TEXTURE_SIZE);
1327 }
1328 }
1329
1330 /* Sort texture sizes by area */
1331 qsort(texture_sizes, NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE,
1332 sizeof(texture_size), &sort_textures);
1333
1334 for (i = 0; i < NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE; i++) {
1335 int num_channels;
1336
1337 /* Check the area - it must be larger than
1338 * all the glyphs
1339 */
1340 texture_size *t = &texture_sizes[i];
1341 int area = t->w * t->h;
1342 int depth = 24;
1343
1344 if (area < total_area) {
1345 continue;
1346 }
1347
1348 /* Check against max values */
1349 if ((t->h < max_h) || (t->w < max_w)) {
1350 continue;
1351 }
1352
1353 TRACE(PREFIX_I "look_for_texture: candidate size: %ix%i\n", t->w, t->h);
1354
1355 /* Check that the texture can, in fact, be created */
1356 num_channels = __allegro_gl_get_num_channels(format);
1357 if (num_channels == 1) {
1358 depth = 8;
1359 }
1360 else if (num_channels == 4) {
1361 depth = 32;
1362 }
1363 else {
1364 depth = 24;
1365 }
1366 bmp = create_bitmap_ex(depth, t->w, t->h);
1367
1368 if (!bmp) {
1369 TRACE(PREFIX_W "look_for_texture: Out of memory while "
1370 "creating bitmap\n");
1371 continue;
1372 }
1373
1374 if (!aglf_check_texture(bmp, format, has_alpha)) {
1375 TRACE(PREFIX_I "look_for_texture: Texture rejected by driver\n");
1376 destroy_bitmap(bmp);
1377 bmp = NULL;
1378 continue;
1379 }
1380
1381 /* Sort out the glyphs */
1382 TRACE(PREFIX_I "look_for_texture: Sorting on bmp: %p, beg: %i, "
1383 "end: %i\n", bmp, beg, end);
1384
1385 if (aglf_sort_out_glyphs(bmp, glyphs, beg, end) == TRUE) {
1386 /* Success? */
1387 return bmp;
1388 }
1389
1390 /* Failure? Try something else */
1391 TRACE(PREFIX_I "look_for_texture: Conversion failed\n");
1392 destroy_bitmap(bmp);
1393 bmp = NULL;
1394 }
1395
1396 return NULL;
1397 }
1398
1399
1400
1401 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
1402 /* This is only used to render chars from an Allegro font which has the
1403 * font_vtable_trans vtable. If the target is an 8-bit bitmap, only the alpha
1404 * channel is used. Otherwise, blit is used, to preserve the alpha channel.
1405 */
1406 static int dummy_render_char(AL_CONST FONT* f, int ch, int fg, int bg,
1407 BITMAP* bmp, int x, int y)
1408 {
1409 FONT_COLOR_DATA* cf = (FONT_COLOR_DATA*)(f->data);
1410 BITMAP *glyph = NULL;
1411
1412 while(cf) {
1413 if(ch >= cf->begin && ch < cf->end) {
1414 glyph = cf->bitmaps[ch - cf->begin];
1415 break;
1416 }
1417 cf = cf->next;
1418 }
1419
1420 if (glyph)
1421 {
1422 if (bitmap_color_depth(bmp) == 8) {
1423 int gx, gy;
1424 for (gy = 0; gy < bmp->h; gy++) {
1425 for (gx = 0; gx < bmp->w; gx++) {
1426 int c = getpixel(glyph, gx, gy);
1427 int a = geta(c);
1428 putpixel(bmp, x + gx, y + gy, a);
1429 }
1430 }
1431 }
1432 else
1433 blit(glyph, bmp, 0, 0, x, y, glyph->w, glyph->h);
1434 return bmp->w;
1435 }
1436 return 0;
1437 }
1438 #endif
1439
1440
1441
1442 /* Function to draw a character in a bitmap for conversion */
1443 static int draw_glyphs(BITMAP *bmp, FONT *f, GLint format, int beg, int end,
1444 AGL_GLYPH *glyphs) {
1445 char buf[32];
1446 int i, j;
1447
1448 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
1449 if (bitmap_color_depth(bmp) == 8 && f->vtable != font_vtable_trans) {
1450 #else
1451 if (bitmap_color_depth(bmp) == 8) {
1452 #endif
1453 /* Generate an alpha font */
1454 BITMAP *rgbbmp = create_bitmap_ex(24, bmp->w, bmp->h);
1455
1456 if (!rgbbmp) {
1457 TRACE(PREFIX_E "convert_allegro_font_to_texture: "
1458 "Ran out of memory while creating %ix%ix%i bitmap!\n",
1459 bmp->w, bmp->h, 24);
1460 return FALSE;
1461 }
1462
1463 clear_bitmap(rgbbmp);
1464
1465 for (i = 0; i < end - beg; i++) {
1466 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
1467
1468 textout_ex(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
1469 glyphs[i].y - glyphs[i].offset_y, -1, -1);
1470 }
1471
1472 /* Convert back to 8bpp */
1473 for (j = 0; j < bmp->h; j++) {
1474 for (i = 0; i < bmp->w; i++) {
1475 int pix = _getpixel24(rgbbmp, i, j);
1476 int r = getr24(pix);
1477 int g = getg24(pix);
1478 int b = getb24(pix);
1479 int gray = (r * 77 + g * 150 + b * 28 + 255) >> 8;
1480 _putpixel(bmp, i, j, MID(0, gray, 255));
1481 }
1482 }
1483 destroy_bitmap(rgbbmp);
1484 }
1485 else {
1486 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
1487 int (*borrowed_color_vtable)(AL_CONST FONT*, int, int, int, BITMAP*, int, int) = NULL;
1488
1489 //In order to keep the alpha channel in textout_ex we borrow
1490 //the color font vtable which uses maked_blit() instead of
1491 //draw_trans_sprite() to draw glyphs.
1492 if (f->vtable == font_vtable_trans) {
1493 borrowed_color_vtable = f->vtable->render_char;
1494 f->vtable->render_char = dummy_render_char;
1495 }
1496 #endif
1497
1498 if (__allegro_gl_get_num_channels(format) == 4) {
1499 clear_to_color(bmp, bitmap_mask_color(bmp));
1500 }
1501 else {
1502 clear_bitmap(bmp);
1503 }
1504
1505 for (i = 0; i < end - beg; i++) {
1506 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
1507 textout_ex(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
1508 glyphs[i].y - glyphs[i].offset_y, -1, -1);
1509 }
1510
1511 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
1512 if (borrowed_color_vtable) {
1513 f->vtable->render_char = borrowed_color_vtable;
1514 }
1515 #endif
1516 }
1517
1518 return TRUE;
1519 }
1520
1521
1522
1523 /* Converts a single font range to a texture.
1524 * dest - Receives the result.
1525 * f - The original font.
1526 * src - The original font data.
1527 */
1528 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA **dest, FONT *f,
1529 void *src, int *height, float scale, GLint format) {
1530
1531 int max = 0;
1532 BITMAP *bmp = NULL;
1533 int beg = 0, end = 0;
1534 int max_w, max_h;
1535 int total_area, gross_area;
1536
1537 AGL_GLYPH *glyph_coords;
1538
1539 union mixed_ptr dat;
1540 dat.ptr = src;
1541
1542 if (is_mono_font(f)) {
1543 beg = dat.mf->begin;
1544 end = dat.mf->end;
1545 max = dat.mf->end - dat.mf->begin;
1546 if (format == -1) {
1547 format = GL_INTENSITY4;
1548 }
1549 }
1550 else if (is_color_font(f)) {
1551 beg = dat.cf->begin;
1552 end = dat.cf->end;
1553 max = dat.cf->end - dat.cf->begin;
1554 if (format == -1) {
1555 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
1556 format = (f->vtable == font_vtable_trans ? GL_RGBA8 : GL_RGB8);
1557 #else
1558 format = GL_RGB8;
1559 #endif
1560 }
1561 }
1562
1563 /* Allocate glyph sizes */
1564 glyph_coords = malloc(max * sizeof(AGL_GLYPH));
1565 memset(glyph_coords, 0, max * sizeof(AGL_GLYPH));
1566
1567 if (crop_font_range(f, dat.ptr, beg, end, glyph_coords,
1568 &total_area, &gross_area, &max_w, &max_h) == FALSE) {
1569 TRACE(PREFIX_I "convert_allegro_font_to_texture: Unable to crop font "
1570 "range\n");
1571 free(glyph_coords);
1572 return;
1573 }
1574
1575 TRACE(PREFIX_I "convert_allegro_font_to_texture: Total area of glyphs: "
1576 "%i pixels (%i pixels gross) - max_w: %i, max_h: %i\n",
1577 total_area, gross_area, max_w, max_h);
1578
1579 /* Sort glyphs by width, then height */
1580 qsort(glyph_coords, end - beg, sizeof(AGL_GLYPH), &sort_glyphs);
1581
1582
1583 /* Now, we look for the appropriate texture size */
1584 bmp = look_for_texture(beg, end, glyph_coords, max_w, max_h,
1585 total_area, format, (*dest)->has_alpha);
1586
1587 /* No texture sizes were found - we should split the font up */
1588 if (!bmp) {
1589 int height1;
1590 union mixed_ptr f1, f2;
1591 FONT_AGL_DATA *dest1, *dest2;
1592
1593 free(glyph_coords);
1594
1595 dest1 = *(dest);
1596 dest2 = malloc(sizeof(FONT_AGL_DATA));
1597
1598 if (!dest2) {
1599 TRACE(PREFIX_E "convert_allegro_font_to_texture: "
1600 "Out of memory while trying to allocate %i bytes.\n",
1601 (int)sizeof(FONT_AGL_DATA));
1602 return;
1603 }
1604
1605 memset(dest2, 0, sizeof(FONT_AGL_DATA));
1606
1607 dest2->next = dest1->next;
1608 dest1->next = dest2;
1609 dest2->is_free_chunk = TRUE;
1610 dest2->format = dest1->format;
1611 dest2->has_alpha = dest1->has_alpha;
1612
1613 if (split_font(f, dat.ptr, &f1.ptr, &f2.ptr) == FALSE) {
1614 TRACE(PREFIX_E "convert_allegro_font_to_texture: Unable "
1615 "to split font!\n");
1616 dest1->next = dest2->next;
1617 free(dest2);
1618 return;
1619 }
1620
1621 aglf_convert_allegro_font_to_texture(&dest1, f, f1.ptr, height, scale,
1622 format);
1623 height1 = (*height);
1624 aglf_convert_allegro_font_to_texture(&dest2, f, f2.ptr, height, scale,
1625 format);
1626 destroy_split_font(f, f1, f2);
1627
1628 if (height1 > (*height))
1629 (*height) = height1;
1630 (*dest) = dest2;
1631
1632 return;
1633 }
1634
1635 TRACE(PREFIX_I "convert_allegro_font_to_texture: Using texture "
1636 "%ix%ix%i for font conversion.\n", bmp->w, bmp->h,
1637 bitmap_color_depth(bmp));
1638
1639 /* Now that all the glyphs are in place, we draw them into the bitmap */
1640 if (draw_glyphs(bmp, f, format, beg, end, glyph_coords) == FALSE) {
1641 destroy_bitmap(bmp);
1642 free(glyph_coords);
1643 return;
1644 }
1645
1646 /* Un-Sort glyphs */
1647 qsort(glyph_coords, end - beg, sizeof(AGL_GLYPH), &unsort_glyphs);
1648
1649 #if (defined SAVE_FONT_SCREENSHOT)
1650 save_shot(bmp);
1651 #endif
1652
1653 (*dest)->list_base =
1654 create_textured_font_call_lists(glyph_coords, max, bmp,
1655 scale, height);
1656
1657 (*dest)->texture = aglf_upload_texture(bmp, format, (*dest)->has_alpha);
1658 (*dest)->type = AGL_FONT_TYPE_TEXTURED;
1659 (*dest)->format = format;
1660 (*dest)->scale = scale;
1661 (*dest)->start = beg;
1662 (*dest)->end = end;
1663 (*dest)->data = bmp;
1664 (*dest)->glyph_coords = glyph_coords;
1665
1666 return;
1667 }
1668
1669
1670
1671 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
1672 void *src, int *height) {
1673
1674 int max = 0;
1675 int i, j, k;
1676 int beg = 0, end = 0;
1677 int mask;
1678 FONT_GLYPH **glyph;
1679
1680 union {
1681 FONT_MONO_DATA* mf;
1682 FONT_COLOR_DATA* cf;
1683 void *ptr;
1684 } dat;
1685
1686 dat.ptr = src;
1687
1688 if (is_mono_font(f))
1689 max = dat.mf->end - dat.mf->begin;
1690 else if (is_color_font(f))
1691 max = dat.cf->end - dat.cf->begin;
1692 else
1693 return;
1694
1695 glyph = malloc(sizeof(FONT_GLYPH*) * max);
1696
1697 if (!glyph) {
1698 TRACE(PREFIX_E "convert_allegro_font_to_bitmap: Ran out of "
1699 "memory while allocating %i bytes\n", (int)sizeof(FONT_GLYPH));
1700 return;
1701 }
1702
1703 *height = f->height;
1704
1705 if (is_mono_font(f)) {
1706
1707 /* for each glyph */
1708 for (i = 0; i < max; i++) {
1709 FONT_GLYPH *oldgl = dat.mf->glyphs[i];
1710
1711 int size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4
1712 * oldgl->h;
1713
1714 /* create new glyph */
1715 FONT_GLYPH *newgl = (FONT_GLYPH*)malloc(size);
1716
1717 if (!newgl)
1718 break;
1719
1720 memset(newgl, 0, size);
1721
1722 newgl->w = oldgl->w;
1723 newgl->h = oldgl->h;
1724
1725 /* update the data */
1726 for (j = 0; j < oldgl->h; j++) {
1727 for (k = 0; k < ((oldgl->w + 7) / 8); k++) {
1728 int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
1729 + k;
1730 newgl->dat[addr] = oldgl->dat[j * ((oldgl->w + 7) / 8) + k];
1731 }
1732 }
1733
1734 glyph[i] = newgl;
1735 }
1736 }
1737 /* Reduce to 1 bit */
1738 else if (is_color_font(f)) {
1739 /* for each glyph */
1740 for (i = 0; i < max; i++) {
1741
1742 int size;
1743 BITMAP *oldgl = dat.cf->bitmaps[i];
1744 FONT_GLYPH *newgl;
1745
1746 mask = bitmap_mask_color(oldgl);
1747
1748 size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4 * oldgl->h;
1749
1750 /* create new glyph */
1751 newgl = (FONT_GLYPH*)malloc(size);
1752
1753 if (!newgl)
1754 break;
1755
1756 memset(newgl, 0, size);
1757
1758 newgl->w = oldgl->w;
1759 newgl->h = oldgl->h;
1760
1761 /* update the data */
1762 for (j = 0; j < oldgl->h; j++) {
1763 for (k = 0; k < oldgl->w; k++) {
1764 int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
1765 + (k / 8);
1766 newgl->dat[addr] |= (getpixel(oldgl, k, j) == mask)
1767 ? 0 : (1 << (k & 7));
1768 }
1769 }
1770
1771 glyph[i] = newgl;
1772 }
1773 }
1774 /* Create call lists */
1775 {
1776 GLuint list = glGenLists(max);
1777
1778 for (i = 0; i < max; i++) {
1779 glNewList(list + i, GL_COMPILE);
1780
1781 glBitmap(glyph[i]->w, glyph[i]->h, 0, 0, glyph[i]->w, 0,
1782 glyph[i]->dat);
1783
1784 glEndList();
1785 }
1786 dest->list_base = list;
1787 }
1788
1789 dest->is_free_chunk = 0;
1790 dest->type = AGL_FONT_TYPE_BITMAP;
1791 dest->start = beg;
1792 dest->end = end;
1793 dest->data = glyph;
1794
1795 return;
1796 }
1797
1798
1799
1800 static int aglf_check_texture(BITMAP *bmp, GLint format, int has_alpha) {
1801
1802 int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP;
1803
1804 if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
1805 || format == GL_INTENSITY4 || format == GL_INTENSITY8
1806 || format == GL_INTENSITY
1807 || format == GL_LUMINANCE4 || format == GL_LUMINANCE8
1808 || format == GL_LUMINANCE
1809 || format == 1) {
1810 flags |= AGL_TEXTURE_ALPHA_ONLY;
1811 }
1812 else if (format == GL_RGBA8) {
1813 if (has_alpha) {
1814 flags |= AGL_TEXTURE_HAS_ALPHA;
1815 }
1816 else {
1817 flags |= AGL_TEXTURE_MASKED;
1818 }
1819 }
1820
1821 return allegro_gl_check_texture_ex(flags, bmp, format);
1822 }
1823
1824
1825
1826 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format, int has_alpha) {
1827
1828 int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP;
1829 GLuint texture;
1830
1831 if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
1832 || format == GL_INTENSITY4 || format == GL_INTENSITY8
1833 || format == GL_INTENSITY
1834 || format == GL_LUMINANCE4 || format == GL_LUMINANCE8
1835 || format == GL_LUMINANCE
1836 || format == 1) {
1837 flags |= AGL_TEXTURE_ALPHA_ONLY;
1838 }
1839 else if (__allegro_gl_get_num_channels(format) == 4) {
1840 if (has_alpha) {
1841 flags |= AGL_TEXTURE_HAS_ALPHA;
1842 }
1843 else {
1844 flags |= AGL_TEXTURE_MASKED;
1845 }
1846 }
1847
1848 TRACE(PREFIX_I "Want texture format: %s\n",
1849 __allegro_gl_get_format_description(format));
1850 texture = allegro_gl_make_texture_ex(flags, bmp, format);
1851 TRACE(PREFIX_I "Texture ID is: %u\n", texture);
1852
1853 return texture;
1854 }
1855
AGL_TEXTURE_MASKED
#define AGL_TEXTURE_MASKED
Generate an alpha channel for this texture, based on the Allegro mask color.
Definition: alleggl.h:537
allegro_gl_destroy_font
void allegro_gl_destroy_font(FONT *f)
void allegro_gl_destroy_font(FONT *usefont)
Definition: aglf.c:573
allegro_gl_make_texture_ex
GLuint allegro_gl_make_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
Uploads an Allegro BITMAP to the GL driver as a texture.
Definition: texture.c:1165
allegro_gl_convert_allegro_font_ex
FONT * allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format)
Converts a regular Allegro FONT to the AGL format for 3D display.
Definition: fontconv.c:688
AGL_FONT_TYPE_TEXTURED
#define AGL_FONT_TYPE_TEXTURED
Indicates that you want fonts to be converted to a texture format.
Definition: alleggl.h:656
allegro_gl_convert_allegro_font
FONT * allegro_gl_convert_allegro_font(FONT *f, int type, float scale)
Equivalent to:
Definition: fontconv.c:623
allegro_gl_get_texture_format
GLint allegro_gl_get_texture_format(BITMAP *bmp)
Returns the OpenGL internal texture format for this bitmap.
Definition: texture.c:248
AGL_TEXTURE_ALPHA_ONLY
#define AGL_TEXTURE_ALPHA_ONLY
Tell AllegroGL that the specified BITMAP is an 8-bpp alpha-only BITMAP.
Definition: alleggl.h:548
AGL_FONT_TYPE_BITMAP
#define AGL_FONT_TYPE_BITMAP
Indicates that you want fonts to be converted to a bitmap format.
Definition: alleggl.h:632
AGL_FONT_TYPE_OUTLINE
#define AGL_FONT_TYPE_OUTLINE
Indicates that you want fonts to be converted to an outline format.
Definition: alleggl.h:644
AGL_TEXTURE_MIPMAP
#define AGL_TEXTURE_MIPMAP
AllegroGL will generate mipmaps for this texture.
Definition: alleggl.h:521
alleggl.h
Main header file for AllegroGL.
allegro_gl_check_texture_ex
int allegro_gl_check_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
Checks whether the specified bitmap is of the proper size for texturing.
Definition: texture.c:495
AGL_TEXTURE_FLIP
#define AGL_TEXTURE_FLIP
Flip the texture on the x-axis.
Definition: alleggl.h:532
AGL_FONT_TYPE_DONT_CARE
#define AGL_FONT_TYPE_DONT_CARE
Indicates that you don&#39;t really care how a font will be converted.
Definition: alleggl.h:621
AGL_TEXTURE_HAS_ALPHA
#define AGL_TEXTURE_HAS_ALPHA
Tell AllegroGL that the bitmap had an alpha channel, so it should be preserved when generating the te...
Definition: alleggl.h:526