AllegroGL  0.4.4
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 */
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 
#define AGL_TEXTURE_MASKED
Generate an alpha channel for this texture, based on the Allegro mask color.
Definition: alleggl.h:537
void allegro_gl_destroy_font(FONT *f)
void allegro_gl_destroy_font(FONT *usefont)
Definition: aglf.c:573
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
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
#define AGL_FONT_TYPE_TEXTURED
Indicates that you want fonts to be converted to a texture format.
Definition: alleggl.h:656
FONT * allegro_gl_convert_allegro_font(FONT *f, int type, float scale)
Equivalent to:
Definition: fontconv.c:623
GLint allegro_gl_get_texture_format(BITMAP *bmp)
Returns the OpenGL internal texture format for this bitmap.
Definition: texture.c:248
#define AGL_TEXTURE_ALPHA_ONLY
Tell AllegroGL that the specified BITMAP is an 8-bpp alpha-only BITMAP.
Definition: alleggl.h:548
#define AGL_FONT_TYPE_BITMAP
Indicates that you want fonts to be converted to a bitmap format.
Definition: alleggl.h:632
#define AGL_FONT_TYPE_OUTLINE
Indicates that you want fonts to be converted to an outline format.
Definition: alleggl.h:644
#define AGL_TEXTURE_MIPMAP
AllegroGL will generate mipmaps for this texture.
Definition: alleggl.h:521
Main header file for AllegroGL.
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
#define AGL_TEXTURE_FLIP
Flip the texture on the x-axis.
Definition: alleggl.h:532
#define AGL_FONT_TYPE_DONT_CARE
Indicates that you don&#39;t really care how a font will be converted.
Definition: alleggl.h:621
#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