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