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
00034
00035 #define FONT_CHARACTER_SPACING 2
00036
00037
00038
00039
00040
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
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
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
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
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
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
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
00209 if (type == AGL_FONT_TYPE_OUTLINE) {
00210
00211 TRACE("** ERROR ** convert_allegro_font: Unable to convert a "
00212 "pixmap font to a vector font.\n");
00213 return NULL;
00214 }
00215
00216
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
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
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
00256 for (i = 0; i < max - 1; i++) {
00257 destdata[i].next = &destdata[i + 1];
00258 }
00259 destdata[max - 1].next = NULL;
00260
00261
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
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
00303
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
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
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
00363
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
00373 for (i = 0; i < end - beg; i++) {
00374 int collide = FALSE;
00375
00376
00377 glyphs[i].x = last_x;
00378 glyphs[i].y = last_line;
00379
00380
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
00401
00402
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
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
00424 last_x = glyphs[min_glyph].x;
00425 last_line = min_line;
00426
00427
00428 i--;
00429 }
00430 else {
00431 last_x += glyphs[i].w + FONT_CHARACTER_SPACING;
00432 }
00433 }
00434
00435
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
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
00480 if (colored) {
00481
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
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
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
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
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
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
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
00631 glyphs[i].x = -1;
00632 }
00633
00634
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
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
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
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
00698 j = glyphs[i].h + glyphs[i].offset_y - 1;
00699 for ( ; 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
00716 for (j = 0; j < glyphs[i].w; j++) {
00717 used = 0;
00718
00719 k = MAX(glyphs[i].offset_y - 1, 0);
00720 for (; 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
00733 j = glyphs[i].w + glyphs[i].offset_x - 1;
00734 for (; j >= glyphs[i].offset_x; j--) {
00735 used = 0;
00736
00737 k = MAX(glyphs[i].offset_y - 1, 0);
00738 for (; 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
00766
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
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
00800
00801
00802
00803
00804
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
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
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
00827
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
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
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
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
00869 return bmp;
00870 }
00871
00872
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
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
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
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
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
01000 qsort(glyph_coords, end - beg, sizeof(glyph), &sort_glyphs);
01001
01002
01003
01004 bmp = look_for_texture(beg, end, glyph_coords, max_w, max_h,
01005 total_area, format);
01006
01007
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
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
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
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
01075 float tx = (float)glyph_coords[i].x / bmp->w;
01076 float ty = 1.0 - (float)glyph_coords[i].y / bmp->h;
01077
01078 float dtx = (float)(glyph_coords[i].w) / bmp->w;
01079 float dty = (float)(glyph_coords[i].h) / bmp->h;
01080
01081
01082 float xoffs = (float)glyph_coords[i].offset_x / scale;
01083 float yoffs = (float)glyph_coords[i].offset_y / scale;
01084
01085 float woffs = (float)glyph_coords[i].w / scale;
01086 float hoffs = (float)glyph_coords[i].h / scale;
01087
01088
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
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
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
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) {
01205
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
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
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
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