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