00001
00002
00003
00008 #include <math.h>
00009 #include <string.h>
00010 #include <stdio.h>
00011
00012 #include <allegro.h>
00013
00014 #include "alleggl.h"
00015 #include "allglint.h"
00016
00017 #ifdef ALLEGRO_MACOSX
00018 #include <OpenGL/glu.h>
00019 #else
00020 #include <GL/glu.h>
00021 #endif
00022
00023 #if defined ALLEGRO_WITH_XWINDOWS && !defined ALLEGROGL_GENERIC_DRIVER
00024 #include <xalleg.h>
00025 #include <GL/glx.h>
00026 #endif
00027
00028 #define PREFIX_E "agl-font ERROR: "
00029
00030
00031
00032 static int aglf_font_generation_mode = AGL_FONT_POLYGONS;
00033
00034
00035
00036
00037
00038 static AL_CONST FONT_AGL_DATA *find_range(AL_CONST FONT_AGL_DATA *f, int c) {
00039
00040 while (f) {
00041 if ((c >= f->start) && (c < f->end))
00042 return f;
00043
00044 f = f->next;
00045 }
00046
00047 return NULL;
00048 }
00049
00050
00051
00052
00053
00067 int allegro_gl_printf(AL_CONST FONT *f, float x, float y, float z, int color,
00068 AL_CONST char *format, ...) {
00069
00070 #define BUF_SIZE 1024
00071 char buf[BUF_SIZE];
00072 va_list ap;
00073
00074 if (!__allegro_gl_valid_context)
00075 return 0;
00076
00077
00078 va_start(ap, format);
00079 uvszprintf(buf, BUF_SIZE, format, ap);
00080 va_end(ap);
00081
00082 #undef BUF_SIZE
00083
00084
00085 {
00086 GLubyte c[4];
00087 c[0] = (GLubyte)getr(color);
00088 c[1] = (GLubyte)getg(color);
00089 c[2] = (GLubyte)getb(color);
00090 c[3] = (__allegro_gl_use_alpha && bitmap_color_depth(screen) == 32)
00091 ? (GLubyte)geta(color) : 255;
00092
00093 glColor4ubv(c);
00094 }
00095
00096 return allegro_gl_printf_ex(f, x, y, z, buf);
00097 }
00098
00099
00100
00101
00102
00103
00169 int allegro_gl_printf_ex(AL_CONST FONT *f, float x, float y, float z,
00170 AL_CONST char *format, ...) {
00171 #define BUF_SIZE 1024
00172 char buf[BUF_SIZE];
00173 va_list ap;
00174
00175 AL_CONST FONT_AGL_DATA *range = NULL;
00176 int c, pos = 0;
00177 int count = 0;
00178 AL_CONST FONT_AGL_DATA *d;
00179 GLint vert_order, cull_mode;
00180 GLint matrix_mode;
00181
00182 int restore_rasterpos = 0;
00183 GLuint old_texture_bind = 0;
00184 GLfloat old_raster_pos[4];
00185
00186
00187 if (!__allegro_gl_valid_context)
00188 return 0;
00189
00190
00191 if (!format || !f) {
00192 TRACE(PREFIX_E "agl_printf: Null parameter\n");
00193 return 0;
00194 }
00195
00196 if (f->vtable != font_vtable_agl) {
00197 TRACE(PREFIX_E "agl_printf: Font parameter isn't of the AGL "
00198 "type.\n");
00199 return 0;
00200 }
00201
00202 d = (AL_CONST FONT_AGL_DATA*)f->data;
00203
00204
00205 va_start(ap, format);
00206 uvszprintf(buf, BUF_SIZE, format, ap);
00207 va_end(ap);
00208
00209 #undef BUF_SIZE
00210
00211 allegro_gl_begin();
00212
00213 glGetIntegerv(GL_MATRIX_MODE, &matrix_mode);
00214 glGetIntegerv(GL_FRONT_FACE, &vert_order);
00215 glGetIntegerv(GL_CULL_FACE_MODE, &cull_mode);
00216
00217 glMatrixMode(GL_MODELVIEW);
00218 glPushMatrix();
00219
00220 glFrontFace(GL_CW);
00221 glCullFace(GL_BACK);
00222
00223 { GLint temp;
00224 glGetIntegerv(GL_TEXTURE_BINDING_2D, &temp);
00225 old_texture_bind = (GLuint)temp;
00226 }
00227
00228 if (d->type == AGL_FONT_TYPE_BITMAP) {
00229 glTranslatef(0, 0, -1);
00230 glBindTexture(GL_TEXTURE_2D, 0);
00231
00232 glGetFloatv(GL_CURRENT_RASTER_POSITION, old_raster_pos);
00233 glRasterPos2f(x, y);
00234 restore_rasterpos = 1;
00235 }
00236 else if (d->type == AGL_FONT_TYPE_OUTLINE) {
00237 glTranslatef(x, y, z);
00238 glBindTexture(GL_TEXTURE_2D, 0);
00239 }
00240 else if (d->type == AGL_FONT_TYPE_TEXTURED) {
00241 glTranslatef(x, y, z);
00242 }
00243
00244
00245 while ((c = ugetc(buf + pos)) != 0) {
00246
00247 pos += ucwidth(c);
00248
00249 if ((!range) || (c < range->start) || (c >= range->end)) {
00250
00251 range = find_range(d, c);
00252
00253 if (!range) {
00254 range = find_range(d, (c = '^'));
00255
00256 if (!range)
00257 continue;
00258 }
00259 }
00260
00261
00262 if (d->type == AGL_FONT_TYPE_TEXTURED) {
00263 glBindTexture(GL_TEXTURE_2D, range->texture);
00264 }
00265
00266
00267 c -= range->start;
00268 c += range->list_base;
00269
00270 glCallList(c);
00271
00272 count++;
00273 }
00274
00275 glPopMatrix();
00276
00277 glMatrixMode(matrix_mode);
00278 glFrontFace(vert_order);
00279 glCullFace(cull_mode);
00280
00281 glBindTexture(GL_TEXTURE_2D, old_texture_bind);
00282
00283 if (restore_rasterpos) {
00284 glRasterPos4fv(old_raster_pos);
00285 }
00286
00287 allegro_gl_end();
00288
00289 return count;
00290 }
00291
00292
00293
00294 #ifndef ALLEGROGL_GENERIC_DRIVER
00295 #ifdef ALLEGRO_WINDOWS
00296
00297 static FONT *win_load_system_font(char *name, int type, int style, int w, int h, float depth, int start, int end) {
00298
00299 HFONT hFont;
00300
00301 FONT_AGL_DATA *data;
00302 FONT *ret;
00303
00304 ret = malloc(sizeof(FONT));
00305 if (!ret) {
00306 TRACE(PREFIX_E "win_load_system_font: Ran out of memory "
00307 "while allocating %i bytes\n", sizeof(FONT));
00308 return NULL;
00309 }
00310 data = malloc(sizeof(FONT_AGL_DATA));
00311 if (!data) {
00312 free(ret);
00313 TRACE(PREFIX_E "win_load_system_font: Ran out of memory "
00314 "while allocating %i bytes\n", sizeof(FONT_AGL_DATA));
00315 return NULL;
00316 }
00317 ret->vtable = font_vtable_agl;
00318 ret->data = data;
00319
00320 data->list_base = glGenLists(end - start);
00321 data->start = start;
00322 data->end = end;
00323 data->next = NULL;
00324 data->is_free_chunk = 0;
00325
00326 if (type == AGL_FONT_TYPE_BITMAP || type == AGL_FONT_TYPE_DONT_CARE) {
00327
00328 HDC dc;
00329
00330 hFont = CreateFont( -h, w,
00331 0, 0,
00332 (style & AGL_FONT_STYLE_BOLD) ? FW_BOLD
00333 : ((style & AGL_FONT_STYLE_BLACK) ? FW_BLACK : FW_NORMAL),
00334 ((style & AGL_FONT_STYLE_ITALIC) ? TRUE : FALSE),
00335 ((style & AGL_FONT_STYLE_UNDERLINE) ? TRUE : FALSE),
00336 ((style & AGL_FONT_STYLE_STRIKEOUT) ? TRUE : FALSE),
00337 ANSI_CHARSET,
00338 OUT_TT_PRECIS,
00339 CLIP_DEFAULT_PRECIS,
00340 (style & AGL_FONT_STYLE_ANTI_ALIASED) ? ANTIALIASED_QUALITY
00341 : DEFAULT_QUALITY,
00342 FF_DONTCARE | DEFAULT_PITCH,
00343 name);
00344
00345 dc = GetDC(win_get_window());
00346
00347 SelectObject(dc, hFont);
00348
00349 wglUseFontBitmaps(dc, start, end - start, data->list_base);
00350 data->type = AGL_FONT_TYPE_BITMAP;
00351 data->data = NULL;
00352 }
00353 else if (type == AGL_FONT_TYPE_OUTLINE) {
00354 HDC dc;
00355
00356 GLYPHMETRICSFLOAT *gmf;
00357 gmf = malloc(sizeof(GLYPHMETRICSFLOAT) * (end - start));
00358 memset(gmf, 0, sizeof(GLYPHMETRICSFLOAT) * (end - start));
00359
00360 hFont = CreateFont( -h, w,
00361 0, 0,
00362 (style & AGL_FONT_STYLE_BOLD) ? FW_BOLD
00363 : ((style & AGL_FONT_STYLE_BLACK) ? FW_BLACK : FW_NORMAL),
00364 ((style & AGL_FONT_STYLE_ITALIC) ? TRUE : FALSE),
00365 ((style & AGL_FONT_STYLE_UNDERLINE) ? TRUE : FALSE),
00366 ((style & AGL_FONT_STYLE_STRIKEOUT) ? TRUE : FALSE),
00367 ANSI_CHARSET,
00368 OUT_TT_PRECIS,
00369 CLIP_DEFAULT_PRECIS,
00370 (style & AGL_FONT_STYLE_ANTI_ALIASED) ? ANTIALIASED_QUALITY
00371 : DEFAULT_QUALITY,
00372 FF_DONTCARE | DEFAULT_PITCH,
00373 name);
00374
00375 dc = GetDC(win_get_window());
00376
00377 SelectObject(dc, hFont);
00378 wglUseFontOutlines(dc, start, end - start, data->list_base,
00379 0.0, depth, (aglf_font_generation_mode == AGL_FONT_POLYGONS)
00380 ? WGL_FONT_POLYGONS : WGL_FONT_LINES, gmf);
00381
00382 data->type = AGL_FONT_TYPE_OUTLINE;
00383 data->data = gmf;
00384 }
00385
00386 return ret;
00387 }
00388 #endif
00389
00390
00391
00392 #ifdef ALLEGRO_WITH_XWINDOWS
00393 static FONT *x_load_system_font(char *name, int type, int style, int w, int h,
00394 float depth, int start, int end) {
00395 FONT_AGL_DATA *data;
00396 FONT *ret;
00397 XFontStruct *xfont;
00398
00399 ret = malloc(sizeof(FONT));
00400 if (!ret) {
00401 TRACE(PREFIX_E "x_load_system_font: Ran out of memory "
00402 "while allocating %i bytes\n", sizeof(FONT));
00403 return NULL;
00404 }
00405 data = malloc(sizeof(FONT_AGL_DATA));
00406 if (!data) {
00407 free(ret);
00408 TRACE(PREFIX_E "x_load_system_font: Ran out of memory "
00409 "while allocating %i bytes\n", sizeof(FONT_AGL_DATA));
00410 return NULL;
00411 }
00412 ret->vtable = font_vtable_agl;
00413 ret->data = data;
00414
00415 data->list_base = glGenLists(end - start);
00416 data->start = start;
00417 data->end = end;
00418 data->next = NULL;
00419 data->is_free_chunk = 0;
00420
00421 if (type == AGL_FONT_TYPE_BITMAP || type == AGL_FONT_TYPE_DONT_CARE) {
00422 char buf[256], major_type[256], minor_type[2];
00423
00424 usprintf(major_type, "medium");
00425 if (style & AGL_FONT_STYLE_BOLD)
00426 usprintf(major_type, "bold");
00427 minor_type[0] = (style & AGL_FONT_STYLE_ITALIC) ? 'i' : 'r';
00428 minor_type[1] = '\0';
00429
00430 usprintf(buf, "-*-%s-%s-%s-normal-*-%i-*-*-*-*-*-*-*", name,
00431 major_type, minor_type, h);
00432
00433 xfont = XLoadQueryFont(_xwin.display, buf);
00434 if (!xfont) {
00435 free(ret);
00436 free(data);
00437 TRACE(PREFIX_E "x_load_system_font: Failed to load "
00438 "%s\n", buf);
00439 return NULL;
00440 }
00441 glXUseXFont(xfont->fid, start, end - start, data->list_base);
00442 data->type = AGL_FONT_TYPE_BITMAP;
00443 data->data = NULL;
00444 XFreeFont(_xwin.display, xfont);
00445 }
00446 else {
00447
00448 return NULL;
00449 }
00450
00451 return ret;
00452 }
00453 #endif
00454 #endif
00455
00456
00457
00458
00473 void allegro_gl_set_font_generation_mode(int mode) {
00474 aglf_font_generation_mode = mode;
00475 return;
00476 }
00477
00478
00479
00480
00489 FONT *allegro_gl_load_system_font(char *name, int style, int w, int h) {
00490
00491 return allegro_gl_load_system_font_ex(name, AGL_FONT_TYPE_OUTLINE,
00492 style, w, h, 0.0f, 32, 256);
00493 }
00494
00495
00496
00497
00498
00530 FONT *allegro_gl_load_system_font_ex(char *name, int type, int style,
00531 int w, int h, float depth, int start, int end) {
00532
00533 FONT *ret = NULL;
00534
00535 if (!__allegro_gl_valid_context)
00536 return NULL;
00537
00538 if (!name) {
00539 TRACE(PREFIX_E "load_system_font: Nameless font\n");
00540 return NULL;
00541 }
00542
00543
00544
00545 #ifndef ALLEGROGL_GENERIC_DRIVER
00546 #ifdef ALLEGRO_WINDOWS
00547 ret = win_load_system_font(name, type, style, w, h, depth, start, end);
00548 #elif defined ALLEGRO_UNIX
00549 XLOCK();
00550 ret = x_load_system_font(name, type, style, w, h, depth, start, end);
00551 XUNLOCK();
00552 #else
00553
00554 #endif
00555 #endif
00556
00557 return ret;
00558 }
00559
00560
00561
00577 void allegro_gl_destroy_font(FONT *f) {
00578
00579 FONT_AGL_DATA *data;
00580
00581 if (!f) {
00582 return;
00583 }
00584 if (f->vtable != font_vtable_agl) {
00585 TRACE(PREFIX_E "destroy_font: Font is not of AGL type\n");
00586 return;
00587 }
00588
00589 data = f->data;
00590
00591 if (!data) {
00592 TRACE(PREFIX_E "destroy_font: Font is inconsistent\n");
00593 return;
00594 }
00595
00596
00597 while (data) {
00598 FONT_AGL_DATA *datanext;
00599
00600
00601 if (data->type == AGL_FONT_TYPE_BITMAP
00602 || data->type == AGL_FONT_TYPE_OUTLINE
00603 || data->type == AGL_FONT_TYPE_TEXTURED) {
00604
00605 if (__allegro_gl_valid_context) {
00606 if (data->list_base)
00607 glDeleteLists(data->list_base, data->end - data->start);
00608 if (data->texture)
00609 glDeleteTextures(1, &data->texture);
00610 }
00611 }
00612 if (data->type == AGL_FONT_TYPE_OUTLINE) {
00613 if (data->data)
00614 free(data->data);
00615 }
00616 else if (data->type == AGL_FONT_TYPE_TEXTURED) {
00617 if (data->data)
00618 destroy_bitmap(data->data);
00619 if (data->glyph_coords)
00620 free(data->glyph_coords);
00621 }
00622 else if (data->type == AGL_FONT_TYPE_BITMAP) {
00623 if (data->data) {
00624 int i;
00625 FONT_GLYPH **gl = data->data;
00626 for (i = 0; i < data->end - data->start; i++) {
00627 if (gl[i])
00628 free(gl[i]);
00629 }
00630 free(gl);
00631 }
00632 }
00633 datanext = data->next;
00634
00635 if (data->is_free_chunk)
00636 free(data);
00637
00638 data = datanext;
00639 }
00640 free(f->data);
00641
00642 if (f != font)
00643 free(f);
00644
00645 return;
00646 }
00647
00648
00649
00650
00693 size_t allegro_gl_list_font_textures(FONT *f, GLuint *ids, size_t max_num_id) {
00694
00695 size_t num_ids = 0;
00696 FONT_AGL_DATA *data;
00697
00698 if (!f) {
00699 return 0;
00700 }
00701 if (f->vtable != font_vtable_agl) {
00702 TRACE(PREFIX_E "list_font_textures: Font is not of AGL type\n");
00703 return 0;
00704 }
00705
00706 data = f->data;
00707
00708 if (!data) {
00709 TRACE(PREFIX_E "list_font_textures: Font is inconsistent\n");
00710 return 0;
00711 }
00712
00713 if (!__allegro_gl_valid_context) {
00714 return 0;
00715 }
00716
00717
00718 while (data) {
00719 if (data->texture) {
00720
00721
00722
00723 if (ids && num_ids < max_num_id) {
00724 ids[num_ids] = data->texture;
00725 }
00726 num_ids++;
00727 }
00728
00729 data = data->next;
00730 }
00731
00732 return num_ids;
00733 }
00734