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

# User Rev Content
1 greg 1.14 /* Copyright (c) 1991 Regents of the University of California */
2 greg 1.1
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 greg 1.8 #include "otypes.h"
21    
22 greg 1.14 #include "ambient.h"
23    
24 greg 1.1 #include "random.h"
25    
26     #define OCTSCALE 0.5 /* ceil((valid rad.)/(cube size)) */
27    
28 greg 1.14 typedef struct ambtree {
29     AMBVAL *alist; /* ambient value list */
30     struct ambtree *kid; /* 8 child nodes */
31     } AMBTREE; /* ambient octree */
32    
33 greg 1.1 extern CUBE thescene; /* contains space boundaries */
34    
35 greg 1.11 #define MAXASET 511 /* maximum number of elements in ambient set */
36     OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
37 greg 1.1
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 greg 2.7 static char *afname; /* ambient file name */
45     static long ambheadlen; /* length of ambient file header */
46 greg 1.1
47 greg 2.6 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
48    
49 greg 1.1 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
50    
51     #define newambtree() (AMBTREE *)calloc(8, sizeof(AMBTREE))
52    
53 greg 2.7 extern long ftell(), lseek();
54 greg 1.1
55 greg 2.7
56 greg 2.3 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 greg 2.4 if (maxarad <= FTINY)
70     maxarad = .001;
71 greg 2.3 }
72    
73    
74 greg 1.1 setambient(afile) /* initialize calculation */
75     char *afile;
76     {
77     AMBVAL amb;
78 greg 2.3 /* init ambient limits */
79     setambres(ambres);
80     /* open ambient file */
81 greg 2.7 if ((afname = afile) != NULL)
82 greg 1.1 if ((ambfp = fopen(afile, "r+")) != NULL) {
83 greg 2.6 initambfile(0);
84 greg 2.5 while (readambval(&amb, ambfp))
85 greg 1.1 avinsert(&amb, &atrunk, thescene.cuorg,
86     thescene.cusize);
87     /* align */
88 greg 2.6 fseek(ambfp, -((ftell(ambfp)-ambheadlen)%AMBVALSIZ), 1);
89     } else if ((ambfp = fopen(afile, "w")) != NULL)
90     initambfile(1);
91     else {
92 greg 1.1 sprintf(errmsg, "cannot open ambient file \"%s\"",
93     afile);
94     error(SYSTEM, errmsg);
95 greg 1.8 }
96     }
97    
98    
99 greg 2.6 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 greg 2.7 } 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 greg 2.6 ambheadlen = ftell(ambfp);
123     }
124    
125    
126 greg 1.8 ambnotify(obj) /* record new modifier */
127     OBJECT obj;
128     {
129 greg 1.11 static int hitlimit = 0;
130 greg 1.8 register OBJREC *o = objptr(obj);
131     register char **amblp;
132    
133 greg 1.11 if (hitlimit || !ismodifier(o->otype))
134 greg 1.8 return;
135     for (amblp = amblist; *amblp != NULL; amblp++)
136     if (!strcmp(o->oname, *amblp)) {
137 greg 1.11 if (ambset[0] >= MAXASET) {
138     error(WARNING, "too many modifiers in ambient list");
139     hitlimit++;
140     return; /* should this be fatal? */
141     }
142 greg 1.8 insertelem(ambset, obj);
143     return;
144 greg 1.1 }
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 greg 1.16 double d;
154 greg 1.1
155     if (ambdiv <= 0) /* no ambient calculation */
156     goto dumbamb;
157     /* check number of bounces */
158 greg 1.16 if (rdepth >= ambounce)
159 greg 1.1 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 greg 1.16 rdepth++;
167     d = doambient(acol, r, r->rweight, NULL, NULL);
168     rdepth--;
169     if (d == 0.0)
170 greg 1.1 goto dumbamb;
171 greg 1.16 return;
172 greg 1.1 }
173     /* get ambient value */
174     setcolor(acol, 0.0, 0.0, 0.0);
175 greg 1.16 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 greg 1.1 dumbamb: /* return global value */
186     copycolor(acol, ambval);
187     }
188    
189    
190     double
191 greg 1.16 sumambient(acol, r, al, at, c0, s) /* get interpolated ambient value */
192 greg 1.1 COLOR acol;
193     register RAY *r;
194 greg 1.16 int al;
195 greg 1.1 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 greg 1.7 /* do this node */
207 greg 1.1 wsum = 0.0;
208     for (av = at->alist; av != NULL; av = av->next) {
209     /*
210 greg 1.16 * Ambient level test.
211 greg 1.1 */
212 greg 1.16 if (av->lvl > al || av->weight < r->rweight-FTINY)
213 greg 1.1 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 greg 1.18 if (d*0.5 < -minarad*ambacc-.001)
240 greg 1.1 continue;
241     /*
242     * Jittering final test reduces image artifacts.
243     */
244     wt = sqrt(e1) + sqrt(e2);
245 greg 2.2 wt *= .9 + .2*urand(9015+samplendx);
246 greg 1.6 if (wt > ambacc)
247 greg 1.1 continue;
248     if (wt <= 1e-3)
249     wt = 1e3;
250     else
251     wt = 1.0 / wt;
252     wsum += wt;
253 greg 1.15 extambient(ct, av, r->rop, r->ron);
254 greg 1.1 scalecolor(ct, wt);
255     addcolor(acol, ct);
256 greg 1.7 }
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 greg 1.16 wsum += sumambient(acol, r, al, at->kid+i, ck0, s);
273 greg 1.1 }
274     return(wsum);
275     }
276    
277    
278     double
279 greg 1.16 makeambient(acol, r, al) /* make a new ambient value */
280 greg 1.1 COLOR acol;
281     register RAY *r;
282 greg 1.16 int al;
283 greg 1.1 {
284     AMBVAL amb;
285 greg 1.14 FVECT gp, gd;
286 greg 1.16 /* compute weight */
287     amb.weight = pow(AVGREFL, (double)al);
288 greg 1.17 if (r->rweight < 0.2*amb.weight) /* heuristic */
289 greg 1.16 amb.weight = r->rweight;
290     /* compute ambient */
291     amb.rad = doambient(acol, r, amb.weight, gp, gd);
292 greg 1.1 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 greg 1.16 amb.lvl = al;
298 greg 1.1 copycolor(amb.val, acol);
299 greg 1.14 VCOPY(amb.gpos, gp);
300     VCOPY(amb.gdir, gd);
301 greg 1.1 /* insert into tree */
302 greg 2.7 avsave(&amb); /* and save to file */
303 greg 1.1 return(amb.rad);
304 greg 1.15 }
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 greg 1.1 }
331    
332    
333     static
334 greg 2.7 avsave(av) /* insert and save an ambient value */
335 greg 1.1 AMBVAL *av;
336     {
337     static int nunflshed = 0;
338 greg 2.6
339 greg 2.7 avinsert(av, &atrunk, thescene.cuorg, thescene.cusize);
340 greg 1.1 if (ambfp == NULL)
341     return;
342 greg 2.5 if (writambval(av, ambfp) < 0)
343 greg 1.1 goto writerr;
344     if (++nunflshed >= AMBFLUSH) {
345 greg 2.7 if (ambsync() == EOF)
346 greg 1.1 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 greg 1.9 copystruct(av, aval);
370 greg 1.1 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 greg 2.7 }
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 greg 1.1 }