ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.7
Committed: Thu Jul 16 13:37:12 1992 UTC (31 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +53 -9 lines
Log Message:
added calls to lock ambient file and guarantee synchronization
between cooperating processes

File Contents

# Content
1 /* Copyright (c) 1991 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * ambient.c - routines dealing with ambient (inter-reflected) component.
9 *
10 * The macro AMBFLUSH (if defined) is the number of ambient values
11 * to wait before flushing to the ambient file.
12 *
13 * 5/9/86
14 */
15
16 #include "ray.h"
17
18 #include "octree.h"
19
20 #include "otypes.h"
21
22 #include "ambient.h"
23
24 #include "random.h"
25
26 #define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
27
28 typedef struct ambtree {
29 AMBVAL *alist; /* ambient value list */
30 struct ambtree *kid; /* 8 child nodes */
31 } AMBTREE; /* ambient octree */
32
33 extern CUBE thescene; /* contains space boundaries */
34
35 #define MAXASET 511 /* maximum number of elements in ambient set */
36 OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
37
38 double maxarad; /* maximum ambient radius */
39 double minarad; /* minimum ambient radius */
40
41 static AMBTREE atrunk; /* our ambient trunk node */
42
43 static FILE *ambfp = NULL; /* ambient file pointer */
44 static char *afname; /* ambient file name */
45 static long ambheadlen; /* length of ambient file header */
46
47 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
48
49 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
50
51 #define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
52
53 extern long ftell(), lseek();
54
55
56 setambres(ar) /* set ambient resolution */
57 int ar;
58 {
59 /* set min & max radii */
60 if (ar <= 0) {
61 minarad = 0.0;
62 maxarad = thescene.cusize / 2.0;
63 } else {
64 minarad = thescene.cusize / ar;
65 maxarad = 16.0 * minarad; /* heuristic */
66 if (maxarad > thescene.cusize / 2.0)
67 maxarad = thescene.cusize / 2.0;
68 }
69 if (maxarad <= FTINY)
70 maxarad = .001;
71 }
72
73
74 setambient(afile) /* initialize calculation */
75 char *afile;
76 {
77 AMBVAL amb;
78 /* init ambient limits */
79 setambres(ambres);
80 /* open ambient file */
81 if ((afname = afile) != NULL)
82 if ((ambfp = fopen(afile, "r+")) != NULL) {
83 initambfile(0);
84 while (readambval(&amb, ambfp))
85 avinsert(&amb, &atrunk, thescene.cuorg,
86 thescene.cusize);
87 /* align */
88 fseek(ambfp, -((ftell(ambfp)-ambheadlen)%AMBVALSIZ), 1);
89 } else if ((ambfp = fopen(afile, "w")) != NULL)
90 initambfile(1);
91 else {
92 sprintf(errmsg, "cannot open ambient file \"%s\"",
93 afile);
94 error(SYSTEM, errmsg);
95 }
96 }
97
98
99 initambfile(creat) /* initialize ambient file */
100 int creat;
101 {
102 extern char *progname, *octname;
103
104 setbuf(ambfp, bmalloc(BUFSIZ));
105 if (creat) { /* new file */
106 fprintf(ambfp, "%s -av %g %g %g -ab %d -aa %g ",
107 progname, colval(ambval,RED),
108 colval(ambval,GRN), colval(ambval,BLU),
109 ambounce, ambacc);
110 fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
111 ambdiv, ambssamp, ambres,
112 octname==NULL ? "" : octname);
113 fputformat(AMBFMT, ambfp);
114 putc('\n', ambfp);
115 putambmagic(ambfp);
116 fflush(ambfp);
117 } else if (checkheader(ambfp, AMBFMT, NULL) < 0
118 || !hasambmagic(ambfp)) {
119 sprintf(errmsg, "\"%s\" is not an ambient file", afname);
120 error(USER, afname);
121 }
122 ambheadlen = ftell(ambfp);
123 }
124
125
126 ambnotify(obj) /* record new modifier */
127 OBJECT obj;
128 {
129 static int hitlimit = 0;
130 register OBJREC *o = objptr(obj);
131 register char **amblp;
132
133 if (hitlimit || !ismodifier(o->otype))
134 return;
135 for (amblp = amblist; *amblp != NULL; amblp++)
136 if (!strcmp(o->oname, *amblp)) {
137 if (ambset[0] >= MAXASET) {
138 error(WARNING, "too many modifiers in ambient list");
139 hitlimit++;
140 return; /* should this be fatal? */
141 }
142 insertelem(ambset, obj);
143 return;
144 }
145 }
146
147
148 ambient(acol, r) /* compute ambient component for ray */
149 COLOR acol;
150 register RAY *r;
151 {
152 static int rdepth = 0; /* ambient recursion */
153 double d;
154
155 if (ambdiv <= 0) /* no ambient calculation */
156 goto dumbamb;
157 /* check number of bounces */
158 if (rdepth >= ambounce)
159 goto dumbamb;
160 /* check ambient list */
161 if (ambincl != -1 && r->ro != NULL &&
162 ambincl != inset(ambset, r->ro->omod))
163 goto dumbamb;
164
165 if (ambacc <= FTINY) { /* no ambient storage */
166 rdepth++;
167 d = doambient(acol, r, r->rweight, NULL, NULL);
168 rdepth--;
169 if (d == 0.0)
170 goto dumbamb;
171 return;
172 }
173 /* get ambient value */
174 setcolor(acol, 0.0, 0.0, 0.0);
175 d = sumambient(acol, r, rdepth,
176 &atrunk, thescene.cuorg, thescene.cusize);
177 if (d > FTINY)
178 scalecolor(acol, 1.0/d);
179 else {
180 d = makeambient(acol, r, rdepth++);
181 rdepth--;
182 }
183 if (d > FTINY)
184 return;
185 dumbamb: /* return global value */
186 copycolor(acol, ambval);
187 }
188
189
190 double
191 sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
192 COLOR acol;
193 register RAY *r;
194 int al;
195 AMBTREE *at;
196 FVECT c0;
197 double s;
198 {
199 extern double sqrt();
200 double d, e1, e2, wt, wsum;
201 COLOR ct;
202 FVECT ck0;
203 int i;
204 register int j;
205 register AMBVAL *av;
206 /* do this node */
207 wsum = 0.0;
208 for (av = at->alist; av != NULL; av = av->next) {
209 /*
210 * Ambient level test.
211 */
212 if (av->lvl > al || av->weight < r->rweight-FTINY)
213 continue;
214 /*
215 * Ambient radius test.
216 */
217 e1 = 0.0;
218 for (j = 0; j < 3; j++) {
219 d = av->pos[j] - r->rop[j];
220 e1 += d * d;
221 }
222 e1 /= av->rad * av->rad;
223 if (e1 > ambacc*ambacc*1.21)
224 continue;
225 /*
226 * Normal direction test.
227 */
228 e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
229 if (e2 < 0.0) e2 = 0.0;
230 if (e1 + e2 > ambacc*ambacc*1.21)
231 continue;
232 /*
233 * Ray behind test.
234 */
235 d = 0.0;
236 for (j = 0; j < 3; j++)
237 d += (r->rop[j] - av->pos[j]) *
238 (av->dir[j] + r->ron[j]);
239 if (d*0.5 < -minarad*ambacc-.001)
240 continue;
241 /*
242 * Jittering final test reduces image artifacts.
243 */
244 wt = sqrt(e1) + sqrt(e2);
245 wt *= .9 + .2*urand(9015+samplendx);
246 if (wt > ambacc)
247 continue;
248 if (wt <= 1e-3)
249 wt = 1e3;
250 else
251 wt = 1.0 / wt;
252 wsum += wt;
253 extambient(ct, av, r->rop, r->ron);
254 scalecolor(ct, wt);
255 addcolor(acol, ct);
256 }
257 if (at->kid == NULL)
258 return(wsum);
259 /* do children */
260 s *= 0.5;
261 for (i = 0; i < 8; i++) {
262 for (j = 0; j < 3; j++) {
263 ck0[j] = c0[j];
264 if (1<<j & i)
265 ck0[j] += s;
266 if (r->rop[j] < ck0[j] - OCTSCALE*s)
267 break;
268 if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
269 break;
270 }
271 if (j == 3)
272 wsum += sumambient(acol, r, al, at->kid+i, ck0, s);
273 }
274 return(wsum);
275 }
276
277
278 double
279 makeambient(acol, r, al) /* make a new ambient value */
280 COLOR acol;
281 register RAY *r;
282 int al;
283 {
284 AMBVAL amb;
285 FVECT gp, gd;
286 /* compute weight */
287 amb.weight = pow(AVGREFL, (double)al);
288 if (r->rweight < 0.2*amb.weight) /* heuristic */
289 amb.weight = r->rweight;
290 /* compute ambient */
291 amb.rad = doambient(acol, r, amb.weight, gp, gd);
292 if (amb.rad == 0.0)
293 return(0.0);
294 /* store it */
295 VCOPY(amb.pos, r->rop);
296 VCOPY(amb.dir, r->ron);
297 amb.lvl = al;
298 copycolor(amb.val, acol);
299 VCOPY(amb.gpos, gp);
300 VCOPY(amb.gdir, gd);
301 /* insert into tree */
302 avsave(&amb); /* and save to file */
303 return(amb.rad);
304 }
305
306
307 extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
308 COLOR cr;
309 register AMBVAL *ap;
310 FVECT pv, nv;
311 {
312 FVECT v1, v2;
313 register int i;
314 double d;
315
316 d = 1.0; /* zeroeth order */
317 /* gradient due to translation */
318 for (i = 0; i < 3; i++)
319 d += ap->gpos[i]*(pv[i]-ap->pos[i]);
320 /* gradient due to rotation */
321 VCOPY(v1, ap->dir);
322 fcross(v2, v1, nv);
323 d += DOT(ap->gdir, v2);
324 if (d <= 0.0) {
325 setcolor(cr, 0.0, 0.0, 0.0);
326 return;
327 }
328 copycolor(cr, ap->val);
329 scalecolor(cr, d);
330 }
331
332
333 static
334 avsave(av) /* insert and save an ambient value */
335 AMBVAL *av;
336 {
337 static int nunflshed = 0;
338
339 avinsert(av, &atrunk, thescene.cuorg, thescene.cusize);
340 if (ambfp == NULL)
341 return;
342 if (writambval(av, ambfp) < 0)
343 goto writerr;
344 if (++nunflshed >= AMBFLUSH) {
345 if (ambsync() == EOF)
346 goto writerr;
347 nunflshed = 0;
348 }
349 return;
350 writerr:
351 error(SYSTEM, "error writing ambient file");
352 }
353
354
355 static
356 avinsert(aval, at, c0, s) /* insert ambient value in a tree */
357 AMBVAL *aval;
358 register AMBTREE *at;
359 FVECT c0;
360 double s;
361 {
362 FVECT ck0;
363 int branch;
364 register AMBVAL *av;
365 register int i;
366
367 if ((av = newambval()) == NULL)
368 goto memerr;
369 copystruct(av, aval);
370 VCOPY(ck0, c0);
371 while (s*(OCTSCALE/2) > av->rad*ambacc) {
372 if (at->kid == NULL)
373 if ((at->kid = newambtree()) == NULL)
374 goto memerr;
375 s *= 0.5;
376 branch = 0;
377 for (i = 0; i < 3; i++)
378 if (av->pos[i] > ck0[i] + s) {
379 ck0[i] += s;
380 branch |= 1 << i;
381 }
382 at = at->kid + branch;
383 }
384 av->next = at->alist;
385 at->alist = av;
386 return;
387 memerr:
388 error(SYSTEM, "out of memory in avinsert");
389 }
390
391
392 #include <fcntl.h>
393
394
395 static
396 ambsync() /* synchronize ambient file */
397 {
398 static FILE *ambinp = NULL;
399 struct flock fls;
400 AMBVAL avs;
401 long lastpos, flen;
402 register int n;
403 /* gain exclusive access */
404 fls.l_type = F_WRLCK;
405 fls.l_whence = 0;
406 fls.l_start = 0L;
407 fls.l_len = 0L;
408 if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
409 error(SYSTEM, "cannot lock ambient file");
410 /* see if file has grown */
411 lastpos = lseek(fileno(ambfp), 0L, 2); /* may move pointer */
412 flen = lseek(fileno(ambfp), 0L, 1); /* new(?) file length */
413 if (n = (flen - lastpos)%AMBVALSIZ) /* assure alignment */
414 lseek(fileno(ambfp), flen -= n, 0);
415 if (n = (flen - lastpos)/AMBVALSIZ) { /* file has grown */
416 if (ambinp == NULL && (ambinp = fopen(afname, "r")) == NULL)
417 error(SYSTEM, "cannot reopen ambient file");
418 fseek(ambinp, lastpos, 0); /* go to previous position */
419 while (n--) { /* load contributed values */
420 readambval(&avs, ambinp);
421 avinsert(&avs,&atrunk,thescene.cuorg,thescene.cusize);
422 }
423 }
424 n = fflush(ambfp); /* calls write() at last */
425 fls.l_type = F_UNLCK; /* release file */
426 fcntl(fileno(ambfp), F_SETLKW, &fls);
427 return(n);
428 }