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