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