xfont.c revision 6e8897ff9f90601ebf6eed500ad942c11b54d1f7
1/*
2 * Mesa 3-D graphics library
3 * Version:  3.1
4 *
5 * Copyright (C) 1999  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR 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(Font font, int first, int count, int listbase)
216{
217   GLXContext CC;
218   Display *dpy;
219   Window win;
220   Pixmap pixmap;
221   GC gc;
222   XGCValues values;
223   unsigned long valuemask;
224   XFontStruct *fs;
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   CC = __glXGetCurrentContext();
235   dpy = CC->currentDpy;
236   win = CC->currentDrawable;
237
238   fs = XQueryFont(dpy, font);
239   if (!fs) {
240      __glXSetError(CC, GL_INVALID_VALUE);
241      return;
242   }
243
244   /* Allocate a bitmap that can fit all characters.  */
245   max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
246   max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
247   max_bm_width = (max_width + 7) / 8;
248   max_bm_height = max_height;
249
250   bm = (GLubyte *) Xmalloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
251   if (!bm) {
252      XFreeFontInfo(NULL, fs, 1);
253      __glXSetError(CC, GL_OUT_OF_MEMORY);
254      return;
255   }
256
257#if 0
258   /* get the page info */
259   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
260   firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
261   lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
262   rows = fs->max_byte1 - fs->min_byte1 + 1;
263   unsigned int first_char, last_char, pages, rows;
264#endif
265
266   /* Save the current packing mode for bitmaps.  */
267   glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
268   glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
269   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
270   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
271   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
272   glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
273
274   /* Enforce a standard packing mode which is compatible with
275      fill_bitmap() from above.  This is actually the default mode,
276      except for the (non)alignment.  */
277   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
278   glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
279   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
280   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
281   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
282   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
283
284   pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
285   values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
286   values.background = WhitePixel(dpy, DefaultScreen(dpy));
287   values.font = fs->fid;
288   valuemask = GCForeground | GCBackground | GCFont;
289   gc = XCreateGC(dpy, pixmap, valuemask, &values);
290   XFreePixmap(dpy, pixmap);
291
292#ifdef DEBUG
293   if (debug_xfonts)
294      dump_font_struct(fs);
295#endif
296
297   for (i = 0; i < count; i++) {
298      unsigned int width, height, bm_width, bm_height;
299      GLfloat x0, y0, dx, dy;
300      XCharStruct *ch;
301      int x, y;
302      unsigned int c = first + i;
303      int list = listbase + i;
304      int valid;
305
306      /* check on index validity and get the bounds */
307      ch = isvalid(fs, c);
308      if (!ch) {
309         ch = &fs->max_bounds;
310         valid = 0;
311      }
312      else {
313         valid = 1;
314      }
315
316#ifdef DEBUG
317      if (debug_xfonts) {
318         char s[7];
319         sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
320         dump_char_struct(ch, s);
321      }
322#endif
323
324      /* glBitmap()' parameters:
325         straight from the glXUseXFont(3) manpage.  */
326      width = ch->rbearing - ch->lbearing;
327      height = ch->ascent + ch->descent;
328      x0 = -ch->lbearing;
329      y0 = ch->descent - 1;
330      dx = ch->width;
331      dy = 0;
332
333      /* X11's starting point.  */
334      x = -ch->lbearing;
335      y = ch->ascent;
336
337      /* Round the width to a multiple of eight.  We will use this also
338         for the pixmap for capturing the X11 font.  This is slightly
339         inefficient, but it makes the OpenGL part real easy.  */
340      bm_width = (width + 7) / 8;
341      bm_height = height;
342
343      glNewList(list, GL_COMPILE);
344      if (valid && (bm_width > 0) && (bm_height > 0)) {
345
346         memset(bm, '\0', bm_width * bm_height);
347         fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
348
349         glBitmap(width, height, x0, y0, dx, dy, bm);
350#ifdef DEBUG
351         if (debug_xfonts) {
352            printf("width/height = %u/%u\n", width, height);
353            printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
354            dump_bitmap(bm_width, bm_height, bm);
355         }
356#endif
357      }
358      else {
359         glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
360      }
361      glEndList();
362   }
363
364   Xfree(bm);
365   XFreeFontInfo(NULL, fs, 1);
366   XFreeGC(dpy, gc);
367
368   /* Restore saved packing modes.  */
369   glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
370   glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
371   glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
372   glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
373   glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
374   glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
375}
376
377#endif
378