1cdc920a0Smrg/*
2cdc920a0Smrg * Mesa 3-D graphics library
3cdc920a0Smrg *
4cdc920a0Smrg * Copyright (C) 1999  Brian Paul   All Rights Reserved.
5cdc920a0Smrg *
6cdc920a0Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7cdc920a0Smrg * copy of this software and associated documentation files (the "Software"),
8cdc920a0Smrg * to deal in the Software without restriction, including without limitation
9cdc920a0Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10cdc920a0Smrg * and/or sell copies of the Software, and to permit persons to whom the
11cdc920a0Smrg * Software is furnished to do so, subject to the following conditions:
12cdc920a0Smrg *
13cdc920a0Smrg * The above copyright notice and this permission notice shall be included
14cdc920a0Smrg * in all copies or substantial portions of the Software.
15cdc920a0Smrg *
16cdc920a0Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17cdc920a0Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18cdc920a0Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
23cdc920a0Smrg */
24cdc920a0Smrg
25cdc920a0Smrg
26cdc920a0Smrg/* xfonts.c -- glXUseXFont() for Mesa written by
27cdc920a0Smrg * Copyright (C) 1995 Thorsten.Ohl @ Physik.TH-Darmstadt.de
28cdc920a0Smrg */
29cdc920a0Smrg
30cdc920a0Smrg/*
31cdc920a0Smrg  This was take from Mesa and modified to work in the real GLX structure.
32cdc920a0Smrg  It provides a fully client side implementation of glXUseXFont and is
33cdc920a0Smrg  called by that routine when direct rendering is enabled.
34cdc920a0Smrg*/
35cdc920a0Smrg
36cdc920a0Smrg#ifdef GLX_DIRECT_RENDERING
37cdc920a0Smrg
38cdc920a0Smrg#include "glxclient.h"
39cdc920a0Smrg
40cdc920a0Smrg/* Some debugging info.  */
41cdc920a0Smrg
42cdc920a0Smrg#ifdef DEBUG
43cdc920a0Smrg#undef _R
44cdc920a0Smrg#undef _G
45cdc920a0Smrg#undef _B
46cdc920a0Smrg#include <ctype.h>
47cdc920a0Smrg
48cdc920a0Smrgint debug_xfonts = 0;
49cdc920a0Smrg
50cdc920a0Smrgstatic void
51cdc920a0Smrgdump_char_struct(XCharStruct * ch, char *prefix)
52cdc920a0Smrg{
53cdc920a0Smrg   printf("%slbearing = %d, rbearing = %d, width = %d\n",
54cdc920a0Smrg          prefix, ch->lbearing, ch->rbearing, ch->width);
55cdc920a0Smrg   printf("%sascent = %d, descent = %d, attributes = %u\n",
56cdc920a0Smrg          prefix, ch->ascent, ch->descent, (unsigned int) ch->attributes);
57cdc920a0Smrg}
58cdc920a0Smrg
59cdc920a0Smrgstatic void
60cdc920a0Smrgdump_font_struct(XFontStruct * font)
61cdc920a0Smrg{
62cdc920a0Smrg   printf("ascent = %d, descent = %d\n", font->ascent, font->descent);
63cdc920a0Smrg   printf("char_or_byte2 = (%u,%u)\n",
64cdc920a0Smrg          font->min_char_or_byte2, font->max_char_or_byte2);
65cdc920a0Smrg   printf("byte1 = (%u,%u)\n", font->min_byte1, font->max_byte1);
66cdc920a0Smrg   printf("all_chars_exist = %s\n", font->all_chars_exist ? "True" : "False");
67cdc920a0Smrg   printf("default_char = %c (\\%03o)\n",
68cdc920a0Smrg          (char) (isprint(font->default_char) ? font->default_char : ' '),
69cdc920a0Smrg          font->default_char);
70cdc920a0Smrg   dump_char_struct(&font->min_bounds, "min> ");
71cdc920a0Smrg   dump_char_struct(&font->max_bounds, "max> ");
72cdc920a0Smrg#if 0
73cdc920a0Smrg   for (c = font->min_char_or_byte2; c <= font->max_char_or_byte2; c++) {
74cdc920a0Smrg      char prefix[8];
75cdc920a0Smrg      sprintf(prefix, "%d> ", c);
76cdc920a0Smrg      dump_char_struct(&font->per_char[c], prefix);
77cdc920a0Smrg   }
78cdc920a0Smrg#endif
79cdc920a0Smrg}
80cdc920a0Smrg
81cdc920a0Smrgstatic void
82cdc920a0Smrgdump_bitmap(unsigned int width, unsigned int height, GLubyte * bitmap)
83cdc920a0Smrg{
84cdc920a0Smrg   unsigned int x, y;
85cdc920a0Smrg
86cdc920a0Smrg   printf("    ");
87cdc920a0Smrg   for (x = 0; x < 8 * width; x++)
88cdc920a0Smrg      printf("%o", 7 - (x % 8));
89cdc920a0Smrg   putchar('\n');
90cdc920a0Smrg   for (y = 0; y < height; y++) {
91cdc920a0Smrg      printf("%3o:", y);
92cdc920a0Smrg      for (x = 0; x < 8 * width; x++)
93cdc920a0Smrg         putchar((bitmap[width * (height - y - 1) + x / 8] & (1 << (7 - (x %
94cdc920a0Smrg                                                                         8))))
95cdc920a0Smrg                 ? '*' : '.');
96cdc920a0Smrg      printf("   ");
97cdc920a0Smrg      for (x = 0; x < width; x++)
98cdc920a0Smrg         printf("0x%02x, ", bitmap[width * (height - y - 1) + x]);
99cdc920a0Smrg      putchar('\n');
100cdc920a0Smrg   }
101cdc920a0Smrg}
102cdc920a0Smrg#endif /* DEBUG */
103cdc920a0Smrg
104cdc920a0Smrg
105cdc920a0Smrg/* Implementation.  */
106cdc920a0Smrg
107cdc920a0Smrg/* Fill a BITMAP with a character C from thew current font
108cdc920a0Smrg   in the graphics context GC.  WIDTH is the width in bytes
109cdc920a0Smrg   and HEIGHT is the height in bits.
110cdc920a0Smrg
111cdc920a0Smrg   Note that the generated bitmaps must be used with
112cdc920a0Smrg
113cdc920a0Smrg        glPixelStorei (GL_UNPACK_SWAP_BYTES, GL_FALSE);
114cdc920a0Smrg        glPixelStorei (GL_UNPACK_LSB_FIRST, GL_FALSE);
115cdc920a0Smrg        glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
116cdc920a0Smrg        glPixelStorei (GL_UNPACK_SKIP_ROWS, 0);
117cdc920a0Smrg        glPixelStorei (GL_UNPACK_SKIP_PIXELS, 0);
118cdc920a0Smrg        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
119cdc920a0Smrg
120cdc920a0Smrg   Possible optimizations:
121cdc920a0Smrg
122cdc920a0Smrg     * use only one reusable pixmap with the maximum dimensions.
123cdc920a0Smrg     * draw the entire font into a single pixmap (careful with
124cdc920a0Smrg       proportional fonts!).
125cdc920a0Smrg*/
126cdc920a0Smrg
127cdc920a0Smrg
128cdc920a0Smrg/*
129cdc920a0Smrg * Generate OpenGL-compatible bitmap.
130cdc920a0Smrg */
131cdc920a0Smrgstatic void
1327ec681f3Smrgfill_bitmap(Display * dpy, int screen, GC gc,
133cdc920a0Smrg            unsigned int width, unsigned int height,
134cdc920a0Smrg            int x0, int y0, unsigned int c, GLubyte * bitmap)
135cdc920a0Smrg{
136cdc920a0Smrg   XImage *image;
137cdc920a0Smrg   unsigned int x, y;
138cdc920a0Smrg   Pixmap pixmap;
139cdc920a0Smrg   XChar2b char2b;
140cdc920a0Smrg
1417ec681f3Smrg   pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), 8 * width, height, 1);
142cdc920a0Smrg   XSetForeground(dpy, gc, 0);
143cdc920a0Smrg   XFillRectangle(dpy, pixmap, gc, 0, 0, 8 * width, height);
144cdc920a0Smrg   XSetForeground(dpy, gc, 1);
145cdc920a0Smrg
146cdc920a0Smrg   char2b.byte1 = (c >> 8) & 0xff;
147cdc920a0Smrg   char2b.byte2 = (c & 0xff);
148cdc920a0Smrg
149cdc920a0Smrg   XDrawString16(dpy, pixmap, gc, x0, y0, &char2b, 1);
150cdc920a0Smrg
151cdc920a0Smrg   image = XGetImage(dpy, pixmap, 0, 0, 8 * width, height, 1, XYPixmap);
152cdc920a0Smrg   if (image) {
153cdc920a0Smrg      /* Fill the bitmap (X11 and OpenGL are upside down wrt each other).  */
154cdc920a0Smrg      for (y = 0; y < height; y++)
155cdc920a0Smrg         for (x = 0; x < 8 * width; x++)
156cdc920a0Smrg            if (XGetPixel(image, x, y))
157cdc920a0Smrg               bitmap[width * (height - y - 1) + x / 8] |=
158cdc920a0Smrg                  (1 << (7 - (x % 8)));
159cdc920a0Smrg      XDestroyImage(image);
160cdc920a0Smrg   }
161cdc920a0Smrg
162cdc920a0Smrg   XFreePixmap(dpy, pixmap);
163cdc920a0Smrg}
164cdc920a0Smrg
165cdc920a0Smrg/*
166cdc920a0Smrg * determine if a given glyph is valid and return the
167cdc920a0Smrg * corresponding XCharStruct.
168cdc920a0Smrg */
169cdc920a0Smrgstatic XCharStruct *
170cdc920a0Smrgisvalid(XFontStruct * fs, int which)
171cdc920a0Smrg{
172cdc920a0Smrg   unsigned int rows, pages;
173cdc920a0Smrg   int byte1 = 0, byte2 = 0;
174cdc920a0Smrg   int i, valid = 1;
175cdc920a0Smrg
176cdc920a0Smrg   rows = fs->max_byte1 - fs->min_byte1 + 1;
177cdc920a0Smrg   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
178cdc920a0Smrg
179cdc920a0Smrg   if (rows == 1) {
180cdc920a0Smrg      /* "linear" fonts */
181cdc920a0Smrg      if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
182cdc920a0Smrg         valid = 0;
183cdc920a0Smrg   }
184cdc920a0Smrg   else {
185cdc920a0Smrg      /* "matrix" fonts */
186cdc920a0Smrg      byte2 = which & 0xff;
187cdc920a0Smrg      byte1 = which >> 8;
188cdc920a0Smrg      if ((fs->min_char_or_byte2 > byte2) ||
189cdc920a0Smrg          (fs->max_char_or_byte2 < byte2) ||
190cdc920a0Smrg          (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
191cdc920a0Smrg         valid = 0;
192cdc920a0Smrg   }
193cdc920a0Smrg
194cdc920a0Smrg   if (valid) {
195cdc920a0Smrg      if (fs->per_char) {
196cdc920a0Smrg         if (rows == 1) {
197cdc920a0Smrg            /* "linear" fonts */
198cdc920a0Smrg            return (fs->per_char + (which - fs->min_char_or_byte2));
199cdc920a0Smrg         }
200cdc920a0Smrg         else {
201cdc920a0Smrg            /* "matrix" fonts */
202cdc920a0Smrg            i = ((byte1 - fs->min_byte1) * pages) +
203cdc920a0Smrg               (byte2 - fs->min_char_or_byte2);
204cdc920a0Smrg            return (fs->per_char + i);
205cdc920a0Smrg         }
206cdc920a0Smrg      }
207cdc920a0Smrg      else {
208cdc920a0Smrg         return (&fs->min_bounds);
209cdc920a0Smrg      }
210cdc920a0Smrg   }
211cdc920a0Smrg   return (NULL);
212cdc920a0Smrg}
213cdc920a0Smrg
214cdc920a0Smrg_X_HIDDEN void
2153464ebd5SriastradhDRI_glXUseXFont(struct glx_context *CC, Font font, int first, int count, int listbase)
216cdc920a0Smrg{
217cdc920a0Smrg   Display *dpy;
2187ec681f3Smrg   int screen;
219cdc920a0Smrg   Pixmap pixmap;
220cdc920a0Smrg   GC gc;
221cdc920a0Smrg   XGCValues values;
222cdc920a0Smrg   unsigned long valuemask;
223cdc920a0Smrg   XFontStruct *fs;
22401e04c3fSmrg
225cdc920a0Smrg   GLint swapbytes, lsbfirst, rowlength;
226cdc920a0Smrg   GLint skiprows, skippixels, alignment;
227cdc920a0Smrg
228cdc920a0Smrg   unsigned int max_width, max_height, max_bm_width, max_bm_height;
229cdc920a0Smrg   GLubyte *bm;
230cdc920a0Smrg
231cdc920a0Smrg   int i;
232cdc920a0Smrg
233cdc920a0Smrg   dpy = CC->currentDpy;
2347ec681f3Smrg   screen = CC->screen;
235af69d88dSmrg
236cdc920a0Smrg   fs = XQueryFont(dpy, font);
237cdc920a0Smrg   if (!fs) {
238cdc920a0Smrg      __glXSetError(CC, GL_INVALID_VALUE);
239cdc920a0Smrg      return;
240cdc920a0Smrg   }
241cdc920a0Smrg
242cdc920a0Smrg   /* Allocate a bitmap that can fit all characters.  */
243cdc920a0Smrg   max_width = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
244cdc920a0Smrg   max_height = fs->max_bounds.ascent + fs->max_bounds.descent;
245cdc920a0Smrg   max_bm_width = (max_width + 7) / 8;
246cdc920a0Smrg   max_bm_height = max_height;
247cdc920a0Smrg
248af69d88dSmrg   bm = malloc((max_bm_width * max_bm_height) * sizeof(GLubyte));
249cdc920a0Smrg   if (!bm) {
250cdc920a0Smrg      XFreeFontInfo(NULL, fs, 1);
251cdc920a0Smrg      __glXSetError(CC, GL_OUT_OF_MEMORY);
252cdc920a0Smrg      return;
253cdc920a0Smrg   }
254cdc920a0Smrg
255cdc920a0Smrg#if 0
256cdc920a0Smrg   /* get the page info */
257cdc920a0Smrg   pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
258cdc920a0Smrg   firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
259cdc920a0Smrg   lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
260cdc920a0Smrg   rows = fs->max_byte1 - fs->min_byte1 + 1;
261cdc920a0Smrg   unsigned int first_char, last_char, pages, rows;
262cdc920a0Smrg#endif
263cdc920a0Smrg
264cdc920a0Smrg   /* Save the current packing mode for bitmaps.  */
265cdc920a0Smrg   glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
266cdc920a0Smrg   glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
267cdc920a0Smrg   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
268cdc920a0Smrg   glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
269cdc920a0Smrg   glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
270cdc920a0Smrg   glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
271cdc920a0Smrg
272cdc920a0Smrg   /* Enforce a standard packing mode which is compatible with
273cdc920a0Smrg      fill_bitmap() from above.  This is actually the default mode,
274cdc920a0Smrg      except for the (non)alignment.  */
275cdc920a0Smrg   glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
276cdc920a0Smrg   glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
277cdc920a0Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
278cdc920a0Smrg   glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
279cdc920a0Smrg   glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
280cdc920a0Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
281cdc920a0Smrg
2827ec681f3Smrg   pixmap = XCreatePixmap(dpy, RootWindow(dpy, screen), 10, 10, 1);
283cdc920a0Smrg   values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
284cdc920a0Smrg   values.background = WhitePixel(dpy, DefaultScreen(dpy));
285cdc920a0Smrg   values.font = fs->fid;
286cdc920a0Smrg   valuemask = GCForeground | GCBackground | GCFont;
287cdc920a0Smrg   gc = XCreateGC(dpy, pixmap, valuemask, &values);
288cdc920a0Smrg   XFreePixmap(dpy, pixmap);
289cdc920a0Smrg
290cdc920a0Smrg#ifdef DEBUG
291cdc920a0Smrg   if (debug_xfonts)
292cdc920a0Smrg      dump_font_struct(fs);
293cdc920a0Smrg#endif
294cdc920a0Smrg
295cdc920a0Smrg   for (i = 0; i < count; i++) {
296cdc920a0Smrg      unsigned int width, height, bm_width, bm_height;
297cdc920a0Smrg      GLfloat x0, y0, dx, dy;
298cdc920a0Smrg      XCharStruct *ch;
299cdc920a0Smrg      int x, y;
300cdc920a0Smrg      unsigned int c = first + i;
301cdc920a0Smrg      int list = listbase + i;
302cdc920a0Smrg      int valid;
303cdc920a0Smrg
304cdc920a0Smrg      /* check on index validity and get the bounds */
305cdc920a0Smrg      ch = isvalid(fs, c);
306cdc920a0Smrg      if (!ch) {
307cdc920a0Smrg         ch = &fs->max_bounds;
308cdc920a0Smrg         valid = 0;
309cdc920a0Smrg      }
310cdc920a0Smrg      else {
311cdc920a0Smrg         valid = 1;
312cdc920a0Smrg      }
313cdc920a0Smrg
314cdc920a0Smrg#ifdef DEBUG
315cdc920a0Smrg      if (debug_xfonts) {
316cdc920a0Smrg         char s[7];
317cdc920a0Smrg         sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
318cdc920a0Smrg         dump_char_struct(ch, s);
319cdc920a0Smrg      }
320cdc920a0Smrg#endif
321cdc920a0Smrg
322cdc920a0Smrg      /* glBitmap()' parameters:
323cdc920a0Smrg         straight from the glXUseXFont(3) manpage.  */
324cdc920a0Smrg      width = ch->rbearing - ch->lbearing;
325cdc920a0Smrg      height = ch->ascent + ch->descent;
326cdc920a0Smrg      x0 = -ch->lbearing;
327cdc920a0Smrg      y0 = ch->descent - 1;
328cdc920a0Smrg      dx = ch->width;
329cdc920a0Smrg      dy = 0;
330cdc920a0Smrg
331cdc920a0Smrg      /* X11's starting point.  */
332cdc920a0Smrg      x = -ch->lbearing;
333cdc920a0Smrg      y = ch->ascent;
334cdc920a0Smrg
335cdc920a0Smrg      /* Round the width to a multiple of eight.  We will use this also
336cdc920a0Smrg         for the pixmap for capturing the X11 font.  This is slightly
337cdc920a0Smrg         inefficient, but it makes the OpenGL part real easy.  */
338cdc920a0Smrg      bm_width = (width + 7) / 8;
339cdc920a0Smrg      bm_height = height;
340cdc920a0Smrg
341cdc920a0Smrg      glNewList(list, GL_COMPILE);
342cdc920a0Smrg      if (valid && (bm_width > 0) && (bm_height > 0)) {
343cdc920a0Smrg
344cdc920a0Smrg         memset(bm, '\0', bm_width * bm_height);
3457ec681f3Smrg         fill_bitmap(dpy, screen, gc, bm_width, bm_height, x, y, c, bm);
346cdc920a0Smrg
347cdc920a0Smrg         glBitmap(width, height, x0, y0, dx, dy, bm);
348cdc920a0Smrg#ifdef DEBUG
349cdc920a0Smrg         if (debug_xfonts) {
350cdc920a0Smrg            printf("width/height = %u/%u\n", width, height);
351cdc920a0Smrg            printf("bm_width/bm_height = %u/%u\n", bm_width, bm_height);
352cdc920a0Smrg            dump_bitmap(bm_width, bm_height, bm);
353cdc920a0Smrg         }
354cdc920a0Smrg#endif
355cdc920a0Smrg      }
356cdc920a0Smrg      else {
357cdc920a0Smrg         glBitmap(0, 0, 0.0, 0.0, dx, dy, NULL);
358cdc920a0Smrg      }
359cdc920a0Smrg      glEndList();
360cdc920a0Smrg   }
361cdc920a0Smrg
362af69d88dSmrg   free(bm);
363cdc920a0Smrg   XFreeFontInfo(NULL, fs, 1);
364cdc920a0Smrg   XFreeGC(dpy, gc);
365cdc920a0Smrg
366cdc920a0Smrg   /* Restore saved packing modes.  */
367cdc920a0Smrg   glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
368cdc920a0Smrg   glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
369cdc920a0Smrg   glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
370cdc920a0Smrg   glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
371cdc920a0Smrg   glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
372cdc920a0Smrg   glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
373cdc920a0Smrg}
374cdc920a0Smrg
375cdc920a0Smrg#endif
376