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