ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/text.c
Revision: 2.25
Committed: Tue Mar 30 16:13:01 2004 UTC (20 years ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad4R1, rad4R0, rad3R6, rad3R6P1, rad3R8, rad3R9
Changes since 2.24: +34 -24 lines
Log Message:
Continued ANSIfication. There are only bits and pieces left now.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: text.c,v 2.24 2004/02/12 18:55:50 greg Exp $";
3 #endif
4 /*
5 * text.c - functions for text patterns and mixtures.
6 */
7
8 #include "copyright.h"
9
10 #include "ray.h"
11 #include "paths.h"
12 #include "otypes.h"
13 #include "rtotypes.h"
14 #include "font.h"
15
16 /*
17 * A text pattern is specified as the text (a file or line),
18 * the upper left anchor point, the right motion vector, the down
19 * motion vector, and the foreground and background brightness.
20 * For a file, the description is as follows:
21 *
22 * modifier brighttext id
23 * 2 fontfile textfile
24 * 0
25 * 11+
26 * Ax Ay Az
27 * Rx Ry Rz
28 * Dx Dy Dz
29 * foreground background
30 * [spacing]
31 *
32 * For a single line, we use:
33 *
34 * modifier brighttext id
35 * N+2 fontfile . This is a line with N words...
36 * 0
37 * 11+
38 * Ax Ay Az
39 * Rx Ry Rz
40 * Dx Dy Dz
41 * foreground background
42 * [spacing]
43 *
44 * Colortext is identical, except colors are given rather than
45 * brightnesses.
46 *
47 * Mixtext has foreground and background modifiers:
48 *
49 * modifier mixtext id
50 * 4+ foremod backmod fontfile text..
51 * 0
52 * 9+
53 * Ax Ay Az
54 * Rx Ry Rz
55 * Dx Dy Dz
56 * [spacing]
57 */
58
59 #define fndx(m) ((m)->otype==MIX_TEXT ? 2 : 0)
60 #define tndx(m) ((m)->otype==MIX_TEXT ? 3 : 1)
61 #define sndx(m) ((m)->otype==PAT_BTEXT ? 11 : \
62 (m)->otype==PAT_CTEXT ? 15 : 9)
63
64 typedef struct tline {
65 struct tline *next; /* pointer to next line */
66 short *spc; /* character spacing */
67 int width; /* total line width */
68 /* followed by the string */
69 } TLINE;
70
71 #define TLSTR(l) ((char *)((l)+1))
72
73 typedef struct {
74 FVECT right, down; /* right and down unit vectors */
75 FONT *f; /* our font */
76 TLINE tl; /* line list */
77 } TEXT;
78
79 static TLINE * tlalloc(char *s);
80 static TEXT * gettext(OBJREC *tm);
81 static int intext(FVECT p, OBJREC *m);
82 static int inglyph(double x, double y, GLYPH *gl);
83
84
85 extern int
86 do_text(
87 register OBJREC *m,
88 RAY *r
89 )
90 {
91 FVECT v;
92 int foreground;
93 /* get transformed position */
94 if (r->rox != NULL)
95 multp3(v, r->rop, r->rox->b.xfm);
96 else
97 VCOPY(v, r->rop);
98 /* check if we are within a text glyph */
99 foreground = intext(v, m);
100 /* modify */
101 if (m->otype == MIX_TEXT) {
102 OBJECT omod;
103 char *modname = m->oargs.sarg[foreground ? 0 : 1];
104 if (!strcmp(modname, VOIDID))
105 omod = OVOID;
106 else if ((omod = lastmod(objndx(m), modname)) == OVOID) {
107 sprintf(errmsg, "undefined modifier \"%s\"", modname);
108 objerror(m, USER, errmsg);
109 }
110 if (rayshade(r, omod)) {
111 if (m->omod != OVOID)
112 objerror(m, USER, "inappropriate modifier");
113 return(1);
114 }
115 } else if (m->otype == PAT_BTEXT) {
116 if (foreground)
117 scalecolor(r->pcol, m->oargs.farg[9]);
118 else
119 scalecolor(r->pcol, m->oargs.farg[10]);
120 } else { /* PAT_CTEXT */
121 COLOR cval;
122 if (foreground)
123 setcolor(cval, m->oargs.farg[9],
124 m->oargs.farg[10],
125 m->oargs.farg[11]);
126 else
127 setcolor(cval, m->oargs.farg[12],
128 m->oargs.farg[13],
129 m->oargs.farg[14]);
130 multcolor(r->pcol, cval);
131 }
132 return(0);
133 }
134
135
136 static TLINE *
137 tlalloc( /* allocate and assign text line */
138 char *s
139 )
140 {
141 register int siz;
142 register TLINE *tl;
143
144 siz = strlen(s) + 1;
145 if ((tl=(TLINE *)malloc(sizeof(TLINE)+siz)) == NULL ||
146 (tl->spc=(short *)malloc(siz*sizeof(short))) == NULL)
147 error(SYSTEM, "out of memory in tlalloc");
148 tl->next = NULL;
149 strcpy(TLSTR(tl), s);
150 return(tl);
151 }
152
153
154 static TEXT *
155 gettext( /* get text structure for material */
156 register OBJREC *tm
157 )
158 {
159 #define R (tm->oargs.farg+3)
160 #define D (tm->oargs.farg+6)
161 FVECT DxR;
162 double d;
163 FILE *fp;
164 char linbuf[512];
165 TEXT *t;
166 register int i;
167 register TLINE *tlp;
168 register char *s;
169
170 if ((t = (TEXT *)tm->os) != NULL)
171 return(t);
172 /* check arguments */
173 if (tm->oargs.nsargs - tndx(tm) < 1 || tm->oargs.nfargs < sndx(tm))
174 objerror(tm, USER, "bad # arguments");
175 if ((t = (TEXT *)malloc(sizeof(TEXT))) == NULL)
176 error(SYSTEM, "out of memory in gettext");
177 /* compute vectors */
178 fcross(DxR, D, R);
179 fcross(t->right, DxR, D);
180 d = DOT(t->right,t->right);
181 if (d <= FTINY*FTINY*FTINY*FTINY)
182 objerror(tm, USER, "illegal motion vector");
183 d = DOT(D,D)/d;
184 for (i = 0; i < 3; i++)
185 t->right[i] *= d;
186 fcross(t->down, R, DxR);
187 d = DOT(R,R)/DOT(t->down,t->down);
188 for (i = 0; i < 3; i++)
189 t->down[i] *= d;
190 /* get text */
191 tlp = &t->tl;
192 if (tm->oargs.nsargs - tndx(tm) > 1) { /* single line */
193 s = linbuf;
194 for (i = tndx(tm)+1; i < tm->oargs.nsargs; i++) {
195 strcpy(s, tm->oargs.sarg[i]);
196 s += strlen(s);
197 *s++ = ' ';
198 }
199 *--s = '\0';
200 tlp->next = tlalloc(linbuf);
201 tlp = tlp->next;
202 } else { /* text file */
203 if ((s = getpath(tm->oargs.sarg[tndx(tm)],
204 getrlibpath(), R_OK)) == NULL) {
205 sprintf(errmsg, "cannot find text file \"%s\"",
206 tm->oargs.sarg[tndx(tm)]);
207 error(USER, errmsg);
208 }
209 if ((fp = fopen(s, "r")) == NULL) {
210 sprintf(errmsg, "cannot open text file \"%s\"", s);
211 error(SYSTEM, errmsg);
212 }
213 while (fgets(linbuf, sizeof(linbuf), fp) != NULL) {
214 s = linbuf + strlen(linbuf) - 1;
215 if (*s == '\n')
216 *s = '\0';
217 tlp->next = tlalloc(linbuf);
218 tlp = tlp->next;
219 }
220 fclose(fp);
221 }
222 tlp->next = NULL;
223 /* get the font */
224 t->f = getfont(tm->oargs.sarg[fndx(tm)]);
225 /* compute character spacing */
226 i = sndx(tm);
227 d = i < tm->oargs.nfargs ? tm->oargs.farg[i] : 0.0;
228 i = d * 255.0;
229 t->tl.width = 0;
230 for (tlp = t->tl.next; tlp != NULL; tlp = tlp->next) {
231 if (i < 0)
232 tlp->width = squeeztext(tlp->spc, TLSTR(tlp), t->f, -i);
233 else if (i > 0)
234 tlp->width = proptext(tlp->spc, TLSTR(tlp), t->f, i, 3);
235 else
236 tlp->width = uniftext(tlp->spc, TLSTR(tlp), t->f);
237 if (tlp->width > t->tl.width)
238 t->tl.width = tlp->width;
239 }
240 /* we're done */
241 tm->os = (char *)t;
242 return(t);
243 #undef R
244 #undef D
245 }
246
247
248 extern void
249 freetext( /* free text structures associated with m */
250 OBJREC *m
251 )
252 {
253 register TEXT *tp;
254 register TLINE *tlp;
255
256 tp = (TEXT *)m->os;
257 if (tp == NULL)
258 return;
259 while ((tlp = tp->tl.next) != NULL) {
260 tp->tl.next = tlp->next;
261 free((void *)tlp->spc);
262 free((void *)tlp);
263 }
264 freefont(tp->f); /* release font reference */
265 free((void *)tp);
266 m->os = NULL;
267 }
268
269
270 static int
271 intext( /* check to see if p is in text glyph */
272 FVECT p,
273 OBJREC *m
274 )
275 {
276 register TEXT *tp;
277 register TLINE *tlp;
278 FVECT v;
279 double y, x;
280 register int i, h;
281 /* first, compute position in text */
282 tp = gettext(m);
283 v[0] = p[0] - m->oargs.farg[0];
284 v[1] = p[1] - m->oargs.farg[1];
285 v[2] = p[2] - m->oargs.farg[2];
286 x = DOT(v, tp->right);
287 i = sndx(m);
288 if (i < m->oargs.nfargs)
289 x *= tp->f->mwidth + 255.*fabs(m->oargs.farg[i]);
290 else
291 x *= 255.;
292 h = x;
293 i = y = DOT(v, tp->down);
294 if (x < 0.0 || y < 0.0)
295 return(0);
296 x -= (double)h;
297 y = ((i+1) - y)*255.;
298 /* find the line position */
299 for (tlp = tp->tl.next; tlp != NULL; tlp = tlp->next)
300 if (--i < 0)
301 break;
302 if (tlp == NULL || h >= tlp->width)
303 return(0);
304 for (i = 0; (h -= tlp->spc[i]) >= 0; i++)
305 if (h < 255 && inglyph(h+x, y,
306 tp->f->fg[TLSTR(tlp)[i]&0xff]))
307 return(1);
308 return(0);
309 }
310
311
312 static int
313 inglyph( /* (x,y) within font glyph gl? */
314 double x, /* real coordinates in range [0,255) */
315 double y,
316 register GLYPH *gl
317 )
318 {
319 int n, ncross;
320 int xlb, ylb;
321 int tv;
322 register GORD *p0, *p1;
323
324 if (gl == NULL)
325 return(0);
326 xlb = x;
327 ylb = y;
328 if (gl->left > xlb || gl->right <= xlb || /* check extent */
329 gl->bottom > ylb || gl->top <= ylb)
330 return(0);
331 xlb = xlb<<1 | 1; /* add 1/2 to test points... */
332 ylb = ylb<<1 | 1; /* ...so no equal comparisons */
333 n = gl->nverts; /* get # of vertices */
334 p0 = gvlist(gl) + 2*(n-1); /* connect last to first */
335 p1 = gvlist(gl);
336 ncross = 0;
337 /* positive x axis cross test */
338 while (n--) {
339 if ((p0[1]<<1 > ylb) ^ (p1[1]<<1 > ylb)) {
340 tv = (p0[0]<<1 > xlb) | ((p1[0]<<1 > xlb) << 1);
341 if (tv == 03)
342 ncross++;
343 else if (tv)
344 ncross += (p1[1] > p0[1]) ^
345 ((p0[1]-y)*(p1[0]-x) >
346 (p0[0]-x)*(p1[1]-y));
347 }
348 p0 = p1;
349 p1 += 2;
350 }
351 return(ncross & 01);
352 }