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