Main Page | Modules | File List | Globals | Related Pages

fontconv.c

Go to the documentation of this file.
00001 
00011 #include <math.h>
00012 #include <string.h>
00013 #include <stdio.h>
00014 
00015 #include <allegro.h>
00016 #include <allegro/internal/aintern.h>
00017 
00018 #include "alleggl.h"
00019 #include "allglint.h"
00020 
00021 #ifdef ALLEGRO_MACOSX
00022 #include <OpenGL/glu.h>
00023 #else
00024 #include <GL/glu.h>
00025 #endif
00026 
00027 #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGROGL_GENERIC_DRIVER
00028 #include <xalleg.h>
00029 #include <GL/glx.h>
00030 #endif
00031 
00032 
00033 /* Number of pixels between characters in a textured font.
00034  */
00035 #define FONT_CHARACTER_SPACING 2
00036 
00037 /* Uncomment to have the font generator dump screenshots of the textures it
00038  * generates.
00039  */
00040 /* #define SAVE_FONT_SCREENSHOT */
00041 
00042 
00043 static int agl_get_font_height(AL_CONST FONT *f);
00044 
00045 
00046 FONT_VTABLE _agl_font_vtable = {
00047     agl_get_font_height,
00048     NULL,
00049     NULL,
00050     NULL,
00051     NULL,
00052     allegro_gl_destroy_font
00053 };
00054 
00055 FONT_VTABLE *font_vtable_agl = &_agl_font_vtable;
00056 
00057 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
00058                                                 void *src, int *height);
00059 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA *dest, FONT *f,
00060                              void *src, int *height, float scale, GLint format);
00061 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format);
00062 static int aglf_check_texture(BITMAP *bmp, GLint format);
00063 
00064 
00065 
00066 union mixed_ptr {
00067     FONT_MONO_DATA* mf;
00068     FONT_COLOR_DATA* cf;
00069     void *ptr;
00070 };
00071 
00072 
00073 
00074 /* Stores info about a glyph before rendering */
00075 typedef struct glyph {
00076     int glyph_num;
00077     int x, y, w, h;
00078     int offset_x, offset_y, offset_w, offset_h;
00079 } glyph;
00080 
00081 
00082 /*   <ofs_x>
00083      +--------------------+
00084      |                    |
00085      |    +-------+       |
00086      |    | glyph |       |
00087      |    +-------+       |
00088      |                    |
00089      +--------------------+
00090           <   w   ><ofs_w >
00091      <      polygon       >
00092 */
00093 
00094 
00095 
00096 /* Stores info about a texture size */
00097 typedef struct texture_size {
00098     int w, h;
00099 } texture_size;
00100 
00101 
00102 
00103 static int agl_get_font_height(AL_CONST FONT *f) {
00104     return f->height;
00105 }
00106 
00107 
00108 
00109 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */
00122 FONT *allegro_gl_convert_allegro_font(FONT *f, int type, float scale) {
00123     GLint format = allegro_gl_get_texture_format(NULL);
00124     return allegro_gl_convert_allegro_font_ex(f, type, scale, format);
00125 }
00126 
00127 
00128 
00129 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */
00179 FONT *allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale,
00180                                          GLint format) {
00181     int max = 0, height;
00182     int i;
00183     FONT *dest;
00184     FONT_AGL_DATA *destdata;
00185 
00186     union {
00187         FONT_MONO_DATA* mf;
00188         FONT_COLOR_DATA* cf;
00189         void *ptr;
00190     } dat;
00191     
00192     if (!__allegro_gl_valid_context) {
00193         return NULL;
00194     }
00195 
00196     if (!f) {
00197         TRACE("** ERROR ** convert_allegro_font: Null source\n");
00198         return NULL;
00199     }
00200     
00201     /* Make sure it's an Allegro font - we don't want any surprises */
00202     if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color) {
00203         TRACE("** ERROR ** convert_allegro_font: Source font is not "
00204               "in Allegro format\n");
00205         return NULL;
00206     }
00207 
00208     /* No vector fonts allowed as destination */
00209     if (type == AGL_FONT_TYPE_OUTLINE) {
00210         /* Can't convert bitmap to vector font */
00211         TRACE("** ERROR ** convert_allegro_font: Unable to convert a "
00212               "pixmap font to a vector font.\n");
00213         return NULL;
00214     }
00215     
00216     /* Make sure the scaling factor is appropreate */
00217     if (fabs(scale) < 0.001) {
00218         TRACE("** Warning ** convert_allegro_font: Scaling factor might be "
00219               "too small: %f\n", scale);
00220     }
00221 
00222 
00223     /* Count number of ranges */
00224     max = 0;
00225     if (f->vtable == font_vtable_mono) {
00226         dat.mf = f->data;
00227         while (dat.mf) {
00228             max++;
00229             dat.mf = dat.mf->next;
00230         }
00231     }
00232     else if (f->vtable == font_vtable_color) {
00233         dat.cf = f->data;
00234         while (dat.cf) {
00235             max++;
00236             dat.cf = dat.cf->next;
00237         }
00238     }
00239 
00240     /* There should really be an API for this */
00241     dest = (FONT*)malloc(sizeof(FONT));
00242     if (!dest) {
00243         TRACE("** ERROR ** convert_allegro_font: Ran out of memory "
00244               "while allocating %i bytes\n", (int)sizeof(FONT));
00245         return NULL;
00246     }
00247     destdata = (FONT_AGL_DATA*)malloc(sizeof(FONT_AGL_DATA) * max);
00248     if (!destdata) {
00249         TRACE("** ERROR ** convert_allegro_font: Ran out of memory "
00250               "while allocating %i bytes\n", (int)sizeof(FONT_AGL_DATA) * max);
00251         return NULL;
00252     }
00253     memset(destdata, 0, sizeof(FONT_AGL_DATA) * max);
00254     
00255     /* Construct the linked list */
00256     for (i = 0; i < max - 1; i++) {
00257         destdata[i].next = &destdata[i + 1];
00258     }
00259     destdata[max - 1].next = NULL;
00260     
00261     /* Set up the font */
00262     dest->data = destdata;
00263     dest->vtable = font_vtable_agl;
00264     dest->height = 0;
00265 
00266     destdata->type = type;
00267 
00268     if (type == AGL_FONT_TYPE_DONT_CARE) {
00269         destdata->type = AGL_FONT_TYPE_TEXTURED;        
00270     }
00271 
00272 
00273     /* Convert each range */
00274     dat.ptr = f->data;
00275     
00276     while (dat.ptr) {
00277     
00278         if (type == AGL_FONT_TYPE_BITMAP) {
00279             aglf_convert_allegro_font_to_bitmap(destdata, f, dat.ptr, &height);
00280         }
00281         else if (type == AGL_FONT_TYPE_TEXTURED) {
00282             aglf_convert_allegro_font_to_texture(destdata, f, dat.ptr, &height,
00283                                                  scale, format);
00284         }
00285             
00286         if (height > dest->height) {
00287             dest->height = height;
00288         }
00289             
00290         dat.ptr = ((f->vtable == font_vtable_mono)
00291                 ? (void*)dat.mf->next : (void*)dat.cf->next);
00292         
00293         destdata = destdata->next;
00294     }
00295     dest->height = height;
00296 
00297     return dest;
00298 }
00299 
00300 
00301 
00302 /* QSort helper for sorting glyphs according to width,
00303  * then height - largest first.
00304  */
00305 static int sort_glyphs(const void *c1, const void *c2) {
00306     glyph *g1 = (glyph*)c1;
00307     glyph *g2 = (glyph*)c2;
00308     
00309     if (g1->w < g2->w) {
00310         return 1;
00311     }
00312     else if (g1->w == g2->w) {
00313         return -g1->h + g2->h;
00314     }
00315     else {
00316         return -1;
00317     }
00318 }
00319 
00320 
00321 
00322 /* QSort helper for unsorting glyphs.
00323  */
00324 static int unsort_glyphs(const void *c1, const void *c2) {
00325     glyph *g1 = (glyph*)c1;
00326     glyph *g2 = (glyph*)c2;
00327     
00328     return g1->glyph_num - g2->glyph_num;
00329 }
00330 
00331 
00332 
00333 /* QSort helper for sorting textures by area.
00334  */
00335 static int sort_textures(const void *c1, const void *c2) {
00336     texture_size *t1 = (texture_size*)c1;
00337     texture_size *t2 = (texture_size*)c2;
00338     
00339     return t1->w * t1->h - t2->w * t2->h;
00340 }
00341 
00342 
00343 
00344 #ifdef DEBUGMODE
00345 static void save_shot(BITMAP *bmp) {
00346 
00347     int i;
00348     char name[128];
00349 
00350     for (i = 0; i < 1000; i++) {
00351         sprintf(name, "fonttest_%02i.bmp", i);
00352         if (!exists(name)) {
00353             save_bmp(name, bmp, NULL);
00354             break;
00355         }
00356     }
00357 }
00358 #endif
00359 
00360 
00361 
00362 /* Helper function. This will try to place all the glyphs in the bitmap the
00363  * best way it can
00364  */
00365 static int aglf_sort_out_glyphs(BITMAP *bmp, glyph *glyphs, const int beg,
00366                                 const int end) {
00367 
00368     int i, j;
00369     int last_line = 0;
00370     int last_x = 0;
00371 
00372     /* We now try to make all the glyphs fit on the bitmap */
00373     for (i = 0; i < end - beg; i++) {
00374         int collide = FALSE;
00375     
00376         /* Place glyphs on last_line */
00377         glyphs[i].x = last_x;
00378         glyphs[i].y = last_line;
00379         
00380         /* Check for collision */
00381         
00382         for (j = 0; j < i; j++) {
00383             if ((glyphs[i].x >= glyphs[j].x + glyphs[j].w)
00384                     || (glyphs[i].y >= glyphs[j].y + glyphs[j].h)
00385                     || (glyphs[j].x >= glyphs[i].x + glyphs[i].w)
00386                     || (glyphs[j].y >= glyphs[i].y + glyphs[i].h)) {
00387                 continue;
00388             }
00389             last_x = glyphs[j].x + glyphs[j].w;
00390             glyphs[i].x = last_x;
00391             j = 0;
00392         }
00393         
00394         if ((last_x + glyphs[i].w > bmp->w)
00395          || (last_line + glyphs[i].h > bmp->h)) {
00396             collide = TRUE;
00397         }
00398 
00399         if (collide) {
00400             /* If there was a collision, we need to find the sprite with
00401              * the smallest height that is still grater than last_line.
00402              * We also need to redo this glyph.
00403              */
00404             int min_line = bmp->h + 1;
00405             int min_glyph = -1;
00406 
00407             for (j = 0; j < i; j++) {
00408                 if ( glyphs[j].y + glyphs[j].h < min_line
00409                   && glyphs[j].y + glyphs[j].h
00410                   > last_line - FONT_CHARACTER_SPACING) {
00411 
00412                     min_line = glyphs[j].y + glyphs[j].h
00413                              + FONT_CHARACTER_SPACING;
00414                     min_glyph = j;
00415                 }
00416             }
00417             /* If it can't possibly all fit, failure */
00418             if (min_glyph == -1) {
00419                 TRACE("* Note * sort_out_glyphs: Unable to fit all glyphs into "
00420                       "the texture.\n");
00421                 return FALSE;
00422             }
00423             /* Otherwise, start over at the top of that glyph */
00424             last_x = glyphs[min_glyph].x;
00425             last_line = min_line;
00426 
00427             /* Redo this glyph */
00428             i--;
00429         }
00430         else {
00431             last_x += glyphs[i].w + FONT_CHARACTER_SPACING;
00432         }
00433     }
00434 
00435     /* All ok */
00436     return TRUE;
00437 }
00438 
00439 
00440 
00441 static int split_font(FONT *f, void *source, void **dest1, void **dest2) {
00442 
00443     union mixed_ptr range1, range2, src;
00444     int colored;
00445     int i;
00446     
00447     (*dest1) = NULL;
00448     (*dest2) = NULL;
00449     src.ptr = source;
00450     
00451     colored = (f->vtable == font_vtable_mono) ? FALSE : TRUE;
00452 
00453     /* Allocate the ranges that we need */
00454     range1.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA)
00455                                 : sizeof(FONT_MONO_DATA));
00456 
00457     if (!range1.ptr) {
00458         TRACE("** ERROR ** split_font() - Ran out of memory while "
00459               "trying ot allocate %i bytes.\n",
00460               colored ? (int)sizeof(FONT_COLOR_DATA)
00461               : (int)sizeof(FONT_MONO_DATA));
00462         return FALSE;
00463     }
00464     range2.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA)
00465                                 : sizeof(FONT_MONO_DATA));
00466 
00467     if (!range2.ptr) {
00468         TRACE("** ERROR ** split_font() - Ran out of memory while "
00469               "trying to allocate %i bytes.\n",
00470               colored ? (int)sizeof(FONT_COLOR_DATA)
00471                       : (int)sizeof(FONT_MONO_DATA));
00472         free(range1.ptr);
00473         return FALSE;
00474     }
00475     
00476     (*dest1) = range1.ptr;
00477     (*dest2) = range2.ptr;
00478     
00479     /* Now we split up the range */
00480     if (colored) {
00481         /* Half the range */
00482         int mid = (src.cf->end - src.cf->begin) / 2;
00483         
00484         range1.cf->begin = src.cf->begin;
00485         range1.cf->end = mid;
00486         range2.cf->begin = mid;
00487         range2.cf->end = src.cf->end;
00488         
00489         range1.cf->next = NULL;
00490         range2.cf->next = NULL;
00491         
00492         /* Split up the bitmaps */
00493         range1.cf->bitmaps = malloc(sizeof(BITMAP*)
00494                                         * (range1.cf->end - range1.cf->begin));
00495         if (!range1.cf->bitmaps) {
00496             TRACE("** ERROR ** split_font() - Ran out of memory "
00497                   "while trying to allocate %i bytes.\n",
00498                   (int)sizeof(BITMAP*) * (range1.cf->end - range1.cf->begin));
00499             free(range1.ptr);
00500             free(range2.ptr);
00501             return FALSE;
00502         }
00503 
00504         range2.cf->bitmaps = malloc(sizeof(BITMAP*)
00505                                          * (range2.cf->end - range2.cf->begin));
00506         if (!range2.cf->bitmaps) {
00507             TRACE("** ERROR ** split_font() - Ran out of memory "
00508                   "while trying to allocate %i bytes.\n",
00509                   (int)sizeof(BITMAP*) * (range2.cf->end - range2.cf->begin));
00510             free(range1.cf->bitmaps);
00511             free(range1.ptr);
00512             free(range2.ptr);
00513             return FALSE;
00514         }
00515 
00516         
00517         for (i = 0; i < (range1.cf->end - range1.cf->begin); i++) {
00518             range1.cf->bitmaps[i] = src.cf->bitmaps[i];
00519         }
00520         for (i = 0; i < (range2.cf->end - range2.cf->begin); i++) {
00521             range2.cf->bitmaps[i] =
00522                        src.cf->bitmaps[i + range2.cf->begin - range1.cf->begin];
00523         }
00524     }
00525     else {
00526         /* Half the range */
00527         int mid = (src.mf->end - src.mf->begin) / 2;
00528         
00529         range1.mf->begin = src.mf->begin;
00530         range1.mf->end = mid;
00531         range2.mf->begin = mid;
00532         range2.mf->end = src.mf->end;
00533         
00534         range1.mf->next = NULL;
00535         range2.mf->next = NULL;
00536         
00537         /* Split up the bitmaps */
00538         range1.mf->glyphs = malloc(sizeof(FONT_GLYPH*)
00539                                          * (range1.mf->end - range1.mf->begin));
00540         if (!range1.mf->glyphs) {
00541             TRACE("** ERROR ** split_font() - Ran out of memory "
00542                   "while trying to allocate %i bytes.\n",
00543                 (int)sizeof(FONT_GLYPH*) * (range1.mf->end - range1.mf->begin));
00544             free(range1.ptr);
00545             free(range2.ptr);
00546             return FALSE;
00547         }
00548 
00549         range2.mf->glyphs = malloc(sizeof(FONT_GLYPH*)
00550                                          * (range2.mf->end - range2.mf->begin));
00551         if (!range2.mf->glyphs) {
00552             TRACE("** ERROR ** split_font() - Ran out of memory "
00553                   "while trying to allocate %i bytes.\n",
00554                 (int)sizeof(FONT_GLYPH*) * (range2.mf->end - range2.mf->begin));
00555             free(range1.mf->glyphs);
00556             free(range1.ptr);
00557             free(range2.ptr);
00558             return FALSE;
00559         }
00560         
00561         for (i = 0; i < (range1.mf->end - range1.mf->begin); i++) {
00562             range1.mf->glyphs[i] = src.mf->glyphs[i];
00563         }
00564         for (i = 0; i < (range2.mf->end - range2.mf->begin); i++) {
00565             range2.mf->glyphs[i] =
00566                         src.mf->glyphs[i + range2.mf->begin - range1.mf->begin];
00567         }
00568     }
00569     
00570     return TRUE;
00571 }
00572 
00573 
00574 
00575 /* Destroys a split font */
00576 static void destroy_split_font(FONT *f, union mixed_ptr range1,
00577                                         union mixed_ptr range2) {
00578     int colored;
00579     
00580     colored = (f->vtable == font_vtable_mono) ? FALSE : TRUE;
00581     
00582     if (colored) {
00583         free(range1.cf->bitmaps);
00584         free(range2.cf->bitmaps);
00585     }
00586     else {
00587         free(range1.mf->glyphs);
00588         free(range2.mf->glyphs);
00589     }
00590     
00591     free(range1.ptr);
00592     free(range2.ptr);
00593     
00594     return;
00595 }
00596 
00597 
00598 
00599 /* Crops a font over a particular range */
00600 static int crop_font_range(FONT *f, void *src, int beg, int end, glyph *glyphs,
00601                            int *net_area, int *gross_area,
00602                            int *max_w, int *max_h) {
00603 
00604     int i, j, k;
00605     BITMAP *temp;
00606     int max = end - beg;
00607     char buf[32];
00608 #if ((ALLEGRO_VERSION >= 4) && (ALLEGRO_SUB_VERSION >= 1) && (ALLEGRO_WIP_VERSION >= 4))
00609 #else
00610     int font_bg = text_mode(0);
00611 #endif
00612 
00613     union mixed_ptr dat;
00614     dat.ptr = src;
00615 
00616     /* Load default sizes */
00617     for (i = 0; i < max; i++) {
00618         glyphs[i].glyph_num = i;
00619 
00620         if (f->vtable == font_vtable_mono) {
00621             glyphs[i].w = dat.mf->glyphs[i]->w + 1;
00622             glyphs[i].h = dat.mf->glyphs[i]->h + 1;
00623         } else {
00624             glyphs[i].w = dat.cf->bitmaps[i]->w + 1;
00625             glyphs[i].h = dat.cf->bitmaps[i]->h + 1;
00626         }
00627         glyphs[i].offset_w = -1;
00628         glyphs[i].offset_h = -1;
00629 
00630         /* Not placed yet */
00631         glyphs[i].x = -1;
00632     }
00633     
00634     /* Allocate a temp bitmap to work with */
00635     temp = create_bitmap(32, 32);
00636     
00637     if (!temp) {
00638         TRACE("** ERROR ** crop_font_range - Unable to create "
00639               "bitmap of size: %ix%i!\n", 32, 32);
00640         goto error;
00641     }
00642     
00643     /* Crop glyphs */
00644     for (i = 0; i < max; i++) {
00645         int used = 0;
00646 
00647         if (glyphs[i].w > temp->w || glyphs[i].h > temp->h) {
00648             int old_w = temp->w, old_h = temp->h;
00649             destroy_bitmap(temp);
00650             temp = create_bitmap(old_w * 2, old_h * 2);
00651             if (!temp) {
00652                 TRACE("** ERROR ** crop_font_range - Unable to "
00653                       "create bitmap of size: %ix%i!\n", old_w * 2, old_h * 2);
00654                 goto error;
00655             }
00656         }
00657         clear(temp);
00658 
00659         usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
00660 
00661 #if ((ALLEGRO_VERSION >= 4) && (ALLEGRO_SUB_VERSION >= 1) && (ALLEGRO_WIP_VERSION >= 4))
00662         textout_ex(temp, f, buf, 0, 0,
00663                     makecol_depth(bitmap_color_depth(temp), 255, 255, 255), 0);
00664 #else
00665         textout(temp, f, buf, 0, 0,
00666                     makecol_depth(bitmap_color_depth(temp), 255, 255, 255));
00667 #endif
00668         
00669     
00670         /* Crop top */
00671         for (j = 0; j < glyphs[i].h; j++) {
00672             used = 0;
00673 
00674             for (k = 0; k < glyphs[i].w; k++) {
00675                 if (getpixel(temp, k, j)) {
00676                     used = 1;
00677                     glyphs[i].offset_y += j;
00678                     glyphs[i].h -= j;
00679                     break;
00680                 }
00681             }
00682             if (used)
00683                 break;
00684         }
00685 
00686         /* If just the top crop killed our glyph, then skip it entirely */
00687         if (!used) {
00688             TRACE("* Note * crop_font_range: skipping glyph %i\n", i);
00689             glyphs[i].offset_y = 0;
00690             glyphs[i].offset_h = glyphs[i].h - 1;
00691             glyphs[i].offset_w = glyphs[i].w - 2;
00692             glyphs[i].h = 1;
00693             glyphs[i].w = 1;
00694             continue;
00695         }
00696         
00697         /* Crop bottom */
00698         j = glyphs[i].h + glyphs[i].offset_y - 1;
00699         for ( /* above */; j >= glyphs[i].offset_y; j--) {
00700             used = 0;
00701 
00702             for (k = 0; k < glyphs[i].w; k++) {
00703                 if (getpixel(temp, k, j)) {
00704                     used = 1;
00705                     glyphs[i].offset_h +=
00706                                        glyphs[i].h + glyphs[i].offset_y - j - 2;
00707                     glyphs[i].h -= glyphs[i].h + glyphs[i].offset_y - j - 1;
00708                     break;
00709                 }
00710             }
00711             if (used)
00712                 break;
00713         }
00714 
00715         /* Crop Left */
00716         for (j = 0; j < glyphs[i].w; j++) {
00717             used = 0;
00718 
00719             k = MAX(glyphs[i].offset_y - 1, 0);
00720             for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
00721                 if (getpixel(temp, j, k)) {
00722                     used = 1;
00723                     glyphs[i].offset_x += j;
00724                     glyphs[i].w -= j;
00725                     break;
00726                 }
00727             }
00728             if (used)
00729                 break;
00730         }
00731 
00732         /* Crop Right */
00733         j = glyphs[i].w + glyphs[i].offset_x - 1;
00734         for (/* above */; j >= glyphs[i].offset_x; j--) {
00735             used = 0;
00736 
00737             k = MAX(glyphs[i].offset_y - 1, 0);
00738             for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
00739                 if (getpixel(temp, j, k)) {
00740                     used = 1;
00741                     glyphs[i].offset_w +=
00742                                        glyphs[i].w + glyphs[i].offset_x - 1 - j;
00743                     glyphs[i].w -= glyphs[i].w + glyphs[i].offset_x - j - 1;
00744                     break;
00745                 }
00746             }
00747             if (used)
00748                 break;
00749         }
00750 #ifdef LOGLEVEL
00751         TRACE("* Note * crop_font_range: Glyph %i (%c) offs: x: %i  y: %i, "
00752               "w: %i  h: %i,  offs: w: %i  h: %i\n", i, i + beg,
00753               glyphs[i].offset_x, glyphs[i].offset_y, glyphs[i].w, glyphs[i].h,
00754               glyphs[i].offset_w, glyphs[i].offset_h);
00755 #endif
00756     }
00757     
00758     destroy_bitmap(temp);
00759 
00760     (*gross_area) = 0;
00761     (*net_area) = 0;
00762     (*max_w) = 0;
00763     (*max_h) = 0;
00764 
00765     /* Find max w and h, total area covered by the bitmaps, and number of
00766      * glyphs
00767      */
00768     for (i = 0; i < max; i++) {
00769         if (glyphs[i].w > *max_w) (*max_w) = glyphs[i].w;
00770         if (glyphs[i].h > *max_h) (*max_h) = glyphs[i].h;
00771         (*net_area) += glyphs[i].w * glyphs[i].h;
00772         (*gross_area) += (glyphs[i].w + FONT_CHARACTER_SPACING)
00773                        * (glyphs[i].h + FONT_CHARACTER_SPACING);
00774     }
00775     return TRUE;
00776 
00777 error:
00778     if (temp) {
00779         destroy_bitmap(temp);
00780     }
00781 #if ((ALLEGRO_VERSION >= 4) && (ALLEGRO_SUB_VERSION >= 1) && (ALLEGRO_WIP_VERSION >= 4))
00782 #else
00783     text_mode(font_bg);
00784 #endif
00785     
00786     return FALSE;
00787 }
00788 
00789 
00790 
00791 /* Tries to find a texture that will fit the font
00792  */
00793 static BITMAP* look_for_texture(int beg, int end, glyph *glyphs,
00794                           int max_w, int max_h, int total_area, GLint format) {
00795     
00796     BITMAP *bmp = NULL;
00797     int i, j;
00798 
00799     /* Max texture size (1 << n) */
00800     /* XXX <rohannessian> We should use ARB_np2 if we can
00801      *
00802      * Other note: w*h shouldn't exceed 31 bits; otherwise, we get funny
00803      * behavior on 32-bit architectures. Limit texture sizes to 32k*32k
00804      * (30 bits).
00805      */
00806 #define MIN_TEXTURE_SIZE 2
00807 #define NUM_TEXTURE_SIZE 13
00808     texture_size texture_sizes[NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE];
00809 
00810     /* Set up texture sizes */
00811     for (i = 0; i < NUM_TEXTURE_SIZE; i++) {
00812         for (j = 0; j < NUM_TEXTURE_SIZE; j++) {
00813             texture_sizes[j + i * NUM_TEXTURE_SIZE].w =
00814                                                     1 << (j + MIN_TEXTURE_SIZE);
00815             texture_sizes[j + i * NUM_TEXTURE_SIZE].h =
00816                                                     1 << (i + MIN_TEXTURE_SIZE);
00817         }
00818     }
00819 
00820     /* Sort texture sizes by area */
00821     qsort(texture_sizes, NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE,
00822                                           sizeof(texture_size), &sort_textures);
00823 
00824     for (i = 0; i < NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE; i++) {
00825         
00826         /* Check the area - it must be larger than
00827          * all the glyphs
00828          */
00829         texture_size *t = &texture_sizes[i];
00830         int area = t->w * t->h;
00831 
00832         TRACE("* Note * look_for_texture: Trying size %ix%i\n", t->w, t->h);
00833 
00834         if (area < total_area) {
00835             TRACE(" * Note * look_for_texture: Area too small. Skipping.\n");
00836             continue;
00837         }
00838             
00839         /* Check against max values */
00840         if ((t->h < max_h) || (t->w < max_w)) {
00841             TRACE("* Note * look_for_texture: Max values not reached\n");
00842             continue;
00843         }
00844 
00845         /* Check that the texture can, in fact, be created */
00846         bmp = create_bitmap_ex((format == GL_ALPHA4
00847             || format == GL_ALPHA8 || format == GL_ALPHA || format == 1)
00848             ? 8 : 24, t->w, t->h);
00849 
00850         if (!bmp) {
00851             TRACE("** Warning ** look_for_texture: Out of memory while "
00852                   "creating bitmap\n");
00853             continue;
00854         }
00855 
00856         if (!aglf_check_texture(bmp, format)) {
00857             TRACE("* Note * look_for_texture: Texture rejected by driver\n");
00858             destroy_bitmap(bmp);
00859             bmp = NULL;
00860             continue;
00861         }
00862 
00863         /* Sort out the glyphs */
00864         TRACE("* Note * look_for_texture: Sorting on bmp: %p, beg: %i, "
00865               "end: %i\n", bmp, beg, end);
00866 
00867         if (aglf_sort_out_glyphs(bmp, glyphs, beg, end) == TRUE) {
00868             /* Success? */
00869             return bmp;
00870         }
00871 
00872         /* Failure? Try something else */
00873         TRACE("* Note * look_for_texture: Conversion failed\n");
00874         destroy_bitmap(bmp);
00875         bmp = NULL;
00876     }
00877     
00878     return NULL;
00879 }
00880 
00881 
00882 
00883 /* Function to draw a character in a bitmap for conversion */
00884 static int draw_glyphs(BITMAP *bmp, FONT *f, GLint format, int beg, int end,
00885                                                                 glyph *glyphs) {
00886     char buf[32];
00887     int i, j;
00888 
00889     if (format == GL_ALPHA4 || format == GL_ALPHA8) {
00890         /* Generate an alpha font */
00891         BITMAP *rgbbmp = create_bitmap_ex(24, bmp->w, bmp->h);
00892         
00893         if (!rgbbmp) {
00894             TRACE("** ERROR ** convert_allegro_font_to_texture: "
00895                   "Ran out of memory while creating %ix%ix%i bitmap!\n",
00896                   bmp->w, bmp->h, 24);
00897             return FALSE;
00898         }
00899 
00900         clear_bitmap(rgbbmp);
00901         
00902         for (i = 0; i < end - beg; i++) {
00903             usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
00904             
00905 #if ((ALLEGRO_VERSION >= 4) && (ALLEGRO_SUB_VERSION >= 1) && (ALLEGRO_WIP_VERSION >= 4))
00906             textout_ex(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
00907                                       glyphs[i].y - glyphs[i].offset_y, -1, -1);
00908 #else
00909             {
00910               int bg = text_mode(-1);
00911               textout(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
00912                                           glyphs[i].y - glyphs[i].offset_y, -1);
00913               text_mode(bg);
00914             }
00915 #endif
00916         }
00917 
00918         /* Convert back to 8bpp */
00919         for (j = 0; j < bmp->h; j++) {
00920             for (i = 0; i < bmp->w; i++) {
00921                 int pix = _getpixel24(rgbbmp, i, j);
00922                 int r = getr24(pix);
00923                 int g = getg24(pix);
00924                 int b = getb24(pix);
00925                 int gray = (r * 77 + g * 150 + b * 28 + 255) >> 8;
00926                 _putpixel(bmp, i, j, MID(0, gray, 255));
00927             }
00928         }
00929         destroy_bitmap(rgbbmp);
00930     }
00931     else {
00932         clear_bitmap(bmp);  
00933 
00934         for (i = 0; i < end - beg; i++) {
00935             usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
00936 #if ((ALLEGRO_VERSION >= 4) && (ALLEGRO_SUB_VERSION >= 1) && (ALLEGRO_WIP_VERSION >= 4))
00937             textout_ex(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
00938                      glyphs[i].y - glyphs[i].offset_y,
00939                      makecol_depth(bitmap_color_depth(bmp), 255, 255, 255), -1);
00940 #else
00941             {
00942               int bg = text_mode(-1);
00943               textout(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
00944                          glyphs[i].y - glyphs[i].offset_y,
00945                          makecol_depth(bitmap_color_depth(bmp), 255, 255, 255));
00946               text_mode(bg);
00947             }
00948 #endif
00949         }
00950     }
00951     
00952     return TRUE;
00953 }
00954 
00955 
00956 
00957 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA *dest, FONT *f,
00958                             void *src, int *height, float scale, GLint format) {
00959 
00960     int max = 0;
00961     int i;
00962     BITMAP *bmp = NULL;
00963     int beg = 0, end = 0;
00964     int max_w, max_h;
00965     int total_area, gross_area;
00966     
00967     glyph *glyph_coords;
00968 
00969     union mixed_ptr dat;
00970     dat.ptr = src;
00971 
00972     if (f->vtable == font_vtable_mono) {
00973         beg = dat.mf->begin;
00974         end = dat.mf->end;
00975         max = dat.mf->end - dat.mf->begin;
00976     }
00977     else if (f->vtable == font_vtable_color) {
00978         beg = dat.cf->begin;
00979         end = dat.cf->end;
00980         max = dat.cf->end - dat.cf->begin;
00981     }
00982 
00983     /* Allocate glyph sizes */
00984     glyph_coords = malloc(max * sizeof(glyph));
00985     memset(glyph_coords, 0, max * sizeof(glyph));
00986     
00987     if (crop_font_range(f, dat.ptr, beg, end, glyph_coords,
00988                           &total_area, &gross_area, &max_w, &max_h) == FALSE) {
00989         TRACE("* Note * convert_allegro_font_to_texture: Unable to crop font "
00990               "range\n");
00991         free(glyph_coords);
00992         return;
00993     }
00994 
00995     TRACE("* Note * convert_allegro_font_to_texture: Total area of glyphs: "
00996           "%i pixels (%i pixels gross) - max_w: %i, max_h: %i\n",
00997           total_area, gross_area, max_w, max_h);
00998 
00999     /* Sort glyphs by width, then height */
01000     qsort(glyph_coords, end - beg, sizeof(glyph), &sort_glyphs);
01001 
01002 
01003     /* Now, we look for the appropreate texture size */
01004     bmp = look_for_texture(beg, end, glyph_coords, max_w, max_h,
01005                            total_area, format);
01006 
01007     /* No texture sizes were found - we should split the font up */
01008     if (!bmp) {
01009         union mixed_ptr f1, f2;
01010         FONT_AGL_DATA *dest1, *dest2;
01011         
01012         free(glyph_coords);
01013 
01014         dest1 = dest;
01015         dest2 = malloc(sizeof(FONT_AGL_DATA));
01016         
01017         if (!dest2) {
01018             TRACE("** ERROR ** convert_allegro_font_to_texture: "
01019                   "Out of memory while trying to allocate %i bytes.\n",
01020                   (int)sizeof(FONT_AGL_DATA));
01021             return;
01022         }
01023 
01024         memset(dest2, 0, sizeof(FONT_AGL_DATA));
01025 
01026         dest2->next = dest1->next;
01027         dest1->next = dest2;
01028         dest2->is_free_chunk = TRUE;
01029         
01030         if (split_font(f, dat.ptr, &f1.ptr, &f2.ptr) == FALSE) {
01031             TRACE("** ERROR ** convert_allegro_font_to_texture: Unable "
01032                   "to split font!\n");
01033             dest1->next = dest2->next;
01034             free(dest2);
01035             return;
01036         }
01037 
01038         aglf_convert_allegro_font_to_texture(dest1, f, &f1, height, scale,
01039                                              format);
01040         aglf_convert_allegro_font_to_texture(dest2, f, &f2, height, scale,
01041                                              format);
01042         destroy_split_font(f, f1, f2);
01043         
01044         return;
01045     }
01046 
01047     TRACE("* Note * convert_allegro_font_to_texture: Using texture of size "
01048           "%ix%i for font conversion.\n", bmp->w, bmp->h);
01049 
01050     /* Now that all the glyphs are in place, we draw them into the bitmap */
01051     if (draw_glyphs(bmp, f, format, beg, end, glyph_coords) == FALSE) {
01052         destroy_bitmap(bmp);
01053         free(glyph_coords);
01054         return;
01055     }
01056 
01057     /* Un-Sort glyphs  */
01058     qsort(glyph_coords, end - beg, sizeof(glyph), &unsort_glyphs);
01059 
01060 #if (defined SAVE_FONT_SCREENSHOT)
01061         save_shot(bmp);
01062 #endif
01063 
01064     /* Create call lists */
01065     {
01066         GLuint list;
01067 
01068         int rev = scale < 0 ? 1 : 0;
01069         scale = fabs(scale);
01070 
01071         list = glGenLists(max);
01072         
01073         for (i = 0; i < max; i++) {
01074             /* Coords of glyph in texture (texture coords) */
01075             float tx = (float)glyph_coords[i].x / bmp->w;
01076             float ty = 1.0 - (float)glyph_coords[i].y / bmp->h;
01077             /* Size of glyph in texture (texture coords) */
01078             float dtx = (float)(glyph_coords[i].w) / bmp->w;
01079             float dty = (float)(glyph_coords[i].h) / bmp->h;
01080 
01081             /* Offset to apply to glyph (output coords) */
01082             float xoffs = (float)glyph_coords[i].offset_x / scale;
01083             float yoffs = (float)glyph_coords[i].offset_y / scale;
01084             /* Size of rendered glyph (output coords) */
01085             float woffs = (float)glyph_coords[i].w / scale;
01086             float hoffs = (float)glyph_coords[i].h / scale;
01087 
01088             /* Size of overall screen character including dead space */
01089             float sizew = (float)(glyph_coords[i].offset_x + glyph_coords[i].w
01090                         + glyph_coords[i].offset_w) / fabs(scale);
01091             float sizeh = (float)(glyph_coords[i].offset_y + glyph_coords[i].h
01092                         + glyph_coords[i].offset_h) / fabs(scale);
01093 
01094             if ((*height) < sizeh)
01095                 *height = sizeh;
01096 
01097             if (rev) {
01098                 hoffs = -hoffs;
01099                 yoffs = -yoffs;
01100             }
01101 
01102             glNewList(list + i, GL_COMPILE);
01103             
01104             glBegin(GL_QUADS);
01105                 glTexCoord2f(tx, ty);
01106                 glVertex2f(xoffs, -yoffs);
01107 
01108                 glTexCoord2f(tx + dtx, ty);
01109                 glVertex2f(xoffs + woffs, -yoffs);
01110 
01111                 glTexCoord2f(tx + dtx, ty - dty);
01112                 glVertex2f(xoffs + woffs, -yoffs - hoffs);
01113 
01114                 glTexCoord2f(tx, ty - dty);
01115                 glVertex2f(xoffs, -yoffs - hoffs);
01116             glEnd();
01117 
01118             glTranslatef(sizew, 0, 0);
01119 
01120             glEndList();
01121         }
01122         dest->list_base = list;
01123     }
01124 
01125     free(glyph_coords);
01126 
01127     dest->texture = aglf_upload_texture(bmp, format);
01128     dest->type = AGL_FONT_TYPE_TEXTURED;
01129     dest->start = beg;
01130     dest->end = end;
01131     dest->data = bmp;
01132 
01133     return;
01134 }
01135 
01136 
01137 
01138 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
01139                                                        void *src, int *height) {
01140 
01141     int max = 0;
01142     int i, j, k;
01143     int beg = 0, end = 0;
01144     int mask;
01145     FONT_GLYPH **glyph;
01146 
01147     union {
01148         FONT_MONO_DATA* mf;
01149         FONT_COLOR_DATA* cf;
01150         void *ptr;
01151     } dat;
01152 
01153     dat.ptr = src;
01154 
01155     if (f->vtable == font_vtable_mono)
01156         max = dat.mf->end - dat.mf->begin;
01157     else if (f->vtable == font_vtable_color)
01158         max = dat.cf->end - dat.cf->begin;
01159     else
01160         return;
01161 
01162     glyph = malloc(sizeof(FONT_GLYPH*) * max);
01163 
01164     if (!glyph) {
01165         TRACE("** ERROR ** convert_allegro_font_to_bitmap: Ran out of "
01166               "memory while allocating %i bytes\n", (int)sizeof(FONT_GLYPH));
01167         return;
01168     }
01169     
01170     *height = f->height;
01171         
01172     if (f->vtable == font_vtable_mono) {        
01173     
01174         /* for each glyph */
01175         for (i = 0; i < max; i++) {     
01176             FONT_GLYPH *oldgl = dat.mf->glyphs[i];
01177     
01178             int size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4
01179                                                                      * oldgl->h;
01180     
01181             /* create new glyph */
01182             FONT_GLYPH *newgl = (FONT_GLYPH*)malloc(size);
01183     
01184             if (!newgl)
01185                 break;
01186     
01187             memset(newgl, 0, size);
01188     
01189             newgl->w = oldgl->w;
01190             newgl->h = oldgl->h;
01191 
01192             /* update the data */
01193             for (j = 0; j < oldgl->h; j++) {
01194                 for (k = 0; k < ((oldgl->w + 7) / 8); k++) {
01195                     int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
01196                                + k;
01197                     newgl->dat[addr] = oldgl->dat[j * ((oldgl->w + 7) / 8) + k];
01198                 }
01199             }
01200 
01201             glyph[i] = newgl;
01202         }
01203     }
01204     else if (f->vtable == font_vtable_color) { /* Reduce to 1 bit */
01205         /* for each glyph */
01206         for (i = 0; i < max; i++) {
01207 
01208             int size;
01209             BITMAP *oldgl = dat.cf->bitmaps[i];
01210             FONT_GLYPH *newgl;
01211         
01212             mask = bitmap_mask_color(oldgl);
01213     
01214             size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4 * oldgl->h;
01215     
01216             /* create new glyph */
01217             newgl = (FONT_GLYPH*)malloc(size);
01218     
01219             if (!newgl)
01220                 break;
01221     
01222             memset(newgl, 0, size);
01223     
01224             newgl->w = oldgl->w;
01225             newgl->h = oldgl->h;
01226 
01227             /* update the data */
01228             for (j = 0; j < oldgl->h; j++) {
01229                 for (k = 0; k < oldgl->w; k++) {
01230                     int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
01231                              + (k / 8);
01232                     newgl->dat[addr] |= (getpixel(oldgl, k, j) == mask)
01233                                      ? 0 : (1 << (k & 7));
01234                 }
01235             }
01236 
01237             glyph[i] = newgl;
01238         }
01239     }
01240     /* Create call lists */
01241     {
01242         GLuint list = glGenLists(max);
01243 
01244         for (i = 0; i < max; i++) {
01245             glNewList(list + i, GL_COMPILE);
01246 
01247             glBitmap(glyph[i]->w, glyph[i]->h, 0, 0, glyph[i]->w, 0,
01248                      glyph[i]->dat);
01249 
01250             glEndList();
01251         }
01252         dest->list_base = list;
01253     }
01254         
01255     dest->is_free_chunk = 0;
01256     dest->type = AGL_FONT_TYPE_BITMAP;
01257     dest->start = beg;
01258     dest->end = end;
01259     dest->data = glyph;
01260 
01261     return;
01262 }
01263 
01264 
01265 
01266 static int aglf_check_texture(BITMAP *bmp, GLint format) {
01267     
01268     int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP;
01269 
01270     if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
01271      || format == 1) {
01272         flags |= AGL_TEXTURE_ALPHA_ONLY;
01273     }
01274 
01275     return allegro_gl_check_texture_ex(flags, bmp, format);
01276 }
01277 
01278 
01279 
01280 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format) {
01281 
01282     int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP;
01283     GLuint texture;
01284 
01285     if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
01286      || format == 1) {
01287         flags |= AGL_TEXTURE_ALPHA_ONLY;
01288     }
01289 
01290     texture = allegro_gl_make_texture_ex(flags, bmp, format);
01291 
01292     return texture;
01293 }
01294 

Generated on Wed Jun 30 23:59:52 2004 for AllegroGL by doxygen 1.3.5