1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg/* xfonts.c -- glXUseXFont() for Mesa written by
27848b8605Smrg * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de
28848b8605Smrg */
29848b8605Smrg
30848b8605Smrg/*
31848b8605Smrg  This was take from Mesa and modified to work in the real GLX structure.
32848b8605Smrg  It provides a fully client side implementation of glXUseXFont and is
33848b8605Smrg  called by that routine when direct rendering is enabled.
34848b8605Smrg*/
35848b8605Smrg
36848b8605Smrg#ifdef GLX_DIRECT_RENDERING
37848b8605Smrg
38848b8605Smrg#include "glxclient.h"
39848b8605Smrg
40848b8605Smrg/* Some debugging info.  */
41848b8605Smrg
42848b8605Smrg#ifdef DEBUG
43848b8605Smrg#undef _R
44848b8605Smrg#undef _G
45848b8605Smrg#undef _B
46848b8605Smrg#include <ctype.h>
47848b8605Smrg
48848b8605Smrgint debug_xfonts = 0;
49848b8605Smrg
50848b8605Smrgstatic void
51848b8605Smrgdump_char_struct(XCharStruct * ch, char *prefix)
52848b8605Smrg{
53848b8605Smrg   printf("%slbearing = %d, rbearing = %d, width = %d\n",
54848b8605Smrg          prefix, ch->lbearing, ch->rbearing, ch->width);
55848b8605Smrg   printf("%sascent = %d, descent = %d, attributes = %u\n",
56848b8605Smrg          prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
57848b8605Smrg}
58848b8605Smrg
59848b8605Smrgstatic void
60848b8605Smrgdump_font_struct(XFontStruct * font)
61848b8605Smrg{
62848b8605Smrg   printf("ascent = %d, descent = %d\n", font->ascent, font->descent);
63848b8605Smrg   printf("char_or_byte2 = (%u,%u)\n",
64848b8605Smrg          font->min_char_or_byte2, font->max_char_or_byte2);
65848b8605Smrg   printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
66848b8605Smrg   printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False");
67848b8605Smrg   printf("default_char = %c (\\%03o)\n",
68848b8605Smrg          (char) (isprint(font->default_char) ? font->default_char : ' '),
69848b8605Smrg          font->default_char);
70848b8605Smrg   dump_char_struct(&font->min_bounds, "min> ");
71848b8605Smrg   dump_char_struct(&font->max_bounds, "max> ");
72848b8605Smrg#if 0
73848b8605Smrg   for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) {
74848b8605Smrg      char prefix[8];
75848b8605Smrg      sprintf(prefix, "%d> ", c);
76848b8605Smrg      dump_char_struct(&font->per_char[c], prefix);
77848b8605Smrg   }
78848b8605Smrg#endif
79848b8605Smrg}
80848b8605Smrg
81848b8605Smrgstatic void
82848b8605Smrgdump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap)
83848b8605Smrg{
84848b8605Smrg   unsigned int x, y;
85848b8605Smrg
86848b8605Smrg   printf("    ");
87848b8605Smrg   for (x = 0; x < 8 * width; x++)
88848b8605Smrg      printf("%o", 7 - (x % 8));
89848b8605Smrg   putchar('\n');
90848b8605Smrg   for (y = 0; y < height; y++) {
91848b8605Smrg      printf("%3o:", y);
92848b8605Smrg      for (x = 0; x < 8 * width; x++)
93848b8605Smrg         putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x %
94848b8605Smrg                                                                         8))))
95848b8605Smrg                 ? '*' : '.');
96848b8605Smrg      printf("   ");
97848b8605Smrg      for (x = 0; x < width; x++)
98848b8605Smrg         printf("0x%02x, ", bitmap[width * (height - y - 1) + x]);
99848b8605Smrg      putchar('\n');
100848b8605Smrg   }
101848b8605Smrg}
102848b8605Smrg#endif /* DEBUG */
103848b8605Smrg
104848b8605Smrg
105848b8605Smrg/* Implementation.  */
106848b8605Smrg
107848b8605Smrg/* Fill a BITMAP with a character C from thew current font
108848b8605Smrg   in the graphics context GC.  WIDTH is the width in bytes
109848b8605Smrg   and HEIGHT is the height in bits.
110848b8605Smrg
111848b8605Smrg   Note that the generated bitmaps must be used with
112848b8605Smrg
113848b8605Smrg        glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
114848b8605Smrg        glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
115848b8605Smrg        glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
116848b8605Smrg        glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
117848b8605Smrg        glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
118848b8605Smrg        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
119848b8605Smrg
120848b8605Smrg   Possible optimizations:
121848b8605Smrg
122848b8605Smrg     * use only one reusable pixmap with the maximum dimensions.
123848b8605Smrg     * draw the entire font into a single pixmap (careful with
124848b8605Smrg       proportional fonts!).
125848b8605Smrg*/
126848b8605Smrg
127848b8605Smrg
128848b8605Smrg/*
129848b8605Smrg * Generate OpenGL-compatible bitmap.
130848b8605Smrg */
131848b8605Smrgstatic void
132848b8605Smrgfill_bitmap(Display * dpy, Window win, GC gc,
133848b8605Smrg            unsigned int width, unsigned int height,
134848b8605Smrg            int x0, int y0, unsigned int c, GLubyte * bitmap)
135848b8605Smrg{
136848b8605Smrg   XImage *image;
137848b8605Smrg   unsigned int x, y;
138848b8605Smrg   Pixmap pixmap;
139848b8605Smrg   XChar2b char2b;
140848b8605Smrg
141848b8605Smrg   pixmap = XCreatePixmap(dpy, win, 8 * width, height, 1);
142848b8605Smrg   XSetForeground(dpy, gc, 0);
143848b8605Smrg   XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height);
144848b8605Smrg   XSetForeground(dpy, gc, 1);
145848b8605Smrg
146848b8605Smrg   char2b.byte1 = (c >> 8) & 0xff;
147848b8605Smrg   char2b.byte2 = (c & 0xff);
148848b8605Smrg
149848b8605Smrg   XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1);
150848b8605Smrg
151848b8605Smrg   image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap);
152848b8605Smrg   if (image) {
153848b8605Smrg      /* Fill the bitmap (X11 and OpenGL are upside down wrt each other).  */
154848b8605Smrg      for (y = 0; y < height; y++)
155848b8605Smrg         for (x = 0; x < 8 * width; x++)
156848b8605Smrg            if (XGetPixel(image, x, y))
157848b8605Smrg               bitmap[width * (height - y - 1) + x / 8] |=
158848b8605Smrg                  (1 << (7 - (x % 8)));
159848b8605Smrg      XDestroyImage(image);
160848b8605Smrg   }
161848b8605Smrg
162848b8605Smrg   XFreePixmap(dpy, pixmap);
163848b8605Smrg}
164848b8605Smrg
165848b8605Smrg/*
166848b8605Smrg * determine if a given glyph is valid and return the
167848b8605Smrg * corresponding XCharStruct.
168848b8605Smrg */
169848b8605Smrgstatic XCharStruct *
170848b8605Smrgisvalid(XFontStruct * fs, int which)
171848b8605Smrg{
172848b8605Smrg   unsigned int rows, pages;
173848b8605Smrg   int byte1 = 0, byte2 = 0;
174848b8605Smrg   int i, valid = 1;
175848b8605Smrg
176848b8605Smrg   rows = fs->max_byte1 - fs->min_byte1 + 1;
177848b8605Smrg   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
178848b8605Smrg
179848b8605Smrg   if (rows == 1) {
180848b8605Smrg      /* "linear" fonts */
181848b8605Smrg      if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
182848b8605Smrg         valid = 0;
183848b8605Smrg   }
184848b8605Smrg   else {
185848b8605Smrg      /* "matrix" fonts */
186848b8605Smrg      byte2 = which & 0xff;
187848b8605Smrg      byte1 = which >> 8;
188848b8605Smrg      if ((fs->min_char_or_byte2 > byte2) ||
189848b8605Smrg          (fs->max_char_or_byte2 < byte2) ||
190848b8605Smrg          (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
191848b8605Smrg         valid = 0;
192848b8605Smrg   }
193848b8605Smrg
194848b8605Smrg   if (valid) {
195848b8605Smrg      if (fs->per_char) {
196848b8605Smrg         if (rows == 1) {
197848b8605Smrg            /* "linear" fonts */
198848b8605Smrg            return (fs->per_char + (which - fs->min_char_or_byte2));
199848b8605Smrg         }
200848b8605Smrg         else {
201848b8605Smrg            /* "matrix" fonts */
202848b8605Smrg            i = ((byte1 - fs->min_byte1) * pages) +
203848b8605Smrg               (byte2 - fs->min_char_or_byte2);
204848b8605Smrg            return (fs->per_char + i);
205848b8605Smrg         }
206848b8605Smrg      }
207848b8605Smrg      else {
208848b8605Smrg         return (&fs->min_bounds);
209848b8605Smrg      }
210848b8605Smrg   }
211848b8605Smrg   return (NULL);
212848b8605Smrg}
213848b8605Smrg
214848b8605Smrg_X_HIDDEN void
215848b8605SmrgDRI_glXUseXFont(struct glx_context *CC, Font font, int first, int count, int listbase)
216848b8605Smrg{
217848b8605Smrg   Display *dpy;
218848b8605Smrg   Window win;
219848b8605Smrg   Pixmap pixmap;
220848b8605Smrg   GC gc;
221848b8605Smrg   XGCValues values;
222848b8605Smrg   unsigned long valuemask;
223848b8605Smrg   XFontStruct *fs;
224b8e80941Smrg
225b8e80941Smrg#if !defined(GLX_USE_APPLEGL)
226848b8605Smrg   __GLXDRIdrawable *glxdraw;
227b8e80941Smrg#endif
228848b8605Smrg
229848b8605Smrg   GLint swapbytes, lsbfirst, rowlength;
230848b8605Smrg   GLint skiprows, skippixels, alignment;
231848b8605Smrg
232848b8605Smrg   unsigned int max_width, max_height, max_bm_width, max_bm_height;
233848b8605Smrg   GLubyte *bm;
234848b8605Smrg
235848b8605Smrg   int i;
236848b8605Smrg
237848b8605Smrg   dpy = CC->currentDpy;
238848b8605Smrg   win = CC->currentDrawable;
239848b8605Smrg
240b8e80941Smrg#if !defined(GLX_USE_APPLEGL)
241848b8605Smrg   glxdraw = GetGLXDRIDrawable(CC->currentDpy, CC->currentDrawable);
242848b8605Smrg   if (glxdraw)
243848b8605Smrg      win = glxdraw->xDrawable;
244b8e80941Smrg#endif
245848b8605Smrg
246848b8605Smrg   fs = XQueryFont(dpy, font);
247848b8605Smrg   if (!fs) {
248848b8605Smrg      __glXSetError(CC, GL_INVALID_VALUE);
249848b8605Smrg      return;
250848b8605Smrg   }
251848b8605Smrg
252848b8605Smrg   /* Allocate a bitmap that can fit all characters.  */
253848b8605Smrg   max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
254848b8605Smrg   max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
255848b8605Smrg   max_bm_width = (max_width + 7) / 8;
256848b8605Smrg   max_bm_height = max_height;
257848b8605Smrg
258848b8605Smrg   bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
259848b8605Smrg   if (!bm) {
260848b8605Smrg      XFreeFontInfo(NULL, fs, 1);
261848b8605Smrg      __glXSetError(CC, GL_OUT_OF_MEMORY);
262848b8605Smrg      return;
263848b8605Smrg   }
264848b8605Smrg
265848b8605Smrg#if 0
266848b8605Smrg   /* get the page info */
267848b8605Smrg   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
268848b8605Smrg   firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
269848b8605Smrg   lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
270848b8605Smrg   rows = fs->max_byte1 - fs->min_byte1 + 1;
271848b8605Smrg   unsigned int first_char, last_char, pages, rows;
272848b8605Smrg#endif
273848b8605Smrg
274848b8605Smrg   /* Save the current packing mode for bitmaps.  */
275848b8605Smrg   glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
276848b8605Smrg   glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
277848b8605Smrg   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
278848b8605Smrg   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
279848b8605Smrg   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
280848b8605Smrg   glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
281848b8605Smrg
282848b8605Smrg   /* Enforce a standard packing mode which is compatible with
283848b8605Smrg      fill_bitmap() from above.  This is actually the default mode,
284848b8605Smrg      except for the (non)alignment.  */
285848b8605Smrg   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
286848b8605Smrg   glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
287848b8605Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
288848b8605Smrg   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
289848b8605Smrg   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
290848b8605Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
291848b8605Smrg
292848b8605Smrg   pixmap = XCreatePixmap(dpy, win, 10, 10, 1);
293848b8605Smrg   values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
294848b8605Smrg   values.background = WhitePixel(dpy, DefaultScreen(dpy));
295848b8605Smrg   values.font = fs->fid;
296848b8605Smrg   valuemask = GCForeground | GCBackground | GCFont;
297848b8605Smrg   gc = XCreateGC(dpy, pixmap, valuemask, &values);
298848b8605Smrg   XFreePixmap(dpy, pixmap);
299848b8605Smrg
300848b8605Smrg#ifdef DEBUG
301848b8605Smrg   if (debug_xfonts)
302848b8605Smrg      dump_font_struct(fs);
303848b8605Smrg#endif
304848b8605Smrg
305848b8605Smrg   for (i = 0; i < count; i++) {
306848b8605Smrg      unsigned int width, height, bm_width, bm_height;
307848b8605Smrg      GLfloat x0, y0, dx, dy;
308848b8605Smrg      XCharStruct *ch;
309848b8605Smrg      int x, y;
310848b8605Smrg      unsigned int c = first + i;
311848b8605Smrg      int list = listbase + i;
312848b8605Smrg      int valid;
313848b8605Smrg
314848b8605Smrg      /* check on index validity and get the bounds */
315848b8605Smrg      ch = isvalid(fs, c);
316848b8605Smrg      if (!ch) {
317848b8605Smrg         ch = &fs->max_bounds;
318848b8605Smrg         valid = 0;
319848b8605Smrg      }
320848b8605Smrg      else {
321848b8605Smrg         valid = 1;
322848b8605Smrg      }
323848b8605Smrg
324848b8605Smrg#ifdef DEBUG
325848b8605Smrg      if (debug_xfonts) {
326848b8605Smrg         char s[7];
327848b8605Smrg         sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
328848b8605Smrg         dump_char_struct(ch, s);
329848b8605Smrg      }
330848b8605Smrg#endif
331848b8605Smrg
332848b8605Smrg      /* glBitmap()' parameters:
333848b8605Smrg         straight from the glXUseXFont(3) manpage.  */
334848b8605Smrg      width = ch->rbearing - ch->lbearing;
335848b8605Smrg      height = ch->ascent + ch->descent;
336848b8605Smrg      x0 = -ch->lbearing;
337848b8605Smrg      y0 = ch->descent - 1;
338848b8605Smrg      dx = ch->width;
339848b8605Smrg      dy = 0;
340848b8605Smrg
341848b8605Smrg      /* X11's starting point.  */
342848b8605Smrg      x = -ch->lbearing;
343848b8605Smrg      y = ch->ascent;
344848b8605Smrg
345848b8605Smrg      /* Round the width to a multiple of eight.  We will use this also
346848b8605Smrg         for the pixmap for capturing the X11 font.  This is slightly
347848b8605Smrg         inefficient, but it makes the OpenGL part real easy.  */
348848b8605Smrg      bm_width = (width + 7) / 8;
349848b8605Smrg      bm_height = height;
350848b8605Smrg
351848b8605Smrg      glNewList(list, GL_COMPILE);
352848b8605Smrg      if (valid && (bm_width > 0) && (bm_height > 0)) {
353848b8605Smrg
354848b8605Smrg         memset(bm, '\0', bm_width * bm_height);
355848b8605Smrg         fill_bitmap(dpy, win, gc, bm_width, bm_height, x, y, c, bm);
356848b8605Smrg
357848b8605Smrg         glBitmap(width, height, x0, y0, dx, dy, bm);
358848b8605Smrg#ifdef DEBUG
359848b8605Smrg         if (debug_xfonts) {
360848b8605Smrg            printf("width/height = %u/%u\n", width, height);
361848b8605Smrg            printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
362848b8605Smrg            dump_bitmap(bm_width, bm_height, bm);
363848b8605Smrg         }
364848b8605Smrg#endif
365848b8605Smrg      }
366848b8605Smrg      else {
367848b8605Smrg         glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
368848b8605Smrg      }
369848b8605Smrg      glEndList();
370848b8605Smrg   }
371848b8605Smrg
372848b8605Smrg   free(bm);
373848b8605Smrg   XFreeFontInfo(NULL, fs, 1);
374848b8605Smrg   XFreeGC(dpy, gc);
375848b8605Smrg
376848b8605Smrg   /* Restore saved packing modes.  */
377848b8605Smrg   glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
378848b8605Smrg   glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
379848b8605Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
380848b8605Smrg   glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
381848b8605Smrg   glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
382848b8605Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
383848b8605Smrg}
384848b8605Smrg
385848b8605Smrg#endif
386