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