fontconv.c

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

Generated on Sun Dec 3 18:06:49 2006 for AllegroGL by  doxygen 1.5.1