17117f1b4Smrg
27117f1b4Smrg/*
37117f1b4Smrg * Mesa 3-D graphics library
47117f1b4Smrg *
57117f1b4Smrg * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/* xfonts.c -- glXUseXFont() for Mesa written by
287117f1b4Smrg * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de
297117f1b4Smrg */
307117f1b4Smrg
3101e04c3fSmrg#include <stdio.h>
327117f1b4Smrg#include "glxheader.h"
33c1f859d4Smrg#include "main/context.h"
347117f1b4Smrg#include "xfonts.h"
357117f1b4Smrg
367117f1b4Smrg
377117f1b4Smrg/* Some debugging info.  */
387117f1b4Smrg
397117f1b4Smrg#ifdef DEBUG
407117f1b4Smrg#include <ctype.h>
417117f1b4Smrg
427117f1b4Smrgint debug_xfonts = 0;
437117f1b4Smrg
447117f1b4Smrgstatic void
457117f1b4Smrgdump_char_struct(XCharStruct * ch, char *prefix)
467117f1b4Smrg{
477117f1b4Smrg   printf("%slbearing = %d, rbearing = %d, width = %d\n",
487117f1b4Smrg	  prefix, ch->lbearing, ch->rbearing, ch->width);
497117f1b4Smrg   printf("%sascent = %d, descent = %d, attributes = %u\n",
507117f1b4Smrg	  prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
517117f1b4Smrg}
527117f1b4Smrg
537117f1b4Smrgstatic void
547117f1b4Smrgdump_font_struct(XFontStruct * font)
557117f1b4Smrg{
567117f1b4Smrg   printf("ascent = %d, descent = %d\n", font->ascent, font->descent);
577117f1b4Smrg   printf("char_or_byte2 = (%u,%u)\n",
587117f1b4Smrg	  font->min_char_or_byte2, font->max_char_or_byte2);
597117f1b4Smrg   printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
607117f1b4Smrg   printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False");
617117f1b4Smrg   printf("default_char = %c (\\%03o)\n",
627117f1b4Smrg	  (char) (isprint(font->default_char) ? font->default_char : ' '),
637117f1b4Smrg	  font->default_char);
647117f1b4Smrg   dump_char_struct(&font->min_bounds, "min> ");
657117f1b4Smrg   dump_char_struct(&font->max_bounds, "max> ");
667117f1b4Smrg#if 0
677117f1b4Smrg   for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) {
687117f1b4Smrg      char prefix[8];
697117f1b4Smrg      sprintf(prefix, "%d> ", c);
707117f1b4Smrg      dump_char_struct(&font->per_char[c], prefix);
717117f1b4Smrg   }
727117f1b4Smrg#endif
737117f1b4Smrg}
747117f1b4Smrg
757117f1b4Smrgstatic void
767117f1b4Smrgdump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap)
777117f1b4Smrg{
787117f1b4Smrg   unsigned int x, y;
797117f1b4Smrg
807117f1b4Smrg   printf("    ");
817117f1b4Smrg   for (x = 0; x < 8 * width; x++)
827117f1b4Smrg      printf("%o", 7 - (x % 8));
837117f1b4Smrg   putchar('\n');
847117f1b4Smrg   for (y = 0; y < height; y++) {
857117f1b4Smrg      printf("%3o:", y);
867117f1b4Smrg      for (x = 0; x < 8 * width; x++)
877117f1b4Smrg	 putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x %
887117f1b4Smrg									 8))))
897117f1b4Smrg		 ? '*' : '.');
907117f1b4Smrg      printf("   ");
917117f1b4Smrg      for (x = 0; x < width; x++)
927117f1b4Smrg	 printf("0x%02x, ", bitmap[width * (height - y - 1) + x]);
937117f1b4Smrg      putchar('\n');
947117f1b4Smrg   }
957117f1b4Smrg}
967117f1b4Smrg#endif /* DEBUG */
977117f1b4Smrg
987117f1b4Smrg
997117f1b4Smrg/* Implementation.  */
1007117f1b4Smrg
1017117f1b4Smrg/* Fill a BITMAP with a character C from thew current font
1027117f1b4Smrg   in the graphics context GC.  WIDTH is the width in bytes
1037117f1b4Smrg   and HEIGHT is the height in bits.
1047117f1b4Smrg
1057117f1b4Smrg   Note that the generated bitmaps must be used with
1067117f1b4Smrg
1077117f1b4Smrg        glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
1087117f1b4Smrg        glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
1097117f1b4Smrg        glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
1107117f1b4Smrg        glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
1117117f1b4Smrg        glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
1127117f1b4Smrg        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
1137117f1b4Smrg
1147117f1b4Smrg   Possible optimizations:
1157117f1b4Smrg
1167117f1b4Smrg     * use only one reusable pixmap with the maximum dimensions.
1177117f1b4Smrg     * draw the entire font into a single pixmap (careful with
1187117f1b4Smrg       proportional fonts!).
1197117f1b4Smrg*/
1207117f1b4Smrg
1217117f1b4Smrg
1227117f1b4Smrg/*
1237117f1b4Smrg * Generate OpenGL-compatible bitmap.
1247117f1b4Smrg */
1257117f1b4Smrgstatic void
1267117f1b4Smrgfill_bitmap(Display * dpy, Window win, GC gc,
1277117f1b4Smrg	    unsigned int width, unsigned int height,
1287117f1b4Smrg	    int x0, int y0, unsigned int c, GLubyte * bitmap)
1297117f1b4Smrg{
1307117f1b4Smrg   XImage *image;
1317117f1b4Smrg   unsigned int x, y;
1327117f1b4Smrg   Pixmap pixmap;
1337117f1b4Smrg   XChar2b char2b;
1347117f1b4Smrg
1357117f1b4Smrg   pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1);
1367117f1b4Smrg   XSetForeground(dpy, gc, 0);
1377117f1b4Smrg   XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height);
1387117f1b4Smrg   XSetForeground(dpy, gc, 1);
1397117f1b4Smrg
1407117f1b4Smrg   char2b.byte1 = (c >> 8) & 0xff;
1417117f1b4Smrg   char2b.byte2 = (c & 0xff);
1427117f1b4Smrg
1437117f1b4Smrg   XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1);
1447117f1b4Smrg
1457117f1b4Smrg   image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap);
1467117f1b4Smrg   if (image) {
1477117f1b4Smrg      /* Fill the bitmap (X11 and OpenGL are upside down wrt each other).  */
1487117f1b4Smrg      for (y = 0; y < height; y++)
1497117f1b4Smrg	 for (x = 0; x < 8 * width; x++)
1507117f1b4Smrg	    if (XGetPixel(image, x, y))
1517117f1b4Smrg	       bitmap[width * (height - y - 1) + x / 8] |=
1527117f1b4Smrg		  (1 << (7 - (x % 8)));
1537117f1b4Smrg      XDestroyImage(image);
1547117f1b4Smrg   }
1557117f1b4Smrg
1567117f1b4Smrg   XFreePixmap(dpy, pixmap);
1577117f1b4Smrg}
1587117f1b4Smrg
1597117f1b4Smrg/*
1607117f1b4Smrg * determine if a given glyph is valid and return the
1617117f1b4Smrg * corresponding XCharStruct.
1627117f1b4Smrg */
1637117f1b4Smrgstatic XCharStruct *
1647117f1b4Smrgisvalid(XFontStruct * fs, unsigned int which)
1657117f1b4Smrg{
1667117f1b4Smrg   unsigned int rows, pages;
1677117f1b4Smrg   unsigned int byte1 = 0, byte2 = 0;
1687117f1b4Smrg   int i, valid = 1;
1697117f1b4Smrg
1707117f1b4Smrg   rows = fs->max_byte1 - fs->min_byte1 + 1;
1717117f1b4Smrg   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
1727117f1b4Smrg
1737117f1b4Smrg   if (rows == 1) {
1747117f1b4Smrg      /* "linear" fonts */
1757117f1b4Smrg      if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
1767117f1b4Smrg	 valid = 0;
1777117f1b4Smrg   }
1787117f1b4Smrg   else {
1797117f1b4Smrg      /* "matrix" fonts */
1807117f1b4Smrg      byte2 = which & 0xff;
1817117f1b4Smrg      byte1 = which >> 8;
1827117f1b4Smrg      if ((fs->min_char_or_byte2 > byte2) ||
1837117f1b4Smrg	  (fs->max_char_or_byte2 < byte2) ||
1847117f1b4Smrg	  (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
1857117f1b4Smrg	 valid = 0;
1867117f1b4Smrg   }
1877117f1b4Smrg
1887117f1b4Smrg   if (valid) {
1897117f1b4Smrg      if (fs->per_char) {
1907117f1b4Smrg	 if (rows == 1) {
1917117f1b4Smrg	    /* "linear" fonts */
1927117f1b4Smrg	    return (fs->per_char + (which - fs->min_char_or_byte2));
1937117f1b4Smrg	 }
1947117f1b4Smrg	 else {
1957117f1b4Smrg	    /* "matrix" fonts */
1967117f1b4Smrg	    i = ((byte1 - fs->min_byte1) * pages) +
1977117f1b4Smrg	       (byte2 - fs->min_char_or_byte2);
1987117f1b4Smrg	    return (fs->per_char + i);
1997117f1b4Smrg	 }
2007117f1b4Smrg      }
2017117f1b4Smrg      else {
2027117f1b4Smrg	 return (&fs->min_bounds);
2037117f1b4Smrg      }
2047117f1b4Smrg   }
2057117f1b4Smrg   return (NULL);
2067117f1b4Smrg}
2077117f1b4Smrg
2087117f1b4Smrg
2097117f1b4Smrgvoid
2107117f1b4SmrgFake_glXUseXFont(Font font, int first, int count, int listbase)
2117117f1b4Smrg{
2127117f1b4Smrg   Display *dpy;
2137117f1b4Smrg   Window win;
2147117f1b4Smrg   Pixmap pixmap;
2157117f1b4Smrg   GC gc;
2167117f1b4Smrg   XGCValues values;
2177117f1b4Smrg   unsigned long valuemask;
2187117f1b4Smrg   XFontStruct *fs;
2197117f1b4Smrg   GLint swapbytes, lsbfirst, rowlength;
2207117f1b4Smrg   GLint skiprows, skippixels, alignment;
2217117f1b4Smrg   unsigned int max_width, max_height, max_bm_width, max_bm_height;
2227117f1b4Smrg   GLubyte *bm;
2237117f1b4Smrg   int i;
2247117f1b4Smrg
2257117f1b4Smrg   dpy = glXGetCurrentDisplay();
2267117f1b4Smrg   if (!dpy)
2277117f1b4Smrg      return;			/* I guess glXMakeCurrent wasn't called */
2287117f1b4Smrg   win = RootWindow(dpy, DefaultScreen(dpy));
2297117f1b4Smrg
2307117f1b4Smrg   fs = XQueryFont(dpy, font);
2317117f1b4Smrg   if (!fs) {
2327117f1b4Smrg      _mesa_error(NULL, GL_INVALID_VALUE,
2337117f1b4Smrg		  "Couldn't get font structure information");
2347117f1b4Smrg      return;
2357117f1b4Smrg   }
2367117f1b4Smrg
2377117f1b4Smrg   /* Allocate a bitmap that can fit all characters.  */
2387117f1b4Smrg   max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
2397117f1b4Smrg   max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
2407117f1b4Smrg   max_bm_width = (max_width + 7) / 8;
2417117f1b4Smrg   max_bm_height = max_height;
2427117f1b4Smrg
243af69d88dSmrg   bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
2447117f1b4Smrg   if (!bm) {
2457117f1b4Smrg      XFreeFontInfo(NULL, fs, 1);
2467117f1b4Smrg      _mesa_error(NULL, GL_OUT_OF_MEMORY,
2477117f1b4Smrg		  "Couldn't allocate bitmap in glXUseXFont()");
2487117f1b4Smrg      return;
2497117f1b4Smrg   }
2507117f1b4Smrg
2517117f1b4Smrg#if 0
2527117f1b4Smrg   /* get the page info */
2537117f1b4Smrg   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
2547117f1b4Smrg   firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
2557117f1b4Smrg   lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
2567117f1b4Smrg   rows = fs->max_byte1 - fs->min_byte1 + 1;
2577117f1b4Smrg   unsigned int first_char, last_char, pages, rows;
2587117f1b4Smrg#endif
2597117f1b4Smrg
2607117f1b4Smrg   /* Save the current packing mode for bitmaps.  */
2617117f1b4Smrg   glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
2627117f1b4Smrg   glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
2637117f1b4Smrg   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
2647117f1b4Smrg   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
2657117f1b4Smrg   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
2667117f1b4Smrg   glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
2677117f1b4Smrg
2687117f1b4Smrg   /* Enforce a standard packing mode which is compatible with
2697117f1b4Smrg      fill_bitmap() from above.  This is actually the default mode,
2707117f1b4Smrg      except for the (non)alignment.  */
2717117f1b4Smrg   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
2727117f1b4Smrg   glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
2737117f1b4Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2747117f1b4Smrg   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
2757117f1b4Smrg   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
2767117f1b4Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2777117f1b4Smrg
2787117f1b4Smrg   pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
2797117f1b4Smrg   values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
2807117f1b4Smrg   values.background = WhitePixel(dpy, DefaultScreen(dpy));
2817117f1b4Smrg   values.font = fs->fid;
2827117f1b4Smrg   valuemask = GCForeground | GCBackground | GCFont;
2837117f1b4Smrg   gc = XCreateGC(dpy, pixmap, valuemask, &values);
2847117f1b4Smrg   XFreePixmap(dpy, pixmap);
2857117f1b4Smrg
2867117f1b4Smrg#ifdef DEBUG
2877117f1b4Smrg   if (debug_xfonts)
2887117f1b4Smrg      dump_font_struct(fs);
2897117f1b4Smrg#endif
2907117f1b4Smrg
2917117f1b4Smrg   for (i = 0; i < count; i++) {
2927117f1b4Smrg      unsigned int width, height, bm_width, bm_height;
2937117f1b4Smrg      GLfloat x0, y0, dx, dy;
2947117f1b4Smrg      XCharStruct *ch;
2957117f1b4Smrg      int x, y;
2967117f1b4Smrg      unsigned int c = first + i;
2977117f1b4Smrg      int list = listbase + i;
2987117f1b4Smrg      int valid;
2997117f1b4Smrg
3007117f1b4Smrg      /* check on index validity and get the bounds */
3017117f1b4Smrg      ch = isvalid(fs, c);
3027117f1b4Smrg      if (!ch) {
3037117f1b4Smrg	 ch = &fs->max_bounds;
3047117f1b4Smrg	 valid = 0;
3057117f1b4Smrg      }
3067117f1b4Smrg      else {
3077117f1b4Smrg	 valid = 1;
3087117f1b4Smrg      }
3097117f1b4Smrg
3107117f1b4Smrg#ifdef DEBUG
3117117f1b4Smrg      if (debug_xfonts) {
3127117f1b4Smrg	 char s[7];
3137117f1b4Smrg	 sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
3147117f1b4Smrg	 dump_char_struct(ch, s);
3157117f1b4Smrg      }
3167117f1b4Smrg#endif
3177117f1b4Smrg
3187117f1b4Smrg      /* glBitmap()' parameters:
3197117f1b4Smrg         straight from the glXUseXFont(3) manpage.  */
3207117f1b4Smrg      width = ch->rbearing - ch->lbearing;
3217117f1b4Smrg      height = ch->ascent + ch->descent;
3227117f1b4Smrg      x0 = -ch->lbearing;
3237117f1b4Smrg      y0 = ch->descent - 0;	/* XXX used to subtract 1 here */
3247117f1b4Smrg      /* but that caused a conformace failure */
3257117f1b4Smrg      dx = ch->width;
3267117f1b4Smrg      dy = 0;
3277117f1b4Smrg
3287117f1b4Smrg      /* X11's starting point.  */
3297117f1b4Smrg      x = -ch->lbearing;
3307117f1b4Smrg      y = ch->ascent;
3317117f1b4Smrg
3327117f1b4Smrg      /* Round the width to a multiple of eight.  We will use this also
3337117f1b4Smrg         for the pixmap for capturing the X11 font.  This is slightly
3347117f1b4Smrg         inefficient, but it makes the OpenGL part real easy.  */
3357117f1b4Smrg      bm_width = (width + 7) / 8;
3367117f1b4Smrg      bm_height = height;
3377117f1b4Smrg
3387117f1b4Smrg      glNewList(list, GL_COMPILE);
3397117f1b4Smrg      if (valid && (bm_width > 0) && (bm_height > 0)) {
3407117f1b4Smrg
341cdc920a0Smrg	 memset(bm, '\0', bm_width * bm_height);
3427117f1b4Smrg	 fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
3437117f1b4Smrg
3447117f1b4Smrg	 glBitmap(width, height, x0, y0, dx, dy, bm);
3457117f1b4Smrg#ifdef DEBUG
3467117f1b4Smrg	 if (debug_xfonts) {
3477117f1b4Smrg	    printf("width/height = %u/%u\n", width, height);
3487117f1b4Smrg	    printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
3497117f1b4Smrg	    dump_bitmap(bm_width, bm_height, bm);
3507117f1b4Smrg	 }
3517117f1b4Smrg#endif
3527117f1b4Smrg      }
3537117f1b4Smrg      else {
3547117f1b4Smrg	 glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
3557117f1b4Smrg      }
3567117f1b4Smrg      glEndList();
3577117f1b4Smrg   }
3587117f1b4Smrg
359af69d88dSmrg   free(bm);
3607117f1b4Smrg   XFreeFontInfo(NULL, fs, 1);
3617117f1b4Smrg   XFreeGC(dpy, gc);
3627117f1b4Smrg
3637117f1b4Smrg   /* Restore saved packing modes.  */
3647117f1b4Smrg   glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
3657117f1b4Smrg   glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
3667117f1b4Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
3677117f1b4Smrg   glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
3687117f1b4Smrg   glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
3697117f1b4Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
3707117f1b4Smrg}
371