AllegroGL 0.4.4
|
00001 /* This code is (C) AllegroGL contributors, and double licensed under 00002 * the GPL and zlib licenses. See gpl.txt or zlib.txt for details. 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 /* Number of pixels between characters in a textured font. 00040 */ 00041 #define FONT_CHARACTER_SPACING 2 00042 00043 /* Uncomment to have the font generator dump screenshots of the textures it 00044 * generates. 00045 */ 00046 /* #define SAVE_FONT_SCREENSHOT */ 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, /* render_char */ 00069 NULL, /* render */ 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 /* Stores info about a texture size */ 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 /* iroundf: 00116 * Round float to nearest integer, away from zero. 00117 */ 00118 static int iroundf(float v) { 00119 float f = floor(v); 00120 float c = ceil(v); 00121 00122 if (v >= 0) { 00123 /* distance to ceil smaller than distance to floor */ 00124 if ((c - v) < (v - f)) 00125 return (int)c; 00126 else 00127 return (int)f; 00128 } 00129 else { 00130 /* distance to ceil smaller than distance to floor */ 00131 if ((c - v) < (v - f)) 00132 return (int)f; 00133 else 00134 return (int)c; 00135 } 00136 } 00137 00138 00139 00140 /* agl_char_length_fractional: 00141 * Returns the width, in fractional pixels of the given character. 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 /* if we don't find the character, then search for the missing 00169 * glyph, but don't get stuck in a loop. */ 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 /* agl_char_length: 00179 * font vtable entry 00180 * Returns the width, in pixels of the given character. 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 /* agl_text_length: 00189 * font vtable entry 00190 * Returns the length, in pixels, of a string as rendered in a font. 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 /* agl_get_font_ranges: 00209 * font vtable entry 00210 * Returns the number of character ranges in a font, or -1 if that information 00211 * is not available. 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 /* agl_get_font_range_begin: 00237 * font vtable entry 00238 * Get first character for font. 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 /* agl_get_font_range_end: 00266 * font vtable entry 00267 * Get last character for font range. 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 /* Creates a call lists from given glyph coords. Returns list base.*/ 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 /* Coords of glyph in texture (texture coords) */ 00304 float tx = (float)coords[i].x / bmp->w; 00305 float ty = 1.0 - (float)coords[i].y / bmp->h; 00306 /* Size of glyph in texture (texture coords) */ 00307 float dtx = (float)(coords[i].w) / bmp->w; 00308 float dty = (float)(coords[i].h) / bmp->h; 00309 00310 /* Offset to apply to glyph (output coords) */ 00311 float xoffs = (float)coords[i].offset_x / scale; 00312 float yoffs = (float)coords[i].offset_y / scale; 00313 /* Size of rendered glyph (output coords) */ 00314 float woffs = (float)coords[i].w / scale; 00315 float hoffs = (float)coords[i].h / scale; 00316 00317 /* Size of overall screen character including dead space */ 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 /* copy_glyph_range: 00358 * Copies part of glyph range. 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 /* for now, just copy glyph coords of the range */ 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 /* calculate the width of the glyphs and find the max height */ 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 /* allocate a new bitmap to hold new glyphs */ 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 /* blit every glyph from the range to the new bitmap */ 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 /* fix new glyphs coords while here */ 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 /* agl_extract_font_range: 00441 * font vtable entry 00442 * Extracts a glyph range from a given font and makes a new font of it. 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 /* check if range boundaries make sense */ 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 /* only textured fonts are supported */ 00467 if (fad->type != AGL_FONT_TYPE_TEXTURED) 00468 return NULL; 00469 00470 /* anticipate invalid range values */ 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 /* find the range that is covered by the requested range 00489 * check if the requested and processed ranges at least overlap 00490 * or if the requested range wraps processed range. 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 /* extract the overlapping range */ 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 /* agl_merge_fonts: 00523 * font vtable entry 00524 * Merges f2 with f1 and returns a new font. 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 /* fonts must be textured and of the same format */ 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 /* alloc output font */ 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 /* agl_transpose_font: 00586 * font vtable entry 00587 * Transposes characters in a font. 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 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */ 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 /* allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format) */ 00688 FONT *allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, 00689 GLint format) { 00690 int max = 0, height = 0; 00691 int i; 00692 FONT *dest; 00693 FONT_AGL_DATA *destdata; 00694 int has_alpha = 0; 00695 00696 union { 00697 FONT_MONO_DATA* mf; 00698 FONT_COLOR_DATA* cf; 00699 void *ptr; 00700 } dat; 00701 00702 if (!__allegro_gl_valid_context) { 00703 return NULL; 00704 } 00705 00706 if (!f) { 00707 TRACE(PREFIX_E "convert_allegro_font: Null source\n"); 00708 return NULL; 00709 } 00710 00711 /* Make sure it's an Allegro font - we don't want any surprises */ 00712 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 00713 if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color && f->vtable != font_vtable_trans) { 00714 #else 00715 if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color) { 00716 #endif 00717 TRACE(PREFIX_I "convert_allegro_font: Source font is not " 00718 "in Allegro format\n"); 00719 return NULL; 00720 } 00721 00722 /* No vector fonts allowed as destination */ 00723 if (type == AGL_FONT_TYPE_OUTLINE) { 00724 /* Can't convert bitmap to vector font */ 00725 TRACE(PREFIX_I "convert_allegro_font: Unable to convert a " 00726 "pixmap font to a vector font.\n"); 00727 return NULL; 00728 } 00729 00730 /* Make sure the scaling factor is appropreate */ 00731 if (fabs(scale) < 0.001) { 00732 TRACE(PREFIX_W "convert_allegro_font: Scaling factor might be " 00733 "too small: %f\n", scale); 00734 } 00735 00736 /* Count number of ranges */ 00737 max = get_font_ranges(f); 00738 00739 /* There should really be an API for this */ 00740 dest = (FONT*)malloc(sizeof(FONT)); 00741 if (!dest) { 00742 TRACE(PREFIX_E "convert_allegro_font: Ran out of memory " 00743 "while allocating %i bytes\n", (int)sizeof(FONT)); 00744 return NULL; 00745 } 00746 destdata = (FONT_AGL_DATA*)malloc(sizeof(FONT_AGL_DATA) * max); 00747 if (!destdata) { 00748 TRACE(PREFIX_E "convert_allegro_font: Ran out of memory " 00749 "while allocating %i bytes\n", (int)sizeof(FONT_AGL_DATA) * max); 00750 return NULL; 00751 } 00752 memset(destdata, 0, sizeof(FONT_AGL_DATA) * max); 00753 00754 /* Construct the linked list */ 00755 for (i = 0; i < max - 1; i++) { 00756 destdata[i].next = &destdata[i + 1]; 00757 } 00758 destdata[max - 1].next = NULL; 00759 00760 /* Set up the font */ 00761 dest->data = destdata; 00762 dest->vtable = font_vtable_agl; 00763 dest->height = 0; 00764 00765 destdata->type = type; 00766 00767 if (type == AGL_FONT_TYPE_DONT_CARE) { 00768 destdata->type = AGL_FONT_TYPE_TEXTURED; 00769 } 00770 00771 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 00772 has_alpha = (f->vtable == font_vtable_trans); 00773 #endif 00774 00775 /* Convert each range */ 00776 dat.ptr = f->data; 00777 00778 while (dat.ptr) { 00779 00780 destdata->has_alpha = has_alpha; 00781 00782 if (type == AGL_FONT_TYPE_BITMAP) { 00783 aglf_convert_allegro_font_to_bitmap(destdata, f, dat.ptr, &height); 00784 } 00785 else if (type == AGL_FONT_TYPE_TEXTURED) { 00786 aglf_convert_allegro_font_to_texture(&destdata, f, dat.ptr, &height, 00787 scale, format); 00788 } 00789 00790 if (height > dest->height) { 00791 dest->height = height; 00792 } 00793 00794 dat.ptr = (is_mono_font(f) ? (void*)dat.mf->next : (void*)dat.cf->next); 00795 00796 destdata = destdata->next; 00797 } 00798 00799 return dest; 00800 } 00801 00802 00803 00804 /* QSort helper for sorting glyphs according to width, 00805 * then height - largest first. 00806 */ 00807 static int sort_glyphs(const void *c1, const void *c2) { 00808 AGL_GLYPH *g1 = (AGL_GLYPH*)c1; 00809 AGL_GLYPH *g2 = (AGL_GLYPH*)c2; 00810 00811 if (g1->w < g2->w) { 00812 return 1; 00813 } 00814 else if (g1->w == g2->w) { 00815 return -g1->h + g2->h; 00816 } 00817 else { 00818 return -1; 00819 } 00820 } 00821 00822 00823 00824 /* QSort helper for unsorting glyphs. 00825 */ 00826 static int unsort_glyphs(const void *c1, const void *c2) { 00827 AGL_GLYPH *g1 = (AGL_GLYPH*)c1; 00828 AGL_GLYPH *g2 = (AGL_GLYPH*)c2; 00829 00830 return g1->glyph_num - g2->glyph_num; 00831 } 00832 00833 00834 00835 /* QSort helper for sorting textures by area. 00836 */ 00837 static int sort_textures(const void *c1, const void *c2) { 00838 texture_size *t1 = (texture_size*)c1; 00839 texture_size *t2 = (texture_size*)c2; 00840 00841 return t1->w * t1->h - t2->w * t2->h; 00842 } 00843 00844 00845 00846 #ifdef SAVE_FONT_SCREENSHOT 00847 static void save_shot(BITMAP *bmp) { 00848 00849 int i; 00850 char name[128]; 00851 00852 for (i = 0; i < 1000; i++) { 00853 /* TGA, in case it is a truecolor font with alpha */ 00854 sprintf(name, "fonttest_%02i.tga", i); 00855 if (!exists(name)) { 00856 save_tga(name, bmp, NULL); 00857 break; 00858 } 00859 } 00860 } 00861 #endif 00862 00863 00864 00865 /* Helper function. This will try to place all the glyphs in the bitmap the 00866 * best way it can 00867 */ 00868 static int aglf_sort_out_glyphs(BITMAP *bmp, AGL_GLYPH *glyphs, const int beg, 00869 const int end) { 00870 00871 int i, j; 00872 int last_line = 0; 00873 int last_x = 0; 00874 00875 /* We now try to make all the glyphs fit on the bitmap */ 00876 for (i = 0; i < end - beg; i++) { 00877 int collide = FALSE; 00878 00879 /* Place glyphs on last_line */ 00880 glyphs[i].x = last_x; 00881 glyphs[i].y = last_line; 00882 00883 /* Check for collision */ 00884 00885 for (j = 0; j < i; j++) { 00886 if ((glyphs[i].x >= glyphs[j].x + glyphs[j].w) 00887 || (glyphs[i].y >= glyphs[j].y + glyphs[j].h) 00888 || (glyphs[j].x >= glyphs[i].x + glyphs[i].w) 00889 || (glyphs[j].y >= glyphs[i].y + glyphs[i].h)) { 00890 continue; 00891 } 00892 last_x = glyphs[j].x + glyphs[j].w; 00893 glyphs[i].x = last_x; 00894 j = 0; 00895 } 00896 00897 if ((last_x + glyphs[i].w > bmp->w) 00898 || (last_line + glyphs[i].h > bmp->h)) { 00899 collide = TRUE; 00900 } 00901 00902 if (collide) { 00903 /* If there was a collision, we need to find the sprite with 00904 * the smallest height that is still grater than last_line. 00905 * We also need to redo this glyph. 00906 */ 00907 int min_line = bmp->h + 1; 00908 int min_glyph = -1; 00909 00910 for (j = 0; j < i; j++) { 00911 if ( glyphs[j].y + glyphs[j].h < min_line 00912 && glyphs[j].y + glyphs[j].h 00913 > last_line - FONT_CHARACTER_SPACING) { 00914 00915 min_line = glyphs[j].y + glyphs[j].h 00916 + FONT_CHARACTER_SPACING; 00917 min_glyph = j; 00918 } 00919 } 00920 /* If it can't possibly all fit, failure */ 00921 if (min_glyph == -1) { 00922 TRACE(PREFIX_I "sort_out_glyphs: Unable to fit all glyphs into " 00923 "the texture.\n"); 00924 return FALSE; 00925 } 00926 /* Otherwise, start over at the top of that glyph */ 00927 last_x = glyphs[min_glyph].x; 00928 last_line = min_line; 00929 00930 /* Redo this glyph */ 00931 i--; 00932 } 00933 else { 00934 last_x += glyphs[i].w + FONT_CHARACTER_SPACING; 00935 } 00936 } 00937 00938 /* All ok */ 00939 return TRUE; 00940 } 00941 00942 00943 00944 static int split_font(FONT *f, void *source, void **dest1, void **dest2) { 00945 00946 union mixed_ptr range1, range2, src; 00947 int colored; 00948 int i; 00949 00950 (*dest1) = NULL; 00951 (*dest2) = NULL; 00952 src.ptr = source; 00953 00954 colored = (is_mono_font(f) ? FALSE : TRUE); 00955 00956 /* Allocate the ranges that we need */ 00957 range1.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA) 00958 : sizeof(FONT_MONO_DATA)); 00959 if (!range1.ptr) { 00960 TRACE(PREFIX_E "split_font() - Ran out of memory while " 00961 "trying ot allocate %i bytes.\n", 00962 colored ? (int)sizeof(FONT_COLOR_DATA) 00963 : (int)sizeof(FONT_MONO_DATA)); 00964 return FALSE; 00965 } 00966 00967 range2.ptr = malloc(colored ? sizeof(FONT_COLOR_DATA) 00968 : sizeof(FONT_MONO_DATA)); 00969 if (!range2.ptr) { 00970 TRACE(PREFIX_E "split_font() - Ran out of memory while " 00971 "trying to allocate %i bytes.\n", 00972 colored ? (int)sizeof(FONT_COLOR_DATA) 00973 : (int)sizeof(FONT_MONO_DATA)); 00974 free(range1.ptr); 00975 return FALSE; 00976 } 00977 00978 (*dest1) = range1.ptr; 00979 (*dest2) = range2.ptr; 00980 00981 /* Now we split up the range */ 00982 if (colored) { 00983 /* Half the range */ 00984 int mid = src.cf->begin + (src.cf->end - src.cf->begin) / 2; 00985 00986 range1.cf->begin = src.cf->begin; 00987 range1.cf->end = mid; 00988 range2.cf->begin = mid; 00989 range2.cf->end = src.cf->end; 00990 00991 range1.cf->next = NULL; 00992 range2.cf->next = NULL; 00993 00994 /* Split up the bitmaps */ 00995 range1.cf->bitmaps = malloc(sizeof(BITMAP*) 00996 * (range1.cf->end - range1.cf->begin)); 00997 if (!range1.cf->bitmaps) { 00998 TRACE(PREFIX_E "split_font() - Ran out of memory " 00999 "while trying to allocate %i bytes.\n", 01000 (int)sizeof(BITMAP*) * (range1.cf->end - range1.cf->begin)); 01001 free(range1.ptr); 01002 free(range2.ptr); 01003 return FALSE; 01004 } 01005 01006 range2.cf->bitmaps = malloc(sizeof(BITMAP*) 01007 * (range2.cf->end - range2.cf->begin)); 01008 if (!range2.cf->bitmaps) { 01009 TRACE(PREFIX_E "split_font() - Ran out of memory " 01010 "while trying to allocate %i bytes.\n", 01011 (int)sizeof(BITMAP*) * (range2.cf->end - range2.cf->begin)); 01012 free(range1.cf->bitmaps); 01013 free(range1.ptr); 01014 free(range2.ptr); 01015 return FALSE; 01016 } 01017 01018 01019 for (i = 0; i < (range1.cf->end - range1.cf->begin); i++) { 01020 range1.cf->bitmaps[i] = src.cf->bitmaps[i]; 01021 } 01022 for (i = 0; i < (range2.cf->end - range2.cf->begin); i++) { 01023 range2.cf->bitmaps[i] = 01024 src.cf->bitmaps[i + range2.cf->begin - range1.cf->begin]; 01025 } 01026 } 01027 else { 01028 /* Half the range */ 01029 int mid = src.mf->begin + (src.mf->end - src.mf->begin) / 2; 01030 01031 range1.mf->begin = src.mf->begin; 01032 range1.mf->end = mid; 01033 range2.mf->begin = mid; 01034 range2.mf->end = src.mf->end; 01035 01036 range1.mf->next = NULL; 01037 range2.mf->next = NULL; 01038 01039 /* Split up the bitmaps */ 01040 range1.mf->glyphs = malloc(sizeof(FONT_GLYPH*) 01041 * (range1.mf->end - range1.mf->begin)); 01042 if (!range1.mf->glyphs) { 01043 TRACE(PREFIX_E "split_font() - Ran out of memory " 01044 "while trying to allocate %i bytes.\n", 01045 (int)sizeof(FONT_GLYPH*) * (range1.mf->end - range1.mf->begin)); 01046 free(range1.ptr); 01047 free(range2.ptr); 01048 return FALSE; 01049 } 01050 01051 range2.mf->glyphs = malloc(sizeof(FONT_GLYPH*) 01052 * (range2.mf->end - range2.mf->begin)); 01053 if (!range2.mf->glyphs) { 01054 TRACE(PREFIX_E "split_font() - Ran out of memory " 01055 "while trying to allocate %i bytes.\n", 01056 (int)sizeof(FONT_GLYPH*) * (range2.mf->end - range2.mf->begin)); 01057 free(range1.mf->glyphs); 01058 free(range1.ptr); 01059 free(range2.ptr); 01060 return FALSE; 01061 } 01062 01063 for (i = 0; i < (range1.mf->end - range1.mf->begin); i++) { 01064 range1.mf->glyphs[i] = src.mf->glyphs[i]; 01065 } 01066 for (i = 0; i < (range2.mf->end - range2.mf->begin); i++) { 01067 range2.mf->glyphs[i] = 01068 src.mf->glyphs[i + range2.mf->begin - range1.mf->begin]; 01069 } 01070 } 01071 01072 return TRUE; 01073 } 01074 01075 01076 01077 /* Destroys a split font */ 01078 static void destroy_split_font(FONT *f, union mixed_ptr range1, 01079 union mixed_ptr range2) { 01080 01081 if (!is_mono_font(f)) { 01082 free(range1.cf->bitmaps); 01083 free(range2.cf->bitmaps); 01084 } 01085 else { 01086 free(range1.mf->glyphs); 01087 free(range2.mf->glyphs); 01088 } 01089 01090 free(range1.ptr); 01091 free(range2.ptr); 01092 01093 return; 01094 } 01095 01096 01097 01098 static int do_crop_font_range(FONT *f, AGL_GLYPH *glyphs, int beg, int end) { 01099 01100 int i, j, k; 01101 int max = end - beg; 01102 char buf[32]; 01103 01104 /* Allocate a temp bitmap to work with */ 01105 BITMAP *temp = create_bitmap(32, 32); 01106 01107 if (!temp) { 01108 TRACE(PREFIX_E "crop_font_range - Unable to create " 01109 "bitmap of size: %ix%i!\n", 32, 32); 01110 goto error; 01111 } 01112 01113 /* Crop glyphs */ 01114 for (i = 0; i < max; i++) { 01115 int used = 0; 01116 01117 if (glyphs[i].w > temp->w || glyphs[i].h > temp->h) { 01118 int old_w = temp->w, old_h = temp->h; 01119 destroy_bitmap(temp); 01120 temp = create_bitmap(old_w * 2, old_h * 2); 01121 if (!temp) { 01122 TRACE(PREFIX_E "crop_font_range - Unable to " 01123 "create bitmap of size: %ix%i!\n", old_w * 2, old_h * 2); 01124 goto error; 01125 } 01126 } 01127 clear(temp); 01128 01129 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0); 01130 01131 textout_ex(temp, f, buf, 0, 0, 01132 makecol_depth(bitmap_color_depth(temp), 255, 255, 255), 0); 01133 01134 /* Crop top */ 01135 for (j = 0; j < glyphs[i].h; j++) { 01136 used = 0; 01137 01138 for (k = 0; k < glyphs[i].w; k++) { 01139 if (getpixel(temp, k, j)) { 01140 used = 1; 01141 glyphs[i].offset_y += j; 01142 glyphs[i].h -= j; 01143 break; 01144 } 01145 } 01146 if (used) 01147 break; 01148 } 01149 01150 /* If just the top crop killed our glyph, then skip it entirely */ 01151 if (!used) { 01152 TRACE(PREFIX_I "crop_font_range: skipping glyph %i\n", i); 01153 glyphs[i].offset_y = 0; 01154 glyphs[i].offset_h = glyphs[i].h - 1; 01155 glyphs[i].offset_w = glyphs[i].w - 2; 01156 glyphs[i].h = 1; 01157 glyphs[i].w = 1; 01158 continue; 01159 } 01160 01161 /* Crop bottom */ 01162 j = glyphs[i].h + glyphs[i].offset_y - 1; 01163 for ( /* above */; j >= glyphs[i].offset_y; j--) { 01164 used = 0; 01165 01166 for (k = 0; k < glyphs[i].w; k++) { 01167 if (getpixel(temp, k, j)) { 01168 used = 1; 01169 glyphs[i].offset_h += 01170 glyphs[i].h + glyphs[i].offset_y - j - 2; 01171 glyphs[i].h -= glyphs[i].h + glyphs[i].offset_y - j - 1; 01172 break; 01173 } 01174 } 01175 if (used) 01176 break; 01177 } 01178 01179 /* Crop Left */ 01180 for (j = 0; j < glyphs[i].w; j++) { 01181 used = 0; 01182 01183 k = MAX(glyphs[i].offset_y - 1, 0); 01184 for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) { 01185 if (getpixel(temp, j, k)) { 01186 used = 1; 01187 glyphs[i].offset_x += j; 01188 glyphs[i].w -= j; 01189 break; 01190 } 01191 } 01192 if (used) 01193 break; 01194 } 01195 01196 /* Crop Right */ 01197 j = glyphs[i].w + glyphs[i].offset_x - 1; 01198 for (/* above */; j >= glyphs[i].offset_x; j--) { 01199 used = 0; 01200 01201 k = MAX(glyphs[i].offset_y - 1, 0); 01202 for (/* above */; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) { 01203 if (getpixel(temp, j, k)) { 01204 used = 1; 01205 glyphs[i].offset_w += 01206 glyphs[i].w + glyphs[i].offset_x - 1 - j; 01207 glyphs[i].w -= glyphs[i].w + glyphs[i].offset_x - j - 1; 01208 break; 01209 } 01210 } 01211 if (used) 01212 break; 01213 } 01214 #ifdef LOGLEVEL 01215 TRACE(PREFIX_I "crop_font_range: Glyph %i (%c) offs: x: %i y: %i, " 01216 "w: %i h: %i, offs: w: %i h: %i\n", i, i + beg, 01217 glyphs[i].offset_x, glyphs[i].offset_y, glyphs[i].w, glyphs[i].h, 01218 glyphs[i].offset_w, glyphs[i].offset_h); 01219 #endif 01220 } 01221 01222 destroy_bitmap(temp); 01223 01224 return TRUE; 01225 01226 error: 01227 if (temp) { 01228 destroy_bitmap(temp); 01229 } 01230 01231 return FALSE; 01232 } 01233 01234 01235 01236 /* Crops a font over a particular range */ 01237 static int crop_font_range(FONT *f, void *src, int beg, int end, 01238 AGL_GLYPH *glyphs, 01239 int *net_area, int *gross_area, 01240 int *max_w, int *max_h) { 01241 01242 int i; 01243 int crop = 1; 01244 int max = end - beg; 01245 int ret = TRUE; 01246 01247 union mixed_ptr dat; 01248 dat.ptr = src; 01249 01250 /* Disable cropping for trucolor fonts. */ 01251 if (is_color_font(f)) { 01252 FONT_COLOR_DATA *fcd = f->data; 01253 if (bitmap_color_depth(fcd->bitmaps[0]) != 8) { 01254 crop = 0; 01255 } 01256 } 01257 01258 /* Load default sizes */ 01259 for (i = 0; i < max; i++) { 01260 glyphs[i].glyph_num = i; 01261 01262 if (is_mono_font(f)) { 01263 glyphs[i].w = dat.mf->glyphs[i]->w + 1; 01264 glyphs[i].h = dat.mf->glyphs[i]->h + 1; 01265 } else { 01266 glyphs[i].w = dat.cf->bitmaps[i]->w + 1; 01267 glyphs[i].h = dat.cf->bitmaps[i]->h + 1; 01268 } 01269 glyphs[i].offset_w = -1; 01270 glyphs[i].offset_h = -1; 01271 01272 /* Not placed yet */ 01273 glyphs[i].x = -1; 01274 } 01275 01276 if (crop) { 01277 ret = do_crop_font_range(f, glyphs, beg, end); 01278 } 01279 01280 (*gross_area) = 0; 01281 (*net_area) = 0; 01282 (*max_w) = 0; 01283 (*max_h) = 0; 01284 01285 /* Find max w and h, total area covered by the bitmaps, and number of 01286 * glyphs 01287 */ 01288 for (i = 0; i < max; i++) { 01289 if (glyphs[i].w > *max_w) (*max_w) = glyphs[i].w; 01290 if (glyphs[i].h > *max_h) (*max_h) = glyphs[i].h; 01291 (*net_area) += glyphs[i].w * glyphs[i].h; 01292 (*gross_area) += (glyphs[i].w + FONT_CHARACTER_SPACING) 01293 * (glyphs[i].h + FONT_CHARACTER_SPACING); 01294 } 01295 return ret; 01296 01297 } 01298 01299 01300 01301 /* Tries to find a texture that will fit the font 01302 */ 01303 static BITMAP* look_for_texture(int beg, int end, AGL_GLYPH *glyphs, 01304 int max_w, int max_h, int total_area, GLint format, int has_alpha) { 01305 01306 BITMAP *bmp = NULL; 01307 int i, j; 01308 01309 /* Max texture size (1 << n) */ 01310 /* XXX <rohannessian> We should use ARB_np2 if we can 01311 * 01312 * Other note: w*h shouldn't exceed 31 bits; otherwise, we get funny 01313 * behavior on 32-bit architectures. Limit texture sizes to 32k*32k 01314 * (30 bits). 01315 */ 01316 #define MIN_TEXTURE_SIZE 2 01317 #define NUM_TEXTURE_SIZE 13 01318 texture_size texture_sizes[NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE]; 01319 01320 /* Set up texture sizes */ 01321 for (i = 0; i < NUM_TEXTURE_SIZE; i++) { 01322 for (j = 0; j < NUM_TEXTURE_SIZE; j++) { 01323 texture_sizes[j + i * NUM_TEXTURE_SIZE].w = 01324 1 << (j + MIN_TEXTURE_SIZE); 01325 texture_sizes[j + i * NUM_TEXTURE_SIZE].h = 01326 1 << (i + MIN_TEXTURE_SIZE); 01327 } 01328 } 01329 01330 /* Sort texture sizes by area */ 01331 qsort(texture_sizes, NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE, 01332 sizeof(texture_size), &sort_textures); 01333 01334 for (i = 0; i < NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE; i++) { 01335 int num_channels; 01336 01337 /* Check the area - it must be larger than 01338 * all the glyphs 01339 */ 01340 texture_size *t = &texture_sizes[i]; 01341 int area = t->w * t->h; 01342 int depth = 24; 01343 01344 if (area < total_area) { 01345 continue; 01346 } 01347 01348 /* Check against max values */ 01349 if ((t->h < max_h) || (t->w < max_w)) { 01350 continue; 01351 } 01352 01353 TRACE(PREFIX_I "look_for_texture: candidate size: %ix%i\n", t->w, t->h); 01354 01355 /* Check that the texture can, in fact, be created */ 01356 num_channels = __allegro_gl_get_num_channels(format); 01357 if (num_channels == 1) { 01358 depth = 8; 01359 } 01360 else if (num_channels == 4) { 01361 depth = 32; 01362 } 01363 else { 01364 depth = 24; 01365 } 01366 bmp = create_bitmap_ex(depth, t->w, t->h); 01367 01368 if (!bmp) { 01369 TRACE(PREFIX_W "look_for_texture: Out of memory while " 01370 "creating bitmap\n"); 01371 continue; 01372 } 01373 01374 if (!aglf_check_texture(bmp, format, has_alpha)) { 01375 TRACE(PREFIX_I "look_for_texture: Texture rejected by driver\n"); 01376 destroy_bitmap(bmp); 01377 bmp = NULL; 01378 continue; 01379 } 01380 01381 /* Sort out the glyphs */ 01382 TRACE(PREFIX_I "look_for_texture: Sorting on bmp: %p, beg: %i, " 01383 "end: %i\n", bmp, beg, end); 01384 01385 if (aglf_sort_out_glyphs(bmp, glyphs, beg, end) == TRUE) { 01386 /* Success? */ 01387 return bmp; 01388 } 01389 01390 /* Failure? Try something else */ 01391 TRACE(PREFIX_I "look_for_texture: Conversion failed\n"); 01392 destroy_bitmap(bmp); 01393 bmp = NULL; 01394 } 01395 01396 return NULL; 01397 } 01398 01399 01400 01401 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 01402 /* This is only used to render chars from an Allegro font which has the 01403 * font_vtable_trans vtable. If the target is an 8-bit bitmap, only the alpha 01404 * channel is used. Otherwise, blit is used, to preserve the alpha channel. 01405 */ 01406 static int dummy_render_char(AL_CONST FONT* f, int ch, int fg, int bg, 01407 BITMAP* bmp, int x, int y) 01408 { 01409 FONT_COLOR_DATA* cf = (FONT_COLOR_DATA*)(f->data); 01410 BITMAP *glyph = NULL; 01411 01412 while(cf) { 01413 if(ch >= cf->begin && ch < cf->end) { 01414 glyph = cf->bitmaps[ch - cf->begin]; 01415 break; 01416 } 01417 cf = cf->next; 01418 } 01419 01420 if (glyph) 01421 { 01422 if (bitmap_color_depth(bmp) == 8) { 01423 int gx, gy; 01424 for (gy = 0; gy < bmp->h; gy++) { 01425 for (gx = 0; gx < bmp->w; gx++) { 01426 int c = getpixel(glyph, gx, gy); 01427 int a = geta(c); 01428 putpixel(bmp, x + gx, y + gy, a); 01429 } 01430 } 01431 } 01432 else 01433 blit(glyph, bmp, 0, 0, x, y, glyph->w, glyph->h); 01434 return bmp->w; 01435 } 01436 return 0; 01437 } 01438 #endif 01439 01440 01441 01442 /* Function to draw a character in a bitmap for conversion */ 01443 static int draw_glyphs(BITMAP *bmp, FONT *f, GLint format, int beg, int end, 01444 AGL_GLYPH *glyphs) { 01445 char buf[32]; 01446 int i, j; 01447 01448 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 01449 if (bitmap_color_depth(bmp) == 8 && f->vtable != font_vtable_trans) { 01450 #else 01451 if (bitmap_color_depth(bmp) == 8) { 01452 #endif 01453 /* Generate an alpha font */ 01454 BITMAP *rgbbmp = create_bitmap_ex(24, bmp->w, bmp->h); 01455 01456 if (!rgbbmp) { 01457 TRACE(PREFIX_E "convert_allegro_font_to_texture: " 01458 "Ran out of memory while creating %ix%ix%i bitmap!\n", 01459 bmp->w, bmp->h, 24); 01460 return FALSE; 01461 } 01462 01463 clear_bitmap(rgbbmp); 01464 01465 for (i = 0; i < end - beg; i++) { 01466 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0); 01467 01468 textout_ex(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x, 01469 glyphs[i].y - glyphs[i].offset_y, -1, -1); 01470 } 01471 01472 /* Convert back to 8bpp */ 01473 for (j = 0; j < bmp->h; j++) { 01474 for (i = 0; i < bmp->w; i++) { 01475 int pix = _getpixel24(rgbbmp, i, j); 01476 int r = getr24(pix); 01477 int g = getg24(pix); 01478 int b = getb24(pix); 01479 int gray = (r * 77 + g * 150 + b * 28 + 255) >> 8; 01480 _putpixel(bmp, i, j, MID(0, gray, 255)); 01481 } 01482 } 01483 destroy_bitmap(rgbbmp); 01484 } 01485 else { 01486 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 01487 int (*borrowed_color_vtable)(AL_CONST FONT*, int, int, int, BITMAP*, int, int) = NULL; 01488 01489 //In order to keep the alpha channel in textout_ex we borrow 01490 //the color font vtable which uses maked_blit() instead of 01491 //draw_trans_sprite() to draw glyphs. 01492 if (f->vtable == font_vtable_trans) { 01493 borrowed_color_vtable = f->vtable->render_char; 01494 f->vtable->render_char = dummy_render_char; 01495 } 01496 #endif 01497 01498 if (__allegro_gl_get_num_channels(format) == 4) { 01499 clear_to_color(bmp, bitmap_mask_color(bmp)); 01500 } 01501 else { 01502 clear_bitmap(bmp); 01503 } 01504 01505 for (i = 0; i < end - beg; i++) { 01506 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0); 01507 textout_ex(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x, 01508 glyphs[i].y - glyphs[i].offset_y, -1, -1); 01509 } 01510 01511 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 01512 if (borrowed_color_vtable) { 01513 f->vtable->render_char = borrowed_color_vtable; 01514 } 01515 #endif 01516 } 01517 01518 return TRUE; 01519 } 01520 01521 01522 01523 /* Converts a single font range to a texture. 01524 * dest - Receives the result. 01525 * f - The original font. 01526 * src - The original font data. 01527 */ 01528 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA **dest, FONT *f, 01529 void *src, int *height, float scale, GLint format) { 01530 01531 int max = 0; 01532 BITMAP *bmp = NULL; 01533 int beg = 0, end = 0; 01534 int max_w, max_h; 01535 int total_area, gross_area; 01536 01537 AGL_GLYPH *glyph_coords; 01538 01539 union mixed_ptr dat; 01540 dat.ptr = src; 01541 01542 if (is_mono_font(f)) { 01543 beg = dat.mf->begin; 01544 end = dat.mf->end; 01545 max = dat.mf->end - dat.mf->begin; 01546 if (format == -1) { 01547 format = GL_INTENSITY4; 01548 } 01549 } 01550 else if (is_color_font(f)) { 01551 beg = dat.cf->begin; 01552 end = dat.cf->end; 01553 max = dat.cf->end - dat.cf->begin; 01554 if (format == -1) { 01555 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 01556 format = (f->vtable == font_vtable_trans ? GL_RGBA8 : GL_RGB8); 01557 #else 01558 format = GL_RGB8; 01559 #endif 01560 } 01561 } 01562 01563 /* Allocate glyph sizes */ 01564 glyph_coords = malloc(max * sizeof(AGL_GLYPH)); 01565 memset(glyph_coords, 0, max * sizeof(AGL_GLYPH)); 01566 01567 if (crop_font_range(f, dat.ptr, beg, end, glyph_coords, 01568 &total_area, &gross_area, &max_w, &max_h) == FALSE) { 01569 TRACE(PREFIX_I "convert_allegro_font_to_texture: Unable to crop font " 01570 "range\n"); 01571 free(glyph_coords); 01572 return; 01573 } 01574 01575 TRACE(PREFIX_I "convert_allegro_font_to_texture: Total area of glyphs: " 01576 "%i pixels (%i pixels gross) - max_w: %i, max_h: %i\n", 01577 total_area, gross_area, max_w, max_h); 01578 01579 /* Sort glyphs by width, then height */ 01580 qsort(glyph_coords, end - beg, sizeof(AGL_GLYPH), &sort_glyphs); 01581 01582 01583 /* Now, we look for the appropriate texture size */ 01584 bmp = look_for_texture(beg, end, glyph_coords, max_w, max_h, 01585 total_area, format, (*dest)->has_alpha); 01586 01587 /* No texture sizes were found - we should split the font up */ 01588 if (!bmp) { 01589 int height1; 01590 union mixed_ptr f1, f2; 01591 FONT_AGL_DATA *dest1, *dest2; 01592 01593 free(glyph_coords); 01594 01595 dest1 = *(dest); 01596 dest2 = malloc(sizeof(FONT_AGL_DATA)); 01597 01598 if (!dest2) { 01599 TRACE(PREFIX_E "convert_allegro_font_to_texture: " 01600 "Out of memory while trying to allocate %i bytes.\n", 01601 (int)sizeof(FONT_AGL_DATA)); 01602 return; 01603 } 01604 01605 memset(dest2, 0, sizeof(FONT_AGL_DATA)); 01606 01607 dest2->next = dest1->next; 01608 dest1->next = dest2; 01609 dest2->is_free_chunk = TRUE; 01610 dest2->format = dest1->format; 01611 dest2->has_alpha = dest1->has_alpha; 01612 01613 if (split_font(f, dat.ptr, &f1.ptr, &f2.ptr) == FALSE) { 01614 TRACE(PREFIX_E "convert_allegro_font_to_texture: Unable " 01615 "to split font!\n"); 01616 dest1->next = dest2->next; 01617 free(dest2); 01618 return; 01619 } 01620 01621 aglf_convert_allegro_font_to_texture(&dest1, f, f1.ptr, height, scale, 01622 format); 01623 height1 = (*height); 01624 aglf_convert_allegro_font_to_texture(&dest2, f, f2.ptr, height, scale, 01625 format); 01626 destroy_split_font(f, f1, f2); 01627 01628 if (height1 > (*height)) 01629 (*height) = height1; 01630 (*dest) = dest2; 01631 01632 return; 01633 } 01634 01635 TRACE(PREFIX_I "convert_allegro_font_to_texture: Using texture " 01636 "%ix%ix%i for font conversion.\n", bmp->w, bmp->h, 01637 bitmap_color_depth(bmp)); 01638 01639 /* Now that all the glyphs are in place, we draw them into the bitmap */ 01640 if (draw_glyphs(bmp, f, format, beg, end, glyph_coords) == FALSE) { 01641 destroy_bitmap(bmp); 01642 free(glyph_coords); 01643 return; 01644 } 01645 01646 /* Un-Sort glyphs */ 01647 qsort(glyph_coords, end - beg, sizeof(AGL_GLYPH), &unsort_glyphs); 01648 01649 #if (defined SAVE_FONT_SCREENSHOT) 01650 save_shot(bmp); 01651 #endif 01652 01653 (*dest)->list_base = 01654 create_textured_font_call_lists(glyph_coords, max, bmp, 01655 scale, height); 01656 01657 (*dest)->texture = aglf_upload_texture(bmp, format, (*dest)->has_alpha); 01658 (*dest)->type = AGL_FONT_TYPE_TEXTURED; 01659 (*dest)->format = format; 01660 (*dest)->scale = scale; 01661 (*dest)->start = beg; 01662 (*dest)->end = end; 01663 (*dest)->data = bmp; 01664 (*dest)->glyph_coords = glyph_coords; 01665 01666 return; 01667 } 01668 01669 01670 01671 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f, 01672 void *src, int *height) { 01673 01674 int max = 0; 01675 int i, j, k; 01676 int beg = 0, end = 0; 01677 int mask; 01678 FONT_GLYPH **glyph; 01679 01680 union { 01681 FONT_MONO_DATA* mf; 01682 FONT_COLOR_DATA* cf; 01683 void *ptr; 01684 } dat; 01685 01686 dat.ptr = src; 01687 01688 if (is_mono_font(f)) 01689 max = dat.mf->end - dat.mf->begin; 01690 else if (is_color_font(f)) 01691 max = dat.cf->end - dat.cf->begin; 01692 else 01693 return; 01694 01695 glyph = malloc(sizeof(FONT_GLYPH*) * max); 01696 01697 if (!glyph) { 01698 TRACE(PREFIX_E "convert_allegro_font_to_bitmap: Ran out of " 01699 "memory while allocating %i bytes\n", (int)sizeof(FONT_GLYPH)); 01700 return; 01701 } 01702 01703 *height = f->height; 01704 01705 if (is_mono_font(f)) { 01706 01707 /* for each glyph */ 01708 for (i = 0; i < max; i++) { 01709 FONT_GLYPH *oldgl = dat.mf->glyphs[i]; 01710 01711 int size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4 01712 * oldgl->h; 01713 01714 /* create new glyph */ 01715 FONT_GLYPH *newgl = (FONT_GLYPH*)malloc(size); 01716 01717 if (!newgl) 01718 break; 01719 01720 memset(newgl, 0, size); 01721 01722 newgl->w = oldgl->w; 01723 newgl->h = oldgl->h; 01724 01725 /* update the data */ 01726 for (j = 0; j < oldgl->h; j++) { 01727 for (k = 0; k < ((oldgl->w + 7) / 8); k++) { 01728 int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4 01729 + k; 01730 newgl->dat[addr] = oldgl->dat[j * ((oldgl->w + 7) / 8) + k]; 01731 } 01732 } 01733 01734 glyph[i] = newgl; 01735 } 01736 } 01737 /* Reduce to 1 bit */ 01738 else if (is_color_font(f)) { 01739 /* for each glyph */ 01740 for (i = 0; i < max; i++) { 01741 01742 int size; 01743 BITMAP *oldgl = dat.cf->bitmaps[i]; 01744 FONT_GLYPH *newgl; 01745 01746 mask = bitmap_mask_color(oldgl); 01747 01748 size = sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4 * oldgl->h; 01749 01750 /* create new glyph */ 01751 newgl = (FONT_GLYPH*)malloc(size); 01752 01753 if (!newgl) 01754 break; 01755 01756 memset(newgl, 0, size); 01757 01758 newgl->w = oldgl->w; 01759 newgl->h = oldgl->h; 01760 01761 /* update the data */ 01762 for (j = 0; j < oldgl->h; j++) { 01763 for (k = 0; k < oldgl->w; k++) { 01764 int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4 01765 + (k / 8); 01766 newgl->dat[addr] |= (getpixel(oldgl, k, j) == mask) 01767 ? 0 : (1 << (k & 7)); 01768 } 01769 } 01770 01771 glyph[i] = newgl; 01772 } 01773 } 01774 /* Create call lists */ 01775 { 01776 GLuint list = glGenLists(max); 01777 01778 for (i = 0; i < max; i++) { 01779 glNewList(list + i, GL_COMPILE); 01780 01781 glBitmap(glyph[i]->w, glyph[i]->h, 0, 0, glyph[i]->w, 0, 01782 glyph[i]->dat); 01783 01784 glEndList(); 01785 } 01786 dest->list_base = list; 01787 } 01788 01789 dest->is_free_chunk = 0; 01790 dest->type = AGL_FONT_TYPE_BITMAP; 01791 dest->start = beg; 01792 dest->end = end; 01793 dest->data = glyph; 01794 01795 return; 01796 } 01797 01798 01799 01800 static int aglf_check_texture(BITMAP *bmp, GLint format, int has_alpha) { 01801 01802 int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP; 01803 01804 if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA 01805 || format == GL_INTENSITY4 || format == GL_INTENSITY8 01806 || format == GL_INTENSITY 01807 || format == GL_LUMINANCE4 || format == GL_LUMINANCE8 01808 || format == GL_LUMINANCE 01809 || format == 1) { 01810 flags |= AGL_TEXTURE_ALPHA_ONLY; 01811 } 01812 else if (format == GL_RGBA8) { 01813 if (has_alpha) { 01814 flags |= AGL_TEXTURE_HAS_ALPHA; 01815 } 01816 else { 01817 flags |= AGL_TEXTURE_MASKED; 01818 } 01819 } 01820 01821 return allegro_gl_check_texture_ex(flags, bmp, format); 01822 } 01823 01824 01825 01826 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format, int has_alpha) { 01827 01828 int flags = AGL_TEXTURE_FLIP | AGL_TEXTURE_MIPMAP; 01829 GLuint texture; 01830 01831 if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA 01832 || format == GL_INTENSITY4 || format == GL_INTENSITY8 01833 || format == GL_INTENSITY 01834 || format == GL_LUMINANCE4 || format == GL_LUMINANCE8 01835 || format == GL_LUMINANCE 01836 || format == 1) { 01837 flags |= AGL_TEXTURE_ALPHA_ONLY; 01838 } 01839 else if (__allegro_gl_get_num_channels(format) == 4) { 01840 if (has_alpha) { 01841 flags |= AGL_TEXTURE_HAS_ALPHA; 01842 } 01843 else { 01844 flags |= AGL_TEXTURE_MASKED; 01845 } 01846 } 01847 01848 TRACE(PREFIX_I "Want texture format: %s\n", 01849 __allegro_gl_get_format_description(format)); 01850 texture = allegro_gl_make_texture_ex(flags, bmp, format); 01851 TRACE(PREFIX_I "Texture ID is: %u\n", texture); 01852 01853 return texture; 01854 } 01855