xfont.c revision cdc920a0
1cdc920a0Smrg/* 2cdc920a0Smrg * Mesa 3-D graphics library 3cdc920a0Smrg * Version: 3.1 4cdc920a0Smrg * 5cdc920a0Smrg * Copyright (C) 1999 Brian Paul All Rights Reserved. 6cdc920a0Smrg * 7cdc920a0Smrg * Permission is hereby granted, free of charge, to any person obtaining a 8cdc920a0Smrg * copy of this software and associated documentation files (the "Software"), 9cdc920a0Smrg * to deal in the Software without restriction, including without limitation 10cdc920a0Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11cdc920a0Smrg * and/or sell copies of the Software, and to permit persons to whom the 12cdc920a0Smrg * Software is furnished to do so, subject to the following conditions: 13cdc920a0Smrg * 14cdc920a0Smrg * The above copyright notice and this permission notice shall be included 15cdc920a0Smrg * in all copies or substantial portions of the Software. 16cdc920a0Smrg * 17cdc920a0Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18cdc920a0Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19cdc920a0Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20cdc920a0Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21cdc920a0Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22cdc920a0Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23cdc920a0Smrg */ 24cdc920a0Smrg 25cdc920a0Smrg 26cdc920a0Smrg/* xfonts.c -- glXUseXFont() for Mesa written by 27cdc920a0Smrg * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de 28cdc920a0Smrg */ 29cdc920a0Smrg 30cdc920a0Smrg/* 31cdc920a0Smrg This was take from Mesa and modified to work in the real GLX structure. 32cdc920a0Smrg It provides a fully client side implementation of glXUseXFont and is 33cdc920a0Smrg called by that routine when direct rendering is enabled. 34cdc920a0Smrg*/ 35cdc920a0Smrg 36cdc920a0Smrg#ifdef GLX_DIRECT_RENDERING 37cdc920a0Smrg 38cdc920a0Smrg#include "glxclient.h" 39cdc920a0Smrg 40cdc920a0Smrg/* Some debugging info. */ 41cdc920a0Smrg 42cdc920a0Smrg#ifdef DEBUG 43cdc920a0Smrg#undef _R 44cdc920a0Smrg#undef _G 45cdc920a0Smrg#undef _B 46cdc920a0Smrg#include <ctype.h> 47cdc920a0Smrg 48cdc920a0Smrgint debug_xfonts = 0; 49cdc920a0Smrg 50cdc920a0Smrgstatic void 51cdc920a0Smrgdump_char_struct(XCharStruct * ch, char *prefix) 52cdc920a0Smrg{ 53cdc920a0Smrg printf("%slbearing = %d, rbearing = %d, width = %d\n", 54cdc920a0Smrg prefix, ch->lbearing, ch->rbearing, ch->width); 55cdc920a0Smrg printf("%sascent = %d, descent = %d, attributes = %u\n", 56cdc920a0Smrg prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes); 57cdc920a0Smrg} 58cdc920a0Smrg 59cdc920a0Smrgstatic void 60cdc920a0Smrgdump_font_struct(XFontStruct * font) 61cdc920a0Smrg{ 62cdc920a0Smrg printf("ascent = %d, descent = %d\n", font->ascent, font->descent); 63cdc920a0Smrg printf("char_or_byte2 = (%u,%u)\n", 64cdc920a0Smrg font->min_char_or_byte2, font->max_char_or_byte2); 65cdc920a0Smrg printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1); 66cdc920a0Smrg printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False"); 67cdc920a0Smrg printf("default_char = %c (\\%03o)\n", 68cdc920a0Smrg (char) (isprint(font->default_char) ? font->default_char : ' '), 69cdc920a0Smrg font->default_char); 70cdc920a0Smrg dump_char_struct(&font->min_bounds, "min> "); 71cdc920a0Smrg dump_char_struct(&font->max_bounds, "max> "); 72cdc920a0Smrg#if 0 73cdc920a0Smrg for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) { 74cdc920a0Smrg char prefix[8]; 75cdc920a0Smrg sprintf(prefix, "%d> ", c); 76cdc920a0Smrg dump_char_struct(&font->per_char[c], prefix); 77cdc920a0Smrg } 78cdc920a0Smrg#endif 79cdc920a0Smrg} 80cdc920a0Smrg 81cdc920a0Smrgstatic void 82cdc920a0Smrgdump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap) 83cdc920a0Smrg{ 84cdc920a0Smrg unsigned int x, y; 85cdc920a0Smrg 86cdc920a0Smrg printf(" "); 87cdc920a0Smrg for (x = 0; x < 8 * width; x++) 88cdc920a0Smrg printf("%o", 7 - (x % 8)); 89cdc920a0Smrg putchar('\n'); 90cdc920a0Smrg for (y = 0; y < height; y++) { 91cdc920a0Smrg printf("%3o:", y); 92cdc920a0Smrg for (x = 0; x < 8 * width; x++) 93cdc920a0Smrg putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x % 94cdc920a0Smrg 8)))) 95cdc920a0Smrg ? '*' : '.'); 96cdc920a0Smrg printf(" "); 97cdc920a0Smrg for (x = 0; x < width; x++) 98cdc920a0Smrg printf("0x%02x, ", bitmap[width * (height - y - 1) + x]); 99cdc920a0Smrg putchar('\n'); 100cdc920a0Smrg } 101cdc920a0Smrg} 102cdc920a0Smrg#endif /* DEBUG */ 103cdc920a0Smrg 104cdc920a0Smrg 105cdc920a0Smrg/* Implementation. */ 106cdc920a0Smrg 107cdc920a0Smrg/* Fill a BITMAP with a character C from thew current font 108cdc920a0Smrg in the graphics context GC. WIDTH is the width in bytes 109cdc920a0Smrg and HEIGHT is the height in bits. 110cdc920a0Smrg 111cdc920a0Smrg Note that the generated bitmaps must be used with 112cdc920a0Smrg 113cdc920a0Smrg glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); 114cdc920a0Smrg glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); 115cdc920a0Smrg glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); 116cdc920a0Smrg glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); 117cdc920a0Smrg glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); 118cdc920a0Smrg glPixelStorei (GL_UNPACK_ALIGNMENT, 1); 119cdc920a0Smrg 120cdc920a0Smrg Possible optimizations: 121cdc920a0Smrg 122cdc920a0Smrg * use only one reusable pixmap with the maximum dimensions. 123cdc920a0Smrg * draw the entire font into a single pixmap (careful with 124cdc920a0Smrg proportional fonts!). 125cdc920a0Smrg*/ 126cdc920a0Smrg 127cdc920a0Smrg 128cdc920a0Smrg/* 129cdc920a0Smrg * Generate OpenGL-compatible bitmap. 130cdc920a0Smrg */ 131cdc920a0Smrgstatic void 132cdc920a0Smrgfill_bitmap(Display * dpy, Window win, GC gc, 133cdc920a0Smrg unsigned int width, unsigned int height, 134cdc920a0Smrg int x0, int y0, unsigned int c, GLubyte * bitmap) 135cdc920a0Smrg{ 136cdc920a0Smrg XImage *image; 137cdc920a0Smrg unsigned int x, y; 138cdc920a0Smrg Pixmap pixmap; 139cdc920a0Smrg XChar2b char2b; 140cdc920a0Smrg 141cdc920a0Smrg pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1); 142cdc920a0Smrg XSetForeground(dpy, gc, 0); 143cdc920a0Smrg XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height); 144cdc920a0Smrg XSetForeground(dpy, gc, 1); 145cdc920a0Smrg 146cdc920a0Smrg char2b.byte1 = (c >> 8) & 0xff; 147cdc920a0Smrg char2b.byte2 = (c & 0xff); 148cdc920a0Smrg 149cdc920a0Smrg XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1); 150cdc920a0Smrg 151cdc920a0Smrg image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap); 152cdc920a0Smrg if (image) { 153cdc920a0Smrg /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */ 154cdc920a0Smrg for (y = 0; y < height; y++) 155cdc920a0Smrg for (x = 0; x < 8 * width; x++) 156cdc920a0Smrg if (XGetPixel(image, x, y)) 157cdc920a0Smrg bitmap[width * (height - y - 1) + x / 8] |= 158cdc920a0Smrg (1 << (7 - (x % 8))); 159cdc920a0Smrg XDestroyImage(image); 160cdc920a0Smrg } 161cdc920a0Smrg 162cdc920a0Smrg XFreePixmap(dpy, pixmap); 163cdc920a0Smrg} 164cdc920a0Smrg 165cdc920a0Smrg/* 166cdc920a0Smrg * determine if a given glyph is valid and return the 167cdc920a0Smrg * corresponding XCharStruct. 168cdc920a0Smrg */ 169cdc920a0Smrgstatic XCharStruct * 170cdc920a0Smrgisvalid(XFontStruct * fs, int which) 171cdc920a0Smrg{ 172cdc920a0Smrg unsigned int rows, pages; 173cdc920a0Smrg int byte1 = 0, byte2 = 0; 174cdc920a0Smrg int i, valid = 1; 175cdc920a0Smrg 176cdc920a0Smrg rows = fs->max_byte1 - fs->min_byte1 + 1; 177cdc920a0Smrg pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; 178cdc920a0Smrg 179cdc920a0Smrg if (rows == 1) { 180cdc920a0Smrg /* "linear" fonts */ 181cdc920a0Smrg if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which)) 182cdc920a0Smrg valid = 0; 183cdc920a0Smrg } 184cdc920a0Smrg else { 185cdc920a0Smrg /* "matrix" fonts */ 186cdc920a0Smrg byte2 = which & 0xff; 187cdc920a0Smrg byte1 = which >> 8; 188cdc920a0Smrg if ((fs->min_char_or_byte2 > byte2) || 189cdc920a0Smrg (fs->max_char_or_byte2 < byte2) || 190cdc920a0Smrg (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1)) 191cdc920a0Smrg valid = 0; 192cdc920a0Smrg } 193cdc920a0Smrg 194cdc920a0Smrg if (valid) { 195cdc920a0Smrg if (fs->per_char) { 196cdc920a0Smrg if (rows == 1) { 197cdc920a0Smrg /* "linear" fonts */ 198cdc920a0Smrg return (fs->per_char + (which - fs->min_char_or_byte2)); 199cdc920a0Smrg } 200cdc920a0Smrg else { 201cdc920a0Smrg /* "matrix" fonts */ 202cdc920a0Smrg i = ((byte1 - fs->min_byte1) * pages) + 203cdc920a0Smrg (byte2 - fs->min_char_or_byte2); 204cdc920a0Smrg return (fs->per_char + i); 205cdc920a0Smrg } 206cdc920a0Smrg } 207cdc920a0Smrg else { 208cdc920a0Smrg return (&fs->min_bounds); 209cdc920a0Smrg } 210cdc920a0Smrg } 211cdc920a0Smrg return (NULL); 212cdc920a0Smrg} 213cdc920a0Smrg 214cdc920a0Smrg_X_HIDDEN void 215cdc920a0SmrgDRI_glXUseXFont(Font font, int first, int count, int listbase) 216cdc920a0Smrg{ 217cdc920a0Smrg GLXContext CC; 218cdc920a0Smrg Display *dpy; 219cdc920a0Smrg Window win; 220cdc920a0Smrg Pixmap pixmap; 221cdc920a0Smrg GC gc; 222cdc920a0Smrg XGCValues values; 223cdc920a0Smrg unsigned long valuemask; 224cdc920a0Smrg XFontStruct *fs; 225cdc920a0Smrg 226cdc920a0Smrg GLint swapbytes, lsbfirst, rowlength; 227cdc920a0Smrg GLint skiprows, skippixels, alignment; 228cdc920a0Smrg 229cdc920a0Smrg unsigned int max_width, max_height, max_bm_width, max_bm_height; 230cdc920a0Smrg GLubyte *bm; 231cdc920a0Smrg 232cdc920a0Smrg int i; 233cdc920a0Smrg 234cdc920a0Smrg CC = __glXGetCurrentContext(); 235cdc920a0Smrg dpy = CC->currentDpy; 236cdc920a0Smrg win = CC->currentDrawable; 237cdc920a0Smrg 238cdc920a0Smrg fs = XQueryFont(dpy, font); 239cdc920a0Smrg if (!fs) { 240cdc920a0Smrg __glXSetError(CC, GL_INVALID_VALUE); 241cdc920a0Smrg return; 242cdc920a0Smrg } 243cdc920a0Smrg 244cdc920a0Smrg /* Allocate a bitmap that can fit all characters. */ 245cdc920a0Smrg max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing; 246cdc920a0Smrg max_height = fs->max_bounds.ascent + fs->max_bounds.descent; 247cdc920a0Smrg max_bm_width = (max_width + 7) / 8; 248cdc920a0Smrg max_bm_height = max_height; 249cdc920a0Smrg 250cdc920a0Smrg bm = (GLubyte *) Xmalloc((max_bm_width * max_bm_height) * sizeof(GLubyte)); 251cdc920a0Smrg if (!bm) { 252cdc920a0Smrg XFreeFontInfo(NULL, fs, 1); 253cdc920a0Smrg __glXSetError(CC, GL_OUT_OF_MEMORY); 254cdc920a0Smrg return; 255cdc920a0Smrg } 256cdc920a0Smrg 257cdc920a0Smrg#if 0 258cdc920a0Smrg /* get the page info */ 259cdc920a0Smrg pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; 260cdc920a0Smrg firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2; 261cdc920a0Smrg lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2; 262cdc920a0Smrg rows = fs->max_byte1 - fs->min_byte1 + 1; 263cdc920a0Smrg unsigned int first_char, last_char, pages, rows; 264cdc920a0Smrg#endif 265cdc920a0Smrg 266cdc920a0Smrg /* Save the current packing mode for bitmaps. */ 267cdc920a0Smrg glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes); 268cdc920a0Smrg glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst); 269cdc920a0Smrg glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength); 270cdc920a0Smrg glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows); 271cdc920a0Smrg glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels); 272cdc920a0Smrg glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); 273cdc920a0Smrg 274cdc920a0Smrg /* Enforce a standard packing mode which is compatible with 275cdc920a0Smrg fill_bitmap() from above. This is actually the default mode, 276cdc920a0Smrg except for the (non)alignment. */ 277cdc920a0Smrg glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); 278cdc920a0Smrg glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); 279cdc920a0Smrg glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 280cdc920a0Smrg glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 281cdc920a0Smrg glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 282cdc920a0Smrg glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 283cdc920a0Smrg 284cdc920a0Smrg pixmap = XCreatePixmap(dpy, win, 10, 10, 1); 285cdc920a0Smrg values.foreground = BlackPixel(dpy, DefaultScreen(dpy)); 286cdc920a0Smrg values.background = WhitePixel(dpy, DefaultScreen(dpy)); 287cdc920a0Smrg values.font = fs->fid; 288cdc920a0Smrg valuemask = GCForeground | GCBackground | GCFont; 289cdc920a0Smrg gc = XCreateGC(dpy, pixmap, valuemask, &values); 290cdc920a0Smrg XFreePixmap(dpy, pixmap); 291cdc920a0Smrg 292cdc920a0Smrg#ifdef DEBUG 293cdc920a0Smrg if (debug_xfonts) 294cdc920a0Smrg dump_font_struct(fs); 295cdc920a0Smrg#endif 296cdc920a0Smrg 297cdc920a0Smrg for (i = 0; i < count; i++) { 298cdc920a0Smrg unsigned int width, height, bm_width, bm_height; 299cdc920a0Smrg GLfloat x0, y0, dx, dy; 300cdc920a0Smrg XCharStruct *ch; 301cdc920a0Smrg int x, y; 302cdc920a0Smrg unsigned int c = first + i; 303cdc920a0Smrg int list = listbase + i; 304cdc920a0Smrg int valid; 305cdc920a0Smrg 306cdc920a0Smrg /* check on index validity and get the bounds */ 307cdc920a0Smrg ch = isvalid(fs, c); 308cdc920a0Smrg if (!ch) { 309cdc920a0Smrg ch = &fs->max_bounds; 310cdc920a0Smrg valid = 0; 311cdc920a0Smrg } 312cdc920a0Smrg else { 313cdc920a0Smrg valid = 1; 314cdc920a0Smrg } 315cdc920a0Smrg 316cdc920a0Smrg#ifdef DEBUG 317cdc920a0Smrg if (debug_xfonts) { 318cdc920a0Smrg char s[7]; 319cdc920a0Smrg sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c); 320cdc920a0Smrg dump_char_struct(ch, s); 321cdc920a0Smrg } 322cdc920a0Smrg#endif 323cdc920a0Smrg 324cdc920a0Smrg /* glBitmap()' parameters: 325cdc920a0Smrg straight from the glXUseXFont(3) manpage. */ 326cdc920a0Smrg width = ch->rbearing - ch->lbearing; 327cdc920a0Smrg height = ch->ascent + ch->descent; 328cdc920a0Smrg x0 = -ch->lbearing; 329cdc920a0Smrg y0 = ch->descent - 1; 330cdc920a0Smrg dx = ch->width; 331cdc920a0Smrg dy = 0; 332cdc920a0Smrg 333cdc920a0Smrg /* X11's starting point. */ 334cdc920a0Smrg x = -ch->lbearing; 335cdc920a0Smrg y = ch->ascent; 336cdc920a0Smrg 337cdc920a0Smrg /* Round the width to a multiple of eight. We will use this also 338cdc920a0Smrg for the pixmap for capturing the X11 font. This is slightly 339cdc920a0Smrg inefficient, but it makes the OpenGL part real easy. */ 340cdc920a0Smrg bm_width = (width + 7) / 8; 341cdc920a0Smrg bm_height = height; 342cdc920a0Smrg 343cdc920a0Smrg glNewList(list, GL_COMPILE); 344cdc920a0Smrg if (valid && (bm_width > 0) && (bm_height > 0)) { 345cdc920a0Smrg 346cdc920a0Smrg memset(bm, '\0', bm_width * bm_height); 347cdc920a0Smrg fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm); 348cdc920a0Smrg 349cdc920a0Smrg glBitmap(width, height, x0, y0, dx, dy, bm); 350cdc920a0Smrg#ifdef DEBUG 351cdc920a0Smrg if (debug_xfonts) { 352cdc920a0Smrg printf("width/height = %u/%u\n", width, height); 353cdc920a0Smrg printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height); 354cdc920a0Smrg dump_bitmap(bm_width, bm_height, bm); 355cdc920a0Smrg } 356cdc920a0Smrg#endif 357cdc920a0Smrg } 358cdc920a0Smrg else { 359cdc920a0Smrg glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL); 360cdc920a0Smrg } 361cdc920a0Smrg glEndList(); 362cdc920a0Smrg } 363cdc920a0Smrg 364cdc920a0Smrg Xfree(bm); 365cdc920a0Smrg XFreeFontInfo(NULL, fs, 1); 366cdc920a0Smrg XFreeGC(dpy, gc); 367cdc920a0Smrg 368cdc920a0Smrg /* Restore saved packing modes. */ 369cdc920a0Smrg glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); 370cdc920a0Smrg glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst); 371cdc920a0Smrg glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength); 372cdc920a0Smrg glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); 373cdc920a0Smrg glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); 374cdc920a0Smrg glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); 375cdc920a0Smrg} 376cdc920a0Smrg 377cdc920a0Smrg#endif 378