1848b8605Smrg/* 2848b8605Smrg * Mesa 3-D graphics library 3848b8605Smrg * 4848b8605Smrg * Copyright (C) 1999 Brian Paul All Rights Reserved. 5848b8605Smrg * 6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7848b8605Smrg * copy of this software and associated documentation files (the "Software"), 8848b8605Smrg * to deal in the Software without restriction, including without limitation 9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 11848b8605Smrg * Software is furnished to do so, subject to the following conditions: 12848b8605Smrg * 13848b8605Smrg * The above copyright notice and this permission notice shall be included 14848b8605Smrg * in all copies or substantial portions of the Software. 15848b8605Smrg * 16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 23848b8605Smrg */ 24848b8605Smrg 25848b8605Smrg 26848b8605Smrg/* xfonts.c -- glXUseXFont() for Mesa written by 27848b8605Smrg * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de 28848b8605Smrg */ 29848b8605Smrg 30848b8605Smrg/* 31848b8605Smrg This was take from Mesa and modified to work in the real GLX structure. 32848b8605Smrg It provides a fully client side implementation of glXUseXFont and is 33848b8605Smrg called by that routine when direct rendering is enabled. 34848b8605Smrg*/ 35848b8605Smrg 36848b8605Smrg#ifdef GLX_DIRECT_RENDERING 37848b8605Smrg 38848b8605Smrg#include "glxclient.h" 39848b8605Smrg 40848b8605Smrg/* Some debugging info. */ 41848b8605Smrg 42848b8605Smrg#ifdef DEBUG 43848b8605Smrg#undef _R 44848b8605Smrg#undef _G 45848b8605Smrg#undef _B 46848b8605Smrg#include <ctype.h> 47848b8605Smrg 48848b8605Smrgint debug_xfonts = 0; 49848b8605Smrg 50848b8605Smrgstatic void 51848b8605Smrgdump_char_struct(XCharStruct * ch, char *prefix) 52848b8605Smrg{ 53848b8605Smrg printf("%slbearing = %d, rbearing = %d, width = %d\n", 54848b8605Smrg prefix, ch->lbearing, ch->rbearing, ch->width); 55848b8605Smrg printf("%sascent = %d, descent = %d, attributes = %u\n", 56848b8605Smrg prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes); 57848b8605Smrg} 58848b8605Smrg 59848b8605Smrgstatic void 60848b8605Smrgdump_font_struct(XFontStruct * font) 61848b8605Smrg{ 62848b8605Smrg printf("ascent = %d, descent = %d\n", font->ascent, font->descent); 63848b8605Smrg printf("char_or_byte2 = (%u,%u)\n", 64848b8605Smrg font->min_char_or_byte2, font->max_char_or_byte2); 65848b8605Smrg printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1); 66848b8605Smrg printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False"); 67848b8605Smrg printf("default_char = %c (\\%03o)\n", 68848b8605Smrg (char) (isprint(font->default_char) ? font->default_char : ' '), 69848b8605Smrg font->default_char); 70848b8605Smrg dump_char_struct(&font->min_bounds, "min> "); 71848b8605Smrg dump_char_struct(&font->max_bounds, "max> "); 72848b8605Smrg#if 0 73848b8605Smrg for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) { 74848b8605Smrg char prefix[8]; 75848b8605Smrg sprintf(prefix, "%d> ", c); 76848b8605Smrg dump_char_struct(&font->per_char[c], prefix); 77848b8605Smrg } 78848b8605Smrg#endif 79848b8605Smrg} 80848b8605Smrg 81848b8605Smrgstatic void 82848b8605Smrgdump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap) 83848b8605Smrg{ 84848b8605Smrg unsigned int x, y; 85848b8605Smrg 86848b8605Smrg printf(" "); 87848b8605Smrg for (x = 0; x < 8 * width; x++) 88848b8605Smrg printf("%o", 7 - (x % 8)); 89848b8605Smrg putchar('\n'); 90848b8605Smrg for (y = 0; y < height; y++) { 91848b8605Smrg printf("%3o:", y); 92848b8605Smrg for (x = 0; x < 8 * width; x++) 93848b8605Smrg putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x % 94848b8605Smrg 8)))) 95848b8605Smrg ? '*' : '.'); 96848b8605Smrg printf(" "); 97848b8605Smrg for (x = 0; x < width; x++) 98848b8605Smrg printf("0x%02x, ", bitmap[width * (height - y - 1) + x]); 99848b8605Smrg putchar('\n'); 100848b8605Smrg } 101848b8605Smrg} 102848b8605Smrg#endif /* DEBUG */ 103848b8605Smrg 104848b8605Smrg 105848b8605Smrg/* Implementation. */ 106848b8605Smrg 107848b8605Smrg/* Fill a BITMAP with a character C from thew current font 108848b8605Smrg in the graphics context GC. WIDTH is the width in bytes 109848b8605Smrg and HEIGHT is the height in bits. 110848b8605Smrg 111848b8605Smrg Note that the generated bitmaps must be used with 112848b8605Smrg 113848b8605Smrg glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE); 114848b8605Smrg glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE); 115848b8605Smrg glPixelStorei (GL_UNPACK_ROW_LENGTH, 0); 116848b8605Smrg glPixelStorei (GL_UNPACK_SKIP_ROWS, 0); 117848b8605Smrg glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0); 118848b8605Smrg glPixelStorei (GL_UNPACK_ALIGNMENT, 1); 119848b8605Smrg 120848b8605Smrg Possible optimizations: 121848b8605Smrg 122848b8605Smrg * use only one reusable pixmap with the maximum dimensions. 123848b8605Smrg * draw the entire font into a single pixmap (careful with 124848b8605Smrg proportional fonts!). 125848b8605Smrg*/ 126848b8605Smrg 127848b8605Smrg 128848b8605Smrg/* 129848b8605Smrg * Generate OpenGL-compatible bitmap. 130848b8605Smrg */ 131848b8605Smrgstatic void 132848b8605Smrgfill_bitmap(Display * dpy, Window win, GC gc, 133848b8605Smrg unsigned int width, unsigned int height, 134848b8605Smrg int x0, int y0, unsigned int c, GLubyte * bitmap) 135848b8605Smrg{ 136848b8605Smrg XImage *image; 137848b8605Smrg unsigned int x, y; 138848b8605Smrg Pixmap pixmap; 139848b8605Smrg XChar2b char2b; 140848b8605Smrg 141848b8605Smrg pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1); 142848b8605Smrg XSetForeground(dpy, gc, 0); 143848b8605Smrg XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height); 144848b8605Smrg XSetForeground(dpy, gc, 1); 145848b8605Smrg 146848b8605Smrg char2b.byte1 = (c >> 8) & 0xff; 147848b8605Smrg char2b.byte2 = (c & 0xff); 148848b8605Smrg 149848b8605Smrg XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1); 150848b8605Smrg 151848b8605Smrg image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap); 152848b8605Smrg if (image) { 153848b8605Smrg /* Fill the bitmap (X11 and OpenGL are upside down wrt each other). */ 154848b8605Smrg for (y = 0; y < height; y++) 155848b8605Smrg for (x = 0; x < 8 * width; x++) 156848b8605Smrg if (XGetPixel(image, x, y)) 157848b8605Smrg bitmap[width * (height - y - 1) + x / 8] |= 158848b8605Smrg (1 << (7 - (x % 8))); 159848b8605Smrg XDestroyImage(image); 160848b8605Smrg } 161848b8605Smrg 162848b8605Smrg XFreePixmap(dpy, pixmap); 163848b8605Smrg} 164848b8605Smrg 165848b8605Smrg/* 166848b8605Smrg * determine if a given glyph is valid and return the 167848b8605Smrg * corresponding XCharStruct. 168848b8605Smrg */ 169848b8605Smrgstatic XCharStruct * 170848b8605Smrgisvalid(XFontStruct * fs, int which) 171848b8605Smrg{ 172848b8605Smrg unsigned int rows, pages; 173848b8605Smrg int byte1 = 0, byte2 = 0; 174848b8605Smrg int i, valid = 1; 175848b8605Smrg 176848b8605Smrg rows = fs->max_byte1 - fs->min_byte1 + 1; 177848b8605Smrg pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; 178848b8605Smrg 179848b8605Smrg if (rows == 1) { 180848b8605Smrg /* "linear" fonts */ 181848b8605Smrg if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which)) 182848b8605Smrg valid = 0; 183848b8605Smrg } 184848b8605Smrg else { 185848b8605Smrg /* "matrix" fonts */ 186848b8605Smrg byte2 = which & 0xff; 187848b8605Smrg byte1 = which >> 8; 188848b8605Smrg if ((fs->min_char_or_byte2 > byte2) || 189848b8605Smrg (fs->max_char_or_byte2 < byte2) || 190848b8605Smrg (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1)) 191848b8605Smrg valid = 0; 192848b8605Smrg } 193848b8605Smrg 194848b8605Smrg if (valid) { 195848b8605Smrg if (fs->per_char) { 196848b8605Smrg if (rows == 1) { 197848b8605Smrg /* "linear" fonts */ 198848b8605Smrg return (fs->per_char + (which - fs->min_char_or_byte2)); 199848b8605Smrg } 200848b8605Smrg else { 201848b8605Smrg /* "matrix" fonts */ 202848b8605Smrg i = ((byte1 - fs->min_byte1) * pages) + 203848b8605Smrg (byte2 - fs->min_char_or_byte2); 204848b8605Smrg return (fs->per_char + i); 205848b8605Smrg } 206848b8605Smrg } 207848b8605Smrg else { 208848b8605Smrg return (&fs->min_bounds); 209848b8605Smrg } 210848b8605Smrg } 211848b8605Smrg return (NULL); 212848b8605Smrg} 213848b8605Smrg 214848b8605Smrg_X_HIDDEN void 215848b8605SmrgDRI_glXUseXFont(struct glx_context *CC, Font font, int first, int count, int listbase) 216848b8605Smrg{ 217848b8605Smrg Display *dpy; 218848b8605Smrg Window win; 219848b8605Smrg Pixmap pixmap; 220848b8605Smrg GC gc; 221848b8605Smrg XGCValues values; 222848b8605Smrg unsigned long valuemask; 223848b8605Smrg XFontStruct *fs; 224b8e80941Smrg 225b8e80941Smrg#if !defined(GLX_USE_APPLEGL) 226848b8605Smrg __GLXDRIdrawable *glxdraw; 227b8e80941Smrg#endif 228848b8605Smrg 229848b8605Smrg GLint swapbytes, lsbfirst, rowlength; 230848b8605Smrg GLint skiprows, skippixels, alignment; 231848b8605Smrg 232848b8605Smrg unsigned int max_width, max_height, max_bm_width, max_bm_height; 233848b8605Smrg GLubyte *bm; 234848b8605Smrg 235848b8605Smrg int i; 236848b8605Smrg 237848b8605Smrg dpy = CC->currentDpy; 238848b8605Smrg win = CC->currentDrawable; 239848b8605Smrg 240b8e80941Smrg#if !defined(GLX_USE_APPLEGL) 241848b8605Smrg glxdraw = GetGLXDRIDrawable(CC->currentDpy, CC->currentDrawable); 242848b8605Smrg if (glxdraw) 243848b8605Smrg win = glxdraw->xDrawable; 244b8e80941Smrg#endif 245848b8605Smrg 246848b8605Smrg fs = XQueryFont(dpy, font); 247848b8605Smrg if (!fs) { 248848b8605Smrg __glXSetError(CC, GL_INVALID_VALUE); 249848b8605Smrg return; 250848b8605Smrg } 251848b8605Smrg 252848b8605Smrg /* Allocate a bitmap that can fit all characters. */ 253848b8605Smrg max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing; 254848b8605Smrg max_height = fs->max_bounds.ascent + fs->max_bounds.descent; 255848b8605Smrg max_bm_width = (max_width + 7) / 8; 256848b8605Smrg max_bm_height = max_height; 257848b8605Smrg 258848b8605Smrg bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte)); 259848b8605Smrg if (!bm) { 260848b8605Smrg XFreeFontInfo(NULL, fs, 1); 261848b8605Smrg __glXSetError(CC, GL_OUT_OF_MEMORY); 262848b8605Smrg return; 263848b8605Smrg } 264848b8605Smrg 265848b8605Smrg#if 0 266848b8605Smrg /* get the page info */ 267848b8605Smrg pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1; 268848b8605Smrg firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2; 269848b8605Smrg lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2; 270848b8605Smrg rows = fs->max_byte1 - fs->min_byte1 + 1; 271848b8605Smrg unsigned int first_char, last_char, pages, rows; 272848b8605Smrg#endif 273848b8605Smrg 274848b8605Smrg /* Save the current packing mode for bitmaps. */ 275848b8605Smrg glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes); 276848b8605Smrg glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst); 277848b8605Smrg glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength); 278848b8605Smrg glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows); 279848b8605Smrg glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels); 280848b8605Smrg glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment); 281848b8605Smrg 282848b8605Smrg /* Enforce a standard packing mode which is compatible with 283848b8605Smrg fill_bitmap() from above. This is actually the default mode, 284848b8605Smrg except for the (non)alignment. */ 285848b8605Smrg glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); 286848b8605Smrg glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); 287848b8605Smrg glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 288848b8605Smrg glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 289848b8605Smrg glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 290848b8605Smrg glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 291848b8605Smrg 292848b8605Smrg pixmap = XCreatePixmap(dpy, win, 10, 10, 1); 293848b8605Smrg values.foreground = BlackPixel(dpy, DefaultScreen(dpy)); 294848b8605Smrg values.background = WhitePixel(dpy, DefaultScreen(dpy)); 295848b8605Smrg values.font = fs->fid; 296848b8605Smrg valuemask = GCForeground | GCBackground | GCFont; 297848b8605Smrg gc = XCreateGC(dpy, pixmap, valuemask, &values); 298848b8605Smrg XFreePixmap(dpy, pixmap); 299848b8605Smrg 300848b8605Smrg#ifdef DEBUG 301848b8605Smrg if (debug_xfonts) 302848b8605Smrg dump_font_struct(fs); 303848b8605Smrg#endif 304848b8605Smrg 305848b8605Smrg for (i = 0; i < count; i++) { 306848b8605Smrg unsigned int width, height, bm_width, bm_height; 307848b8605Smrg GLfloat x0, y0, dx, dy; 308848b8605Smrg XCharStruct *ch; 309848b8605Smrg int x, y; 310848b8605Smrg unsigned int c = first + i; 311848b8605Smrg int list = listbase + i; 312848b8605Smrg int valid; 313848b8605Smrg 314848b8605Smrg /* check on index validity and get the bounds */ 315848b8605Smrg ch = isvalid(fs, c); 316848b8605Smrg if (!ch) { 317848b8605Smrg ch = &fs->max_bounds; 318848b8605Smrg valid = 0; 319848b8605Smrg } 320848b8605Smrg else { 321848b8605Smrg valid = 1; 322848b8605Smrg } 323848b8605Smrg 324848b8605Smrg#ifdef DEBUG 325848b8605Smrg if (debug_xfonts) { 326848b8605Smrg char s[7]; 327848b8605Smrg sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c); 328848b8605Smrg dump_char_struct(ch, s); 329848b8605Smrg } 330848b8605Smrg#endif 331848b8605Smrg 332848b8605Smrg /* glBitmap()' parameters: 333848b8605Smrg straight from the glXUseXFont(3) manpage. */ 334848b8605Smrg width = ch->rbearing - ch->lbearing; 335848b8605Smrg height = ch->ascent + ch->descent; 336848b8605Smrg x0 = -ch->lbearing; 337848b8605Smrg y0 = ch->descent - 1; 338848b8605Smrg dx = ch->width; 339848b8605Smrg dy = 0; 340848b8605Smrg 341848b8605Smrg /* X11's starting point. */ 342848b8605Smrg x = -ch->lbearing; 343848b8605Smrg y = ch->ascent; 344848b8605Smrg 345848b8605Smrg /* Round the width to a multiple of eight. We will use this also 346848b8605Smrg for the pixmap for capturing the X11 font. This is slightly 347848b8605Smrg inefficient, but it makes the OpenGL part real easy. */ 348848b8605Smrg bm_width = (width + 7) / 8; 349848b8605Smrg bm_height = height; 350848b8605Smrg 351848b8605Smrg glNewList(list, GL_COMPILE); 352848b8605Smrg if (valid && (bm_width > 0) && (bm_height > 0)) { 353848b8605Smrg 354848b8605Smrg memset(bm, '\0', bm_width * bm_height); 355848b8605Smrg fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm); 356848b8605Smrg 357848b8605Smrg glBitmap(width, height, x0, y0, dx, dy, bm); 358848b8605Smrg#ifdef DEBUG 359848b8605Smrg if (debug_xfonts) { 360848b8605Smrg printf("width/height = %u/%u\n", width, height); 361848b8605Smrg printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height); 362848b8605Smrg dump_bitmap(bm_width, bm_height, bm); 363848b8605Smrg } 364848b8605Smrg#endif 365848b8605Smrg } 366848b8605Smrg else { 367848b8605Smrg glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL); 368848b8605Smrg } 369848b8605Smrg glEndList(); 370848b8605Smrg } 371848b8605Smrg 372848b8605Smrg free(bm); 373848b8605Smrg XFreeFontInfo(NULL, fs, 1); 374848b8605Smrg XFreeGC(dpy, gc); 375848b8605Smrg 376848b8605Smrg /* Restore saved packing modes. */ 377848b8605Smrg glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes); 378848b8605Smrg glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst); 379848b8605Smrg glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength); 380848b8605Smrg glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows); 381848b8605Smrg glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels); 382848b8605Smrg glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); 383848b8605Smrg} 384848b8605Smrg 385848b8605Smrg#endif 386