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