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(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
225   GLint swapbytes, lsbfirst, rowlength;
226   GLint skiprows, skippixels, alignment;
227
228   unsigned int max_width, max_height, max_bm_width, max_bm_height;
229   GLubyte *bm;
230
231   int i;
232
233   dpy = CC->currentDpy;
234   win = CC->currentDrawable;
235
236   fs = XQueryFont(dpy, font);
237   if (!fs) {
238      __glXSetError(CC, GL_INVALID_VALUE);
239      return;
240   }
241
242   /* Allocate a bitmap that can fit all characters.  */
243   max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
244   max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
245   max_bm_width = (max_width + 7) / 8;
246   max_bm_height = max_height;
247
248   bm = (GLubyte *) Xmalloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
249   if (!bm) {
250      XFreeFontInfo(NULL, fs, 1);
251      __glXSetError(CC, GL_OUT_OF_MEMORY);
252      return;
253   }
254
255#if 0
256   /* get the page info */
257   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
258   firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
259   lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
260   rows = fs->max_byte1 - fs->min_byte1 + 1;
261   unsigned int first_char, last_char, pages, rows;
262#endif
263
264   /* Save the current packing mode for bitmaps.  */
265   glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
266   glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
267   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
268   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
269   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
270   glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
271
272   /* Enforce a standard packing mode which is compatible with
273      fill_bitmap() from above.  This is actually the default mode,
274      except for the (non)alignment.  */
275   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
276   glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
277   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
278   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
279   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
280   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
281
282   pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
283   values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
284   values.background = WhitePixel(dpy, DefaultScreen(dpy));
285   values.font = fs->fid;
286   valuemask = GCForeground | GCBackground | GCFont;
287   gc = XCreateGC(dpy, pixmap, valuemask, &values);
288   XFreePixmap(dpy, pixmap);
289
290#ifdef DEBUG
291   if (debug_xfonts)
292      dump_font_struct(fs);
293#endif
294
295   for (i = 0; i < count; i++) {
296      unsigned int width, height, bm_width, bm_height;
297      GLfloat x0, y0, dx, dy;
298      XCharStruct *ch;
299      int x, y;
300      unsigned int c = first + i;
301      int list = listbase + i;
302      int valid;
303
304      /* check on index validity and get the bounds */
305      ch = isvalid(fs, c);
306      if (!ch) {
307         ch = &fs->max_bounds;
308         valid = 0;
309      }
310      else {
311         valid = 1;
312      }
313
314#ifdef DEBUG
315      if (debug_xfonts) {
316         char s[7];
317         sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
318         dump_char_struct(ch, s);
319      }
320#endif
321
322      /* glBitmap()' parameters:
323         straight from the glXUseXFont(3) manpage.  */
324      width = ch->rbearing - ch->lbearing;
325      height = ch->ascent + ch->descent;
326      x0 = -ch->lbearing;
327      y0 = ch->descent - 1;
328      dx = ch->width;
329      dy = 0;
330
331      /* X11's starting point.  */
332      x = -ch->lbearing;
333      y = ch->ascent;
334
335      /* Round the width to a multiple of eight.  We will use this also
336         for the pixmap for capturing the X11 font.  This is slightly
337         inefficient, but it makes the OpenGL part real easy.  */
338      bm_width = (width + 7) / 8;
339      bm_height = height;
340
341      glNewList(list, GL_COMPILE);
342      if (valid && (bm_width > 0) && (bm_height > 0)) {
343
344         memset(bm, '\0', bm_width * bm_height);
345         fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
346
347         glBitmap(width, height, x0, y0, dx, dy, bm);
348#ifdef DEBUG
349         if (debug_xfonts) {
350            printf("width/height = %u/%u\n", width, height);
351            printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
352            dump_bitmap(bm_width, bm_height, bm);
353         }
354#endif
355      }
356      else {
357         glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
358      }
359      glEndList();
360   }
361
362   Xfree(bm);
363   XFreeFontInfo(NULL, fs, 1);
364   XFreeGC(dpy, gc);
365
366   /* Restore saved packing modes.  */
367   glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
368   glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
369   glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
370   glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
371   glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
372   glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
373}
374
375#endif
376