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