ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/text.c
Revision: 2.20
Committed: Sat Feb 22 02:07:29 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.19: +62 -13 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.20 static const char RCSid[] = "$Id$";
3 greg 1.1 #endif
4     /*
5     * text.c - functions for text patterns and mixtures.
6     */
7    
8 greg 2.20 /* ====================================================================
9     * The Radiance Software License, Version 1.0
10     *
11     * Copyright (c) 1990 - 2002 The Regents of the University of California,
12     * through Lawrence Berkeley National Laboratory. All rights reserved.
13     *
14     * Redistribution and use in source and binary forms, with or without
15     * modification, are permitted provided that the following conditions
16     * are met:
17     *
18     * 1. Redistributions of source code must retain the above copyright
19     * notice, this list of conditions and the following disclaimer.
20     *
21     * 2. Redistributions in binary form must reproduce the above copyright
22     * notice, this list of conditions and the following disclaimer in
23     * the documentation and/or other materials provided with the
24     * distribution.
25     *
26     * 3. The end-user documentation included with the redistribution,
27     * if any, must include the following acknowledgment:
28     * "This product includes Radiance software
29     * (http://radsite.lbl.gov/)
30     * developed by the Lawrence Berkeley National Laboratory
31     * (http://www.lbl.gov/)."
32     * Alternately, this acknowledgment may appear in the software itself,
33     * if and wherever such third-party acknowledgments normally appear.
34     *
35     * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
36     * and "The Regents of the University of California" must
37     * not be used to endorse or promote products derived from this
38     * software without prior written permission. For written
39     * permission, please contact [email protected].
40     *
41     * 5. Products derived from this software may not be called "Radiance",
42     * nor may "Radiance" appear in their name, without prior written
43     * permission of Lawrence Berkeley National Laboratory.
44     *
45     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
46     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48     * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
49     * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52     * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
55     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56     * SUCH DAMAGE.
57     * ====================================================================
58     *
59     * This software consists of voluntary contributions made by many
60     * individuals on behalf of Lawrence Berkeley National Laboratory. For more
61     * information on Lawrence Berkeley National Laboratory, please see
62     * <http://www.lbl.gov/>.
63     */
64    
65 greg 1.1 #include "ray.h"
66    
67     #include "otypes.h"
68    
69 greg 2.2 #include "font.h"
70    
71 greg 1.1 /*
72     * A text pattern is specified as the text (a file or line),
73     * the upper left anchor point, the right motion vector, the down
74     * motion vector, and the foreground and background brightness.
75     * For a file, the description is as follows:
76     *
77     * modifier brighttext id
78     * 2 fontfile textfile
79     * 0
80 greg 2.4 * 11+
81 greg 1.1 * Ax Ay Az
82     * Rx Ry Rz
83     * Dx Dy Dz
84     * foreground background
85 greg 2.4 * [spacing]
86 greg 1.1 *
87     * For a single line, we use:
88     *
89     * modifier brighttext id
90     * N+2 fontfile . This is a line with N words...
91     * 0
92 greg 2.4 * 11+
93 greg 1.1 * Ax Ay Az
94     * Rx Ry Rz
95     * Dx Dy Dz
96     * foreground background
97 greg 2.4 * [spacing]
98 greg 1.1 *
99     * Colortext is identical, except colors are given rather than
100 greg 2.15 * brightnesses.
101 greg 1.1 *
102 greg 2.15 * Mixtext has foreground and background modifiers:
103     *
104 greg 1.1 * modifier mixtext id
105     * 4+ foremod backmod fontfile text..
106     * 0
107 greg 2.4 * 9+
108 greg 1.1 * Ax Ay Az
109     * Rx Ry Rz
110     * Dx Dy Dz
111 greg 2.4 * [spacing]
112 greg 1.1 */
113    
114     #define fndx(m) ((m)->otype==MIX_TEXT ? 2 : 0)
115     #define tndx(m) ((m)->otype==MIX_TEXT ? 3 : 1)
116 greg 2.4 #define sndx(m) ((m)->otype==PAT_BTEXT ? 11 : \
117     (m)->otype==PAT_CTEXT ? 15 : 9)
118 greg 1.1
119 greg 1.8 typedef struct tline {
120     struct tline *next; /* pointer to next line */
121 greg 2.4 short *spc; /* character spacing */
122     int width; /* total line width */
123 greg 1.8 /* followed by the string */
124     } TLINE;
125    
126 greg 1.9 #define TLSTR(l) ((char *)((l)+1))
127 greg 1.8
128 greg 1.7 typedef struct {
129     FVECT right, down; /* right and down unit vectors */
130     FONT *f; /* our font */
131 greg 1.8 TLINE tl; /* line list */
132 greg 1.7 } TEXT;
133    
134     TEXT *gettext();
135 greg 1.1
136 greg 1.8 TLINE *tlalloc();
137    
138 greg 1.1
139 greg 2.16 do_text(m, r)
140 greg 1.1 register OBJREC *m;
141     RAY *r;
142     {
143 greg 1.10 FVECT v;
144 greg 1.1 int foreground;
145 greg 1.7 /* get transformed position */
146 greg 1.4 if (r->rox != NULL)
147     multp3(v, r->rop, r->rox->b.xfm);
148     else
149     VCOPY(v, r->rop);
150 greg 1.7 /* check if we are within a text glyph */
151     foreground = intext(v, m);
152 greg 1.1 /* modify */
153     if (m->otype == MIX_TEXT) {
154     OBJECT omod;
155     char *modname = m->oargs.sarg[foreground ? 0 : 1];
156     if (!strcmp(modname, VOIDID))
157     omod = OVOID;
158 gwlarson 2.18 else if ((omod = lastmod(objndx(m), modname)) == OVOID) {
159 greg 1.1 sprintf(errmsg, "undefined modifier \"%s\"", modname);
160     objerror(m, USER, errmsg);
161     }
162 greg 2.12 if (rayshade(r, omod)) {
163     if (m->omod != OVOID)
164     objerror(m, USER, "inappropriate modifier");
165     return(1);
166     }
167 greg 2.15 } else if (m->otype == PAT_BTEXT) {
168 greg 1.1 if (foreground)
169 greg 1.7 scalecolor(r->pcol, m->oargs.farg[9]);
170 greg 1.1 else
171 greg 1.7 scalecolor(r->pcol, m->oargs.farg[10]);
172 greg 1.1 } else { /* PAT_CTEXT */
173     COLOR cval;
174     if (foreground)
175 greg 1.7 setcolor(cval, m->oargs.farg[9],
176     m->oargs.farg[10],
177     m->oargs.farg[11]);
178 greg 1.1 else
179 greg 1.7 setcolor(cval, m->oargs.farg[12],
180     m->oargs.farg[13],
181     m->oargs.farg[14]);
182 greg 1.1 multcolor(r->pcol, cval);
183     }
184 greg 2.12 return(0);
185 greg 1.1 }
186    
187    
188 greg 1.8 TLINE *
189     tlalloc(s) /* allocate and assign text line */
190     char *s;
191     {
192 greg 2.4 register int siz;
193 greg 1.8 register TLINE *tl;
194    
195 greg 2.4 siz = strlen(s) + 1;
196     if ((tl=(TLINE *)malloc(sizeof(TLINE)+siz)) == NULL ||
197     (tl->spc=(short *)malloc(siz*sizeof(short))) == NULL)
198 greg 1.8 error(SYSTEM, "out of memory in tlalloc");
199     tl->next = NULL;
200     strcpy(TLSTR(tl), s);
201     return(tl);
202     }
203    
204    
205 greg 1.7 TEXT *
206     gettext(tm) /* get text structure for material */
207 greg 1.1 register OBJREC *tm;
208     {
209 greg 1.7 #define R (tm->oargs.farg+3)
210     #define D (tm->oargs.farg+6)
211     FVECT DxR;
212     double d;
213 greg 1.1 FILE *fp;
214     char linbuf[512];
215 greg 1.8 TEXT *t;
216 greg 1.1 register int i;
217 greg 1.8 register TLINE *tlp;
218 greg 1.1 register char *s;
219    
220 greg 1.7 if ((t = (TEXT *)tm->os) != NULL)
221     return(t);
222     /* check arguments */
223 greg 2.4 if (tm->oargs.nsargs - tndx(tm) < 1 || tm->oargs.nfargs < sndx(tm))
224 greg 1.7 objerror(tm, USER, "bad # arguments");
225     if ((t = (TEXT *)malloc(sizeof(TEXT))) == NULL)
226 greg 2.10 error(SYSTEM, "out of memory in gettext");
227 greg 1.7 /* compute vectors */
228     fcross(DxR, D, R);
229     fcross(t->right, DxR, D);
230 gregl 2.17 d = DOT(t->right,t->right);
231 gwlarson 2.19 if (d <= FTINY*FTINY*FTINY*FTINY)
232 gregl 2.17 objerror(tm, USER, "illegal motion vector");
233     d = DOT(D,D)/d;
234 greg 1.7 for (i = 0; i < 3; i++)
235     t->right[i] *= d;
236     fcross(t->down, R, DxR);
237 greg 1.9 d = DOT(R,R)/DOT(t->down,t->down);
238 greg 1.7 for (i = 0; i < 3; i++)
239     t->down[i] *= d;
240     /* get text */
241 greg 1.8 tlp = &t->tl;
242 greg 1.7 if (tm->oargs.nsargs - tndx(tm) > 1) { /* single line */
243     s = linbuf;
244     for (i = tndx(tm)+1; i < tm->oargs.nsargs; i++) {
245     strcpy(s, tm->oargs.sarg[i]);
246     s += strlen(s);
247     *s++ = ' ';
248 greg 1.1 }
249 greg 1.7 *--s = '\0';
250 greg 1.8 tlp->next = tlalloc(linbuf);
251     tlp = tlp->next;
252 greg 1.7 } else { /* text file */
253     if ((s = getpath(tm->oargs.sarg[tndx(tm)],
254 greg 2.13 getlibpath(), R_OK)) == NULL) {
255 greg 1.7 sprintf(errmsg, "cannot find text file \"%s\"",
256     tm->oargs.sarg[tndx(tm)]);
257     error(USER, errmsg);
258     }
259     if ((fp = fopen(s, "r")) == NULL) {
260 greg 2.4 sprintf(errmsg, "cannot open text file \"%s\"", s);
261 greg 1.7 error(SYSTEM, errmsg);
262     }
263 greg 1.8 while (fgets(linbuf, sizeof(linbuf), fp) != NULL) {
264 greg 1.7 s = linbuf + strlen(linbuf) - 1;
265     if (*s == '\n')
266     *s = '\0';
267 greg 1.8 tlp->next = tlalloc(linbuf);
268     tlp = tlp->next;
269 greg 1.7 }
270     fclose(fp);
271 greg 1.1 }
272 greg 1.8 tlp->next = NULL;
273 greg 1.7 /* get the font */
274     t->f = getfont(tm->oargs.sarg[fndx(tm)]);
275 greg 2.4 /* compute character spacing */
276     i = sndx(tm);
277     d = i < tm->oargs.nfargs ? tm->oargs.farg[i] : 0.0;
278 greg 2.14 i = d * 255.0;
279 greg 2.6 t->tl.width = 0;
280 greg 2.4 for (tlp = t->tl.next; tlp != NULL; tlp = tlp->next) {
281     if (i < 0)
282     tlp->width = squeeztext(tlp->spc, TLSTR(tlp), t->f, -i);
283     else if (i > 0)
284     tlp->width = proptext(tlp->spc, TLSTR(tlp), t->f, i, 3);
285     else
286     tlp->width = uniftext(tlp->spc, TLSTR(tlp), t->f);
287 greg 2.6 if (tlp->width > t->tl.width)
288     t->tl.width = tlp->width;
289 greg 2.4 }
290 greg 1.7 /* we're done */
291     tm->os = (char *)t;
292     return(t);
293     #undef R
294     #undef D
295 greg 1.1 }
296    
297    
298 greg 1.7 freetext(m) /* free text structures associated with m */
299     OBJREC *m;
300     {
301 greg 2.9 register TEXT *tp;
302     register TLINE *tlp;
303 greg 1.7
304     tp = (TEXT *)m->os;
305     if (tp == NULL)
306     return;
307 greg 2.9 while ((tlp = tp->tl.next) != NULL) {
308     tp->tl.next = tlp->next;
309 greg 2.20 free((void *)tlp->spc);
310     free((void *)tlp);
311 greg 2.4 }
312 greg 2.20 freefont(tp->f); /* release font reference */
313     free((void *)tp);
314 greg 1.7 m->os = NULL;
315     }
316    
317    
318     intext(p, m) /* check to see if p is in text glyph */
319     FVECT p;
320 greg 1.8 OBJREC *m;
321 greg 1.7 {
322     register TEXT *tp;
323 greg 1.8 register TLINE *tlp;
324 greg 1.10 FVECT v;
325     double y, x;
326 greg 2.4 register int i, h;
327 greg 1.7 /* first, compute position in text */
328 greg 1.9 tp = gettext(m);
329 greg 1.7 v[0] = p[0] - m->oargs.farg[0];
330     v[1] = p[1] - m->oargs.farg[1];
331     v[2] = p[2] - m->oargs.farg[2];
332 greg 2.6 x = DOT(v, tp->right);
333     i = sndx(m);
334     if (i < m->oargs.nfargs)
335 greg 2.14 x *= tp->f->mwidth + 255.*fabs(m->oargs.farg[i]);
336 greg 2.6 else
337 greg 2.14 x *= 255.;
338 greg 2.6 h = x;
339 greg 2.4 i = y = DOT(v, tp->down);
340 greg 1.7 if (x < 0.0 || y < 0.0)
341     return(0);
342 greg 2.4 x -= (double)h;
343 greg 2.14 y = ((i+1) - y)*255.;
344 greg 2.4 /* find the line position */
345 greg 1.8 for (tlp = tp->tl.next; tlp != NULL; tlp = tlp->next)
346 greg 2.4 if (--i < 0)
347 greg 1.8 break;
348 greg 2.4 if (tlp == NULL || h >= tlp->width)
349 greg 1.7 return(0);
350 greg 2.4 for (i = 0; (h -= tlp->spc[i]) >= 0; i++)
351 greg 2.14 if (h < 255 && inglyph(h+x, y,
352 greg 2.4 tp->f->fg[TLSTR(tlp)[i]&0xff]))
353     return(1);
354     return(0);
355 greg 1.7 }
356    
357    
358 greg 1.1 inglyph(x, y, gl) /* (x,y) within font glyph gl? */
359 greg 2.14 double x, y; /* real coordinates in range [0,255) */
360 greg 2.3 register GLYPH *gl;
361 greg 1.1 {
362     int n, ncross;
363 greg 2.5 int xlb, ylb;
364     int tv;
365 greg 2.2 register GORD *p0, *p1;
366 greg 1.1
367 greg 1.7 if (gl == NULL)
368 greg 1.1 return(0);
369 greg 2.5 xlb = x;
370     ylb = y;
371     if (gl->left > xlb || gl->right <= xlb || /* check extent */
372     gl->bottom > ylb || gl->top <= ylb)
373     return(0);
374     xlb = xlb<<1 | 1; /* add 1/2 to test points... */
375     ylb = ylb<<1 | 1; /* ...so no equal comparisons */
376 greg 2.2 n = gl->nverts; /* get # of vertices */
377     p0 = gvlist(gl) + 2*(n-1); /* connect last to first */
378     p1 = gvlist(gl);
379 greg 1.1 ncross = 0;
380     /* positive x axis cross test */
381     while (n--) {
382 greg 2.5 if ((p0[1]<<1 > ylb) ^ (p1[1]<<1 > ylb)) {
383     tv = p0[0]<<1 > xlb | (p1[0]<<1 > xlb) << 1;
384     if (tv == 03)
385 greg 1.1 ncross++;
386 greg 2.5 else if (tv)
387 greg 1.1 ncross += (p1[1] > p0[1]) ^
388     ((p0[1]-y)*(p1[0]-x) >
389     (p0[0]-x)*(p1[1]-y));
390 greg 2.5 }
391 greg 1.1 p0 = p1;
392     p1 += 2;
393     }
394     return(ncross & 01);
395     }