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