1 /*
2  * Copyright (C) 1997-2005, R3vis Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18  *
19  * Original Contributor:
20  *   Wes Bethel, R3vis Corporation, Marin County, California
21  * Additional Contributor(s):
22  *
23  * The OpenRM project is located at http://openrm.sourceforge.net/.
24  */
25 /*
26  * $Id: rmxtext.c,v 1.8 2005/06/06 02:04:29 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.8 $
29  * $Log: rmxtext.c,v $
30  * Revision 1.8  2005/06/06 02:04:29  wes
31  * Lots of small additions to clean up compiler warnings.
32  *
33  * Revision 1.7  2005/05/06 16:38:58  wes
34  *  Added code inside private_rmPrepareBitmapFont to detect the absence
35  * of an open X Display, and generate an error msg rather than just die
36  * with a segfault.
37  *
38  * Revision 1.6  2005/02/19 16:40:20  wes
39  * Distro sync and consolidation.
40  * Repairs to fix memory leak associated with repeated calls to rmPipeNew,
41  * rmPipeMakeCurrent, rmPipeClose.
42  *
43  * Revision 1.5  2005/01/23 17:00:22  wes
44  * Copyright updated to 2005.
45  *
46  * Revision 1.4  2004/01/16 16:49:50  wes
47  * Updated copyright line for 2004.
48  *
49  * Revision 1.3  2003/02/14 00:20:29  wes
50  * Minor tweaks to avoid compile problems on SGI.
51  *
52  * Revision 1.2  2003/02/02 02:07:16  wes
53  * Updated copyright to 2003.
54  *
55  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
56  * Manual rebuild of rm150 repository.
57  *
58  * Revision 1.10  2003/01/16 22:21:17  wes
59  * Updated all source files to reflect new organization of header files:
60  * all header files formerly located in include/rmaux, include/rmi, include/rmv
61  * are now located in include/rm.
62  *
63  * Revision 1.9  2002/12/04 14:50:33  wes
64  * Cleanup SGI compiles.
65  *
66  * Revision 1.8  2002/08/29 22:20:32  wes
67  *
68  * Massive upgrade to accommodate dynamic object reallocation within
69  * the component manager, and within the context cache. Use the
70  * debug #define DEBUG_LEVEL DEBUG_REALLOC_TRACE to get a printf
71  * whenever a realloc occurs. With this upgrade, there are no
72  * OpenRM limits on the size of the scene graph. There will be external
73  * limits, such as the amount of RAM and the amount of space available
74  * to your OpenGL implementation.
75  *
76  * Revision 1.7  2002/04/30 19:37:09  wes
77  * Updated copyright dates.
78  *
79  * Revision 1.6  2001/06/03 20:47:52  wes
80  * Removed last vestiges of the notion of a "current pipe."
81  *
82  * Revision 1.5  2001/03/31 17:12:39  wes
83  * v1.4.0-alpha-2 checkin.
84  *
85  * Revision 1.4  2000/12/03 22:35:39  wes
86  * Mods for thread safety.
87  *
88  * Revision 1.3  2000/05/17 14:25:56  wes
89  * Fixed compile warnings on rmTextPropsSet/GetAttribs().
90  *
91  * Revision 1.2  2000/04/20 16:29:47  wes
92  * Documentation additions/enhancements, some code rearragement.
93  *
94  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
95  * OpenRM 1.2 Checkin
96  *
97  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
98  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
99  *
100  */
101 
102 #include <string.h>
103 #include <rm/rm.h>
104 #include "rmprivat.h"
105 
106 /*
107  * ----------------------------------------------------
108  * @Name rmTextGetExtents
109  @pstart
110  RMenum rmTextGetExtents (const char *string,
111 		          int fontEnum,
112 			  int sizeEnum,
113 			  int boldEnum,
114 			  int italicEnum,
115 			  int *widthReturn,
116 			  int *heightReturn,
117 			  const RMpipe *renderPipe)
118  @pend
119 
120  @astart
121  const char *string - a character string (input).
122 
123  int fontEnum - an integer value specifying a font family. May be one
124     of RM_FONT_SERIF, RM_FONT_SANS, RM_FONT_MONO, RM_FONT_SYMBOL or
125     RM_FONT_DINGBATS (input).
126 
127  int sizeEnum - an integer font size enumerator. May be one of
128     RM_FONT_XXS, RM_FONT_XS, RM_FONT_S, RM_FONT_M, RM_FONT_L,
129     RM_FONT_XL, RM_FONT_XXL.
130 
131  int boldEnum, italicEnum - integer values indicating whether or not
132     to the text string is in boldface or italicized. Valid values are
133     RM_TRUE or RM_FALSE (input).
134 
135  int *widthReturn, *heightReturn - pointers to integers. The width and
136     height of the rendered text string is returned in through these
137     parameters.  Values of NULL are acceptable (return).
138 
139  const RMpipe *renderPipe - a handle to an RMpipe (input).
140  @aend
141 
142  @dstart
143 
144  Use this routine to obtain the pixel dimensions of the bounding box
145  of a text string. The text string may be rendered in one of a number
146  of fonts, at one of a number of pre-specified sizes and with or
147  without emboldening or italicization.
148 
149  This routine doesn't actually cause any rendering to occur on-screen,
150  but does require that RM be completely initialized.
151 
152  10/2000 - Added the renderPipe parameter.
153 
154  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
155 
156  Either, or both, of widthReturn or heightReturn may be NULL,
157  indicating the application is not interested in those values.
158 
159  @dend
160  * ----------------------------------------------------
161  */
162 RMenum
rmTextGetExtents(const char * string,int fontEnum,int sizeEnum,RMenum boldEnum,RMenum italicEnum,int * widthReturn,int * heightReturn,const RMpipe * renderPipe)163 rmTextGetExtents (const char *string,
164 		  int fontEnum,
165 		  int sizeEnum,
166 		  RMenum boldEnum,
167 		  RMenum italicEnum,
168 		  int *widthReturn,
169 		  int *heightReturn,
170 		  const RMpipe *renderPipe)
171 {
172     char        mystring[128];
173     RMtextProps tp;
174     RMtextPrim  p;
175     RMfontRegistry *fr;
176 
177     if ((RM_ASSERT(string, "rmTextGetExtents() error: the input string is NULL") == RM_WHACKED) ||
178 	(RM_ASSERT(renderPipe, "rmTextGetExtents() error: the input RMpipe is NULL") == RM_WHACKED))
179 	return(RM_WHACKED);
180 
181     rmTextPropsSetAttribs(&tp, fontEnum, sizeEnum, boldEnum, italicEnum, RM_LEFT, RM_BOTTOM);
182     private_rmPrepareBitmapFont(&tp, (RMpipe *)renderPipe);
183 
184     strcpy(mystring, string);
185     p.string = mystring;
186 
187     fr = private_rmFontRegistryEntry(fontEnum, sizeEnum, italicEnum, boldEnum, renderPipe->contextCache->pipeFontRegistry);
188 
189     private_rmTextPrimComputeCW(&p, fr, renderPipe);
190 
191     if (widthReturn != NULL)
192 	*widthReturn = p.bw;
193 
194     if (heightReturn != NULL)
195 	*heightReturn = p.bh;
196 
197     return(RM_CHILL);
198 }
199 
200 
201 #ifdef RM_X
202 /*
203  * The following four arrays are used to construct an X font name
204  * from user parameters.  The user can specify an enumerated font family
205  * name, an enumerated size, and boolean values for italic and embolden.
206  *
207  * The stuff in these four arrays is concatenated together to produce a
208  * font name that X can digest.
209  *
210  * Tue Jun  3 17:15:38 PDT 1997
211  * there's a really weird bug that appears when running on an SGI
212  * machine but displaying on solaris/opengl.  it turns out that bitmaps
213  * which are not an even multiple of 8 in width (ie, not on a byte boundary)
214  * don't seem to work right.  i'm not sure if this bug is in the solaris
215  * opengl ....  what i'm going to do is wait a little bit for the
216  * next version of opengl from sun.  if that doesn't fix the problem, then
217  * what we can do is alter the width of our bitmap mask so that we
218  * have as a width a value which is an even multiple of 8.  the code
219  * works fine on both SGI and SUn, the problem shows up when displaying
220  * across a network onto a sun from an sgi.
221  *
222  * Thu Jun  5 12:53:06 MDT 1997
223  * added code to call the scalable zapf dingbat font.  for the future, a
224  * nice enhancement to this code would be to load ONLY scalable fonts. it
225  * would streamline the code a little bit.
226  *
227  * Sat Jun 14 15:45:03 MDT 1997
228  * use RMbitmaps rather than a char[][] inside the internal text primitive.
229  *
230  * Fri Nov 28 12:20:45 PST 1997
231  * reorgs to isolate X dependancies.
232  */
233 
234 static char *font_families_x[] =
235 {
236   "adobe-times",	/* RM_FONT_SERIF */
237   "adobe-helvetica",	/* RM_FONT_SANS */
238   "adobe-courier",	/* RM_FONT_MONO */
239   "adobe-symbol",	/* RM_FONT_SYMBOL */
240   "*-*dingbats"		/* RM_FONT_DINGBATS */
241 };
242 
243 static char *font_sizes_x[] =
244 {
245     "8",		/* RM_XXS */
246     "10",		/* RM_XS */
247     "12",		/* RM_S */
248     "14",		/* RM_M */
249     "18",		/* RM_L */
250     "24",		/* RM_XL */
251     "34"		/* RM_XXL */
252 };
253 
254 /* hard to believe, but these are different */
255 static char *font_sans_italic_x[]=
256 {
257     "r",		/* for RM_FALSE on italic */
258     "o"			/* for RM_TRUE on italic */
259 };
260 static char *font_serif_italic_x[]=
261 {
262     "r",		/* for RM_FALSE on italic */
263     "i"			/* for RM_TRUE on italic */
264 };
265 
266 static char *font_bold_x[] =
267 {
268     "medium",		/* for RM_FALSE on bold */
269     "bold"		/* for RM_TRUE on bold */
270 };
271 
272 /* these fonts get used if the user doesn't explicitly ask for one, or
273    if one of the requested fonts doesn't exist. the goal is to have
274    something reasonable happen in the presence of an error condition. */
275 
276 #define NFALLBACK_FONTS 3
277 char fallback_fonts[NFALLBACK_FONTS][80] =
278 {
279     "*-times-*-r-*14*",	/* try to grab a 14 point times-roman font */
280     "*times-roman*",	/* try to grab a plain old times-roman font */
281     "fixed"		/* grab a really ugly font */
282 };
283 
284 
285 #define DepthOf(disp)	DefaultDepth(disp, DefaultScreen(disp))
286 #define PlanesOf(disp)	((1 << DepthOf(disp)) - 1)   /* or AllPlanes */
287 
288 
289 /* PRIVATE
290  *
291  * this private routine will check to see if a given font family/size/style
292  * has been initialized for use. if not, it will prepare the given font
293  * specification for use by the system.
294  */
295 RMenum
private_rmPrepareBitmapFont(RMtextProps * t,RMpipe * p)296 private_rmPrepareBitmapFont (RMtextProps *t,
297 			     RMpipe *p)
298 {
299    RMfontRegistry *fr;
300    XFontStruct    *xfs;
301 
302    fr = private_rmFontRegistryEntry(t->fontEnum, t->sizeEnum, t->italicEnum, t->boldEnum, p->contextCache->pipeFontRegistry);
303 
304    if (fr == NULL)
305        return(RM_WHACKED);
306 
307    if (fr->initialized == 0)	/* this font/size/style not yet initialized */
308    {
309        char    font[128];
310        char   *typeface;
311        int     rmtfont;
312        int     height;
313        RMenum     weight;		/* what's this supposed to be? */
314        RMenum     italic;		/* what's this supposed to be? */
315        int     iweight, iitalic;
316        GLuint  base;
317        RMenum  hjustify, vjustify;
318 
319        rmTextPropsGetAttribs(t, &rmtfont, &height, &weight, &italic, &hjustify, &vjustify);
320 
321        iweight = (weight == RM_TRUE) ? 1 : 0;
322        iitalic = (italic == RM_TRUE) ? 1 : 0;
323        typeface = font_families_x[rmtfont];
324 
325        /* build an X font name from user parameters. */
326        memset(font, 0, 128);
327        font[0] = '-';
328 
329        /* do the font family - note that rmtfont is an index - therefore the RM_FONT_*
330 	set of enums are really indices, not RMenums proper at this time.*/
331 
332        strcat(font,font_families_x[rmtfont]);
333        strcat(font,"-");
334 
335        /* do the embolden. symbol fonts aren't emboldened */
336        if ((rmtfont == RM_FONT_SYMBOL) || (rmtfont == RM_FONT_DINGBATS))
337 	   strcat(font, font_bold_x[RM_FALSE]);
338        else
339 	   strcat(font, font_bold_x[iweight]);
340        strcat(font,"-");
341 
342        /* do the italics. symbol fonts aren't emboldened */
343        if (rmtfont == RM_FONT_SYMBOL)
344 	   strcat(font, font_serif_italic_x[RM_FALSE]);
345        else
346 	   if (rmtfont == RM_FONT_SERIF)
347 	       strcat(font, font_serif_italic_x[iitalic]);
348 	   else	/* assume all non-serif fonts behave the same*/
349 	       strcat(font, font_sans_italic_x[iitalic]);
350 
351        strcat(font,"-normal--");
352 
353        /* do the size */
354        if (rmtfont != RM_FONT_DINGBATS)
355        {
356 	   strcat(font, font_sizes_x[height]);
357 	   strcat(font,"-*");
358        }
359        else /* this is ugly...yep */
360        {
361 	   char     buf[32];
362 	   int      screen, res_x, res_y;
363 	   int      points;
364 	   Display *dpy;
365 
366 	   dpy = rmxPipeGetDisplay(p);
367 	   screen = DefaultScreen(dpy);
368 
369 	   /* calculate our screen resolution in dots per inch. 25.4mm = 1 inch */
370 	   res_x = DisplayWidth(dpy, screen) / (DisplayWidthMM(dpy, screen) / 25.4);
371 	   res_y = DisplayHeight(dpy, screen) / (DisplayHeightMM(dpy, screen) / 25.4);
372 	   sscanf(font_sizes_x[height], "%d", &points);
373 	   points *= 10;
374 	   memset(buf, 0, 32);
375 	   sprintf(buf, "%d", points);
376 
377 	   strcat(font, "*-");
378 	   strcat(font, buf);
379 	   strcat(font, "-");
380 
381 	   memset(buf, 0, 32);
382 	   sprintf(buf, "%d", res_x);
383 	   strcat(font, buf);
384 	   strcat(font, "-");
385 	   sprintf(buf, "%d", res_y);
386 	   strcat(font, buf);
387 	   strcat(font, "-p-0-*-fontspecific");
388        }
389 
390        /* first, load a font...maybe... */
391        if (rmxPipeGetDisplay(p) == NULL)
392        {
393 	   rmError("private_rmPrepareBitmapFont fatal error: the input RMpipe does not have a valid, open XDisplay. Please assign one using rmxPipeSetDisplay prior to attempting to draw text objects. ");
394 	   exit(-1);
395        }
396 
397        xfs = XLoadQueryFont(rmxPipeGetDisplay(p), font);
398 
399        if (xfs == NULL)		/* cant find the requested font */
400        {
401 	   char s[256];
402 	   int  i;
403 
404 	   sprintf(s, "warning: private_rmPrepareBitmapFont() cannot find the X font named <%s> to honor your request. Will attempt to find a generic system font to use instead. \n", font);
405 	   rmWarning(s);
406 
407 	   for (i = 0; i < NFALLBACK_FONTS; i++)
408 	   {
409 	       fprintf(stderr, " trying the font: <%s> \n", fallback_fonts[i]);
410 	       xfs = XLoadQueryFont(rmxPipeGetDisplay(p), fallback_fonts[i]);
411 
412 	       if (xfs != NULL)
413 		  break;
414 	   }
415 
416 	   /*
417 	    * if things are really bad, we can't get any fonts, even one of
418 	    * the ugly fallback fonts. if things are this bad, we wave the
419 	    * white flag and exit.
420 	    *
421 	    * i've never seen this code block get executed, but it's in
422 	    * here just in case...
423 	    */
424 	   if (i == NFALLBACK_FONTS)
425 	   {
426 	       rmError(" RM can't find any fonts on this system, and is unable continue.");
427 	       exit(-1);
428 	   }
429        }
430 
431        if ((base = glGenLists(96)) == 0)
432 	   return(RM_WHACKED);
433        glXUseXFont(xfs->fid, 32, 96, base);
434 
435        fr->initialized = 1;
436        fr->listbase = base;
437        fr->listCount = 96;
438        fr->refcount = 1;
439        fr->fontinfo = (void *) xfs;
440        fr->listoffset = 32;
441    }
442    else
443        fr->refcount += 1;
444 
445 #if 0
446    /* removed display list stuff from the scene graph!*/
447    t->listbase = fr->listbase;
448    t->listoffset = 32;
449    t->fontinfo = fr->fontinfo;
450 #endif
451 
452    return(RM_CHILL);
453 }
454 
455 
456 /* PRIVATE
457  *
458  * compute width/height of a text string using Xlib. this routine is used
459  * by rmTextGetExtents, as well as by the text drawing routine.
460  */
461 int
private_rmTextPrimComputeCW(RMtextPrim * p,RMfontRegistry * fr,const RMpipe * pipe)462 private_rmTextPrimComputeCW (RMtextPrim *p,
463 			     RMfontRegistry *fr,
464 			     const RMpipe *pipe)
465 {
466     char        *s;
467     int          n;
468     int          direction_return;
469     int          font_ascent_return, font_descent_return;
470     XCharStruct  overall_return;
471     XFontStruct *xfs;
472 
473     pipe = NULL; 		/* foil compiler warning */
474 
475     xfs = (XFontStruct *)(fr->fontinfo);
476     s = p->string;
477     n = strlen(s);
478 
479     XTextExtents(xfs, s, n, &direction_return, &font_ascent_return, &font_descent_return, &overall_return);
480 
481     p->bw = overall_return.width;
482     p->bh = overall_return.ascent + overall_return.descent;
483 
484     return(RM_CHILL);
485 }
486 
487 #endif /* RM_X */
488 /* EOF */
489