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