18 #include <allegro/internal/aintern.h> 24 #include <OpenGL/glu.h> 29 #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGROGL_GENERIC_DRIVER 34 #define PREFIX_I "agl-font INFO: " 35 #define PREFIX_W "agl-font WARNING: " 36 #define PREFIX_E "agl-font ERROR: " 41 #define FONT_CHARACTER_SPACING 2 49 static int agl_get_font_height(AL_CONST FONT *f);
50 static int agl_char_length(
const FONT *f,
int ch);
51 static int agl_text_length(
const FONT *f,
const char *str);
53 static int agl_get_font_ranges(FONT *f);
54 static int agl_get_font_range_begin(FONT *f,
int range);
55 static int agl_get_font_range_end(FONT *f,
int range);
56 static FONT *agl_extract_font_range(FONT *f,
int start,
int end);
57 static FONT *agl_merge_fonts(FONT *f1, FONT *f2);
59 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0) 60 static int agl_transpose_font(FONT *f,
int drange);
64 FONT_VTABLE _agl_font_vtable = {
72 agl_get_font_range_begin,
73 agl_get_font_range_end,
74 agl_extract_font_range,
76 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0) 82 FONT_VTABLE *font_vtable_agl = &_agl_font_vtable;
84 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
85 void *src,
int *height);
86 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA **dest, FONT *f,
87 void *src,
int *height,
float scale, GLint format);
88 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format,
int has_alpha);
89 static int aglf_check_texture(BITMAP *bmp, GLint format,
int has_alpha);
90 static BITMAP* look_for_texture(
int beg,
int end, AGL_GLYPH *glyphs,
91 int max_w,
int max_h,
int total_area,
92 GLint format,
int has_alpha);
104 typedef struct texture_size {
110 static int agl_get_font_height(AL_CONST FONT *f) {
118 static int iroundf(
float v) {
124 if ((c - v) < (v - f))
131 if ((c - v) < (v - f))
143 static float agl_char_length_fractional(
const FONT *f,
int ch) {
144 FONT_AGL_DATA *fad = f->data;
148 if (ch >= fad->start && ch < fad->end) {
149 AGL_GLYPH *coords = &(fad->glyph_coords[ch - fad->start]);
150 return (coords->offset_x + coords->w + coords->offset_w)
159 if (ch >= fad->start && ch < fad->end) {
160 FONT_GLYPH **gl = fad->data;
161 return gl[ch - fad->start]->w;
170 if (ch != allegro_404_char)
171 return agl_char_length_fractional(f, allegro_404_char);
182 static int agl_char_length(
const FONT *f,
int ch) {
183 return iroundf(agl_char_length_fractional(f, ch));
192 static int agl_text_length(
const FONT *f,
const char *str) {
199 while ( (ch = ugetxc(&p)) ) {
200 l += agl_char_length_fractional(f, ch);
213 static int agl_get_font_ranges(FONT *f) {
220 fad = (FONT_AGL_DATA*)(f->data);
223 FONT_AGL_DATA *next = fad->next;
240 static int agl_get_font_range_begin(FONT *f,
int range) {
250 fad = (FONT_AGL_DATA*)(f->data);
251 while (fad && n <= range) {
252 FONT_AGL_DATA *next = fad->next;
254 if (!next || range == n)
269 static int agl_get_font_range_end(FONT *f,
int range) {
270 FONT_AGL_DATA* fad = 0;
276 fad = (FONT_AGL_DATA*)(f->data);
278 while (fad && (n <= range || range == -1)) {
279 FONT_AGL_DATA *next = fad->next;
280 if (!next || range == n)
292 static int create_textured_font_call_lists(AGL_GLYPH *coords,
int max, BITMAP *bmp,
293 float scale,
int *height) {
297 int rev = scale < 0 ? 1 : 0;
300 list = glGenLists(max);
302 for (i = 0; i < max; i++) {
304 float tx = (float)coords[i].x / bmp->w;
305 float ty = 1.0 - (
float)coords[i].y / bmp->h;
307 float dtx = (float)(coords[i].w) / bmp->w;
308 float dty = (float)(coords[i].h) / bmp->h;
311 float xoffs = (float)coords[i].offset_x / scale;
312 float yoffs = (float)coords[i].offset_y / scale;
314 float woffs = (float)coords[i].w / scale;
315 float hoffs = (float)coords[i].h / scale;
318 float sizew = (float)(coords[i].offset_x + coords[i].w
319 + coords[i].offset_w) / scale;
320 int sizeh = iroundf((coords[i].offset_y + coords[i].h
321 + coords[i].offset_h) / scale);
323 if ((*height) < sizeh)
331 glNewList(list + i, GL_COMPILE);
334 glTexCoord2f(tx, ty);
335 glVertex2f(xoffs, -yoffs);
337 glTexCoord2f(tx + dtx, ty);
338 glVertex2f(xoffs + woffs, -yoffs);
340 glTexCoord2f(tx + dtx, ty - dty);
341 glVertex2f(xoffs + woffs, -yoffs - hoffs);
343 glTexCoord2f(tx, ty - dty);
344 glVertex2f(xoffs, -yoffs - hoffs);
347 glTranslatef(sizew, 0, 0);
360 static FONT_AGL_DATA* copy_glyph_range(FONT_AGL_DATA *fad,
int start,
int end,
362 int i, count, w = 0, h = 0;
364 BITMAP *bmp, *srcbmp;
365 FONT_AGL_DATA *newfad = NULL;
372 coords = malloc(count *
sizeof (AGL_GLYPH));
375 for (i = 0; i < count; i++) {
376 coords[i] = fad->glyph_coords[start - fad->start + i];
377 coords[i].glyph_num = i;
381 for (i = 0; i < count; i++) {
382 int hh = coords[i].h + coords[i].offset_y + coords[i].offset_h;
385 w += coords[i].w + coords[i].offset_w + coords[i].offset_x;
388 srcbmp = (BITMAP*)fad->data;
391 w = __allegro_gl_make_power_of_2(w);
392 h = __allegro_gl_make_power_of_2(h);
393 bmp = create_bitmap_ex(bitmap_color_depth(srcbmp), w, h);
395 TRACE(PREFIX_E
"copy_glyph_range: Unable to create bitmap of size" 396 "%ix%i pixels!\n", w, h);
401 if (__allegro_gl_get_num_channels(fad->format) == 4) {
402 clear_to_color(bmp, bitmap_mask_color(bmp));
410 for (i = 0; i < count; i++) {
411 int ch = start - fad->start + i;
412 int ww = coords[i].w + coords[i].offset_w + coords[i].offset_x;
413 blit(srcbmp, bmp, fad->glyph_coords[ch].x, 0, w, 0, ww, bmp->h);
419 newfad = malloc(
sizeof(
struct FONT_AGL_DATA));
422 newfad->is_free_chunk = 0;
423 newfad->scale = fad->scale;
424 newfad->format = fad->format;
425 newfad->has_alpha = fad->has_alpha;
426 newfad->start = start;
429 newfad->glyph_coords = coords;
431 newfad->list_base = create_textured_font_call_lists(coords, count, bmp,
432 newfad->scale, height);
433 newfad->texture = aglf_upload_texture(bmp, newfad->format, newfad->has_alpha);
444 static FONT *agl_extract_font_range(FONT *f,
int start,
int end) {
446 FONT_AGL_DATA *fad, *next, *newfad = NULL;
453 if (start == -1 && end == -1) {
455 else if (start == -1 && end > agl_get_font_range_begin(f, -1)) {
457 else if (end == -1 && start <= agl_get_font_range_end(f, -1)) {
459 else if (start <= end && start != -1 && end != -1) {
464 fad = (FONT_AGL_DATA*)f->data;
471 start = MAX(start, agl_get_font_range_begin(f, -1));
473 end = MIN(end, agl_get_font_range_end(f, -1));
476 end = agl_get_font_range_end(f, -1);
480 retval = malloc(
sizeof (
struct FONT));
482 retval->vtable = font_vtable_agl;
492 if ((start >= next->start && start < next->end)
493 || (end <= next->end && end > next->start)
494 || (start < next->start && end > next->end)) {
495 int local_start, local_end;
498 local_start = MAX(next->start, start);
499 local_end = MIN(next->end, end);
502 newfad->next = copy_glyph_range(next, local_start, local_end,
504 newfad = newfad->next;
505 newfad->is_free_chunk = TRUE;
508 newfad = copy_glyph_range(next, local_start, local_end,
510 retval->data = newfad;
526 static FONT *agl_merge_fonts(FONT *f1, FONT *f2) {
528 FONT_AGL_DATA *fad1, *fad2, *fad = NULL;
534 fad1 = (FONT_AGL_DATA*)f1->data;
535 fad2 = (FONT_AGL_DATA*)f2->data;
542 if (fad1->format != fad2->format)
546 retval = malloc(
sizeof(
struct FONT));
547 retval->vtable = font_vtable_agl;
548 retval->height = MAX(f1->height, f2->height);
550 while (fad1 || fad2) {
551 if (fad1 && (!fad2 || fad1->start < fad2->start)) {
553 fad->next = copy_glyph_range(fad1, fad1->start, fad1->end,
556 fad->is_free_chunk = TRUE;
559 fad = copy_glyph_range(fad1, fad1->start, fad1->end, &phony);
566 fad->next = copy_glyph_range(fad2, fad2->start, fad2->end,
569 fad->is_free_chunk = TRUE;
572 fad = copy_glyph_range(fad2, fad2->start, fad2->end, &phony);
584 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 0) 589 static int agl_transpose_font(FONT *f,
int drange) {
590 FONT_AGL_DATA* fad = 0;
595 fad = (FONT_AGL_DATA*)(f->data);
598 FONT_AGL_DATA* next = fad->next;
599 fad->start += drange;
690 int max = 0, height = 0;
693 FONT_AGL_DATA *destdata;
702 if (!__allegro_gl_valid_context) {
707 TRACE(PREFIX_E
"convert_allegro_font: Null source\n");
712 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 713 if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color && f->vtable != font_vtable_trans) {
715 if (f->vtable != font_vtable_mono && f->vtable != font_vtable_color) {
717 TRACE(PREFIX_I
"convert_allegro_font: Source font is not " 718 "in Allegro format\n");
725 TRACE(PREFIX_I
"convert_allegro_font: Unable to convert a " 726 "pixmap font to a vector font.\n");
731 if (fabs(scale) < 0.001) {
732 TRACE(PREFIX_W
"convert_allegro_font: Scaling factor might be " 733 "too small: %f\n", scale);
737 max = get_font_ranges(f);
740 dest = (FONT*)malloc(
sizeof(FONT));
742 TRACE(PREFIX_E
"convert_allegro_font: Ran out of memory " 743 "while allocating %i bytes\n", (
int)
sizeof(FONT));
746 destdata = (FONT_AGL_DATA*)malloc(
sizeof(FONT_AGL_DATA) * max);
748 TRACE(PREFIX_E
"convert_allegro_font: Ran out of memory " 749 "while allocating %i bytes\n", (
int)
sizeof(FONT_AGL_DATA) * max);
752 memset(destdata, 0,
sizeof(FONT_AGL_DATA) * max);
755 for (i = 0; i < max - 1; i++) {
756 destdata[i].next = &destdata[i + 1];
758 destdata[max - 1].next = NULL;
761 dest->data = destdata;
762 dest->vtable = font_vtable_agl;
765 destdata->type = type;
771 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 772 has_alpha = (f->vtable == font_vtable_trans);
780 destdata->has_alpha = has_alpha;
783 aglf_convert_allegro_font_to_bitmap(destdata, f, dat.ptr, &height);
786 aglf_convert_allegro_font_to_texture(&destdata, f, dat.ptr, &height,
790 if (height > dest->height) {
791 dest->height = height;
794 dat.ptr = (is_mono_font(f) ? (
void*)dat.mf->next : (
void*)dat.cf->next);
796 destdata = destdata->next;
807 static int sort_glyphs(
const void *c1,
const void *c2) {
808 AGL_GLYPH *g1 = (AGL_GLYPH*)c1;
809 AGL_GLYPH *g2 = (AGL_GLYPH*)c2;
814 else if (g1->w == g2->w) {
815 return -g1->h + g2->h;
826 static int unsort_glyphs(
const void *c1,
const void *c2) {
827 AGL_GLYPH *g1 = (AGL_GLYPH*)c1;
828 AGL_GLYPH *g2 = (AGL_GLYPH*)c2;
830 return g1->glyph_num - g2->glyph_num;
837 static int sort_textures(
const void *c1,
const void *c2) {
838 texture_size *t1 = (texture_size*)c1;
839 texture_size *t2 = (texture_size*)c2;
841 return t1->w * t1->h - t2->w * t2->h;
846 #ifdef SAVE_FONT_SCREENSHOT 847 static void save_shot(BITMAP *bmp) {
852 for (i = 0; i < 1000; i++) {
854 sprintf(name,
"fonttest_%02i.tga", i);
856 save_tga(name, bmp, NULL);
868 static int aglf_sort_out_glyphs(BITMAP *bmp, AGL_GLYPH *glyphs,
const int beg,
876 for (i = 0; i < end - beg; i++) {
880 glyphs[i].x = last_x;
881 glyphs[i].y = last_line;
885 for (j = 0; j < i; j++) {
886 if ((glyphs[i].x >= glyphs[j].x + glyphs[j].w)
887 || (glyphs[i].y >= glyphs[j].y + glyphs[j].h)
888 || (glyphs[j].x >= glyphs[i].x + glyphs[i].w)
889 || (glyphs[j].y >= glyphs[i].y + glyphs[i].h)) {
892 last_x = glyphs[j].x + glyphs[j].w;
893 glyphs[i].x = last_x;
897 if ((last_x + glyphs[i].w > bmp->w)
898 || (last_line + glyphs[i].h > bmp->h)) {
907 int min_line = bmp->h + 1;
910 for (j = 0; j < i; j++) {
911 if ( glyphs[j].y + glyphs[j].h < min_line
912 && glyphs[j].y + glyphs[j].h
913 > last_line - FONT_CHARACTER_SPACING) {
915 min_line = glyphs[j].y + glyphs[j].h
916 + FONT_CHARACTER_SPACING;
921 if (min_glyph == -1) {
922 TRACE(PREFIX_I
"sort_out_glyphs: Unable to fit all glyphs into " 927 last_x = glyphs[min_glyph].x;
928 last_line = min_line;
934 last_x += glyphs[i].w + FONT_CHARACTER_SPACING;
944 static int split_font(FONT *f,
void *source,
void **dest1,
void **dest2) {
946 union mixed_ptr range1, range2, src;
954 colored = (is_mono_font(f) ? FALSE : TRUE);
957 range1.ptr = malloc(colored ?
sizeof(FONT_COLOR_DATA)
958 :
sizeof(FONT_MONO_DATA));
960 TRACE(PREFIX_E
"split_font() - Ran out of memory while " 961 "trying ot allocate %i bytes.\n",
962 colored ? (
int)
sizeof(FONT_COLOR_DATA)
963 : (
int)
sizeof(FONT_MONO_DATA));
967 range2.ptr = malloc(colored ?
sizeof(FONT_COLOR_DATA)
968 :
sizeof(FONT_MONO_DATA));
970 TRACE(PREFIX_E
"split_font() - Ran out of memory while " 971 "trying to allocate %i bytes.\n",
972 colored ? (
int)
sizeof(FONT_COLOR_DATA)
973 : (
int)
sizeof(FONT_MONO_DATA));
978 (*dest1) = range1.ptr;
979 (*dest2) = range2.ptr;
984 int mid = src.cf->begin + (src.cf->end - src.cf->begin) / 2;
986 range1.cf->begin = src.cf->begin;
987 range1.cf->end = mid;
988 range2.cf->begin = mid;
989 range2.cf->end = src.cf->end;
991 range1.cf->next = NULL;
992 range2.cf->next = NULL;
995 range1.cf->bitmaps = malloc(
sizeof(BITMAP*)
996 * (range1.cf->end - range1.cf->begin));
997 if (!range1.cf->bitmaps) {
998 TRACE(PREFIX_E
"split_font() - Ran out of memory " 999 "while trying to allocate %i bytes.\n",
1000 (
int)
sizeof(BITMAP*) * (range1.cf->end - range1.cf->begin));
1006 range2.cf->bitmaps = malloc(
sizeof(BITMAP*)
1007 * (range2.cf->end - range2.cf->begin));
1008 if (!range2.cf->bitmaps) {
1009 TRACE(PREFIX_E
"split_font() - Ran out of memory " 1010 "while trying to allocate %i bytes.\n",
1011 (
int)
sizeof(BITMAP*) * (range2.cf->end - range2.cf->begin));
1012 free(range1.cf->bitmaps);
1019 for (i = 0; i < (range1.cf->end - range1.cf->begin); i++) {
1020 range1.cf->bitmaps[i] = src.cf->bitmaps[i];
1022 for (i = 0; i < (range2.cf->end - range2.cf->begin); i++) {
1023 range2.cf->bitmaps[i] =
1024 src.cf->bitmaps[i + range2.cf->begin - range1.cf->begin];
1029 int mid = src.mf->begin + (src.mf->end - src.mf->begin) / 2;
1031 range1.mf->begin = src.mf->begin;
1032 range1.mf->end = mid;
1033 range2.mf->begin = mid;
1034 range2.mf->end = src.mf->end;
1036 range1.mf->next = NULL;
1037 range2.mf->next = NULL;
1040 range1.mf->glyphs = malloc(
sizeof(FONT_GLYPH*)
1041 * (range1.mf->end - range1.mf->begin));
1042 if (!range1.mf->glyphs) {
1043 TRACE(PREFIX_E
"split_font() - Ran out of memory " 1044 "while trying to allocate %i bytes.\n",
1045 (
int)
sizeof(FONT_GLYPH*) * (range1.mf->end - range1.mf->begin));
1051 range2.mf->glyphs = malloc(
sizeof(FONT_GLYPH*)
1052 * (range2.mf->end - range2.mf->begin));
1053 if (!range2.mf->glyphs) {
1054 TRACE(PREFIX_E
"split_font() - Ran out of memory " 1055 "while trying to allocate %i bytes.\n",
1056 (
int)
sizeof(FONT_GLYPH*) * (range2.mf->end - range2.mf->begin));
1057 free(range1.mf->glyphs);
1063 for (i = 0; i < (range1.mf->end - range1.mf->begin); i++) {
1064 range1.mf->glyphs[i] = src.mf->glyphs[i];
1066 for (i = 0; i < (range2.mf->end - range2.mf->begin); i++) {
1067 range2.mf->glyphs[i] =
1068 src.mf->glyphs[i + range2.mf->begin - range1.mf->begin];
1078 static void destroy_split_font(FONT *f,
union mixed_ptr range1,
1079 union mixed_ptr range2) {
1081 if (!is_mono_font(f)) {
1082 free(range1.cf->bitmaps);
1083 free(range2.cf->bitmaps);
1086 free(range1.mf->glyphs);
1087 free(range2.mf->glyphs);
1098 static int do_crop_font_range(FONT *f, AGL_GLYPH *glyphs,
int beg,
int end) {
1101 int max = end - beg;
1105 BITMAP *temp = create_bitmap(32, 32);
1108 TRACE(PREFIX_E
"crop_font_range - Unable to create " 1109 "bitmap of size: %ix%i!\n", 32, 32);
1114 for (i = 0; i < max; i++) {
1117 if (glyphs[i].w > temp->w || glyphs[i].h > temp->h) {
1118 int old_w = temp->w, old_h = temp->h;
1119 destroy_bitmap(temp);
1120 temp = create_bitmap(old_w * 2, old_h * 2);
1122 TRACE(PREFIX_E
"crop_font_range - Unable to " 1123 "create bitmap of size: %ix%i!\n", old_w * 2, old_h * 2);
1129 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
1131 textout_ex(temp, f, buf, 0, 0,
1132 makecol_depth(bitmap_color_depth(temp), 255, 255, 255), 0);
1135 for (j = 0; j < glyphs[i].h; j++) {
1138 for (k = 0; k < glyphs[i].w; k++) {
1139 if (getpixel(temp, k, j)) {
1141 glyphs[i].offset_y += j;
1152 TRACE(PREFIX_I
"crop_font_range: skipping glyph %i\n", i);
1153 glyphs[i].offset_y = 0;
1154 glyphs[i].offset_h = glyphs[i].h - 1;
1155 glyphs[i].offset_w = glyphs[i].w - 2;
1162 j = glyphs[i].h + glyphs[i].offset_y - 1;
1163 for ( ; j >= glyphs[i].offset_y; j--) {
1166 for (k = 0; k < glyphs[i].w; k++) {
1167 if (getpixel(temp, k, j)) {
1169 glyphs[i].offset_h +=
1170 glyphs[i].h + glyphs[i].offset_y - j - 2;
1171 glyphs[i].h -= glyphs[i].h + glyphs[i].offset_y - j - 1;
1180 for (j = 0; j < glyphs[i].w; j++) {
1183 k = MAX(glyphs[i].offset_y - 1, 0);
1184 for (; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
1185 if (getpixel(temp, j, k)) {
1187 glyphs[i].offset_x += j;
1197 j = glyphs[i].w + glyphs[i].offset_x - 1;
1198 for (; j >= glyphs[i].offset_x; j--) {
1201 k = MAX(glyphs[i].offset_y - 1, 0);
1202 for (; k < glyphs[i].offset_y + glyphs[i].h + 1; k++) {
1203 if (getpixel(temp, j, k)) {
1205 glyphs[i].offset_w +=
1206 glyphs[i].w + glyphs[i].offset_x - 1 - j;
1207 glyphs[i].w -= glyphs[i].w + glyphs[i].offset_x - j - 1;
1215 TRACE(PREFIX_I
"crop_font_range: Glyph %i (%c) offs: x: %i y: %i, " 1216 "w: %i h: %i, offs: w: %i h: %i\n", i, i + beg,
1217 glyphs[i].offset_x, glyphs[i].offset_y, glyphs[i].w, glyphs[i].h,
1218 glyphs[i].offset_w, glyphs[i].offset_h);
1222 destroy_bitmap(temp);
1228 destroy_bitmap(temp);
1237 static int crop_font_range(FONT *f,
void *src,
int beg,
int end,
1239 int *net_area,
int *gross_area,
1240 int *max_w,
int *max_h) {
1244 int max = end - beg;
1247 union mixed_ptr dat;
1251 if (is_color_font(f)) {
1252 FONT_COLOR_DATA *fcd = f->data;
1253 if (bitmap_color_depth(fcd->bitmaps[0]) != 8) {
1259 for (i = 0; i < max; i++) {
1260 glyphs[i].glyph_num = i;
1262 if (is_mono_font(f)) {
1263 glyphs[i].w = dat.mf->glyphs[i]->w + 1;
1264 glyphs[i].h = dat.mf->glyphs[i]->h + 1;
1266 glyphs[i].w = dat.cf->bitmaps[i]->w + 1;
1267 glyphs[i].h = dat.cf->bitmaps[i]->h + 1;
1269 glyphs[i].offset_w = -1;
1270 glyphs[i].offset_h = -1;
1277 ret = do_crop_font_range(f, glyphs, beg, end);
1288 for (i = 0; i < max; i++) {
1289 if (glyphs[i].w > *max_w) (*max_w) = glyphs[i].w;
1290 if (glyphs[i].h > *max_h) (*max_h) = glyphs[i].h;
1291 (*net_area) += glyphs[i].w * glyphs[i].h;
1292 (*gross_area) += (glyphs[i].w + FONT_CHARACTER_SPACING)
1293 * (glyphs[i].h + FONT_CHARACTER_SPACING);
1303 static BITMAP* look_for_texture(
int beg,
int end, AGL_GLYPH *glyphs,
1304 int max_w,
int max_h,
int total_area, GLint format,
int has_alpha) {
1316 #define MIN_TEXTURE_SIZE 2 1317 #define NUM_TEXTURE_SIZE 13 1318 texture_size texture_sizes[NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE];
1321 for (i = 0; i < NUM_TEXTURE_SIZE; i++) {
1322 for (j = 0; j < NUM_TEXTURE_SIZE; j++) {
1323 texture_sizes[j + i * NUM_TEXTURE_SIZE].w =
1324 1 << (j + MIN_TEXTURE_SIZE);
1325 texture_sizes[j + i * NUM_TEXTURE_SIZE].h =
1326 1 << (i + MIN_TEXTURE_SIZE);
1331 qsort(texture_sizes, NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE,
1332 sizeof(texture_size), &sort_textures);
1334 for (i = 0; i < NUM_TEXTURE_SIZE * NUM_TEXTURE_SIZE; i++) {
1340 texture_size *t = &texture_sizes[i];
1341 int area = t->w * t->h;
1344 if (area < total_area) {
1349 if ((t->h < max_h) || (t->w < max_w)) {
1353 TRACE(PREFIX_I
"look_for_texture: candidate size: %ix%i\n", t->w, t->h);
1356 num_channels = __allegro_gl_get_num_channels(format);
1357 if (num_channels == 1) {
1360 else if (num_channels == 4) {
1366 bmp = create_bitmap_ex(depth, t->w, t->h);
1369 TRACE(PREFIX_W
"look_for_texture: Out of memory while " 1370 "creating bitmap\n");
1374 if (!aglf_check_texture(bmp, format, has_alpha)) {
1375 TRACE(PREFIX_I
"look_for_texture: Texture rejected by driver\n");
1376 destroy_bitmap(bmp);
1382 TRACE(PREFIX_I
"look_for_texture: Sorting on bmp: %p, beg: %i, " 1383 "end: %i\n", bmp, beg, end);
1385 if (aglf_sort_out_glyphs(bmp, glyphs, beg, end) == TRUE) {
1391 TRACE(PREFIX_I
"look_for_texture: Conversion failed\n");
1392 destroy_bitmap(bmp);
1401 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 1406 static int dummy_render_char(AL_CONST FONT* f,
int ch,
int fg,
int bg,
1407 BITMAP* bmp,
int x,
int y)
1409 FONT_COLOR_DATA* cf = (FONT_COLOR_DATA*)(f->data);
1410 BITMAP *glyph = NULL;
1413 if(ch >= cf->begin && ch < cf->end) {
1414 glyph = cf->bitmaps[ch - cf->begin];
1422 if (bitmap_color_depth(bmp) == 8) {
1424 for (gy = 0; gy < bmp->h; gy++) {
1425 for (gx = 0; gx < bmp->w; gx++) {
1426 int c = getpixel(glyph, gx, gy);
1428 putpixel(bmp, x + gx, y + gy, a);
1433 blit(glyph, bmp, 0, 0, x, y, glyph->w, glyph->h);
1443 static int draw_glyphs(BITMAP *bmp, FONT *f, GLint format,
int beg,
int end,
1444 AGL_GLYPH *glyphs) {
1448 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 1449 if (bitmap_color_depth(bmp) == 8 && f->vtable != font_vtable_trans) {
1451 if (bitmap_color_depth(bmp) == 8) {
1454 BITMAP *rgbbmp = create_bitmap_ex(24, bmp->w, bmp->h);
1457 TRACE(PREFIX_E
"convert_allegro_font_to_texture: " 1458 "Ran out of memory while creating %ix%ix%i bitmap!\n",
1459 bmp->w, bmp->h, 24);
1463 clear_bitmap(rgbbmp);
1465 for (i = 0; i < end - beg; i++) {
1466 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
1468 textout_ex(rgbbmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
1469 glyphs[i].y - glyphs[i].offset_y, -1, -1);
1473 for (j = 0; j < bmp->h; j++) {
1474 for (i = 0; i < bmp->w; i++) {
1475 int pix = _getpixel24(rgbbmp, i, j);
1476 int r = getr24(pix);
1477 int g = getg24(pix);
1478 int b = getb24(pix);
1479 int gray = (r * 77 + g * 150 + b * 28 + 255) >> 8;
1480 _putpixel(bmp, i, j, MID(0, gray, 255));
1483 destroy_bitmap(rgbbmp);
1486 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 1487 int (*borrowed_color_vtable)(AL_CONST FONT*, int, int, int, BITMAP*, int, int) = NULL;
1492 if (f->vtable == font_vtable_trans) {
1493 borrowed_color_vtable = f->vtable->render_char;
1494 f->vtable->render_char = dummy_render_char;
1498 if (__allegro_gl_get_num_channels(format) == 4) {
1499 clear_to_color(bmp, bitmap_mask_color(bmp));
1505 for (i = 0; i < end - beg; i++) {
1506 usetc(buf + usetc(buf, glyphs[i].glyph_num + beg), 0);
1507 textout_ex(bmp, f, buf, glyphs[i].x - glyphs[i].offset_x,
1508 glyphs[i].y - glyphs[i].offset_y, -1, -1);
1511 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 1512 if (borrowed_color_vtable) {
1513 f->vtable->render_char = borrowed_color_vtable;
1528 static void aglf_convert_allegro_font_to_texture(FONT_AGL_DATA **dest, FONT *f,
1529 void *src,
int *height,
float scale, GLint format) {
1533 int beg = 0, end = 0;
1535 int total_area, gross_area;
1537 AGL_GLYPH *glyph_coords;
1539 union mixed_ptr dat;
1542 if (is_mono_font(f)) {
1543 beg = dat.mf->begin;
1545 max = dat.mf->end - dat.mf->begin;
1547 format = GL_INTENSITY4;
1550 else if (is_color_font(f)) {
1551 beg = dat.cf->begin;
1553 max = dat.cf->end - dat.cf->begin;
1555 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1) 1556 format = (f->vtable == font_vtable_trans ? GL_RGBA8 : GL_RGB8);
1564 glyph_coords = malloc(max *
sizeof(AGL_GLYPH));
1565 memset(glyph_coords, 0, max *
sizeof(AGL_GLYPH));
1567 if (crop_font_range(f, dat.ptr, beg, end, glyph_coords,
1568 &total_area, &gross_area, &max_w, &max_h) == FALSE) {
1569 TRACE(PREFIX_I
"convert_allegro_font_to_texture: Unable to crop font " 1575 TRACE(PREFIX_I
"convert_allegro_font_to_texture: Total area of glyphs: " 1576 "%i pixels (%i pixels gross) - max_w: %i, max_h: %i\n",
1577 total_area, gross_area, max_w, max_h);
1580 qsort(glyph_coords, end - beg,
sizeof(AGL_GLYPH), &sort_glyphs);
1584 bmp = look_for_texture(beg, end, glyph_coords, max_w, max_h,
1585 total_area, format, (*dest)->has_alpha);
1590 union mixed_ptr f1, f2;
1591 FONT_AGL_DATA *dest1, *dest2;
1596 dest2 = malloc(
sizeof(FONT_AGL_DATA));
1599 TRACE(PREFIX_E
"convert_allegro_font_to_texture: " 1600 "Out of memory while trying to allocate %i bytes.\n",
1601 (
int)
sizeof(FONT_AGL_DATA));
1605 memset(dest2, 0,
sizeof(FONT_AGL_DATA));
1607 dest2->next = dest1->next;
1608 dest1->next = dest2;
1609 dest2->is_free_chunk = TRUE;
1610 dest2->format = dest1->format;
1611 dest2->has_alpha = dest1->has_alpha;
1613 if (split_font(f, dat.ptr, &f1.ptr, &f2.ptr) == FALSE) {
1614 TRACE(PREFIX_E
"convert_allegro_font_to_texture: Unable " 1615 "to split font!\n");
1616 dest1->next = dest2->next;
1621 aglf_convert_allegro_font_to_texture(&dest1, f, f1.ptr, height, scale,
1623 height1 = (*height);
1624 aglf_convert_allegro_font_to_texture(&dest2, f, f2.ptr, height, scale,
1626 destroy_split_font(f, f1, f2);
1628 if (height1 > (*height))
1629 (*height) = height1;
1635 TRACE(PREFIX_I
"convert_allegro_font_to_texture: Using texture " 1636 "%ix%ix%i for font conversion.\n", bmp->w, bmp->h,
1637 bitmap_color_depth(bmp));
1640 if (draw_glyphs(bmp, f, format, beg, end, glyph_coords) == FALSE) {
1641 destroy_bitmap(bmp);
1647 qsort(glyph_coords, end - beg,
sizeof(AGL_GLYPH), &unsort_glyphs);
1649 #if (defined SAVE_FONT_SCREENSHOT) 1653 (*dest)->list_base =
1654 create_textured_font_call_lists(glyph_coords, max, bmp,
1657 (*dest)->texture = aglf_upload_texture(bmp, format, (*dest)->has_alpha);
1659 (*dest)->format = format;
1660 (*dest)->scale = scale;
1661 (*dest)->start = beg;
1663 (*dest)->data = bmp;
1664 (*dest)->glyph_coords = glyph_coords;
1671 static void aglf_convert_allegro_font_to_bitmap(FONT_AGL_DATA *dest, FONT *f,
1672 void *src,
int *height) {
1676 int beg = 0, end = 0;
1682 FONT_COLOR_DATA* cf;
1688 if (is_mono_font(f))
1689 max = dat.mf->end - dat.mf->begin;
1690 else if (is_color_font(f))
1691 max = dat.cf->end - dat.cf->begin;
1695 glyph = malloc(
sizeof(FONT_GLYPH*) * max);
1698 TRACE(PREFIX_E
"convert_allegro_font_to_bitmap: Ran out of " 1699 "memory while allocating %i bytes\n", (
int)
sizeof(FONT_GLYPH));
1703 *height = f->height;
1705 if (is_mono_font(f)) {
1708 for (i = 0; i < max; i++) {
1709 FONT_GLYPH *oldgl = dat.mf->glyphs[i];
1711 int size =
sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4
1715 FONT_GLYPH *newgl = (FONT_GLYPH*)malloc(size);
1720 memset(newgl, 0, size);
1722 newgl->w = oldgl->w;
1723 newgl->h = oldgl->h;
1726 for (j = 0; j < oldgl->h; j++) {
1727 for (k = 0; k < ((oldgl->w + 7) / 8); k++) {
1728 int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
1730 newgl->dat[addr] = oldgl->dat[j * ((oldgl->w + 7) / 8) + k];
1738 else if (is_color_font(f)) {
1740 for (i = 0; i < max; i++) {
1743 BITMAP *oldgl = dat.cf->bitmaps[i];
1746 mask = bitmap_mask_color(oldgl);
1748 size =
sizeof(FONT_GLYPH) + ((oldgl->w + 31) / 32) * 4 * oldgl->h;
1751 newgl = (FONT_GLYPH*)malloc(size);
1756 memset(newgl, 0, size);
1758 newgl->w = oldgl->w;
1759 newgl->h = oldgl->h;
1762 for (j = 0; j < oldgl->h; j++) {
1763 for (k = 0; k < oldgl->w; k++) {
1764 int addr = (oldgl->h - j - 1) * ((oldgl->w + 31) / 32) * 4
1766 newgl->dat[addr] |= (getpixel(oldgl, k, j) == mask)
1767 ? 0 : (1 << (k & 7));
1776 GLuint list = glGenLists(max);
1778 for (i = 0; i < max; i++) {
1779 glNewList(list + i, GL_COMPILE);
1781 glBitmap(glyph[i]->w, glyph[i]->h, 0, 0, glyph[i]->w, 0,
1786 dest->list_base = list;
1789 dest->is_free_chunk = 0;
1800 static int aglf_check_texture(BITMAP *bmp, GLint format,
int has_alpha) {
1804 if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
1805 || format == GL_INTENSITY4 || format == GL_INTENSITY8
1806 || format == GL_INTENSITY
1807 || format == GL_LUMINANCE4 || format == GL_LUMINANCE8
1808 || format == GL_LUMINANCE
1812 else if (format == GL_RGBA8) {
1826 static GLuint aglf_upload_texture(BITMAP *bmp, GLint format,
int has_alpha) {
1831 if (format == GL_ALPHA4 || format == GL_ALPHA8 || format == GL_ALPHA
1832 || format == GL_INTENSITY4 || format == GL_INTENSITY8
1833 || format == GL_INTENSITY
1834 || format == GL_LUMINANCE4 || format == GL_LUMINANCE8
1835 || format == GL_LUMINANCE
1839 else if (__allegro_gl_get_num_channels(format) == 4) {
1848 TRACE(PREFIX_I
"Want texture format: %s\n",
1849 __allegro_gl_get_format_description(format));
1851 TRACE(PREFIX_I
"Texture ID is: %u\n", texture);
#define AGL_TEXTURE_MASKED
Generate an alpha channel for this texture, based on the Allegro mask color.
void allegro_gl_destroy_font(FONT *f)
void allegro_gl_destroy_font(FONT *usefont)
GLuint allegro_gl_make_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
Uploads an Allegro BITMAP to the GL driver as a texture.
FONT * allegro_gl_convert_allegro_font_ex(FONT *f, int type, float scale, GLint format)
Converts a regular Allegro FONT to the AGL format for 3D display.
#define AGL_FONT_TYPE_TEXTURED
Indicates that you want fonts to be converted to a texture format.
FONT * allegro_gl_convert_allegro_font(FONT *f, int type, float scale)
Equivalent to:
GLint allegro_gl_get_texture_format(BITMAP *bmp)
Returns the OpenGL internal texture format for this bitmap.
#define AGL_TEXTURE_ALPHA_ONLY
Tell AllegroGL that the specified BITMAP is an 8-bpp alpha-only BITMAP.
#define AGL_FONT_TYPE_BITMAP
Indicates that you want fonts to be converted to a bitmap format.
#define AGL_FONT_TYPE_OUTLINE
Indicates that you want fonts to be converted to an outline format.
#define AGL_TEXTURE_MIPMAP
AllegroGL will generate mipmaps for this texture.
Main header file for AllegroGL.
int allegro_gl_check_texture_ex(int flags, BITMAP *bmp, GLint internal_format)
Checks whether the specified bitmap is of the proper size for texturing.
#define AGL_TEXTURE_FLIP
Flip the texture on the x-axis.
#define AGL_FONT_TYPE_DONT_CARE
Indicates that you don't really care how a font will be converted.
#define AGL_TEXTURE_HAS_ALPHA
Tell AllegroGL that the bitmap had an alpha channel, so it should be preserved when generating the te...