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