xfonts.c revision 6fc61407a31dc1ea2e00b803c7f6d355f278fb0d
1/* $Id: xfonts.c,v 1.5 1999/12/12 17:04:50 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.3
6 *
7 * Copyright (C) 1999  Brian Paul   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/* xfonts.c -- glXUseXFont() for Mesa written by
29 * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de
30 */
31
32
33#ifdef HAVE_CONFIG_H
34#include "conf.h"
35#endif
36
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <X11/Xlib.h>
41#include <X11/Xutil.h>
42#include "GL/gl.h"
43#include "GL/glx.h"
44#include "GL/xmesa.h"
45#include "context.h"
46#include "mem.h"
47#include "xmesaP.h"
48
49/* Some debugging info.  */
50
51#ifdef DEBUG
52#undef _R
53#undef _G
54#undef _B
55#include <ctype.h>
56
57int debug_xfonts = 0;
58
59static void
60dump_char_struct (XCharStruct *ch, char *prefix)
61{
62  printf ("%slbearing = %d, rbearing = %d, width = %d\n",
63          prefix, ch->lbearing, ch->rbearing, ch->width);
64  printf ("%sascent = %d, descent = %d, attributes = %u\n",
65          prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
66}
67
68static void
69dump_font_struct (XFontStruct *font)
70{
71  printf ("ascent = %d, descent = %d\n", font->ascent, font->descent);
72  printf ("char_or_byte2 = (%u,%u)\n",
73          font->min_char_or_byte2, font->max_char_or_byte2);
74  printf ("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
75  printf ("all_chars_exist = %s\n", font->all_chars_exist ? "True" :
76"False");
77  printf ("default_char = %c (\\%03o)\n",
78          (char) (isprint (font->default_char) ? font->default_char : ' '),
79          font->default_char);
80  dump_char_struct (&font->min_bounds, "min> ");
81  dump_char_struct (&font->max_bounds, "max> ");
82#if 0
83  for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++)
84    {
85      char prefix[8];
86      sprintf (prefix, "%d> ", c);
87      dump_char_struct (&font->per_char[c], prefix);
88    }
89#endif
90}
91
92static void
93dump_bitmap (unsigned int width, unsigned int height, GLubyte *bitmap)
94{
95  unsigned int x, y;
96
97  printf ("    ");
98  for (x = 0; x < 8*width; x++)
99    printf ("%o", 7 - (x % 8));
100  putchar ('\n');
101  for (y = 0; y < height; y++)
102    {
103      printf ("%3o:", y);
104      for (x = 0; x < 8*width; x++)
105        putchar ((bitmap[width*(height - y - 1) + x/8] & (1 << (7 - (x %
1068))))
107                 ? '*' : '.');
108      printf ("   ");
109      for (x = 0; x < width; x++)
110        printf ("0x%02x, ", bitmap[width*(height - y - 1) + x]);
111      putchar ('\n');
112    }
113}
114#endif /* DEBUG */
115
116
117/* Implementation.  */
118
119/* Fill a BITMAP with a character C from thew current font
120   in the graphics context GC.  WIDTH is the width in bytes
121   and HEIGHT is the height in bits.
122
123   Note that the generated bitmaps must be used with
124
125        glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
126        glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
127        glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
128        glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
129        glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
130        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
131
132   Possible optimizations:
133
134     * use only one reusable pixmap with the maximum dimensions.
135     * draw the entire font into a single pixmap (careful with
136       proportional fonts!).
137*/
138
139
140/*
141 * Generate OpenGL-compatible bitmap.
142 */
143static void
144fill_bitmap (Display *dpy, Window win, GC gc,
145             unsigned int width, unsigned int height,
146             int x0, int y0, unsigned int c, GLubyte *bitmap)
147{
148  XImage *image;
149  unsigned int x, y;
150  Pixmap pixmap;
151  XChar2b char2b;
152
153  pixmap = XCreatePixmap (dpy, win, 8*width, height, 1);
154  XSetForeground(dpy, gc, 0);
155  XFillRectangle (dpy, pixmap, gc, 0, 0, 8*width, height);
156  XSetForeground(dpy, gc, 1);
157
158  char2b.byte1 = (c >> 8) & 0xff;
159  char2b.byte2 = (c & 0xff);
160
161  XDrawString16 (dpy, pixmap, gc, x0, y0, &char2b, 1);
162
163  image = XGetImage (dpy, pixmap, 0, 0, 8*width, height, 1, XYPixmap);
164  if (image) {
165    /* Fill the bitmap (X11 and OpenGL are upside down wrt each other).  */
166    for (y = 0; y < height; y++)
167      for (x = 0; x < 8*width; x++)
168        if (XGetPixel (image, x, y))
169          bitmap[width*(height - y - 1) + x/8] |= (1 << (7 - (x % 8)));
170    XDestroyImage (image);
171  }
172
173  XFreePixmap (dpy, pixmap);
174}
175
176/*
177 * determine if a given glyph is valid and return the
178 * corresponding XCharStruct.
179 */
180static XCharStruct *isvalid(XFontStruct *fs, int which)
181{
182  unsigned int  rows,pages;
183  int           byte1,byte2;
184  int           i,valid = 1;
185
186  rows = fs->max_byte1 - fs->min_byte1 + 1;
187  pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
188
189  if (rows == 1) {
190    /* "linear" fonts */
191    if ((fs->min_char_or_byte2 > which) ||
192        (fs->max_char_or_byte2 < which)) valid = 0;
193  } else {
194    /* "matrix" fonts */
195    byte2 = which & 0xff;
196    byte1 = which >> 8;
197    if ((fs->min_char_or_byte2 > byte2) ||
198        (fs->max_char_or_byte2 < byte2) ||
199        (fs->min_byte1 > byte1) ||
200        (fs->max_byte1 < byte1)) valid = 0;
201  }
202
203  if (valid) {
204    if (fs->per_char) {
205      if (rows == 1) {
206        /* "linear" fonts */
207        return(fs->per_char + (which-fs->min_char_or_byte2) );
208      } else {
209        /* "matrix" fonts */
210        i = ((byte1 - fs->min_byte1) * pages) +
211             (byte2 - fs->min_char_or_byte2);
212        return(fs->per_char + i);
213      }
214    } else {
215        return(&fs->min_bounds);
216    }
217  }
218  return(NULL);
219}
220
221
222void Fake_glXUseXFont( Font font, int first, int count, int listbase )
223{
224  XMesaContext CC;
225  Display *dpy;
226  Window win;
227  Pixmap pixmap;
228  GC gc;
229  XGCValues values;
230  unsigned long valuemask;
231  XFontStruct *fs;
232
233  GLint swapbytes, lsbfirst, rowlength;
234  GLint skiprows, skippixels, alignment;
235
236  unsigned int max_width, max_height, max_bm_width, max_bm_height;
237  GLubyte *bm;
238
239  int i;
240
241  CC = XMesaGetCurrentContext();
242  dpy = CC->display;
243  win = CC->xm_buffer->frontbuffer;
244
245  fs = XQueryFont (dpy, font);
246  if (!fs)
247    {
248      gl_error (CC->gl_ctx, GL_INVALID_VALUE,
249                "Couldn't get font structure information");
250      return;
251    }
252
253  /* Allocate a bitmap that can fit all characters.  */
254  max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
255  max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
256  max_bm_width = (max_width + 7) / 8;
257  max_bm_height = max_height;
258
259  bm = (GLubyte *) MALLOC((max_bm_width * max_bm_height) * sizeof
260(GLubyte));
261  if (!bm) {
262      XFreeFontInfo( NULL, fs, 0 );
263      gl_error (CC->gl_ctx, GL_OUT_OF_MEMORY,
264                "Couldn't allocate bitmap in glXUseXFont()");
265      return;
266    }
267
268#if 0
269  /* get the page info */
270  pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
271  firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
272  lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
273  rows = fs->max_byte1 - fs->min_byte1 + 1;
274  unsigned int first_char, last_char, pages, rows;
275#endif
276
277  /* Save the current packing mode for bitmaps.  */
278  glGetIntegerv (GL_UNPACK_SWAP_BYTES, &swapbytes);
279  glGetIntegerv (GL_UNPACK_LSB_FIRST, &lsbfirst);
280  glGetIntegerv (GL_UNPACK_ROW_LENGTH, &rowlength);
281  glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skiprows);
282  glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skippixels);
283  glGetIntegerv (GL_UNPACK_ALIGNMENT, &alignment);
284
285  /* Enforce a standard packing mode which is compatible with
286     fill_bitmap() from above.  This is actually the default mode,
287     except for the (non)alignment.  */
288  glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
289  glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
290  glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
291  glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
292  glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
293  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
294
295  pixmap = XCreatePixmap (dpy, win, 10, 10, 1);
296  values.foreground = BlackPixel (dpy, DefaultScreen (dpy));
297  values.background = WhitePixel (dpy, DefaultScreen (dpy));
298  values.font = fs->fid;
299  valuemask = GCForeground | GCBackground | GCFont;
300  gc = XCreateGC (dpy, pixmap, valuemask, &values);
301  XFreePixmap (dpy, pixmap);
302
303#ifdef DEBUG
304  if (debug_xfonts)
305    dump_font_struct (fs);
306#endif
307
308  for (i = 0; i < count; i++)
309    {
310      unsigned int width, height, bm_width, bm_height;
311      GLfloat x0, y0, dx, dy;
312      XCharStruct *ch;
313      int x, y;
314      unsigned int c = first + i;
315      int list = listbase + i;
316      int valid;
317
318      /* check on index validity and get the bounds */
319      ch = isvalid(fs, c);
320      if (!ch) {
321        ch = &fs->max_bounds;
322        valid = 0;
323      } else {
324        valid = 1;
325      }
326
327#ifdef DEBUG
328      if (debug_xfonts) {
329          char s[7];
330          sprintf (s, isprint (c) ? "%c> " : "\\%03o> ", c);
331          dump_char_struct (ch, s);
332      }
333#endif
334
335      /* glBitmap()' parameters:
336         straight from the glXUseXFont(3) manpage.  */
337      width = ch->rbearing - ch->lbearing;
338      height = ch->ascent + ch->descent;
339      x0 = - ch->lbearing;
340      y0 = ch->descent - 0;  /* XXX used to subtract 1 here */
341                             /* but that caused a conformace failure */
342      dx = ch->width;
343      dy = 0;
344
345      /* X11's starting point.  */
346      x = - ch->lbearing;
347      y = ch->ascent;
348
349      /* Round the width to a multiple of eight.  We will use this also
350         for the pixmap for capturing the X11 font.  This is slightly
351         inefficient, but it makes the OpenGL part real easy.  */
352      bm_width = (width + 7) / 8;
353      bm_height = height;
354
355      glNewList (list, GL_COMPILE);
356        if (valid && (bm_width > 0) && (bm_height > 0)) {
357
358            MEMSET (bm, '\0', bm_width * bm_height);
359            fill_bitmap (dpy, win, gc, bm_width, bm_height, x, y, c, bm);
360
361            glBitmap (width, height, x0, y0, dx, dy, bm);
362#ifdef DEBUG
363            if (debug_xfonts) {
364                printf ("width/height = %u/%u\n", width, height);
365                printf ("bm_width/bm_height = %u/%u\n", bm_width,
366bm_height);
367                dump_bitmap (bm_width, bm_height, bm);
368              }
369#endif
370          } else {
371            glBitmap (0, 0, 0.0, 0.0, dx, dy, NULL);
372          }
373      glEndList ();
374    }
375
376  free (bm);
377  XFreeFontInfo( NULL, fs, 0 );
378  XFreeGC (dpy, gc);
379
380  /* Restore saved packing modes.  */
381  glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
382  glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
383  glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
384  glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
385  glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
386  glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
387}
388
389void xmesa_xfonts_dummy( void )
390{
391   /* silence unused var warnings */
392   (void) kernel8;
393   (void) DitherValues;
394   (void) HPCR_DRGB;
395   (void) kernel1;
396}
397
398/* The End. */
399