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