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