17117f1b4Smrg 27117f1b4Smrg/* 37117f1b4Smrg * Mesa 3-D graphics library 47117f1b4Smrg * 57117f1b4Smrg * Copyright (C) 1999-2000 Brian Paul All Rights Reserved. 67117f1b4Smrg * 77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 87117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 97117f1b4Smrg * to deal in the Software without restriction, including without limitation 107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 127117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 137117f1b4Smrg * 147117f1b4Smrg * The above copyright notice and this permission notice shall be included 157117f1b4Smrg * in all copies or substantial portions of the Software. 167117f1b4Smrg * 177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 247117f1b4Smrg */ 257117f1b4Smrg 267117f1b4Smrg 277117f1b4Smrg/* xfonts.c -- glXUseXFont() for Mesa written by 287117f1b4Smrg * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de 297117f1b4Smrg */ 307117f1b4Smrg 3101e04c3fSmrg#include <stdio.h> 327117f1b4Smrg#include "glxheader.h" 33c1f859d4Smrg#include "main/context.h" 347117f1b4Smrg#include "xfonts.h" 357117f1b4Smrg 367117f1b4Smrg 377117f1b4Smrg/* Some debugging info. */ 387117f1b4Smrg 397117f1b4Smrg#ifdef DEBUG 407117f1b4Smrg#include <ctype.h> 417117f1b4Smrg 427117f1b4Smrgint debug_xfonts = 0; 437117f1b4Smrg 447117f1b4Smrgstatic void 457117f1b4Smrgdump_char_struct(XCharStruct * ch, char *prefix) 467117f1b4Smrg{ 477117f1b4Smrg printf("%slbearing = %d, rbearing = %d, width = %d\n", 487117f1b4Smrg prefix, ch->lbearing, ch->rbearing, ch->width); 497117f1b4Smrg printf("%sascent = %d, descent = %d, attributes = %u\n", 507117f1b4Smrg prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes); 517117f1b4Smrg} 527117f1b4Smrg 537117f1b4Smrgstatic void 547117f1b4Smrgdump_font_struct(XFontStruct * font) 557117f1b4Smrg{ 567117f1b4Smrg printf("ascent = %d, descent = %d\n", font->ascent, font->descent); 577117f1b4Smrg printf("char_or_byte2 = (%u,%u)\n", 587117f1b4Smrg font->min_char_or_byte2, font->max_char_or_byte2); 597117f1b4Smrg printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1); 607117f1b4Smrg printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False"); 617117f1b4Smrg printf("default_char = %c (\\%03o)\n", 627117f1b4Smrg (char) (isprint(font->default_char) ? font->default_char : ' '), 637117f1b4Smrg font->default_char); 647117f1b4Smrg dump_char_struct(&font->min_bounds, "min> "); 657117f1b4Smrg dump_char_struct(&font->max_bounds, "max> "); 667117f1b4Smrg#if 0 677117f1b4Smrg for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) { 687117f1b4Smrg char prefix[8]; 697117f1b4Smrg sprintf(prefix, "%d> ", c); 707117f1b4Smrg dump_char_struct(&font->per_char[c], prefix); 717117f1b4Smrg } 727117f1b4Smrg#endif 737117f1b4Smrg} 747117f1b4Smrg 757117f1b4Smrgstatic void 767117f1b4Smrgdump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap) 777117f1b4Smrg{ 787117f1b4Smrg unsigned int x, y; 797117f1b4Smrg 807117f1b4Smrg printf(" "); 817117f1b4Smrg for (x = 0; x < 8 * width; x++) 827117f1b4Smrg printf("%o", 7 - (x % 8)); 837117f1b4Smrg putchar('\n'); 847117f1b4Smrg for (y = 0; y < height; y++) { 857117f1b4Smrg printf("%3o:", y); 867117f1b4Smrg for (x = 0; x < 8 * width; x++) 877117f1b4Smrg putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x % 887117f1b4Smrg 8)))) 897117f1b4Smrg ? '*' : '.'); 907117f1b4Smrg printf(" "); 917117f1b4Smrg for (x = 0; x < width; x++) 927117f1b4Smrg printf("0x%02x, ", bitmap[width * (height - y - 1) + x]); 937117f1b4Smrg putchar('\n'); 947117f1b4Smrg } 957117f1b4Smrg} 967117f1b4Smrg#endif /* DEBUG */ 977117f1b4Smrg 987117f1b4Smrg 997117f1b4Smrg/* Implementation. */ 1007117f1b4Smrg 1017117f1b4Smrg/* Fill a BITMAP with a character C from thew current font 1027117f1b4Smrg in the graphics context GC. WIDTH is the width in bytes 1037117f1b4Smrg and HEIGHT is the height in bits. 1047117f1b4Smrg 1057117f1b4Smrg Note that the generated bitmaps must be used with 1067117f1b4Smrg 1077117f1b4Smrg glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); 1087117f1b4Smrg glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); 1097117f1b4Smrg glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); 1107117f1b4Smrg glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); 1117117f1b4Smrg glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); 1127117f1b4Smrg glPixelStorei (GL_UNPACK_ALIGNMENT, 1); 1137117f1b4Smrg 1147117f1b4Smrg Possible optimizations: 1157117f1b4Smrg 1167117f1b4Smrg * use only one reusable pixmap with the maximum dimensions. 1177117f1b4Smrg * draw the entire font into a single pixmap (careful with 1187117f1b4Smrg proportional fonts!). 1197117f1b4Smrg*/ 1207117f1b4Smrg 1217117f1b4Smrg 1227117f1b4Smrg/* 1237117f1b4Smrg * Generate OpenGL-compatible bitmap. 1247117f1b4Smrg */ 1257117f1b4Smrgstatic void 1267117f1b4Smrgfill_bitmap(Display * dpy, Window win, GC gc, 1277117f1b4Smrg unsigned int width, unsigned int height, 1287117f1b4Smrg int x0, int y0, unsigned int c, GLubyte * bitmap) 1297117f1b4Smrg{ 1307117f1b4Smrg XImage *image; 1317117f1b4Smrg unsigned int x, y; 1327117f1b4Smrg Pixmap pixmap; 1337117f1b4Smrg XChar2b char2b; 1347117f1b4Smrg 1357117f1b4Smrg pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1); 1367117f1b4Smrg XSetForeground(dpy, gc, 0); 1377117f1b4Smrg XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height); 1387117f1b4Smrg XSetForeground(dpy, gc, 1); 1397117f1b4Smrg 1407117f1b4Smrg char2b.byte1 = (c >> 8) & 0xff; 1417117f1b4Smrg char2b.byte2 = (c & 0xff); 1427117f1b4Smrg 1437117f1b4Smrg XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1); 1447117f1b4Smrg 1457117f1b4Smrg image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap); 1467117f1b4Smrg if (image) { 1477117f1b4Smrg /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */ 1487117f1b4Smrg for (y = 0; y < height; y++) 1497117f1b4Smrg for (x = 0; x < 8 * width; x++) 1507117f1b4Smrg if (XGetPixel(image, x, y)) 1517117f1b4Smrg bitmap[width * (height - y - 1) + x / 8] |= 1527117f1b4Smrg (1 << (7 - (x % 8))); 1537117f1b4Smrg XDestroyImage(image); 1547117f1b4Smrg } 1557117f1b4Smrg 1567117f1b4Smrg XFreePixmap(dpy, pixmap); 1577117f1b4Smrg} 1587117f1b4Smrg 1597117f1b4Smrg/* 1607117f1b4Smrg * determine if a given glyph is valid and return the 1617117f1b4Smrg * corresponding XCharStruct. 1627117f1b4Smrg */ 1637117f1b4Smrgstatic XCharStruct * 1647117f1b4Smrgisvalid(XFontStruct * fs, unsigned int which) 1657117f1b4Smrg{ 1667117f1b4Smrg unsigned int rows, pages; 1677117f1b4Smrg unsigned int byte1 = 0, byte2 = 0; 1687117f1b4Smrg int i, valid = 1; 1697117f1b4Smrg 1707117f1b4Smrg rows = fs->max_byte1 - fs->min_byte1 + 1; 1717117f1b4Smrg pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; 1727117f1b4Smrg 1737117f1b4Smrg if (rows == 1) { 1747117f1b4Smrg /* "linear" fonts */ 1757117f1b4Smrg if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which)) 1767117f1b4Smrg valid = 0; 1777117f1b4Smrg } 1787117f1b4Smrg else { 1797117f1b4Smrg /* "matrix" fonts */ 1807117f1b4Smrg byte2 = which & 0xff; 1817117f1b4Smrg byte1 = which >> 8; 1827117f1b4Smrg if ((fs->min_char_or_byte2 > byte2) || 1837117f1b4Smrg (fs->max_char_or_byte2 < byte2) || 1847117f1b4Smrg (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1)) 1857117f1b4Smrg valid = 0; 1867117f1b4Smrg } 1877117f1b4Smrg 1887117f1b4Smrg if (valid) { 1897117f1b4Smrg if (fs->per_char) { 1907117f1b4Smrg if (rows == 1) { 1917117f1b4Smrg /* "linear" fonts */ 1927117f1b4Smrg return (fs->per_char + (which - fs->min_char_or_byte2)); 1937117f1b4Smrg } 1947117f1b4Smrg else { 1957117f1b4Smrg /* "matrix" fonts */ 1967117f1b4Smrg i = ((byte1 - fs->min_byte1) * pages) + 1977117f1b4Smrg (byte2 - fs->min_char_or_byte2); 1987117f1b4Smrg return (fs->per_char + i); 1997117f1b4Smrg } 2007117f1b4Smrg } 2017117f1b4Smrg else { 2027117f1b4Smrg return (&fs->min_bounds); 2037117f1b4Smrg } 2047117f1b4Smrg } 2057117f1b4Smrg return (NULL); 2067117f1b4Smrg} 2077117f1b4Smrg 2087117f1b4Smrg 2097117f1b4Smrgvoid 2107117f1b4SmrgFake_glXUseXFont(Font font, int first, int count, int listbase) 2117117f1b4Smrg{ 2127117f1b4Smrg Display *dpy; 2137117f1b4Smrg Window win; 2147117f1b4Smrg Pixmap pixmap; 2157117f1b4Smrg GC gc; 2167117f1b4Smrg XGCValues values; 2177117f1b4Smrg unsigned long valuemask; 2187117f1b4Smrg XFontStruct *fs; 2197117f1b4Smrg GLint swapbytes, lsbfirst, rowlength; 2207117f1b4Smrg GLint skiprows, skippixels, alignment; 2217117f1b4Smrg unsigned int max_width, max_height, max_bm_width, max_bm_height; 2227117f1b4Smrg GLubyte *bm; 2237117f1b4Smrg int i; 2247117f1b4Smrg 2257117f1b4Smrg dpy = glXGetCurrentDisplay(); 2267117f1b4Smrg if (!dpy) 2277117f1b4Smrg return; /* I guess glXMakeCurrent wasn't called */ 2287117f1b4Smrg win = RootWindow(dpy, DefaultScreen(dpy)); 2297117f1b4Smrg 2307117f1b4Smrg fs = XQueryFont(dpy, font); 2317117f1b4Smrg if (!fs) { 2327117f1b4Smrg _mesa_error(NULL, GL_INVALID_VALUE, 2337117f1b4Smrg "Couldn't get font structure information"); 2347117f1b4Smrg return; 2357117f1b4Smrg } 2367117f1b4Smrg 2377117f1b4Smrg /* Allocate a bitmap that can fit all characters. */ 2387117f1b4Smrg max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing; 2397117f1b4Smrg max_height = fs->max_bounds.ascent + fs->max_bounds.descent; 2407117f1b4Smrg max_bm_width = (max_width + 7) / 8; 2417117f1b4Smrg max_bm_height = max_height; 2427117f1b4Smrg 243af69d88dSmrg bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte)); 2447117f1b4Smrg if (!bm) { 2457117f1b4Smrg XFreeFontInfo(NULL, fs, 1); 2467117f1b4Smrg _mesa_error(NULL, GL_OUT_OF_MEMORY, 2477117f1b4Smrg "Couldn't allocate bitmap in glXUseXFont()"); 2487117f1b4Smrg return; 2497117f1b4Smrg } 2507117f1b4Smrg 2517117f1b4Smrg#if 0 2527117f1b4Smrg /* get the page info */ 2537117f1b4Smrg pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; 2547117f1b4Smrg firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2; 2557117f1b4Smrg lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2; 2567117f1b4Smrg rows = fs->max_byte1 - fs->min_byte1 + 1; 2577117f1b4Smrg unsigned int first_char, last_char, pages, rows; 2587117f1b4Smrg#endif 2597117f1b4Smrg 2607117f1b4Smrg /* Save the current packing mode for bitmaps. */ 2617117f1b4Smrg glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes); 2627117f1b4Smrg glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst); 2637117f1b4Smrg glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength); 2647117f1b4Smrg glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows); 2657117f1b4Smrg glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels); 2667117f1b4Smrg glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); 2677117f1b4Smrg 2687117f1b4Smrg /* Enforce a standard packing mode which is compatible with 2697117f1b4Smrg fill_bitmap() from above. This is actually the default mode, 2707117f1b4Smrg except for the (non)alignment. */ 2717117f1b4Smrg glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); 2727117f1b4Smrg glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); 2737117f1b4Smrg glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 2747117f1b4Smrg glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 2757117f1b4Smrg glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 2767117f1b4Smrg glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 2777117f1b4Smrg 2787117f1b4Smrg pixmap = XCreatePixmap(dpy, win, 10, 10, 1); 2797117f1b4Smrg values.foreground = BlackPixel(dpy, DefaultScreen(dpy)); 2807117f1b4Smrg values.background = WhitePixel(dpy, DefaultScreen(dpy)); 2817117f1b4Smrg values.font = fs->fid; 2827117f1b4Smrg valuemask = GCForeground | GCBackground | GCFont; 2837117f1b4Smrg gc = XCreateGC(dpy, pixmap, valuemask, &values); 2847117f1b4Smrg XFreePixmap(dpy, pixmap); 2857117f1b4Smrg 2867117f1b4Smrg#ifdef DEBUG 2877117f1b4Smrg if (debug_xfonts) 2887117f1b4Smrg dump_font_struct(fs); 2897117f1b4Smrg#endif 2907117f1b4Smrg 2917117f1b4Smrg for (i = 0; i < count; i++) { 2927117f1b4Smrg unsigned int width, height, bm_width, bm_height; 2937117f1b4Smrg GLfloat x0, y0, dx, dy; 2947117f1b4Smrg XCharStruct *ch; 2957117f1b4Smrg int x, y; 2967117f1b4Smrg unsigned int c = first + i; 2977117f1b4Smrg int list = listbase + i; 2987117f1b4Smrg int valid; 2997117f1b4Smrg 3007117f1b4Smrg /* check on index validity and get the bounds */ 3017117f1b4Smrg ch = isvalid(fs, c); 3027117f1b4Smrg if (!ch) { 3037117f1b4Smrg ch = &fs->max_bounds; 3047117f1b4Smrg valid = 0; 3057117f1b4Smrg } 3067117f1b4Smrg else { 3077117f1b4Smrg valid = 1; 3087117f1b4Smrg } 3097117f1b4Smrg 3107117f1b4Smrg#ifdef DEBUG 3117117f1b4Smrg if (debug_xfonts) { 3127117f1b4Smrg char s[7]; 3137117f1b4Smrg sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c); 3147117f1b4Smrg dump_char_struct(ch, s); 3157117f1b4Smrg } 3167117f1b4Smrg#endif 3177117f1b4Smrg 3187117f1b4Smrg /* glBitmap()' parameters: 3197117f1b4Smrg straight from the glXUseXFont(3) manpage. */ 3207117f1b4Smrg width = ch->rbearing - ch->lbearing; 3217117f1b4Smrg height = ch->ascent + ch->descent; 3227117f1b4Smrg x0 = -ch->lbearing; 3237117f1b4Smrg y0 = ch->descent - 0; /* XXX used to subtract 1 here */ 3247117f1b4Smrg /* but that caused a conformace failure */ 3257117f1b4Smrg dx = ch->width; 3267117f1b4Smrg dy = 0; 3277117f1b4Smrg 3287117f1b4Smrg /* X11's starting point. */ 3297117f1b4Smrg x = -ch->lbearing; 3307117f1b4Smrg y = ch->ascent; 3317117f1b4Smrg 3327117f1b4Smrg /* Round the width to a multiple of eight. We will use this also 3337117f1b4Smrg for the pixmap for capturing the X11 font. This is slightly 3347117f1b4Smrg inefficient, but it makes the OpenGL part real easy. */ 3357117f1b4Smrg bm_width = (width + 7) / 8; 3367117f1b4Smrg bm_height = height; 3377117f1b4Smrg 3387117f1b4Smrg glNewList(list, GL_COMPILE); 3397117f1b4Smrg if (valid && (bm_width > 0) && (bm_height > 0)) { 3407117f1b4Smrg 341cdc920a0Smrg memset(bm, '\0', bm_width * bm_height); 3427117f1b4Smrg fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm); 3437117f1b4Smrg 3447117f1b4Smrg glBitmap(width, height, x0, y0, dx, dy, bm); 3457117f1b4Smrg#ifdef DEBUG 3467117f1b4Smrg if (debug_xfonts) { 3477117f1b4Smrg printf("width/height = %u/%u\n", width, height); 3487117f1b4Smrg printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height); 3497117f1b4Smrg dump_bitmap(bm_width, bm_height, bm); 3507117f1b4Smrg } 3517117f1b4Smrg#endif 3527117f1b4Smrg } 3537117f1b4Smrg else { 3547117f1b4Smrg glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL); 3557117f1b4Smrg } 3567117f1b4Smrg glEndList(); 3577117f1b4Smrg } 3587117f1b4Smrg 359af69d88dSmrg free(bm); 3607117f1b4Smrg XFreeFontInfo(NULL, fs, 1); 3617117f1b4Smrg XFreeGC(dpy, gc); 3627117f1b4Smrg 3637117f1b4Smrg /* Restore saved packing modes. */ 3647117f1b4Smrg glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); 3657117f1b4Smrg glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst); 3667117f1b4Smrg glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength); 3677117f1b4Smrg glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); 3687117f1b4Smrg glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); 3697117f1b4Smrg glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); 3707117f1b4Smrg} 371