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