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