• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "main/imports.h"
35 #include "xfonts.h"
36 
37 
38 /* Some debugging info.  */
39 
40 #ifdef DEBUG
41 #include <ctype.h>
42 
43 int debug_xfonts = 0;
44 
45 static void
dump_char_struct(XCharStruct * ch,char * prefix)46 dump_char_struct(XCharStruct * ch, char *prefix)
47 {
48    printf("%slbearing = %d, rbearing = %d, width = %d\n",
49 	  prefix, ch->lbearing, ch->rbearing, ch->width);
50    printf("%sascent = %d, descent = %d, attributes = %u\n",
51 	  prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
52 }
53 
54 static void
dump_font_struct(XFontStruct * font)55 dump_font_struct(XFontStruct * font)
56 {
57    printf("ascent = %d, descent = %d\n", font->ascent, font->descent);
58    printf("char_or_byte2 = (%u,%u)\n",
59 	  font->min_char_or_byte2, font->max_char_or_byte2);
60    printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
61    printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False");
62    printf("default_char = %c (\\%03o)\n",
63 	  (char) (isprint(font->default_char) ? font->default_char : ' '),
64 	  font->default_char);
65    dump_char_struct(&font->min_bounds, "min> ");
66    dump_char_struct(&font->max_bounds, "max> ");
67 #if 0
68    for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) {
69       char prefix[8];
70       sprintf(prefix, "%d> ", c);
71       dump_char_struct(&font->per_char[c], prefix);
72    }
73 #endif
74 }
75 
76 static void
dump_bitmap(unsigned int width,unsigned int height,GLubyte * bitmap)77 dump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap)
78 {
79    unsigned int x, y;
80 
81    printf("    ");
82    for (x = 0; x < 8 * width; x++)
83       printf("%o", 7 - (x % 8));
84    putchar('\n');
85    for (y = 0; y < height; y++) {
86       printf("%3o:", y);
87       for (x = 0; x < 8 * width; x++)
88 	 putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x %
89 									 8))))
90 		 ? '*' : '.');
91       printf("   ");
92       for (x = 0; x < width; x++)
93 	 printf("0x%02x, ", bitmap[width * (height - y - 1) + x]);
94       putchar('\n');
95    }
96 }
97 #endif /* DEBUG */
98 
99 
100 /* Implementation.  */
101 
102 /* Fill a BITMAP with a character C from thew current font
103    in the graphics context GC.  WIDTH is the width in bytes
104    and HEIGHT is the height in bits.
105 
106    Note that the generated bitmaps must be used with
107 
108         glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
109         glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
110         glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
111         glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
112         glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
113         glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
114 
115    Possible optimizations:
116 
117      * use only one reusable pixmap with the maximum dimensions.
118      * draw the entire font into a single pixmap (careful with
119        proportional fonts!).
120 */
121 
122 
123 /*
124  * Generate OpenGL-compatible bitmap.
125  */
126 static void
fill_bitmap(Display * dpy,Window win,GC gc,unsigned int width,unsigned int height,int x0,int y0,unsigned int c,GLubyte * bitmap)127 fill_bitmap(Display * dpy, Window win, GC gc,
128 	    unsigned int width, unsigned int height,
129 	    int x0, int y0, unsigned int c, GLubyte * bitmap)
130 {
131    XImage *image;
132    unsigned int x, y;
133    Pixmap pixmap;
134    XChar2b char2b;
135 
136    pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1);
137    XSetForeground(dpy, gc, 0);
138    XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height);
139    XSetForeground(dpy, gc, 1);
140 
141    char2b.byte1 = (c >> 8) & 0xff;
142    char2b.byte2 = (c & 0xff);
143 
144    XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1);
145 
146    image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap);
147    if (image) {
148       /* Fill the bitmap (X11 and OpenGL are upside down wrt each other).  */
149       for (y = 0; y < height; y++)
150 	 for (x = 0; x < 8 * width; x++)
151 	    if (XGetPixel(image, x, y))
152 	       bitmap[width * (height - y - 1) + x / 8] |=
153 		  (1 << (7 - (x % 8)));
154       XDestroyImage(image);
155    }
156 
157    XFreePixmap(dpy, pixmap);
158 }
159 
160 /*
161  * determine if a given glyph is valid and return the
162  * corresponding XCharStruct.
163  */
164 static XCharStruct *
isvalid(XFontStruct * fs,unsigned int which)165 isvalid(XFontStruct * fs, unsigned int which)
166 {
167    unsigned int rows, pages;
168    unsigned int byte1 = 0, byte2 = 0;
169    int i, valid = 1;
170 
171    rows = fs->max_byte1 - fs->min_byte1 + 1;
172    pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
173 
174    if (rows == 1) {
175       /* "linear" fonts */
176       if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
177 	 valid = 0;
178    }
179    else {
180       /* "matrix" fonts */
181       byte2 = which & 0xff;
182       byte1 = which >> 8;
183       if ((fs->min_char_or_byte2 > byte2) ||
184 	  (fs->max_char_or_byte2 < byte2) ||
185 	  (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
186 	 valid = 0;
187    }
188 
189    if (valid) {
190       if (fs->per_char) {
191 	 if (rows == 1) {
192 	    /* "linear" fonts */
193 	    return (fs->per_char + (which - fs->min_char_or_byte2));
194 	 }
195 	 else {
196 	    /* "matrix" fonts */
197 	    i = ((byte1 - fs->min_byte1) * pages) +
198 	       (byte2 - fs->min_char_or_byte2);
199 	    return (fs->per_char + i);
200 	 }
201       }
202       else {
203 	 return (&fs->min_bounds);
204       }
205    }
206    return (NULL);
207 }
208 
209 
210 void
Fake_glXUseXFont(Font font,int first,int count,int listbase)211 Fake_glXUseXFont(Font font, int first, int count, int listbase)
212 {
213    Display *dpy;
214    Window win;
215    Pixmap pixmap;
216    GC gc;
217    XGCValues values;
218    unsigned long valuemask;
219    XFontStruct *fs;
220    GLint swapbytes, lsbfirst, rowlength;
221    GLint skiprows, skippixels, alignment;
222    unsigned int max_width, max_height, max_bm_width, max_bm_height;
223    GLubyte *bm;
224    int i;
225 
226    dpy = glXGetCurrentDisplay();
227    if (!dpy)
228       return;			/* I guess glXMakeCurrent wasn't called */
229    win = RootWindow(dpy, DefaultScreen(dpy));
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 = 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