fontconv.c

Go to the documentation of this file.
00001 
00010 #include <math.h>
00011 #include <string.h>
00012 #include <stdio.h>
00013 
00014 #include <allegro.h>
00015 #include <allegro/internal/aintern.h>
00016 
00017 #include "alleggl.h"
00018 #include "allglint.h"
00019 
00020 #ifdef ALLEGRO_MACOSX
00021 #include <OpenGL/glu.h>
00022 #else
00023 #include <GL/glu.h>
00024 #endif
00025 
00026 #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGROGL_GENERIC_DRIVER
00027 #include <xalleg.h>
00028 #include <GL/glx.h>
00029 #endif
00030 
00031 
00032 /* Number of pixels between characters in a textured font.
00033  */
00034 #define FONT_CHARACTER_SPACING 2
00035 
00036 /* Uncomment to have the font generator dump screenshots of the textures it
00037  * generates.
00038  */
00039 /* #define SAVE_FONT_SCREENSHOT */
00040 
00041 
00042 static int agl_get_font_height(AL_CONST FONT *f);
00043 static int agl_char_length(const FONT *f, int ch);
00044 static int agl_text_length(const FONT *f, const char *str);
00045 
00046 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00047 static int agl_get_font_ranges(FONT *f);
00048 static int agl_get_font_range_begin(FONT *f, int range);
00049 static int agl_get_font_range_end(FONT *f, int range);
00050 static FONT *agl_extract_font_range(FONT *f, int start, int end);
00051 static FONT *agl_merge_fonts(FONT *f1, FONT *f2);
00052 #endif
00053 
00054 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0)
00055 static int agl_transpose_font(FONT *f, int drange);
00056 #endif
00057 
00058 
00059 FONT_VTABLE _agl_font_vtable = {
00060     agl_get_font_height,
00061     agl_char_length,
00062     agl_text_length,
00063     NULL, /* render_char */
00064     NULL, /* render */
00065     allegro_gl_destroy_font,
00066 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00067     agl_get_font_ranges,
00068     agl_get_font_range_begin,
00069     agl_get_font_range_end,
00070     agl_extract_font_range,
00071     agl_merge_fonts,
00072 #endif
00073 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0)
00074     agl_transpose_font
00075 #endif
00076 };
00077 
00078 
00079 FONT_VTABLE *font_vtable_agl = &_agl_font_vtable;
00080 
00081 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
00082                                                 void *src, int *height);
00083 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA *dest, FONT *f,
00084                              void *src, int *height, float scale, GLint format);
00085 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format, int has_alpha);
00086 static int aglf_check_texture(BITMAP *bmp, GLint format, int has_alpha);
00087 static BITMAP* look_for_texture(int beg, int end, AGL_GLYPH *glyphs,
00088                                 int max_w, int max_h, int total_area,
00089                                 GLint format, int has_alpha);
00090 static int get_format_num_channels(GLenum format);
00091 
00092 
00093 
00094 union mixed_ptr {
00095     FONT_MONO_DATA* mf;
00096     FONT_COLOR_DATA* cf;
00097     void *ptr;
00098 };
00099 
00100 
00101 /* Stores info about a texture size */
00102 typedef struct texture_size {
00103     int w, h;
00104 } texture_size;
00105 
00106 
00107 
00108 static int agl_get_font_height(AL_CONST FONT *f) {
00109     return f->height;
00110 }
00111 
00112 
00113 /* iroundf:
00114  * Round float to nearest integer, away from zero.
00115  */
00116 static int iroundf(float v) {
00117     float f = floor(v);
00118     float c = ceil(v);
00119 
00120     if (v >= 0) {
00121         /* distance to ceil smaller than distance to floor */
00122         if ((c - v) < (v - f))
00123             return (int)c;
00124         else
00125             return (int)f;
00126     }
00127     else {
00128         /* distance to ceil smaller than distance to floor */
00129         if ((c - v) < (v - f)) 
00130             return (int)f;
00131         else
00132             return (int)c;
00133     }
00134 }
00135 
00136 
00137 
00138 /* agl_char_length_fractional:
00139  * Returns the width, in fractional pixels of the given character.
00140  */
00141 static float agl_char_length_fractional(const FONT *f, int ch) {
00142     FONT_AGL_DATA *fad = f->data;
00143 
00144     if (fad->type == AGL_FONT_TYPE_TEXTURED) {
00145         while (fad) {
00146             if (ch >= fad->start && ch < fad->end) {
00147                 AGL_GLYPH *coords = &(fad->glyph_coords[ch - fad->start]);
00148                 return (coords->offset_x + coords->w + coords->offset_w)
00149                        / fabs(fad->scale);
00150             }
00151 
00152             fad = fad->next;
00153         }
00154     }
00155     else if (fad->type == AGL_FONT_TYPE_BITMAP) {
00156         while (fad) {
00157             if (ch >= fad->start && ch < fad->end) {
00158                 FONT_GLYPH **gl = fad->data;
00159                 return gl[ch - fad->start]->w;
00160             }
00161 
00162             fad = fad->next;
00163         }
00164     }
00165 
00166     /* if we don't find the character, then search for the missing
00167      * glyph, but don't get stuck in a loop. */
00168     if (ch != allegro_404_char)
00169         return agl_char_length_fractional(f, allegro_404_char);
00170 
00171     return 0;
00172 }
00173 
00174 
00175 
00176 /* agl_char_length:
00177  * font vtable entry
00178  * Returns the width, in pixels of the given character.
00179  */
00180 static int agl_char_length(const FONT *f, int ch) {
00181     return iroundf(agl_char_length_fractional(f, ch));
00182 }
00183 
00184 
00185 
00186 /* agl_text_length:
00187  * font vtable entry
00188  * Returns the length, in pixels, of a string as rendered in a font.
00189  */
00190 static int agl_text_length(const FONT *f, const char *str) {
00191     int ch = 0;
00192     float l = 0;
00193     const char *p = str;
00194     ASSERT(f);
00195     ASSERT(str);
00196 
00197     while ( (ch = ugetxc(&p)) ) {
00198         l += agl_char_length_fractional(f, ch);
00199     }
00200 
00201     return iroundf(l);
00202 }
00203 
00204 
00205 
00206 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00207 /* agl_get_font_ranges:
00208  * font vtable entry
00209  * Returns the number of character ranges in a font, or -1 if that information
00210  *   is not available.
00211  */
00212 static int agl_get_font_ranges(FONT *f) {
00213     FONT_AGL_DATA *fad;
00214     int ranges = 0;
00215 
00216     if (!f)
00217         return 0;
00218 
00219     fad = (FONT_AGL_DATA*)(f->data);
00220 
00221     while (fad) {
00222         FONT_AGL_DATA *next = fad->next;
00223 
00224         ranges++;
00225         if (!next)
00226             return ranges;
00227         fad = next;
00228     }
00229 
00230     return -1;
00231 }
00232 #endif
00233 
00234 
00235 
00236 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00237 /* agl_get_font_range_begin:
00238  * font vtable entry
00239  * Get first character for font.
00240  */
00241 static int agl_get_font_range_begin(FONT *f, int range) {
00242     FONT_AGL_DATA *fad;
00243     int n = 0;
00244 
00245     if (!f || !f->data)
00246         return -1;
00247 
00248     if (range < 0)
00249         range = 0;
00250 
00251     fad = (FONT_AGL_DATA*)(f->data);
00252     while (fad && n <= range) {
00253         FONT_AGL_DATA *next = fad->next;
00254 
00255         if (!next || range == n)
00256             return fad->start;
00257         fad = next;
00258         n++;
00259     }
00260 
00261     return -1;
00262 }
00263 #endif
00264 
00265 
00266 
00267 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00268 /* agl_get_font_range_end:
00269  * font vtable entry
00270  * Get last character for font range.
00271  */
00272 static int agl_get_font_range_end(FONT *f, int range) {
00273     FONT_AGL_DATA* fad = 0;
00274     int n = 0;
00275 
00276     if (!f || !f->data)
00277         return -1;
00278 
00279     fad = (FONT_AGL_DATA*)(f->data);
00280 
00281     while (fad && (n <= range || range == -1)) {
00282         FONT_AGL_DATA *next = fad->next;
00283         if (!next || range == n)
00284             return fad->end - 1;
00285         fad = next;
00286         n++;
00287     }
00288     
00289     return -1;
00290 }
00291 #endif
00292 
00293 
00294 
00295 /* Creates a call lists from given glyph coords. Returns list base.*/
00296 static int create_textured_font_call_lists(AGL_GLYPH *coords, int max, BITMAP *bmp,
00297                                                     float scale, int *height) {
00298     GLuint list;
00299     int i;
00300 
00301     int rev = scale < 0 ? 1 : 0;
00302     scale = fabs(scale);
00303 
00304     list = glGenLists(max);
00305         
00306     for (i = 0; i < max; i++) {
00307         /* Coords of glyph in texture (texture coords) */
00308         float tx = (float)coords[i].x / bmp->w;
00309         float ty = 1.0 - (float)coords[i].y / bmp->h;
00310         /* Size of glyph in texture (texture coords) */
00311         float dtx = (float)(coords[i].w) / bmp->w;
00312         float dty = (float)(coords[i].h) / bmp->h;
00313 
00314         /* Offset to apply to glyph (output coords) */
00315         float xoffs = (float)coords[i].offset_x / scale;
00316         float yoffs = (float)coords[i].offset_y / scale;
00317         /* Size of rendered glyph (output coords) */
00318         float woffs = (float)coords[i].w / scale;
00319         float hoffs = (float)coords[i].h / scale;
00320 
00321         /* Size of overall screen character including dead space */
00322         float sizew = (float)(coords[i].offset_x + coords[i].w
00323                     + coords[i].offset_w) / scale;
00324         int sizeh = iroundf((coords[i].offset_y + coords[i].h
00325                     + coords[i].offset_h) / scale);
00326 
00327         if ((*height) < sizeh)
00328             *height = sizeh;
00329 
00330         if (rev) {
00331             hoffs = -hoffs;
00332             yoffs = -yoffs;
00333         }
00334 
00335         glNewList(list + i, GL_COMPILE);
00336             
00337         glBegin(GL_QUADS);
00338             glTexCoord2f(tx, ty);
00339             glVertex2f(xoffs, -yoffs);
00340 
00341             glTexCoord2f(tx + dtx, ty);
00342             glVertex2f(xoffs + woffs, -yoffs);
00343 
00344             glTexCoord2f(tx + dtx, ty - dty);
00345             glVertex2f(xoffs + woffs, -yoffs - hoffs);
00346 
00347             glTexCoord2f(tx, ty - dty);
00348             glVertex2f(xoffs, -yoffs - hoffs);
00349         glEnd();
00350 
00351         glTranslatef(sizew, 0, 0);
00352 
00353         glEndList();
00354     }
00355 
00356     return list;
00357 }
00358 
00359 
00360 
00361 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00362 /* copy_glyph_range:
00363  * Copies part of glyph range.
00364  */
00365 static FONT_AGL_DATA* copy_glyph_range(FONT_AGL_DATA *fad, int start, int end,
00366                                                                 int *height) {
00367     int i, count, w = 0, h = 0;
00368     AGL_GLYPH *coords;
00369     BITMAP *bmp, *srcbmp;
00370     FONT_AGL_DATA *newfad = NULL;
00371 
00372     if (fad->type != AGL_FONT_TYPE_TEXTURED)
00373         return NULL;
00374 
00375     count = end - start;
00376 
00377     coords = malloc(count * sizeof (AGL_GLYPH));
00378         
00379     /* for now, just copy glyph coords of the range */
00380     for (i = 0; i < count; i++)
00381         coords[i] = fad->glyph_coords[start - fad->start + i];
00382             
00383     /* calculate the width of the glyphs and find the max height */ 
00384     for (i = 0; i < count; i++) {
00385         int hh = coords[i].h + coords[i].offset_y + coords[i].offset_h;
00386         if (h < hh)
00387             h = hh;
00388         w += coords[i].w + coords[i].offset_w + coords[i].offset_x;
00389     }
00390 
00391     srcbmp = (BITMAP*)fad->data;
00392 
00393     /* allocate a new bitmap to hold new glyphs */
00394     w = __allegro_gl_make_power_of_2(w);
00395     h = __allegro_gl_make_power_of_2(h);
00396     bmp = create_bitmap_ex(bitmap_color_depth(srcbmp), w, h);
00397     if (!bmp) {
00398         TRACE("** ERROR ** copy_glyph_range: Unable to create bitmap of size"
00399                 "%ix%i pixels!", w, h);
00400         free(coords);
00401         return NULL;
00402     }
00403 
00404     if (get_format_num_channels(fad->format) == 4) {
00405         clear_to_color(bmp, bitmap_mask_color(bmp));
00406     }
00407     else {
00408         clear_bitmap(bmp);
00409     }
00410 
00411     /* blit every glyph from the range to the new bitmap */
00412     w = 0;
00413     for (i = 0; i < count; i++) {
00414         int ch = start - fad->start + i;
00415         int ww = coords[i].w + coords[i].offset_w + coords[i].offset_x;
00416         blit(srcbmp, bmp, fad->glyph_coords[ch].x, 0, w, 0, ww, bmp->h);
00417         /* fix new glyphs coords while here */
00418         coords[i].x = w;
00419         w += ww;
00420     }
00421 
00422     newfad = malloc(sizeof(struct FONT_AGL_DATA));
00423 
00424     newfad->type = AGL_FONT_TYPE_TEXTURED;
00425     newfad->is_free_chunk = 0;
00426     newfad->scale = fad->scale;
00427     newfad->format = fad->format;
00428     newfad->has_alpha = fad->has_alpha;
00429     newfad->start = start;
00430     newfad->end = end;
00431     newfad->data = bmp;
00432     newfad->glyph_coords = coords;
00433     newfad->next = NULL;
00434     newfad->list_base = create_textured_font_call_lists(coords, count, bmp,
00435                                                     newfad->scale, height);
00436     newfad->texture = aglf_upload_texture(bmp, newfad->format, newfad->has_alpha);
00437 
00438     return newfad;
00439 }
00440 #endif
00441 
00442 
00443 
00444 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00445 /* agl_extract_font_range:
00446  * font vtable entry
00447  * Extracts a glyph range from a given font and makes a new font of it.
00448  */
00449 static FONT *agl_extract_font_range(FONT *f, int start, int end) {
00450     FONT *retval = NULL;
00451     FONT_AGL_DATA *fad, *next, *newfad = NULL;
00452     int count;
00453 
00454     if (!f)
00455         return NULL;
00456 
00457     /* check if range boundaries make sense */
00458     if (start == -1 && end == -1) {
00459     }
00460     else if (start == -1 && end > agl_get_font_range_begin(f, -1)) {
00461     }
00462     else if (end == -1 && start <= agl_get_font_range_end(f, -1)) {
00463     }
00464     else if (start <= end && start != -1 && end != -1) {
00465     }
00466     else
00467         return NULL;
00468 
00469     fad = (FONT_AGL_DATA*)f->data;
00470 
00471     /* only textured fonts are supported */
00472     if (fad->type != AGL_FONT_TYPE_TEXTURED)
00473         return NULL;
00474 
00475     /* anticipate invalid range values */
00476     start = MAX(start, agl_get_font_range_begin(f, -1));
00477     if (end > -1) {
00478         end = MIN(end, agl_get_font_range_end(f, -1));
00479     }
00480     else {
00481         end = agl_get_font_range_end(f, -1);
00482     }
00483     end++;
00484 
00485     retval = malloc(sizeof (struct FONT));
00486     retval->height = 0;
00487     retval->vtable = font_vtable_agl;
00488 
00489     next = fad;
00490     count = end - start;
00491 
00492     while (next) {
00493         /* find the range that is covered by the requested range
00494          * check if the requested and processed ranges at least overlap
00495          *    or if the requested range wraps processed range.
00496          */
00497         if ((start >= next->start && start < next->end)
00498          || (end   <= next->end   && end   > next->start)
00499          || (start <  next->start && end   > next->end)) {
00500             int local_start, local_end;
00501 
00502             /* extract the overlapping range */
00503             local_start = MAX(next->start, start);
00504             local_end = MIN(next->end, end);
00505 
00506             if (newfad) {
00507                 newfad->next = copy_glyph_range(fad, local_start, local_end,
00508                                                             &(retval->height));
00509                 newfad = newfad->next;
00510             }
00511             else {
00512                 newfad = copy_glyph_range(fad, local_start, local_end,
00513                                                             &(retval->height));
00514                 retval->data = newfad;
00515             }
00516         }
00517             
00518         next = fad->next;
00519     }
00520 
00521     return retval;
00522 }
00523 #endif
00524 
00525 
00526 
00527 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 18)
00528 /* agl_merge_fonts:
00529  * font vtable entry
00530  * Merges f2 with f1 and returns a new font.
00531  */
00532 static FONT *agl_merge_fonts(FONT *f1, FONT *f2) {
00533     FONT *retval;
00534     FONT_AGL_DATA *fad1, *fad2, *fad = NULL;
00535     int phony;
00536 
00537     if (!f1 || !f2)
00538         return NULL;
00539 
00540     fad1 = (FONT_AGL_DATA*)f1->data;
00541     fad2 = (FONT_AGL_DATA*)f2->data;
00542 
00543     /* fonts must be textured and of the same format */
00544     if (fad1->type != AGL_FONT_TYPE_TEXTURED ||
00545         fad2->type != AGL_FONT_TYPE_TEXTURED)
00546         return NULL;
00547 
00548     if (fad1->format != fad2->format)
00549         return NULL;
00550 
00551     /* alloc output font */
00552     retval = malloc(sizeof(struct FONT));
00553     retval->vtable = font_vtable_agl;
00554     retval->height = MAX(f1->height, f2->height);
00555 
00556     while (fad1 || fad2) {
00557         if (fad1 && (!fad2 || fad1->start < fad2->start)) {
00558             if (fad) {
00559                 fad->next = copy_glyph_range(fad1, fad1->start, fad1->end,
00560                                                                         &phony);
00561                 fad = fad->next;
00562             }
00563             else {
00564                 fad = copy_glyph_range(fad1, fad1->start, fad1->end, &phony);
00565                 retval->data = fad;
00566             }
00567             fad1 = fad1->next;
00568         }
00569         else {
00570             if (fad) {
00571                 fad->next = copy_glyph_range(fad2, fad2->start, fad2->end,
00572                                                                     &phony);
00573                 fad = fad->next;
00574             }
00575             else {
00576                 fad = copy_glyph_range(fad2, fad2->start, fad2->end, &phony);
00577                 retval->data = fad;
00578             }
00579             fad2 = fad2->next;
00580         }
00581     }
00582 
00583     return retval;
00584 }
00585 #endif
00586 
00587 
00588 
00589 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0)
00590 /* agl_transpose_font:
00591  * font vtable entry
00592  * Transposes characters in a font.
00593  */
00594 static int agl_transpose_font(FONT *f, int drange) {
00595     FONT_AGL_DATA* fad = 0;
00596 
00597     if (!f)
00598         return -1;
00599 
00600     fad = (FONT_AGL_DATA*)(f->data);
00601 
00602     while(fad) {
00603         FONT_AGL_DATA* next = fad->next;
00604         fad->start += drange;
00605         fad->end += drange;
00606         fad = next;
00607     }
00608 
00609     return 0;
00610 }
00611 #endif
00612 
00613 
00614 
00615 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */
00628 FONT *allegro_gl_convert_allegro_font(FONT *f, int type, float scale) {
00629     GLint format = allegro_gl_get_texture_format(NULL);
00630     return allegro_gl_convert_allegro_font_ex(f, type, scale, format);
00631 }
00632 
00633 
00634 
00635 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */
00690 FONT *allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale,
00691                                          GLint format) {
00692     int max = 0, height = 0;
00693     int i;
00694     FONT *dest;
00695     FONT_AGL_DATA *destdata;
00696 
00697     union {
00698         FONT_MONO_DATA* mf;
00699         FONT_COLOR_DATA* cf;
00700         void *ptr;
00701     } dat;
00702     
00703     if (!__allegro_gl_valid_context) {
00704         return NULL;
00705     }
00706 
00707     if (!f) {
00708         TRACE("** ERROR ** convert_allegro_font: Null source\n");
00709         return NULL;
00710     }
00711 
00712     /* Make sure it's an Allegro font - we don't want any surprises */
00713 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
00714     if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color && f->vtable != font_vtable_trans) {
00715 #else
00716     if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color) {
00717 #endif
00718         TRACE("** ERROR ** convert_allegro_font: Source font is not "
00719               "in Allegro format\n");
00720         return NULL;
00721     }
00722 
00723     /* No vector fonts allowed as destination */
00724     if (type == AGL_FONT_TYPE_OUTLINE) {
00725         /* Can't convert bitmap to vector font */
00726         TRACE("** ERROR ** convert_allegro_font: Unable to convert a "
00727               "pixmap font to a vector font.\n");
00728         return NULL;
00729     }
00730 
00731     /* Make sure the scaling factor is appropreate */
00732     if (fabs(scale) < 0.001) {
00733         TRACE("** Warning ** convert_allegro_font: Scaling factor might be "
00734               "too small: %f\n", scale);
00735     }
00736 
00737     /* Count number of ranges */
00738     max = get_font_ranges(f);;
00739 
00740     /* There should really be an API for this */
00741     dest = (FONT*)malloc(sizeof(FONT));
00742     if (!dest) {
00743         TRACE("** ERROR ** convert_allegro_font: Ran out of memory "
00744               "while allocating %i bytes\n", (int)sizeof(FONT));
00745         return NULL;
00746     }
00747     destdata = (FONT_AGL_DATA*)malloc(sizeof(FONT_AGL_DATA) * max);
00748     if (!destdata) {
00749         TRACE("** ERROR ** convert_allegro_font: Ran out of memory "
00750               "while allocating %i bytes\n", (int)sizeof(FONT_AGL_DATA) * max);
00751         return NULL;
00752     }
00753     memset(destdata, 0, sizeof(FONT_AGL_DATA) * max);
00754     
00755     /* Construct the linked list */
00756     for (i = 0; i < max - 1; i++) {
00757         destdata[i].next = &destdata[i + 1];
00758     }
00759     destdata[max - 1].next = NULL;
00760     
00761     /* Set up the font */
00762     dest->data = destdata;
00763     dest->vtable = font_vtable_agl;
00764     dest->height = 0;
00765 
00766     destdata->type = type;
00767 
00768     if (type == AGL_FONT_TYPE_DONT_CARE) {
00769         destdata->type = AGL_FONT_TYPE_TEXTURED;
00770     }
00771 
00772 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
00773     destdata->has_alpha = (f->vtable == font_vtable_trans);
00774 #else
00775     destdata->has_alpha = 0;
00776 #endif
00777 
00778     /* Convert each range */
00779     dat.ptr = f->data;
00780 
00781     while (dat.ptr) {
00782 
00783         if (type == AGL_FONT_TYPE_BITMAP) {
00784             aglf_convert_allegro_font_to_bitmap(destdata, f, dat.ptr, &height);
00785         }
00786         else if (type == AGL_FONT_TYPE_TEXTURED) {
00787             aglf_convert_allegro_font_to_texture(destdata, f, dat.ptr, &height,
00788                                                  scale, format);
00789         }
00790             
00791         if (height > dest->height) {
00792             dest->height = height;
00793         }
00794             
00795         dat.ptr = ((f->vtable == font_vtable_mono)
00796                 ? (void*)dat.mf->next : (void*)dat.cf->next);
00797         
00798         destdata = destdata->next;
00799     }
00800     dest->height = height;
00801 
00802     return dest;
00803 }
00804 
00805 
00806 
00807 /* QSort helper for sorting glyphs according to width,
00808  * then height - largest first.
00809  */
00810 static int sort_glyphs(const void *c1, const void *c2) {
00811     AGL_GLYPH *g1 = (AGL_GLYPH*)c1;
00812     AGL_GLYPH *g2 = (AGL_GLYPH*)c2;
00813     
00814     if (g1->w < g2->w) {
00815         return 1;
00816     }
00817     else if (g1->w == g2->w) {
00818         return -g1->h + g2->h;
00819     }
00820     else {
00821         return -1;
00822     }
00823 }
00824 
00825 
00826 
00827 /* QSort helper for unsorting glyphs.
00828  */
00829 static int unsort_glyphs(const void *c1, const void *c2) {
00830     AGL_GLYPH *g1 = (AGL_GLYPH*)c1;
00831     AGL_GLYPH *g2 = (AGL_GLYPH*)c2;
00832     
00833     return g1->glyph_num - g2->glyph_num;
00834 }
00835 
00836 
00837 
00838 /* QSort helper for sorting textures by area.
00839  */
00840 static int sort_textures(const void *c1, const void *c2) {
00841     texture_size *t1 = (texture_size*)c1;
00842     texture_size *t2 = (texture_size*)c2;
00843     
00844     return t1->w * t1->h - t2->w * t2->h;
00845 }
00846 
00847 
00848 
00849 #ifdef SAVE_FONT_SCREENSHOT
00850 static void save_shot(BITMAP *bmp) {
00851 
00852     int i;
00853     char name[128];
00854 
00855     for (i = 0; i < 1000; i++) {
00856         /* TGA, in case it is a truecolor font with alpha */
00857         sprintf(name, "fonttest_%02i.tga", i);
00858         if (!exists(name)) {
00859             save_tga(name, bmp, NULL);
00860             break;
00861         }
00862     }
00863 }
00864 #endif
00865 
00866 
00867 
00868 /* Helper function. This will try to place all the glyphs in the bitmap the
00869  * best way it can
00870  */
00871 static int aglf_sort_out_glyphs(BITMAP *bmp, AGL_GLYPH *glyphs, const int beg,
00872                                 const int end) {
00873 
00874     int i, j;
00875     int last_line = 0;
00876     int last_x = 0;
00877 
00878     /* We now try to make all the glyphs fit on the bitmap */
00879     for (i = 0; i < end - beg; i++) {
00880         int collide = FALSE;
00881     
00882         /* Place glyphs on last_line */
00883         glyphs[i].x = last_x;
00884         glyphs[i].y = last_line;
00885         
00886         /* Check for collision */
00887         
00888         for (j = 0; j < i; j++) {
00889             if ((glyphs[i].x >= glyphs[j].x + glyphs[j].w)
00890                     || (glyphs[i].y >= glyphs[j].y + glyphs[j].h)
00891                     || (glyphs[j].x >= glyphs[i].x + glyphs[i].w)
00892                     || (glyphs[j].y >= glyphs[i].y + glyphs[i].h)) {
00893                 continue;
00894             }
00895             last_x = glyphs[j].x + glyphs[j].w;
00896             glyphs[i].x = last_x;
00897             j = 0;
00898         }
00899         
00900         if ((last_x + glyphs[i].w > bmp->w)
00901          || (last_line + glyphs[i].h > bmp->h)) {
00902             collide = TRUE;
00903         }
00904 
00905         if (collide) {
00906             /* If there was a collision, we need to find the sprite with
00907              * the smallest height that is still grater than last_line.
00908              * We also need to redo this glyph.
00909              */
00910             int min_line = bmp->h + 1;
00911             int min_glyph = -1;
00912 
00913             for (j = 0; j < i; j++) {
00914                 if ( glyphs[j].y + glyphs[j].h < min_line
00915                   && glyphs[j].y + glyphs[j].h
00916                   > last_line - FONT_CHARACTER_SPACING) {
00917 
00918                     min_line = glyphs[j].y + glyphs[j].h
00919                              + FONT_CHARACTER_SPACING;
00920                     min_glyph = j;
00921                 }
00922             }
00923             /* If it can't possibly all fit, failure */
00924             if (min_glyph == -1) {
00925                 TRACE("* Note * sort_out_glyphs: Unable to fit all glyphs into "
00926                       "the texture.\n");
00927                 return FALSE;
00928             }
00929             /* Otherwise, start over at the top of that glyph */
00930             last_x = glyphs[min_glyph].x;
00931             last_line = min_line;
00932 
00933             /* Redo this glyph */
00934             i--;
00935         }
00936         else {
00937             last_x += glyphs[i].w + FONT_CHARACTER_SPACING;
00938         }
00939     }
00940 
00941     /* All ok */
00942     return TRUE;
00943 }
00944 
00945 
00946 
00947 static int split_font(FONT *f, void *source, void **dest1, void **dest2) {
00948 
00949     union mixed_ptr range1, range2, src;
00950     int colored;
00951     int i;
00952     
00953     (*dest1) = NULL;
00954     (*dest2) = NULL;
00955     src.ptr = source;
00956     
00957     colored = (f->vtable == font_vtable_mono) ? FALSE : TRUE;
00958 
00959     /* Allocate the ranges that we need */
00960     range1.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA)
00961                                 : sizeof(FONT_MONO_DATA));
00962 
00963     if (!range1.ptr) {
00964         TRACE("** ERROR ** split_font() - Ran out of memory while "
00965               "trying ot allocate %i bytes.\n",
00966               colored ? (int)sizeof(FONT_COLOR_DATA)
00967               : (int)sizeof(FONT_MONO_DATA));
00968         return FALSE;
00969     }
00970     range2.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA)
00971                                 : sizeof(FONT_MONO_DATA));
00972 
00973     if (!range2.ptr) {
00974         TRACE("** ERROR ** split_font() - Ran out of memory while "
00975               "trying to allocate %i bytes.\n",
00976               colored ? (int)sizeof(FONT_COLOR_DATA)
00977                       : (int)sizeof(FONT_MONO_DATA));
00978         free(range1.ptr);
00979         return FALSE;
00980     }
00981     
00982     (*dest1) = range1.ptr;
00983     (*dest2) = range2.ptr;
00984     
00985     /* Now we split up the range */
00986     if (colored) {
00987         /* Half the range */
00988         int mid = (src.cf->end - src.cf->begin) / 2;
00989         
00990         range1.cf->begin = src.cf->begin;
00991         range1.cf->end = mid;
00992         range2.cf->begin = mid;
00993         range2.cf->end = src.cf->end;
00994         
00995         range1.cf->next = NULL;
00996         range2.cf->next = NULL;
00997         
00998         /* Split up the bitmaps */
00999         range1.cf->bitmaps = malloc(sizeof(BITMAP*)
01000                                         * (range1.cf->end - range1.cf->begin));
01001         if (!range1.cf->bitmaps) {
01002             TRACE("** ERROR ** split_font() - Ran out of memory "
01003                   "while trying to allocate %i bytes.\n",
01004                   (int)sizeof(BITMAP*) * (range1.cf->end - range1.cf->begin));
01005             free(range1.ptr);
01006             free(range2.ptr);
01007             return FALSE;
01008         }
01009 
01010         range2.cf->bitmaps = malloc(sizeof(BITMAP*)
01011                                          * (range2.cf->end - range2.cf->begin));
01012         if (!range2.cf->bitmaps) {
01013             TRACE("** ERROR ** split_font() - Ran out of memory "
01014                   "while trying to allocate %i bytes.\n",
01015                   (int)sizeof(BITMAP*) * (range2.cf->end - range2.cf->begin));
01016             free(range1.cf->bitmaps);
01017             free(range1.ptr);
01018             free(range2.ptr);
01019             return FALSE;
01020         }
01021 
01022         
01023         for (i = 0; i < (range1.cf->end - range1.cf->begin); i++) {
01024             range1.cf->bitmaps[i] = src.cf->bitmaps[i];
01025         }
01026         for (i = 0; i < (range2.cf->end - range2.cf->begin); i++) {
01027             range2.cf->bitmaps[i] =
01028                        src.cf->bitmaps[i + range2.cf->begin - range1.cf->begin];
01029         }
01030     }
01031     else {
01032         /* Half the range */
01033         int mid = (src.mf->end - src.mf->begin) / 2;
01034         
01035         range1.mf->begin = src.mf->begin;
01036         range1.mf->end = mid;
01037         range2.mf->begin = mid;
01038         range2.mf->end = src.mf->end;
01039         
01040         range1.mf->next = NULL;
01041         range2.mf->next = NULL;
01042         
01043         /* Split up the bitmaps */
01044         range1.mf->glyphs = malloc(sizeof(FONT_GLYPH*)
01045                                          * (range1.mf->end - range1.mf->begin));
01046         if (!range1.mf->glyphs) {
01047             TRACE("** ERROR ** split_font() - Ran out of memory "
01048                   "while trying to allocate %i bytes.\n",
01049                 (int)sizeof(FONT_GLYPH*) * (range1.mf->end - range1.mf->begin));
01050             free(range1.ptr);
01051             free(range2.ptr);
01052             return FALSE;
01053         }
01054 
01055         range2.mf->glyphs = malloc(sizeof(FONT_GLYPH*)
01056                                          * (range2.mf->end - range2.mf->begin));
01057         if (!range2.mf->glyphs) {
01058             TRACE("** ERROR ** split_font() - Ran out of memory "
01059                   "while trying to allocate %i bytes.\n",
01060                 (int)sizeof(FONT_GLYPH*) * (range2.mf->end - range2.mf->begin));
01061             free(range1.mf->glyphs);
01062             free(range1.ptr);
01063             free(range2.ptr);
01064             return FALSE;
01065         }
01066         
01067         for (i = 0; i < (range1.mf->end - range1.mf->begin); i++) {
01068             range1.mf->glyphs[i] = src.mf->glyphs[i];
01069         }
01070         for (i = 0; i < (range2.mf->end - range2.mf->begin); i++) {
01071             range2.mf->glyphs[i] =
01072                         src.mf->glyphs[i + range2.mf->begin - range1.mf->begin];
01073         }
01074     }
01075     
01076     return TRUE;
01077 }
01078 
01079 
01080 
01081 /* Destroys a split font */
01082 static void destroy_split_font(FONT *f, union mixed_ptr range1,
01083                                         union mixed_ptr range2) {
01084     int colored;
01085     
01086     colored = (f->vtable == font_vtable_mono) ? FALSE : TRUE;
01087     
01088     if (colored) {
01089         free(range1.cf->bitmaps);
01090         free(range2.cf->bitmaps);
01091     }
01092     else {
01093         free(range1.mf->glyphs);
01094         free(range2.mf->glyphs);
01095     }
01096     
01097     free(range1.ptr);
01098     free(range2.ptr);
01099     
01100     return;
01101 }
01102 
01103 
01104 
01105 static int do_crop_font_range(FONT *f, AGL_GLYPH *glyphs, int beg, int end) {
01106 
01107     int i, j, k;
01108     int max = end - beg;
01109     char buf[32];
01110 
01111 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 4)
01112 #else
01113     int font_bg = text_mode(0);
01114 #endif
01115 
01116     /* Allocate a temp bitmap to work with */
01117     BITMAP *temp = create_bitmap(32, 32);
01118 
01119     if (!temp) {
01120         TRACE("** ERROR ** crop_font_range - Unable to create "
01121               "bitmap of size: %ix%i!\n", 32, 32);
01122         goto error;
01123     }
01124     
01125     /* Crop glyphs */
01126     for (i = 0; i < max; i++) {
01127         int used = 0;
01128 
01129         if (glyphs[i].w > temp->w || glyphs[i].h > temp->h) {
01130             int old_w = temp->w, old_h = temp->h;
01131             destroy_bitmap(temp);
01132             temp = create_bitmap(old_w * 2, old_h * 2);
01133             if (!temp) {
01134                 TRACE("** ERROR ** crop_font_range - Unable to "
01135                       "create bitmap of size: %ix%i!\n", old_w * 2, old_h * 2);
01136                 goto error;
01137             }
01138         }
01139         clear(temp);
01140 
01141         usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
01142 
01143 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 4)
01144         textout_ex(temp, f, buf, 0, 0,
01145                     makecol_depth(bitmap_color_depth(temp), 255, 255, 255), 0);
01146 #else
01147         textout(temp, f, buf, 0, 0,
01148                     makecol_depth(bitmap_color_depth(temp), 255, 255, 255));
01149 #endif
01150         
01151     
01152         /* Crop top */
01153         for (j = 0; j < glyphs[i].h; j++) {
01154             used = 0;
01155 
01156             for (k = 0; k < glyphs[i].w; k++) {
01157                 if (getpixel(temp, k, j)) {
01158                     used = 1;
01159                     glyphs[i].offset_y += j;
01160                     glyphs[i].h -= j;
01161                     break;
01162                 }
01163             }
01164             if (used)
01165                 break;
01166         }
01167 
01168         /* If just the top crop killed our glyph, then skip it entirely */
01169         if (!used) {
01170             TRACE("* Note * crop_font_range: skipping glyph %i\n", i);
01171             glyphs[i].offset_y = 0;
01172             glyphs[i].offset_h = glyphs[i].h - 1;
01173             glyphs[i].offset_w = glyphs[i].w - 2;
01174             glyphs[i].h = 1;
01175             glyphs[i].w = 1;
01176             continue;
01177         }
01178         
01179         /* Crop bottom */
01180         j = glyphs[i].h + glyphs[i].offset_y - 1;
01181         for ( /* above */; j >= glyphs[i].offset_y; j--) {
01182             used = 0;
01183 
01184             for (k = 0; k < glyphs[i].w; k++) {
01185                 if (getpixel(temp, k, j)) {
01186                     used = 1;
01187                     glyphs[i].offset_h +=
01188                                        glyphs[i].h + glyphs[i].offset_y - j - 2;
01189                     glyphs[i].h -= glyphs[i].h + glyphs[i].offset_y - j - 1;
01190                     break;
01191                 }
01192             }
01193             if (used)
01194                 break;
01195         }
01196 
01197         /* Crop Left */
01198         for (j = 0; j < glyphs[i].w; j++) {
01199             used = 0;
01200 
01201             k = MAX(glyphs[i].offset_y - 1, 0);
01202             for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
01203                 if (getpixel(temp, j, k)) {
01204                     used = 1;
01205                     glyphs[i].offset_x += j;
01206                     glyphs[i].w -= j;
01207                     break;
01208                 }
01209             }
01210             if (used)
01211                 break;
01212         }
01213 
01214         /* Crop Right */
01215         j = glyphs[i].w + glyphs[i].offset_x - 1;
01216         for (/* above */; j >= glyphs[i].offset_x; j--) {
01217             used = 0;
01218 
01219             k = MAX(glyphs[i].offset_y - 1, 0);
01220             for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
01221                 if (getpixel(temp, j, k)) {
01222                     used = 1;
01223                     glyphs[i].offset_w +=
01224                                        glyphs[i].w + glyphs[i].offset_x - 1 - j;
01225                     glyphs[i].w -= glyphs[i].w + glyphs[i].offset_x - j - 1;
01226                     break;
01227                 }
01228             }
01229             if (used)
01230                 break;
01231         }
01232 #ifdef LOGLEVEL
01233         TRACE("* Note * crop_font_range: Glyph %i (%c) offs: x: %i  y: %i, "
01234               "w: %i  h: %i,  offs: w: %i  h: %i\n", i, i + beg,
01235               glyphs[i].offset_x, glyphs[i].offset_y, glyphs[i].w, glyphs[i].h,
01236               glyphs[i].offset_w, glyphs[i].offset_h);
01237 #endif
01238     }
01239     
01240     destroy_bitmap(temp);
01241 
01242     return TRUE;
01243 
01244 error:
01245     if (temp) {
01246         destroy_bitmap(temp);
01247     }
01248 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 4)
01249 #else
01250     text_mode(font_bg);
01251 #endif
01252     return FALSE;   
01253 }
01254 
01255 
01256 
01257 /* Crops a font over a particular range */
01258 static int crop_font_range(FONT *f, void *src, int beg, int end,
01259                            AGL_GLYPH *glyphs,
01260                            int *net_area, int *gross_area,
01261                            int *max_w, int *max_h) {
01262 
01263     int i;
01264     int crop = 1;
01265     int max = end - beg;
01266     int ret = TRUE;
01267 
01268     union mixed_ptr dat;
01269     dat.ptr = src;
01270 
01271     /* Disable cropping for trucolor fonts. */
01272 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01273     if (f->vtable == font_vtable_color || f->vtable == font_vtable_trans) {
01274 #else
01275     if (f->vtable == font_vtable_color) {
01276 #endif
01277         FONT_COLOR_DATA *fcd = f->data;
01278         if (bitmap_color_depth(fcd->bitmaps[0]) != 8) {
01279             crop = 0;
01280         }
01281     }
01282 
01283     /* Load default sizes */
01284     for (i = 0; i < max; i++) {
01285         glyphs[i].glyph_num = i;
01286 
01287         if (f->vtable == font_vtable_mono) {
01288             glyphs[i].w = dat.mf->glyphs[i]->w + 1;
01289             glyphs[i].h = dat.mf->glyphs[i]->h + 1;
01290         } else {
01291             glyphs[i].w = dat.cf->bitmaps[i]->w + 1;
01292             glyphs[i].h = dat.cf->bitmaps[i]->h + 1;
01293         }
01294         glyphs[i].offset_w = -1;
01295         glyphs[i].offset_h = -1;
01296 
01297         /* Not placed yet */
01298         glyphs[i].x = -1;
01299     }
01300     
01301     if (crop) {
01302         ret = do_crop_font_range(f, glyphs, beg, end);
01303     }
01304 
01305     (*gross_area) = 0;
01306     (*net_area) = 0;
01307     (*max_w) = 0;
01308     (*max_h) = 0;
01309 
01310     /* Find max w and h, total area covered by the bitmaps, and number of
01311      * glyphs
01312      */
01313     for (i = 0; i < max; i++) {
01314         if (glyphs[i].w > *max_w) (*max_w) = glyphs[i].w;
01315         if (glyphs[i].h > *max_h) (*max_h) = glyphs[i].h;
01316         (*net_area) += glyphs[i].w * glyphs[i].h;
01317         (*gross_area) += (glyphs[i].w + FONT_CHARACTER_SPACING)
01318                        * (glyphs[i].h + FONT_CHARACTER_SPACING);
01319     }
01320     return ret;
01321 
01322 }
01323 
01324 
01325 
01326 static int get_format_num_channels(GLenum format) {
01327         
01328     switch (format) {
01329     case 1:
01330     case GL_ALPHA:
01331     case GL_ALPHA4:
01332     case GL_ALPHA8:
01333     case GL_ALPHA12:
01334     case GL_ALPHA16:
01335     case GL_ALPHA16F_ARB:
01336     case GL_ALPHA32F_ARB:
01337     case GL_INTENSITY:
01338     case GL_INTENSITY4:
01339     case GL_INTENSITY8:
01340     case GL_INTENSITY12:
01341     case GL_INTENSITY16:
01342     case GL_INTENSITY16F_ARB:
01343     case GL_INTENSITY32F_ARB:
01344     case GL_LUMINANCE:
01345     case GL_LUMINANCE4:
01346     case GL_LUMINANCE8:
01347     case GL_LUMINANCE12:
01348     case GL_LUMINANCE16:
01349     case GL_LUMINANCE16F_ARB:
01350     case GL_LUMINANCE32F_ARB:
01351         return 1;
01352     case 2:
01353     case GL_LUMINANCE_ALPHA:
01354     case GL_LUMINANCE4_ALPHA4:
01355     case GL_LUMINANCE12_ALPHA4:
01356     case GL_LUMINANCE8_ALPHA8:
01357     case GL_LUMINANCE6_ALPHA2:
01358     case GL_LUMINANCE12_ALPHA12:
01359     case GL_LUMINANCE16_ALPHA16:
01360     case GL_LUMINANCE_ALPHA16F_ARB:
01361     case GL_LUMINANCE_ALPHA32F_ARB:
01362         return 2;
01363     case 3:
01364     case GL_RGB:
01365     case GL_R3_G3_B2:
01366     case GL_RGB4:
01367     case GL_RGB5:
01368     case GL_RGB8:
01369     case GL_RGB10:
01370     case GL_RGB12:
01371     case GL_RGB16:
01372     case GL_RGB16F_ARB:
01373     case GL_RGB32F_ARB:
01374         return 3;
01375     case 4:
01376     case GL_RGBA:
01377     case GL_RGBA2:
01378     case GL_RGBA4:
01379     case GL_RGB5_A1:
01380     case GL_RGBA8:
01381     case GL_RGB10_A2:
01382     case GL_RGBA12:
01383     case GL_RGBA16:
01384     case GL_RGBA16F_ARB:
01385     case GL_RGBA32F_ARB:
01386         return 4;
01387     default:
01388         return 0;
01389     }
01390 }
01391 
01392 
01393 
01394 /* Tries to find a texture that will fit the font
01395  */
01396 static BITMAP* look_for_texture(int beg, int end, AGL_GLYPH *glyphs,
01397             int max_w, int max_h, int total_area, GLint format, int has_alpha) {
01398 
01399     BITMAP *bmp = NULL;
01400     int i, j;
01401 
01402     /* Max texture size (1 << n) */
01403     /* XXX <rohannessian> We should use ARB_np2 if we can
01404      *
01405      * Other note: w*h shouldn't exceed 31 bits; otherwise, we get funny
01406      * behavior on 32-bit architectures. Limit texture sizes to 32k*32k
01407      * (30 bits).
01408      */
01409 #define MIN_TEXTURE_SIZE 2
01410 #define NUM_TEXTURE_SIZE 13
01411     texture_size texture_sizes[NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE];
01412 
01413     /* Set up texture sizes */
01414     for (i = 0; i < NUM_TEXTURE_SIZE; i++) {
01415         for (j = 0; j < NUM_TEXTURE_SIZE; j++) {
01416             texture_sizes[j + i * NUM_TEXTURE_SIZE].w =
01417                                                     1 << (j + MIN_TEXTURE_SIZE);
01418             texture_sizes[j + i * NUM_TEXTURE_SIZE].h =
01419                                                     1 << (i + MIN_TEXTURE_SIZE);
01420         }
01421     }
01422 
01423     /* Sort texture sizes by area */
01424     qsort(texture_sizes, NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE,
01425                                           sizeof(texture_size), &sort_textures);
01426 
01427     for (i = 0; i < NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE; i++) {
01428         int num_channels;
01429         
01430         /* Check the area - it must be larger than
01431          * all the glyphs
01432          */
01433         texture_size *t = &texture_sizes[i];
01434         int area = t->w * t->h;
01435         int depth = 24;
01436 
01437         TRACE("* Note * look_for_texture: Trying size %ix%i\n", t->w, t->h);
01438 
01439         if (area < total_area) {
01440             TRACE(" * Note * look_for_texture: Area too small. Skipping.\n");
01441             continue;
01442         }
01443             
01444         /* Check against max values */
01445         if ((t->h < max_h) || (t->w < max_w)) {
01446             TRACE("* Note * look_for_texture: Max values not reached\n");
01447             continue;
01448         }
01449 
01450         /* Check that the texture can, in fact, be created */
01451         num_channels = get_format_num_channels(format);
01452         if (num_channels == 1) {
01453             depth = 8;
01454         }
01455         else if (num_channels == 4) {
01456             depth = 32;
01457         }
01458         else {
01459             depth = 24;
01460         }
01461         bmp = create_bitmap_ex(depth, t->w, t->h);
01462 
01463         if (!bmp) {
01464             TRACE("** Warning ** look_for_texture: Out of memory while "
01465                   "creating bitmap\n");
01466             continue;
01467         }
01468 
01469         if (!aglf_check_texture(bmp, format, has_alpha)) {
01470             TRACE("* Note * look_for_texture: Texture rejected by driver\n");
01471             destroy_bitmap(bmp);
01472             bmp = NULL;
01473             continue;
01474         }
01475 
01476         /* Sort out the glyphs */
01477         TRACE("* Note * look_for_texture: Sorting on bmp: %p, beg: %i, "
01478               "end: %i\n", bmp, beg, end);
01479 
01480         if (aglf_sort_out_glyphs(bmp, glyphs, beg, end) == TRUE) {
01481             /* Success? */
01482             return bmp;
01483         }
01484 
01485         /* Failure? Try something else */
01486         TRACE("* Note * look_for_texture: Conversion failed\n");
01487         destroy_bitmap(bmp);
01488         bmp = NULL;
01489     }
01490     
01491     return NULL;
01492 }
01493 
01494 
01495 
01496 /* Function to draw a character in a bitmap for conversion */
01497 static int draw_glyphs(BITMAP *bmp, FONT *f, GLint format, int beg, int end,
01498                        AGL_GLYPH *glyphs) {
01499     char buf[32];
01500     int i, j;
01501 
01502     if (bitmap_color_depth(bmp) == 8) {
01503         /* Generate an alpha font */
01504         BITMAP *rgbbmp = create_bitmap_ex(24, bmp->w, bmp->h);
01505         
01506         if (!rgbbmp) {
01507             TRACE("** ERROR ** convert_allegro_font_to_texture: "
01508                   "Ran out of memory while creating %ix%ix%i bitmap!\n",
01509                   bmp->w, bmp->h, 24);
01510             return FALSE;
01511         }
01512 
01513         clear_bitmap(rgbbmp);
01514         
01515         for (i = 0; i < end - beg; i++) {
01516             usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
01517             
01518 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 4)
01519             textout_ex(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
01520                                       glyphs[i].y - glyphs[i].offset_y, -1, -1);
01521 #else
01522             {
01523               int bg = text_mode(-1);
01524               textout(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
01525                                           glyphs[i].y - glyphs[i].offset_y, -1);
01526               text_mode(bg);
01527             }
01528 #endif
01529         }
01530 
01531         /* Convert back to 8bpp */
01532         for (j = 0; j < bmp->h; j++) {
01533             for (i = 0; i < bmp->w; i++) {
01534                 int pix = _getpixel24(rgbbmp, i, j);
01535                 int r = getr24(pix);
01536                 int g = getg24(pix);
01537                 int b = getb24(pix);
01538                 int gray = (r * 77 + g * 150 + b * 28 + 255) >> 8;
01539                 _putpixel(bmp, i, j, MID(0, gray, 255));
01540             }
01541         }
01542         destroy_bitmap(rgbbmp);
01543     }
01544     else {
01545 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01546         int borrowed_color_vtable = FALSE;
01547 
01548         //In order to keep the alpha channel in textout_ex we borrow
01549         //the color font vtable which uses maked_blit() instead of
01550         //draw_trans_sprite() to draw glyphs.
01551         if (f->vtable == font_vtable_trans) {
01552             f->vtable = font_vtable_color;
01553             borrowed_color_vtable = TRUE;
01554         }
01555 #endif
01556 
01557         if (get_format_num_channels(format) == 4) {
01558             clear_to_color(bmp, bitmap_mask_color(bmp));
01559         }
01560         else {
01561             clear_bitmap(bmp);
01562         }
01563 
01564         for (i = 0; i < end - beg; i++) {
01565             usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
01566 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 1, 4)
01567             textout_ex(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
01568                      glyphs[i].y - glyphs[i].offset_y, -1, -1);
01569 #else
01570             {
01571               int bg = text_mode(-1);
01572               textout(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
01573                          glyphs[i].y - glyphs[i].offset_y, -1);
01574               text_mode(bg);
01575             }
01576 #endif
01577         }
01578 
01579 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01580         if (borrowed_color_vtable) {
01581             f->vtable = font_vtable_trans;
01582         }
01583 #endif
01584     }
01585 
01586     return TRUE;
01587 }
01588 
01589 
01590 
01591 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA *dest, FONT *f,
01592                             void *src, int *height, float scale, GLint format) {
01593 
01594     int max = 0;
01595     BITMAP *bmp = NULL;
01596     int beg = 0, end = 0;
01597     int max_w, max_h;
01598     int total_area, gross_area;
01599     
01600     AGL_GLYPH *glyph_coords;
01601 
01602     union mixed_ptr dat;
01603     dat.ptr = src;
01604 
01605     if (f->vtable == font_vtable_mono) {
01606         beg = dat.mf->begin;
01607         end = dat.mf->end;
01608         max = dat.mf->end - dat.mf->begin;
01609         if (format == -1) {
01610             format = GL_INTENSITY4;
01611         }
01612     }
01613 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01614     else if (f->vtable == font_vtable_color || f->vtable == font_vtable_trans) {
01615 #else
01616     else if (f->vtable == font_vtable_color) {
01617 #endif
01618         beg = dat.cf->begin;
01619         end = dat.cf->end;
01620         max = dat.cf->end - dat.cf->begin;
01621         if (format == -1) {
01622 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01623             format = f->vtable == font_vtable_trans ? GL_RGBA8 : GL_RGB8;
01624 #else
01625             format = GL_RGB8;
01626 #endif
01627         }
01628     }
01629 
01630     /* Allocate glyph sizes */
01631     glyph_coords = malloc(max * sizeof(AGL_GLYPH));
01632     memset(glyph_coords, 0, max * sizeof(AGL_GLYPH));
01633 
01634     if (crop_font_range(f, dat.ptr, beg, end, glyph_coords,
01635                           &total_area, &gross_area, &max_w, &max_h) == FALSE) {
01636         TRACE("* Note * convert_allegro_font_to_texture: Unable to crop font "
01637               "range\n");
01638         free(glyph_coords);
01639         return;
01640     }
01641 
01642     TRACE("* Note * convert_allegro_font_to_texture: Total area of glyphs: "
01643           "%i pixels (%i pixels gross) - max_w: %i, max_h: %i\n",
01644           total_area, gross_area, max_w, max_h);
01645 
01646     /* Sort glyphs by width, then height */
01647     qsort(glyph_coords, end - beg, sizeof(AGL_GLYPH), &sort_glyphs);
01648 
01649 
01650     /* Now, we look for the appropreate texture size */
01651     bmp = look_for_texture(beg, end, glyph_coords, max_w, max_h,
01652                            total_area, format, dest->has_alpha);
01653 
01654     /* No texture sizes were found - we should split the font up */
01655     if (!bmp) {
01656         union mixed_ptr f1, f2;
01657         FONT_AGL_DATA *dest1, *dest2;
01658 
01659         free(glyph_coords);
01660 
01661         dest1 = dest;
01662         dest2 = malloc(sizeof(FONT_AGL_DATA));
01663 
01664         if (!dest2) {
01665             TRACE("** ERROR ** convert_allegro_font_to_texture: "
01666                   "Out of memory while trying to allocate %i bytes.\n",
01667                   (int)sizeof(FONT_AGL_DATA));
01668             return;
01669         }
01670 
01671         memset(dest2, 0, sizeof(FONT_AGL_DATA));
01672 
01673         dest2->next = dest1->next;
01674         dest1->next = dest2;
01675         dest2->is_free_chunk = TRUE;
01676         
01677         if (split_font(f, dat.ptr, &f1.ptr, &f2.ptr) == FALSE) {
01678             TRACE("** ERROR ** convert_allegro_font_to_texture: Unable "
01679                   "to split font!\n");
01680             dest1->next = dest2->next;
01681             free(dest2);
01682             return;
01683         }
01684 
01685         aglf_convert_allegro_font_to_texture(dest1, f, &f1, height, scale,
01686                                              format);
01687         aglf_convert_allegro_font_to_texture(dest2, f, &f2, height, scale,
01688                                              format);
01689         destroy_split_font(f, f1, f2);
01690         
01691         return;
01692     }
01693 
01694     TRACE("* Note * convert_allegro_font_to_texture: Using texture of size "
01695           "%ix%i for font conversion.\n", bmp->w, bmp->h);
01696 
01697     /* Now that all the glyphs are in place, we draw them into the bitmap */
01698     if (draw_glyphs(bmp, f, format, beg, end, glyph_coords) == FALSE) {
01699         destroy_bitmap(bmp);
01700         free(glyph_coords);
01701         return;
01702     }
01703 
01704     /* Un-Sort glyphs  */
01705     qsort(glyph_coords, end - beg, sizeof(AGL_GLYPH), &unsort_glyphs);
01706 
01707 #if (defined SAVE_FONT_SCREENSHOT)
01708         save_shot(bmp);
01709 #endif
01710 
01711     dest->list_base =
01712              create_textured_font_call_lists(glyph_coords, max, bmp,
01713                                              scale, height);
01714 
01715     dest->texture = aglf_upload_texture(bmp, format, dest->has_alpha);
01716     dest->type = AGL_FONT_TYPE_TEXTURED;
01717     dest->format = format;
01718     dest->scale = scale;
01719     dest->start = beg;
01720     dest->end = end;
01721     dest->data = bmp;
01722     dest->glyph_coords = glyph_coords;
01723 
01724     return;
01725 }
01726 
01727 
01728 
01729 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
01730                                                        void *src, int *height) {
01731 
01732     int max = 0;
01733     int i, j, k;
01734     int beg = 0, end = 0;
01735     int mask;
01736     FONT_GLYPH **glyph;
01737 
01738     union {
01739         FONT_MONO_DATA* mf;
01740         FONT_COLOR_DATA* cf;
01741         void *ptr;
01742     } dat;
01743 
01744     dat.ptr = src;
01745 
01746     if (f->vtable == font_vtable_mono)
01747         max = dat.mf->end - dat.mf->begin;
01748 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01749     else if (f->vtable == font_vtable_color || f->vtable == font_vtable_trans)
01750 #else
01751     else if (f->vtable == font_vtable_color)
01752 #endif
01753         max = dat.cf->end - dat.cf->begin;
01754     else
01755         return;
01756 
01757     glyph = malloc(sizeof(FONT_GLYPH*) * max);
01758 
01759     if (!glyph) {
01760         TRACE("** ERROR ** convert_allegro_font_to_bitmap: Ran out of "
01761               "memory while allocating %i bytes\n", (int)sizeof(FONT_GLYPH));
01762         return;
01763     }
01764     
01765     *height = f->height;
01766         
01767     if (f->vtable == font_vtable_mono) {        
01768     
01769         /* for each glyph */
01770         for (i = 0; i < max; i++) {     
01771             FONT_GLYPH *oldgl = dat.mf->glyphs[i];
01772     
01773             int size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4
01774                                                                      * oldgl->h;
01775     
01776             /* create new glyph */
01777             FONT_GLYPH *newgl = (FONT_GLYPH*)malloc(size);
01778     
01779             if (!newgl)
01780                 break;
01781     
01782             memset(newgl, 0, size);
01783     
01784             newgl->w = oldgl->w;
01785             newgl->h = oldgl->h;
01786 
01787             /* update the data */
01788             for (j = 0; j < oldgl->h; j++) {
01789                 for (k = 0; k < ((oldgl->w + 7) / 8); k++) {
01790                     int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
01791                                + k;
01792                     newgl->dat[addr] = oldgl->dat[j * ((oldgl->w + 7) / 8) + k];
01793                 }
01794             }
01795 
01796             glyph[i] = newgl;
01797         }
01798     }
01799     /* Reduce to 1 bit */
01800 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
01801     else if (f->vtable == font_vtable_color || f->vtable == font_vtable_trans) {
01802 #else
01803     else if (f->vtable == font_vtable_color) {
01804 #endif
01805         /* for each glyph */
01806         for (i = 0; i < max; i++) {
01807 
01808             int size;
01809             BITMAP *oldgl = dat.cf->bitmaps[i];
01810             FONT_GLYPH *newgl;
01811 
01812             mask = bitmap_mask_color(oldgl);
01813 
01814             size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4 * oldgl->h;
01815 
01816             /* create new glyph */
01817             newgl = (FONT_GLYPH*)malloc(size);
01818 
01819             if (!newgl)
01820                 break;
01821 
01822             memset(newgl, 0, size);
01823 
01824             newgl->w = oldgl->w;
01825             newgl->h = oldgl->h;
01826 
01827             /* update the data */
01828             for (j = 0; j < oldgl->h; j++) {
01829                 for (k = 0; k < oldgl->w; k++) {
01830                     int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
01831                              + (k / 8);
01832                     newgl->dat[addr] |= (getpixel(oldgl, k, j) == mask)
01833                                      ? 0 : (1 << (k & 7));
01834                 }
01835             }
01836 
01837             glyph[i] = newgl;
01838         }
01839     }
01840     /* Create call lists */
01841     {
01842         GLuint list = glGenLists(max);
01843 
01844         for (i = 0; i < max; i++) {
01845             glNewList(list + i, GL_COMPILE);
01846 
01847             glBitmap(glyph[i]->w, glyph[i]->h, 0, 0, glyph[i]->w, 0,
01848                      glyph[i]->dat);
01849 
01850             glEndList();
01851         }
01852         dest->list_base = list;
01853     }
01854         
01855     dest->is_free_chunk = 0;
01856     dest->type = AGL_FONT_TYPE_BITMAP;
01857     dest->start = beg;
01858     dest->end = end;
01859     dest->data = glyph;
01860 
01861     return;
01862 }
01863 
01864 
01865 
01866 static int aglf_check_texture(BITMAP *bmp, GLint format, int has_alpha) {
01867 
01868     int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP;
01869 
01870     if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
01871      || format == GL_INTENSITY4 || format == GL_INTENSITY8
01872      || format == GL_INTENSITY
01873      || format == GL_LUMINANCE4 || format == GL_LUMINANCE8
01874      || format == GL_LUMINANCE
01875      || format == 1) {
01876         flags |= AGL_TEXTURE_ALPHA_ONLY;
01877     }
01878     else if (format == GL_RGBA8) {
01879         if (has_alpha) {
01880             flags |= AGL_TEXTURE_HAS_ALPHA;
01881         }
01882         else {
01883             flags |= AGL_TEXTURE_MASKED;
01884         }
01885     }
01886 
01887     return allegro_gl_check_texture_ex(flags, bmp, format);
01888 }
01889 
01890 
01891 
01892 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format, int has_alpha) {
01893 
01894     int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP;
01895     GLuint texture;
01896 
01897     if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
01898      || format == GL_INTENSITY4 || format == GL_INTENSITY8
01899      || format == GL_INTENSITY
01900      || format == GL_LUMINANCE4 || format == GL_LUMINANCE8
01901      || format == GL_LUMINANCE
01902      || format == 1) {
01903         flags |= AGL_TEXTURE_ALPHA_ONLY;
01904     }
01905     else if (get_format_num_channels(format) == 4) {
01906         if (has_alpha) {
01907             flags |= AGL_TEXTURE_HAS_ALPHA;
01908         }
01909         else {
01910             flags |= AGL_TEXTURE_MASKED;
01911         }
01912     }
01913 
01914     TRACE("* Want texture format: 0x%x\n", format);
01915     texture = allegro_gl_make_texture_ex(flags, bmp, format);
01916     TRACE("* Texture ID is: %u\n", texture);
01917 
01918     return texture;
01919 }
01920 

Generated on Mon Apr 3 18:20:13 2006 for AllegroGL by  doxygen 1.4.6