ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/ambient.c
Revision: 2.34
Committed: Mon Nov 6 12:03:13 1995 UTC (28 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.33: +12 -7 lines
Log Message:
added texturing to ambient value computation using extambient()

File Contents

# Content
1 /* Copyright (c) 1995 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
11 #include "ray.h"
12
13 #include "octree.h"
14
15 #include "otypes.h"
16
17 #include "ambient.h"
18
19 #include "random.h"
20
21 #ifndef OCTSCALE
22 #define OCTSCALE 1.0 /* ceil((valid rad.)/(cube size)) */
23 #endif
24 #ifndef AMBVWT
25 #define AMBVWT 250 /* relative ambient value weight (# calcs) */
26 #endif
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 extern char *shm_boundary; /* memory sharing boundary */
36
37 #define MAXASET 511 /* maximum number of elements in ambient set */
38 OBJECT ambset[MAXASET+1]={0}; /* ambient include/exclude set */
39
40 double maxarad; /* maximum ambient radius */
41 double minarad; /* minimum ambient radius */
42
43 static AMBTREE atrunk; /* our ambient trunk node */
44
45 static FILE *ambfp = NULL; /* ambient file pointer */
46 static int nunflshed = 0; /* number of unflushed ambient values */
47
48 #ifndef SORT_THRESH
49 #ifdef BIGMEM
50 #define SORT_THRESH ((9L<<20)/sizeof(AMBVAL))
51 #else
52 #define SORT_THRESH ((3L<<20)/sizeof(AMBVAL))
53 #endif
54 #endif
55 #ifndef SORT_INTVL
56 #define SORT_INTVL (SORT_THRESH*256)
57 #endif
58 #ifndef MAX_SORT_INTVL
59 #define MAX_SORT_INTVL (SORT_INTVL<<4)
60 #endif
61
62 static COLOR avsum = BLKCOLOR; /* computed ambient value sum */
63 static unsigned int nambvals = 0; /* number of computed ambient values */
64 static unsigned long ambclock = 0; /* ambient access clock */
65 static unsigned long lastsort = 0; /* time of last value sort */
66 static long sortintvl = SORT_INTVL; /* time until next sort */
67
68 #define MAXACLOCK (1L<<30) /* clock turnover value */
69 /*
70 * Track access times unless we are sharing ambient values
71 * through memory on a multiprocessor, when we want to avoid
72 * claiming our own memory (copy on write).
73 */
74 #define tracktime (shm_boundary == NULL || ambfp == NULL)
75
76 #define AMBFLUSH (BUFSIZ/AMBVALSIZ)
77
78 #define newambval() (AMBVAL *)bmalloc(sizeof(AMBVAL))
79
80 extern long ftell(), lseek();
81 static int initambfile(), avsave(), avinsert(), sortambvals();
82 static AMBVAL *avstore();
83 #ifdef F_SETLKW
84 static aflock();
85 #endif
86
87
88 setambres(ar) /* set ambient resolution */
89 int ar;
90 {
91 ambres = ar < 0 ? 0 : ar; /* may be done already */
92 /* set min & max radii */
93 if (ar <= 0) {
94 minarad = 0;
95 maxarad = thescene.cusize / 2.0;
96 } else {
97 minarad = thescene.cusize / ar;
98 maxarad = 64 * minarad; /* heuristic */
99 if (maxarad > thescene.cusize / 2.0)
100 maxarad = thescene.cusize / 2.0;
101 }
102 if (minarad <= FTINY)
103 minarad = 10*FTINY;
104 if (maxarad <= minarad)
105 maxarad = 64 * minarad;
106 }
107
108
109 setambacc(newa) /* set ambient accuracy */
110 double newa;
111 {
112 double ambdiff;
113
114 if (newa < 0.0)
115 newa = 0.0;
116 ambdiff = fabs(newa - ambacc);
117 if (ambdiff >= .01 && (ambacc = newa) > FTINY && nambvals > 0)
118 sortambvals(1); /* rebuild tree */
119 }
120
121
122 setambient(afile) /* initialize calculation */
123 char *afile;
124 {
125 long headlen;
126 AMBVAL amb;
127 /* init ambient limits */
128 setambres(ambres);
129 setambacc(ambacc);
130 if (afile == NULL)
131 return;
132 if (ambacc <= FTINY) {
133 sprintf(errmsg, "zero ambient accuracy so \"%s\" not opened",
134 afile);
135 error(WARNING, errmsg);
136 return;
137 }
138 /* open ambient file */
139 if ((ambfp = fopen(afile, "r+")) != NULL) {
140 initambfile(0);
141 headlen = ftell(ambfp);
142 while (readambval(&amb, ambfp))
143 avinsert(avstore(&amb));
144 /* align */
145 fseek(ambfp, -((ftell(ambfp)-headlen)%AMBVALSIZ), 1);
146 } else if ((ambfp = fopen(afile, "w+")) != NULL)
147 initambfile(1);
148 else {
149 sprintf(errmsg, "cannot open ambient file \"%s\"", afile);
150 error(SYSTEM, errmsg);
151 }
152 nunflshed++; /* lie */
153 ambsync();
154 }
155
156
157 ambnotify(obj) /* record new modifier */
158 OBJECT obj;
159 {
160 static int hitlimit = 0;
161 register OBJREC *o = objptr(obj);
162 register char **amblp;
163
164 if (hitlimit || !ismodifier(o->otype))
165 return;
166 for (amblp = amblist; *amblp != NULL; amblp++)
167 if (!strcmp(o->oname, *amblp)) {
168 if (ambset[0] >= MAXASET) {
169 error(WARNING, "too many modifiers in ambient list");
170 hitlimit++;
171 return; /* should this be fatal? */
172 }
173 insertelem(ambset, obj);
174 return;
175 }
176 }
177
178
179 ambient(acol, r, nrm) /* compute ambient component for ray */
180 COLOR acol;
181 register RAY *r;
182 FVECT nrm;
183 {
184 static int rdepth = 0; /* ambient recursion */
185 double d;
186
187 if (ambdiv <= 0) /* no ambient calculation */
188 goto dumbamb;
189 /* check number of bounces */
190 if (rdepth >= ambounce)
191 goto dumbamb;
192 /* check ambient list */
193 if (ambincl != -1 && r->ro != NULL &&
194 ambincl != inset(ambset, r->ro->omod))
195 goto dumbamb;
196
197 if (ambacc <= FTINY) { /* no ambient storage */
198 rdepth++;
199 d = doambient(acol, r, r->rweight, NULL, NULL);
200 rdepth--;
201 if (d <= FTINY)
202 goto dumbamb;
203 return;
204 }
205 /* resort memory? */
206 sortambvals(0);
207 /* get ambient value */
208 setcolor(acol, 0.0, 0.0, 0.0);
209 d = sumambient(acol, r, nrm, rdepth,
210 &atrunk, thescene.cuorg, thescene.cusize);
211 if (d > FTINY) {
212 scalecolor(acol, 1.0/d);
213 return;
214 }
215 rdepth++; /* need to cache new value */
216 d = makeambient(acol, r, nrm, rdepth-1);
217 rdepth--;
218 if (d > FTINY)
219 return;
220 dumbamb: /* return global value */
221 copycolor(acol, ambval);
222 #if AMBVWT
223 if (nambvals == 0)
224 return;
225 scalecolor(acol, (double)AMBVWT);
226 addcolor(acol, avsum); /* average in computations */
227 d = 1.0/(AMBVWT+nambvals);
228 scalecolor(acol, d);
229 #endif
230 }
231
232
233 double
234 sumambient(acol, r, rn, al, at, c0, s) /* get interpolated ambient value */
235 COLOR acol;
236 register RAY *r;
237 FVECT rn;
238 int al;
239 AMBTREE *at;
240 FVECT c0;
241 double s;
242 {
243 double d, e1, e2, wt, wsum;
244 COLOR ct;
245 FVECT ck0;
246 int i;
247 register int j;
248 register AMBVAL *av;
249
250 wsum = 0.0;
251 /* do this node */
252 for (av = at->alist; av != NULL; av = av->next) {
253 if (tracktime)
254 av->latick = ambclock++;
255 /*
256 * Ambient level test.
257 */
258 if (av->lvl > al) /* list sorted, so this works */
259 break;
260 if (av->weight < r->rweight-FTINY)
261 continue;
262 /*
263 * Ambient radius test.
264 */
265 d = av->pos[0] - r->rop[0];
266 e1 = d * d;
267 d = av->pos[1] - r->rop[1];
268 e1 += d * d;
269 d = av->pos[2] - r->rop[2];
270 e1 += d * d;
271 e1 /= av->rad * av->rad;
272 if (e1 > ambacc*ambacc*1.21)
273 continue;
274 /*
275 * Normal direction test.
276 */
277 e2 = (1.0 - DOT(av->dir, r->ron)) * r->rweight;
278 if (e2 < 0.0) e2 = 0.0;
279 if (e1 + e2 > ambacc*ambacc*1.21)
280 continue;
281 /*
282 * Ray behind test.
283 */
284 d = 0.0;
285 for (j = 0; j < 3; j++)
286 d += (r->rop[j] - av->pos[j]) *
287 (av->dir[j] + r->ron[j]);
288 if (d*0.5 < -minarad*ambacc-.001)
289 continue;
290 /*
291 * Jittering final test reduces image artifacts.
292 */
293 wt = sqrt(e1) + sqrt(e2);
294 if (wt > ambacc*(.9+.2*urand(9015+samplendx)))
295 continue;
296 if (wt <= 1e-3)
297 wt = 1e3;
298 else
299 wt = 1.0 / wt;
300 wsum += wt;
301 extambient(ct, av, r->rop, rn);
302 scalecolor(ct, wt);
303 addcolor(acol, ct);
304 }
305 if (at->kid == NULL)
306 return(wsum);
307 /* do children */
308 s *= 0.5;
309 for (i = 0; i < 8; i++) {
310 for (j = 0; j < 3; j++) {
311 ck0[j] = c0[j];
312 if (1<<j & i)
313 ck0[j] += s;
314 if (r->rop[j] < ck0[j] - OCTSCALE*s)
315 break;
316 if (r->rop[j] > ck0[j] + (1.0+OCTSCALE)*s)
317 break;
318 }
319 if (j == 3)
320 wsum += sumambient(acol, r, rn, al, at->kid+i, ck0, s);
321 }
322 return(wsum);
323 }
324
325
326 double
327 makeambient(acol, r, rn, al) /* make a new ambient value */
328 COLOR acol;
329 register RAY *r;
330 FVECT rn;
331 int al;
332 {
333 AMBVAL amb;
334 FVECT gp, gd;
335 /* compute weight */
336 amb.weight = pow(AVGREFL, (double)al);
337 if (r->rweight < 0.1*amb.weight) /* heuristic */
338 amb.weight = r->rweight;
339 /* compute ambient */
340 amb.rad = doambient(acol, r, amb.weight, gp, gd);
341 if (amb.rad <= FTINY)
342 return(0.0);
343 /* store it */
344 VCOPY(amb.pos, r->rop);
345 VCOPY(amb.dir, r->ron);
346 amb.lvl = al;
347 copycolor(amb.val, acol);
348 VCOPY(amb.gpos, gp);
349 VCOPY(amb.gdir, gd);
350 /* insert into tree */
351 avsave(&amb); /* and save to file */
352 if (rn != r->ron)
353 extambient(acol, &amb, r->rop, rn); /* texture */
354 return(amb.rad);
355 }
356
357
358 extambient(cr, ap, pv, nv) /* extrapolate value at pv, nv */
359 COLOR cr;
360 register AMBVAL *ap;
361 FVECT pv, nv;
362 {
363 FVECT v1, v2;
364 register int i;
365 double d;
366
367 d = 1.0; /* zeroeth order */
368 /* gradient due to translation */
369 for (i = 0; i < 3; i++)
370 d += ap->gpos[i]*(pv[i]-ap->pos[i]);
371 /* gradient due to rotation */
372 VCOPY(v1, ap->dir);
373 fcross(v2, v1, nv);
374 d += DOT(ap->gdir, v2);
375 if (d <= 0.0) {
376 setcolor(cr, 0.0, 0.0, 0.0);
377 return;
378 }
379 copycolor(cr, ap->val);
380 scalecolor(cr, d);
381 }
382
383
384 static
385 initambfile(creat) /* initialize ambient file */
386 int creat;
387 {
388 extern char *progname, *octname, VersionID[];
389
390 #ifdef F_SETLKW
391 aflock(creat ? F_WRLCK : F_RDLCK);
392 #endif
393 #ifdef MSDOS
394 setmode(fileno(ambfp), O_BINARY);
395 #endif
396 setbuf(ambfp, bmalloc(BUFSIZ+8));
397 if (creat) { /* new file */
398 newheader("RADIANCE", ambfp);
399 fprintf(ambfp, "%s -av %g %g %g -ab %d -aa %g ",
400 progname, colval(ambval,RED),
401 colval(ambval,GRN), colval(ambval,BLU),
402 ambounce, ambacc);
403 fprintf(ambfp, "-ad %d -as %d -ar %d %s\n",
404 ambdiv, ambssamp, ambres,
405 octname==NULL ? "" : octname);
406 fprintf(ambfp, "SOFTWARE= %s\n", VersionID);
407 fputformat(AMBFMT, ambfp);
408 putc('\n', ambfp);
409 putambmagic(ambfp);
410 } else if (checkheader(ambfp, AMBFMT, NULL) < 0 || !hasambmagic(ambfp))
411 error(USER, "bad ambient file");
412 }
413
414
415 static
416 avsave(av) /* insert and save an ambient value */
417 AMBVAL *av;
418 {
419 avinsert(avstore(av));
420 if (ambfp == NULL)
421 return;
422 if (writambval(av, ambfp) < 0)
423 goto writerr;
424 if (++nunflshed >= AMBFLUSH)
425 if (ambsync() == EOF)
426 goto writerr;
427 return;
428 writerr:
429 error(SYSTEM, "error writing ambient file");
430 }
431
432
433 static AMBVAL *
434 avstore(aval) /* allocate memory and store aval */
435 register AMBVAL *aval;
436 {
437 register AMBVAL *av;
438
439 if ((av = newambval()) == NULL)
440 error(SYSTEM, "out of memory in avstore");
441 copystruct(av, aval);
442 av->latick = ambclock;
443 av->next = NULL;
444 addcolor(avsum, av->val); /* add to sum for averaging */
445 nambvals++;
446 return(av);
447 }
448
449
450 #define ATALLOCSZ 512 /* #/8 trees to allocate at once */
451
452 static AMBTREE *atfreelist = NULL; /* free ambient tree structures */
453
454
455 static
456 AMBTREE *
457 newambtree() /* allocate 8 ambient tree structs */
458 {
459 register AMBTREE *atp, *upperlim;
460
461 if (atfreelist == NULL) { /* get more nodes */
462 atfreelist = (AMBTREE *)bmalloc(ATALLOCSZ*8*sizeof(AMBTREE));
463 if (atfreelist == NULL)
464 return(NULL);
465 /* link new free list */
466 upperlim = atfreelist + 8*(ATALLOCSZ-1);
467 for (atp = atfreelist; atp < upperlim; atp += 8)
468 atp->kid = atp + 8;
469 atp->kid = NULL;
470 }
471 atp = atfreelist;
472 atfreelist = atp->kid;
473 bzero((char *)atp, 8*sizeof(AMBTREE));
474 return(atp);
475 }
476
477
478 static
479 freeambtree(atp) /* free 8 ambient tree structs */
480 AMBTREE *atp;
481 {
482 atp->kid = atfreelist;
483 atfreelist = atp;
484 }
485
486
487 static
488 avinsert(av) /* insert ambient value in our tree */
489 register AMBVAL *av;
490 {
491 register AMBTREE *at;
492 register AMBVAL *ap;
493 AMBVAL avh;
494 FVECT ck0;
495 double s;
496 int branch;
497 register int i;
498
499 if (av->rad <= FTINY)
500 error(CONSISTENCY, "zero ambient radius in avinsert");
501 at = &atrunk;
502 VCOPY(ck0, thescene.cuorg);
503 s = thescene.cusize;
504 while (s*(OCTSCALE/2) > av->rad*ambacc) {
505 if (at->kid == NULL)
506 if ((at->kid = newambtree()) == NULL)
507 error(SYSTEM, "out of memory in avinsert");
508 s *= 0.5;
509 branch = 0;
510 for (i = 0; i < 3; i++)
511 if (av->pos[i] > ck0[i] + s) {
512 ck0[i] += s;
513 branch |= 1 << i;
514 }
515 at = at->kid + branch;
516 }
517 avh.next = at->alist; /* order by increasing level */
518 for (ap = &avh; ap->next != NULL; ap = ap->next)
519 if (ap->next->lvl >= av->lvl)
520 break;
521 av->next = ap->next;
522 ap->next = av;
523 at->alist = avh.next;
524 }
525
526
527 static
528 unloadatree(at, f) /* unload an ambient value tree */
529 register AMBTREE *at;
530 int (*f)();
531 {
532 register AMBVAL *av;
533 register int i;
534 /* transfer values at this node */
535 for (av = at->alist; av != NULL; av = at->alist) {
536 at->alist = av->next;
537 (*f)(av);
538 }
539 if (at->kid == NULL)
540 return;
541 for (i = 0; i < 8; i++) /* transfer and free children */
542 unloadatree(at->kid+i, f);
543 freeambtree(at->kid);
544 at->kid = NULL;
545 }
546
547
548 static AMBVAL **avlist1, **avlist2; /* ambient value lists for sorting */
549 static int i_avlist; /* index for lists */
550
551
552 static
553 av2list(av)
554 AMBVAL *av;
555 {
556 #ifdef DEBUG
557 if (i_avlist >= nambvals)
558 error(CONSISTENCY, "too many ambient values in av2list1");
559 #endif
560 avlist1[i_avlist] = avlist2[i_avlist] = av;
561 i_avlist++;
562 }
563
564
565 static int
566 alatcmp(avp1, avp2) /* compare ambient values for MRA */
567 AMBVAL **avp1, **avp2;
568 {
569 return((**avp2).latick - (**avp1).latick);
570 }
571
572
573 static int
574 aposcmp(avp1, avp2) /* compare ambient value positions */
575 AMBVAL **avp1, **avp2;
576 {
577 return(*avp1 - *avp2);
578 }
579
580
581 #ifdef DEBUG
582 static int
583 avlmemi(avaddr) /* find list position from address */
584 AMBVAL *avaddr;
585 {
586 register AMBVAL **avlpp;
587
588 avlpp = (AMBVAL **)bsearch((char *)&avaddr, (char *)avlist2,
589 nambvals, sizeof(AMBVAL *), aposcmp);
590 if (avlpp == NULL)
591 error(CONSISTENCY, "address not found in avlmemi");
592 return(avlpp - avlist2);
593 }
594 #else
595 #define avlmemi(avaddr) ((AMBVAL **)bsearch((char *)&avaddr,(char *)avlist2, \
596 nambvals,sizeof(AMBVAL *),aposcmp) - avlist2)
597 #endif
598
599
600 static
601 sortambvals(always) /* resort ambient values */
602 int always;
603 {
604 AMBTREE oldatrunk;
605 AMBVAL tav, *tap, *pnext;
606 register int i, j;
607 /* see if it's time yet */
608 if (!always && (ambclock < lastsort+sortintvl ||
609 nambvals < SORT_THRESH))
610 return;
611 /*
612 * The idea here is to minimize memory thrashing
613 * in VM systems by improving reference locality.
614 * We do this by periodically sorting our stored ambient
615 * values in memory in order of most recently to least
616 * recently accessed. This ordering was chosen so that new
617 * ambient values (which tend to be less important) go into
618 * higher memory with the infrequently accessed values.
619 * Since we expect our values to need sorting less
620 * frequently as the process continues, we double our
621 * waiting interval after each call.
622 * This routine is also called by setambacc() with
623 * the "always" parameter set to 1 so that the ambient
624 * tree will be rebuilt with the new accuracy parameter.
625 */
626 if (tracktime) { /* allocate pointer arrays to sort */
627 avlist1 = (AMBVAL **)malloc(nambvals*sizeof(AMBVAL *));
628 avlist2 = (AMBVAL **)malloc(nambvals*sizeof(AMBVAL *));
629 } else
630 avlist1 = avlist2 = NULL;
631 if (avlist2 == NULL) { /* no time tracking -- rebuild tree? */
632 if (avlist1 != NULL)
633 free((char *)avlist1);
634 if (always) { /* rebuild without sorting */
635 copystruct(&oldatrunk, &atrunk);
636 atrunk.alist = NULL;
637 atrunk.kid = NULL;
638 unloadatree(&oldatrunk, avinsert);
639 }
640 } else { /* sort memory by last access time */
641 /*
642 * Sorting memory is tricky because it isn't contiguous.
643 * We have to sort an array of pointers by MRA and also
644 * by memory position. We then copy values in "loops"
645 * to minimize memory hits. Nevertheless, we will visit
646 * everyone at least twice, and this is an expensive process
647 * when we're thrashing, which is when we need to do it.
648 */
649 #ifdef DEBUG
650 sprintf(errmsg, "sorting %u ambient values at ambclock=%lu...",
651 nambvals, ambclock);
652 eputs(errmsg);
653 #endif
654 i_avlist = 0;
655 unloadatree(&atrunk, av2list); /* empty current tree */
656 #ifdef DEBUG
657 if (i_avlist < nambvals)
658 error(CONSISTENCY, "missing ambient values in sortambvals");
659 #endif
660 qsort((char *)avlist1, nambvals, sizeof(AMBVAL *), alatcmp);
661 qsort((char *)avlist2, nambvals, sizeof(AMBVAL *), aposcmp);
662 for (i = 0; i < nambvals; i++) {
663 if (avlist1[i] == NULL)
664 continue;
665 tap = avlist2[i];
666 copystruct(&tav, tap);
667 for (j = i; (pnext = avlist1[j]) != tap;
668 j = avlmemi(pnext)) {
669 copystruct(avlist2[j], pnext);
670 avinsert(avlist2[j]);
671 avlist1[j] = NULL;
672 }
673 copystruct(avlist2[j], &tav);
674 avinsert(avlist2[j]);
675 avlist1[j] = NULL;
676 }
677 free((char *)avlist1);
678 free((char *)avlist2);
679 /* compute new sort interval */
680 sortintvl = ambclock - lastsort;
681 if (sortintvl >= MAX_SORT_INTVL/2)
682 sortintvl = MAX_SORT_INTVL;
683 else
684 sortintvl <<= 1; /* wait twice as long next */
685 #ifdef DEBUG
686 eputs("done\n");
687 #endif
688 }
689 if (ambclock >= MAXACLOCK)
690 ambclock = MAXACLOCK/2;
691 lastsort = ambclock;
692 }
693
694
695 #ifdef F_SETLKW
696
697 static
698 aflock(typ) /* lock/unlock ambient file */
699 int typ;
700 {
701 static struct flock fls; /* static so initialized to zeroes */
702
703 fls.l_type = typ;
704 if (fcntl(fileno(ambfp), F_SETLKW, &fls) < 0)
705 error(SYSTEM, "cannot (un)lock ambient file");
706 }
707
708
709 int
710 ambsync() /* synchronize ambient file */
711 {
712 static FILE *ambinp = NULL;
713 static long lastpos = -1;
714 long flen;
715 AMBVAL avs;
716 register int n;
717
718 if (nunflshed == 0)
719 return(0);
720 if (lastpos < 0) /* initializing (locked in initambfile) */
721 goto syncend;
722 /* gain exclusive access */
723 aflock(F_WRLCK);
724 /* see if file has grown */
725 if ((flen = lseek(fileno(ambfp), 0L, 2)) < 0)
726 goto seekerr;
727 if (n = flen - lastpos) { /* file has grown */
728 if (ambinp == NULL) { /* use duplicate filedes */
729 ambinp = fdopen(dup(fileno(ambfp)), "r");
730 if (ambinp == NULL)
731 error(SYSTEM, "fdopen failed in ambsync");
732 }
733 if (fseek(ambinp, lastpos, 0) < 0)
734 goto seekerr;
735 while (n >= AMBVALSIZ) { /* load contributed values */
736 readambval(&avs, ambinp);
737 avinsert(avstore(&avs));
738 n -= AMBVALSIZ;
739 }
740 /*** seek always as safety measure
741 if (n) ***/ /* alignment */
742 if (lseek(fileno(ambfp), flen-n, 0) < 0)
743 goto seekerr;
744 }
745 #ifdef DEBUG
746 if (ambfp->_ptr - ambfp->_base != nunflshed*AMBVALSIZ) {
747 sprintf(errmsg, "ambient file buffer at %d rather than %d",
748 ambfp->_ptr - ambfp->_base,
749 nunflshed*AMBVALSIZ);
750 error(CONSISTENCY, errmsg);
751 }
752 #endif
753 syncend:
754 n = fflush(ambfp); /* calls write() at last */
755 if ((lastpos = lseek(fileno(ambfp), 0L, 1)) < 0)
756 goto seekerr;
757 aflock(F_UNLCK); /* release file */
758 nunflshed = 0;
759 return(n);
760 seekerr:
761 error(SYSTEM, "seek failed in ambsync");
762 }
763
764 #else
765
766 int
767 ambsync() /* flush ambient file */
768 {
769 if (nunflshed == 0)
770 return(0);
771 nunflshed = 0;
772 return(fflush(ambfp));
773 }
774
775 #endif