ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/text.c
Revision: 2.29
Committed: Wed Nov 15 18:02:53 2023 UTC (6 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.28: +10 -9 lines
Log Message:
feat(rpict,rtrace,rcontrib,rtpict): Hyperspectral rendering (except photon map)

File Contents

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