ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimove1.c
Revision: 3.2
Committed: Tue Feb 25 02:47:24 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.1: +1 -56 lines
Log Message:
Replaced inline copyright notice with #include "copyright.h"

File Contents

# User Rev Content
1 greg 3.1 #ifndef lint
2     static const char RCSid[] = "$Id$";
3     #endif
4     /*
5     * ranimove1.c
6     *
7     * Basic frame rendering routines for ranimate(1).
8     *
9     * Created by Gregory Ward on Wed Jan 08 2003.
10     */
11    
12 greg 3.2 #include "copyright.h"
13 greg 3.1
14     #include "ranimove.h"
15     #include "otypes.h"
16     #include "random.h"
17    
18     double acctab[256]; /* accuracy value table */
19    
20     int hres, vres; /* frame resolution (fcur) */
21     double pixaspect; /* pixel aspect ratio */
22    
23     VIEW vw; /* view for this frame */
24     COLOR *cbuffer; /* color at each pixel */
25     float *zbuffer; /* depth at each pixel */
26     OBJECT *obuffer; /* object id at each pixel */
27     short *xmbuffer; /* x motion at each pixel */
28     short *ymbuffer; /* y motion at each pixel */
29     BYTE *abuffer; /* accuracy at each pixel */
30     BYTE *sbuffer; /* sample count per pixel */
31    
32     VIEW vwprev; /* last frame's view */
33     COLOR *cprev; /* last frame colors */
34     float *zprev; /* last frame depth */
35     OBJECT *oprev; /* last frame objects */
36     BYTE *aprev; /* last frame accuracy */
37    
38     float *cerrmap; /* conspicuous error map */
39     COLOR *val2map; /* value-squared map for variance */
40    
41     double frm_stop; /* when to stop rendering this frame */
42    
43     double hlsmax; /* maximum high-level saliency this frame */
44    
45    
46     void
47     write_map(mp, fn) /* write out float map (debugging) */
48     float *mp;
49     char *fn;
50     {
51     FILE *fp = fopen(fn, "w");
52     COLOR scanbuf[2048];
53     int x, y;
54    
55     if (fp == NULL)
56     return;
57     newheader("RADIANCE", fp);
58     fputformat(COLRFMT, fp);
59     fputc('\n', fp); /* end header */
60     fprtresolu(hres, vres, fp);
61     for (y = vres; y--; ) { /* write scanlines */
62     float *bp = mp + (y+1)*hres - 1;
63     for (x = hres; x--; bp--)
64     setcolor(scanbuf[x], *bp, *bp, *bp);
65     if (fwritescan(scanbuf, hres, fp) < 0)
66     break;
67     }
68     fclose(fp);
69     }
70    
71    
72     static void
73     next_frame() /* prepare next frame buffer */
74     {
75     VIEW *fv;
76     char *err;
77     /* get previous view */
78     if (vw.type != 0)
79     copystruct(&vwprev, &vw);
80     else if (fcur > 1 && (fv = getview(fcur-1)) != NULL) {
81     copystruct(&vwprev, fv);
82     if (setview(&vwprev) != NULL)
83     vwprev.type = 0;
84     }
85     /* get current view */
86     if ((fv = getview(fcur)) == NULL) {
87     sprintf(errmsg, "cannot get view for frame %d", fcur);
88     error(USER, errmsg);
89     }
90     copystruct(&vw, fv);
91     if ((err = setview(&vw)) != NULL) {
92     sprintf(errmsg, "view error at frame %d: %s", fcur, err);
93     error(USER, errmsg);
94     }
95     if (cbuffer == NULL) {
96     /* compute resolution and allocate */
97     switch (sscanf(vval(RESOLUTION), "%d %d %lf",
98     &hres, &vres, &pixaspect)) {
99     case 1:
100     vres = hres;
101     /* fall through */
102     case 2:
103     pixaspect = 1.;
104     /* fall through */
105     case 3:
106     if ((hres > 0 & vres > 0))
107     break;
108     /* fall through */
109     default:
110     sprintf(errmsg, "bad %s value", vnam(RESOLUTION));
111     error(USER, errmsg);
112     }
113     normaspect(viewaspect(&vw), &pixaspect, &hres, &vres);
114     cbuffer = (COLOR *)malloc(sizeof(COLOR)*hres*vres);
115     zbuffer = (float *)malloc(sizeof(float)*hres*vres);
116     obuffer = (OBJECT *)malloc(sizeof(OBJECT)*hres*vres);
117     xmbuffer = (short *)malloc(sizeof(short)*hres*vres);
118     ymbuffer = (short *)malloc(sizeof(short)*hres*vres);
119     abuffer = (BYTE *)calloc(hres*vres, sizeof(BYTE));
120     sbuffer = (BYTE *)calloc(hres*vres, sizeof(BYTE));
121     cprev = (COLOR *)malloc(sizeof(COLOR)*hres*vres);
122     zprev = (float *)malloc(sizeof(float)*hres*vres);
123     oprev = (OBJECT *)malloc(sizeof(OBJECT)*hres*vres);
124     aprev = (BYTE *)malloc(sizeof(BYTE)*hres*vres);
125     if ((cbuffer==NULL | zbuffer==NULL | obuffer==NULL |
126     xmbuffer==NULL | ymbuffer==NULL |
127     abuffer==NULL | sbuffer==NULL |
128     cprev==NULL | zprev == NULL |
129     oprev==NULL | aprev==NULL))
130     error(SYSTEM, "out of memory in init_frame");
131     frm_stop = getTime() + rtperfrm;
132     } else {
133     COLOR *cp; /* else just swap buffers */
134     float *fp;
135     OBJECT *op;
136     BYTE *bp;
137     cp = cprev; cprev = cbuffer; cbuffer = cp;
138     fp = zprev; zprev = zbuffer; zbuffer = fp;
139     op = oprev; oprev = obuffer; obuffer = op;
140     bp = aprev; aprev = abuffer; abuffer = bp;
141     bzero(abuffer, sizeof(BYTE)*hres*vres);
142     bzero(sbuffer, sizeof(BYTE)*hres*vres);
143     frm_stop += rtperfrm;
144     }
145     cerrmap = NULL;
146     val2map = NULL;
147     }
148    
149    
150     #define SAMPDIST 3 /* Maximum distance to neighbor sample */
151     #define SAMPDIST2 (SAMPDIST*SAMPDIST)
152    
153    
154     static int
155     sample_here(x, y) /* 4x4 quincunx sample at this pixel? */
156     register int x, y;
157     {
158     if (y & 0x1) /* every other row has samples */
159     return(0);
160     if (y & 0x3) /* every fourth row is offset */
161     x += 2;
162     return((x & 0x3) == 0); /* every fourth column is sampled */
163     }
164    
165    
166     void
167     sample_pos(hv, x, y, sn) /* compute jittered sample position */
168     double hv[2];
169     int x, y;
170     int sn;
171     {
172     int hl[2];
173    
174     hl[0] = x; hl[1] = y;
175     multisamp(hv, 2, urand(ilhash(hl,2) + sn));
176     hv[0] = ((double)x + hv[0]) / (double)hres;
177     hv[1] = ((double)y + hv[1]) / (double)vres;
178     }
179    
180    
181     double
182     sample_wt(xo, yo) /* compute interpolant sample weight */
183     int xo, yo;
184     {
185     static double etab[400];
186     int rad2 = xo*xo + yo*yo;
187     int i;
188    
189     if (etab[0] <= FTINY) /* initialize exponent table */
190     for (i = 400; i--; )
191     etab[i] = exp(-0.1*i);
192    
193     /* look up Gaussian */
194     i = (int)((10.*3./(double)SAMPDIST2)*rad2 + .5);
195     if (i >= 400)
196     return(0.0);
197     return(etab[i]);
198     }
199    
200    
201     static int
202     offset_cmp(p1, p2) /* compare offset distances */
203     const void *p1, *p2;
204     {
205     return(*(const int *)p1 - *(const int *)p2);
206     }
207    
208    
209     int
210     getclosest(iarr, nc, x, y) /* get nc closest neighbors on same object */
211     int *iarr;
212     int nc;
213     int x, y;
214     {
215     #define NSCHECK ((2*SAMPDIST+1)*(2*SAMPDIST+1))
216     static int hro, vro;
217     static int ioffs[NSCHECK];
218     OBJECT myobj;
219     int i0, nf;
220     register int i, j;
221     /* get our object number */
222     myobj = obuffer[fndx(x, y)];
223     /* special case for borders */
224     if ((x < SAMPDIST | x >= hres-SAMPDIST |
225     y < SAMPDIST | y >= vres-SAMPDIST)) {
226     int tndx[NSCHECK][2];
227     nf = 0;
228     for (j = y - SAMPDIST; j <= y + SAMPDIST; j++) {
229     if (j >= vres) break;
230     if (j < 0) j = 0;
231     for (i = x - SAMPDIST; i <= x + SAMPDIST; i++) {
232     if (i >= hres) break;
233     if (i < 0) i = 0;
234     i0 = fndx(i, j);
235     if (!sbuffer[i0])
236     continue;
237     if ((myobj != OVOID & obuffer[i0] != myobj))
238     continue;
239     tndx[nf][0] = (i-x)*(i-x) + (j-y)*(j-y);
240     tndx[nf][1] = i0;
241     nf++;
242     }
243     }
244     qsort((void *)tndx, nf, 2*sizeof(int), offset_cmp);
245     if (nf > nc)
246     nf = nc;
247     for (i = nf; i--; )
248     iarr[i] = tndx[i][1];
249     return(nf);
250     }
251     /* initialize offset array */
252     if ((hres != hro | vres != vro)) {
253     int toffs[NSCHECK][2];
254     i0 = fndx(SAMPDIST, SAMPDIST);
255     nf = 0;
256     for (i = 0; i <= 2*SAMPDIST; i++)
257     for (j = 0; j <= 2*SAMPDIST; j++) {
258     toffs[nf][0] = (i-SAMPDIST)*(i-SAMPDIST) +
259     (j-SAMPDIST)*(j-SAMPDIST);
260     toffs[nf][1] = fndx(i, j) - i0;
261     nf++;
262     }
263     qsort((void *)toffs, nf, 2*sizeof(int), offset_cmp);
264     for (i = NSCHECK; i--; )
265     ioffs[i] = toffs[i][1];
266     hro = hres;
267     vro = vres;
268     }
269     /* find up to nc neighbors */
270     i0 = fndx(x, y);
271     for (j = 0, nf = 0; (j < NSCHECK & nf < nc); j++) {
272     i = i0 + ioffs[j];
273     if (sbuffer[i] && (myobj == OVOID | obuffer[i] == myobj))
274     iarr[nf++] = i;
275     }
276     /* return number found */
277     return(nf);
278     #undef NSCHECK
279     }
280    
281    
282     static void
283     setmotion(n, wpos) /* compute motion vector for this pixel */
284     register int n;
285     FVECT wpos;
286     {
287     FVECT ovp;
288     MAT4 xfm;
289     double d;
290     int moi;
291     int xp, yp;
292     /* ID object and update maximum HLS */
293     moi = getmove(obuffer[n]);
294     if (moi >= 0 && obj_move[moi].cprio > hlsmax)
295     hlsmax = obj_move[moi].cprio;
296     if (vwprev.type == 0) /* return leaves MO_UNK */
297     return;
298     if (moi >= 0) { /* move object point back */
299     multp3(ovp, wpos, obj_move[moi].bxfm);
300     wpos = ovp;
301     }
302     viewloc(ovp, &vwprev, wpos);
303     if (ovp[2] <= FTINY)
304     return;
305     xp = (int)(ovp[0]*hres);
306     yp = (int)(ovp[1]*vres);
307     xmbuffer[n] = xp - (n % hres);
308     ymbuffer[n] = yp - (n / hres);
309     if ((xp < 0 | xp >= hres))
310     return;
311     if ((yp < 0 | yp >= vres))
312     return;
313     n = fndx(xp, yp);
314     if ((zprev[n] < 0.97*ovp[2] | zprev[n] > 1.03*ovp[2]))
315     oprev[n] = OVOID; /* assume it's a bad match */
316     }
317    
318    
319     static void
320     init_frame_sample() /* sample our initial frame */
321     {
322     RAY ir;
323     int x, y;
324     register int n;
325    
326     if (!silent) {
327     printf("\tComputing initial samples...");
328     fflush(stdout);
329     }
330     hlsmax = CSF_SMN;
331     for (y = vres; y--; )
332     for (x = hres; x--; ) {
333     double hv[2];
334     n = fndx(x, y);
335     xmbuffer[n] = MO_UNK;
336     ymbuffer[n] = MO_UNK;
337     sample_pos(hv, x, y, 0);
338     ir.rmax = viewray(ir.rorg, ir.rdir, &vw, hv[0], hv[1]);
339     if (ir.rmax < -FTINY) {
340     setcolor(cbuffer[n], 0., 0., 0.);
341     zbuffer[n] = FHUGE;
342     obuffer[n] = OVOID;
343     abuffer[n] = ADISTANT;
344     continue;
345     }
346     if (!sample_here(x, y)) { /* just cast */
347     rayorigin(&ir, NULL, PRIMARY, 1.0);
348     if (!localhit(&ir, &thescene)) {
349     if (ir.ro != &Aftplane)
350     sourcehit(&ir);
351     copycolor(cbuffer[n], ir.rcol);
352     zbuffer[n] = ir.rot;
353     obuffer[n] = ir.robj;
354     abuffer[n] = ADISTANT;
355     sbuffer[n] = 1;
356     } else {
357     zbuffer[n] = ir.rot;
358     obuffer[n] = ir.robj;
359     setmotion(n, ir.rop);
360     }
361     continue;
362     }
363     if (nprocs > 1) { /* get sample */
364     int rval;
365     rayorigin(&ir, NULL, PRIMARY, 1.0);
366     ir.rno = n;
367     rval = ray_pqueue(&ir);
368     if (!rval)
369     continue;
370     if (rval < 0)
371     quit(1);
372     n = ir.rno;
373     } else
374     ray_trace(&ir);
375     copycolor(cbuffer[n], ir.rcol);
376     zbuffer[n] = ir.rot;
377     obuffer[n] = ir.robj;
378     sbuffer[n] = 1;
379     if (ir.rot >= FHUGE)
380     abuffer[n] = ADISTANT;
381     else {
382     abuffer[n] = ALOWQ;
383     setmotion(n, ir.rop);
384     }
385     }
386     if (nprocs > 1) /* get stragglers */
387     while (ray_presult(&ir, 0)) {
388     n = ir.rno;
389     copycolor(cbuffer[n], ir.rcol);
390     zbuffer[n] = ir.rot;
391     obuffer[n] = ir.robj;
392     sbuffer[n] = 1;
393     if (ir.rot >= FHUGE)
394     abuffer[n] = ADISTANT;
395     else {
396     abuffer[n] = ALOWQ;
397     setmotion(n, ir.rop);
398     }
399     }
400     /* ambiguate object boundaries */
401     for (y = vres-1; y--; )
402     for (x = hres-1; x--; ) {
403     OBJECT obj;
404     n = fndx(x, y);
405     if ((obj = obuffer[n]) == OVOID)
406     continue;
407     if ((obuffer[n+1] != OVOID & obuffer[n+1] != obj)) {
408     obuffer[n] = OVOID;
409     obuffer[n+1] = OVOID;
410     }
411     if ((obuffer[n+hres] != OVOID & obuffer[n+hres] != obj)) {
412     obuffer[n] = OVOID;
413     obuffer[n+hres] = OVOID;
414     }
415     }
416    
417     if (!silent)
418     printf("done\n");
419     }
420    
421    
422     int
423     getambcolor(clr, obj) /* get ambient color for object if we can */
424     COLOR clr;
425     int obj;
426     {
427     register OBJREC *op;
428    
429     if (obj == OVOID)
430     return(0);
431     op = objptr(obj);
432     if ((op->otype == OBJ_INSTANCE & op->omod == OVOID))
433     return(0);
434     /* search for material */
435     do {
436     if (op->omod == OVOID || ofun[op->otype].flags & T_X)
437     return(0);
438     op = objptr(op->omod);
439     } while (!ismaterial(op->otype));
440     /*
441     * Since this routine is called to compute the difference
442     * from rendering with and without interreflections,
443     * we don't want to return colors for materials that are
444     * explicitly excluded from the HQ ambient calculation.
445     */
446     if (hirendparams.ambincl >= 0) {
447     int i;
448     char *lv;
449     for (i = 0; (lv = rpambmod(&hirendparams,i)) != NULL; i++)
450     if (lv[0] == op->oname[0] &&
451     !strcmp(lv+1, op->oname+1))
452     break;
453     if ((lv != NULL) != hirendparams.ambincl)
454     return(0);
455     }
456     switch (op->otype) {
457     case MAT_PLASTIC:
458     case MAT_METAL:
459     case MAT_PLASTIC2:
460     case MAT_METAL2:
461     case MAT_PFUNC:
462     case MAT_MFUNC:
463     case MAT_PDATA:
464     case MAT_MDATA:
465     case MAT_TRANS:
466     case MAT_TRANS2:
467     case MAT_TFUNC:
468     case MAT_TDATA:
469     if (op->oargs.nfargs < 3)
470     return(0);
471     setcolor(clr, op->oargs.farg[0], op->oargs.farg[1],
472     op->oargs.farg[2]);
473     return(1);
474     case MAT_BRTDF:
475     if (op->oargs.nfargs < 6)
476     return(0);
477     setcolor(clr, op->oargs.farg[0]+op->oargs.farg[3],
478     op->oargs.farg[1]+op->oargs.farg[4],
479     op->oargs.farg[2]+op->oargs.farg[5]);
480     scalecolor(clr, 0.5);
481     return(1);
482     case MAT_LIGHT:
483     case MAT_GLOW:
484     case MAT_ILLUM:
485     setcolor(clr, 0., 0., 0.);
486     return(1);
487     }
488     return(0);
489     }
490    
491    
492     double
493     estimaterr(cs, cs2, ns, ns0) /* estimate relative error from samples */
494     COLOR cs, cs2;
495     int ns;
496     {
497     double d, d2, brt;
498    
499     if (ns <= 1 || (brt = bright(cs)/ns) < 1e-14)
500     return(1.0);
501     /* use largest of RGB std. dev. */
502     d2 = colval(cs2,RED) - colval(cs,RED)*colval(cs,RED)/ns;
503     d = colval(cs2,GRN) - colval(cs,GRN)*colval(cs,GRN)/ns;
504     if (d > d2) d2 = d;
505     d = colval(cs2,BLU) - colval(cs,BLU)*colval(cs,BLU)/ns;
506     if (d > d2) d2 = d;
507     /* use s.d. if <= 1 central sample */
508     if (ns0 <= 1)
509     return(sqrt(d2/(ns-1))/brt);
510     /* use s.d./sqrt(ns0) otherwise */
511     return(sqrt(d2/((ns-1)*ns0))/brt);
512     }
513    
514    
515     double
516     comperr(neigh, nc, ns0) /* estimate relative error in neighborhood */
517     int *neigh;
518     int nc;
519     int ns0;
520     {
521     COLOR csum, csum2;
522     COLOR ctmp;
523     int i;
524     int ns;
525     register int n;
526     /* add together samples */
527     setcolor(csum, 0., 0., 0.);
528     setcolor(csum2, 0., 0., 0.);
529     for (i = 0, ns = 0; (i < nc & ns < NSAMPOK); i++) {
530     n = neigh[i];
531     addcolor(csum, cbuffer[n]);
532     if (val2map != NULL) {
533     addcolor(csum2, val2map[n]);
534     ns += sbuffer[n];
535     continue;
536     }
537     if (sbuffer[n] != 1)
538     error(CONSISTENCY, "bad count in comperr");
539     setcolor(ctmp,
540     colval(cbuffer[n],RED)*colval(cbuffer[n],RED),
541     colval(cbuffer[n],GRN)*colval(cbuffer[n],GRN),
542     colval(cbuffer[n],BLU)*colval(cbuffer[n],BLU));
543     addcolor(csum2, ctmp);
544     ns++;
545     }
546     return(estimaterr(csum, csum2, ns, ns0));
547     }
548    
549    
550     void
551     comp_frame_error() /* initialize frame error values */
552     {
553     BYTE *edone = NULL;
554     COLOR objamb;
555     double eest;
556     int neigh[NSAMPOK];
557     int nc;
558     int x, y, i, j;
559     register int n;
560    
561     if (!silent) {
562     printf("\tComputing error map\n");
563     fflush(stdout);
564     }
565     if (acctab[0] <= FTINY) /* initialize accuracy table */
566     for (i = 256; i--; )
567     acctab[i] = errorf(i);
568     /* estimate sample error */
569     if (!curparams->ambounce && hirendparams.ambounce) {
570     /*
571     * Our error estimate for the initial value is based
572     * on the assumption that most of it comes from the
573     * lack of an interreflection calculation. The relative
574     * error should be less than the ambient value divided
575     * by the returned ray value -- we take half of this.
576     */
577     edone = (BYTE *)calloc(hres*vres, sizeof(BYTE));
578     for (y = vres; y--; )
579     for (x = hres; x--; ) {
580     n = fndx(x, y);
581     if ((abuffer[n] != ALOWQ | obuffer[n] == OVOID))
582     continue;
583     if (!getambcolor(objamb, obuffer[n]))
584     continue;
585     multcolor(objamb, ambval);
586     if ((eest = bright(cbuffer[n])) <= FTINY)
587     continue;
588     eest = bright(objamb) / eest;
589     if (eest > 1.) /* should we report this? */
590     continue;
591     eest *= 0.50; /* use 50% ambient error */
592     i = errori(eest);
593     if (i < AMIN) i = AMIN;
594     else if (i >= ADISTANT/2) i = ADISTANT/2-1;
595     abuffer[n] = i;
596     edone[n] = 1;
597     }
598     }
599     /* final statistical estimate */
600     for (y = vres; y--; )
601     for (x = hres; x--; ) {
602     n = fndx(x, y);
603     if (abuffer[n] == ADISTANT)
604     continue; /* don't update these */
605     if (edone != NULL && edone[n])
606     continue; /* already done this */
607     if (sbuffer[n] >= 255) {
608     abuffer[n] = ADISTANT;
609     continue; /* can't take any more */
610     }
611     nc = getclosest(neigh, NSAMPOK, x, y);
612     if (nc <= 0) {
613     abuffer[n] = ANOVAL;
614     continue; /* no clue what to do for him */
615     }
616     i = errori(comperr(neigh, nc, sbuffer[n]));
617     if (i < AMIN) i = AMIN;
618     else if (i >= ADISTANT) i = ADISTANT-1;
619     abuffer[n] = i;
620     /* can't be better than closest */
621     if (i < abuffer[neigh[0]] && abuffer[neigh[0]] >= AMIN)
622     abuffer[n] = abuffer[neigh[0]];
623     }
624     if (edone != NULL)
625     free((void *)edone);
626     }
627    
628    
629     void
630     init_frame() /* render base (low quality) frame */
631     {
632     int restart;
633    
634     /* allocate/swap buffers */
635     next_frame();
636     /* check rendering status */
637     restart = (!nobjects || vdef(MOVE));
638     if (!restart && curparams != &lorendparams && nprocs > 1)
639     restart = -1;
640     if (restart > 0)
641     if (nprocs > 1)
642     ray_pdone(1);
643     else
644     ray_done(1);
645     /* post low quality parameters */
646     if (curparams != &lorendparams)
647     ray_restore(curparams = &lorendparams);
648     if (restart > 0) { /* load new octree */
649     char *oct = getoctspec(fcur);
650     if (oct == NULL) {
651     sprintf(errmsg, "cannot get scene for frame %d", fcur);
652     error(USER, errmsg);
653     }
654     if (!silent) {
655     printf("\tLoading octree...");
656     fflush(stdout);
657     }
658     if (nprocs > 1)
659     ray_pinit(oct, nprocs);
660     else
661     ray_init(oct);
662     } else if (restart < 0) { /* update children */
663     if (!silent) {
664     printf("\tRestarting %d processes...", nprocs);
665     fflush(stdout);
666     }
667     ray_pclose(0);
668     ray_popen(nprocs);
669     }
670     if (restart && !silent)
671     printf("done\n");
672     /* sample frame buffer */
673     init_frame_sample();
674     /* initialize frame error */
675     comp_frame_error();
676     return;
677     {
678     float *ebuf = (float *)malloc(sizeof(float)*hres*vres);
679     char fnm[256];
680     register int n;
681     for (n = hres*vres; n--; )
682     ebuf[n] = acctab[abuffer[n]];
683     sprintf(fnm, vval(BASENAME), fcur);
684     strcat(fnm, "_inerr.pic");
685     write_map(ebuf, fnm);
686     free((void *)ebuf);
687     }
688     }
689    
690    
691     void
692     filter_frame() /* interpolation, motion-blur, and exposure */
693     {
694     double expval = expspec_val(getexp(fcur));
695     int x, y;
696     int neigh[NPINTERP];
697     int nc;
698     COLOR cval;
699     double w, wsum;
700     register int n;
701    
702     #if 0
703     /* XXX TEMPORARY!! */
704     conspicuity();
705     write_map(cerrmap, "outcmap.pic");
706     {
707     float *ebuf = (float *)malloc(sizeof(float)*hres*vres);
708     for (n = hres*vres; n--; )
709     ebuf[n] = acctab[abuffer[n]];
710     write_map(ebuf, "outerr.pic");
711     free((void *)ebuf);
712     }
713     #endif
714    
715     if (!silent) {
716     printf("\tFiltering frame\n");
717     fflush(stdout);
718     }
719     /* normalize samples */
720     for (y = vres; y--; )
721     for (x = hres; x--; ) {
722     n = fndx(x, y);
723     if (sbuffer[n] <= 1)
724     continue;
725     w = 1.0/(double)sbuffer[n];
726     scalecolor(cbuffer[n], w);
727     }
728     /* interpolate samples */
729     for (y = vres; y--; )
730     for (x = hres; x--; ) {
731     n = fndx(x, y);
732     if (sbuffer[n])
733     continue;
734     nc = getclosest(neigh, NPINTERP, x, y);
735     setcolor(cbuffer[n], 0., 0., 0.);
736     wsum = 0.;
737     while (nc-- > 0) {
738     copycolor(cval, cbuffer[neigh[nc]]);
739     w = sample_wt((neigh[nc]%hres) - x,
740     (neigh[nc]/hres) - y);
741     scalecolor(cval, w);
742     addcolor(cbuffer[n], cval);
743     wsum += w;
744     }
745     if (wsum > FTINY) {
746     w = 1.0/wsum;
747     scalecolor(cbuffer[n], w);
748     }
749     }
750     /* motion blur if requested */
751     if (mblur > .02) {
752     int len;
753     int xs, ys, xl, yl;
754     int rise, run;
755     long rise2, run2;
756     int n2;
757     int cnt;
758     /* sum in motion streaks */
759     bzero(outbuffer, sizeof(COLOR)*hres*vres);
760     bzero(wbuffer, sizeof(float)*hres*vres);
761     for (y = vres; y--; )
762     for (x = hres; x--; ) {
763     n = fndx(x, y);
764     if (xmbuffer[n] == MO_UNK) {
765     run = rise = 0;
766     } else {
767     run = (int)(mblur*xmbuffer[n]);
768     rise = (int)(mblur*ymbuffer[n]);
769     }
770     if (!(run | rise)) {
771     addcolor(outbuffer[n], cbuffer[n]);
772     wbuffer[n] += 1.;
773     continue;
774     }
775     xl = x - run/4;
776     yl = y - rise/4;
777     if (run < 0) { xs = -1; run = -run; }
778     else xs = 1;
779     if (rise < 0) { ys = -1; rise = -rise; }
780     else ys = 1;
781     rise2 = run2 = 0L;
782     if (rise > run) {
783     cnt = rise + 1;
784     w = 1./cnt;
785     copycolor(cval, cbuffer[n]);
786     scalecolor(cval, w);
787     while (cnt)
788     if (rise2 >= run2) {
789     if ((xl >= 0 & xl < hres &
790     yl >= 0 & yl < vres)) {
791     n2 = fndx(xl, yl);
792     addcolor(outbuffer[n2],
793     cval);
794     wbuffer[n2] += w;
795     }
796     yl += ys;
797     run2 += run;
798     cnt--;
799     } else {
800     xl += xs;
801     rise2 += rise;
802     }
803     } else {
804     cnt = run + 1;
805     w = 1./cnt;
806     copycolor(cval, cbuffer[n]);
807     scalecolor(cval, w);
808     while (cnt)
809     if (run2 >= rise2) {
810     if ((xl >= 0 & xl < hres &
811     yl >= 0 & yl < vres)) {
812     n2 = fndx(xl, yl);
813     addcolor(outbuffer[n2],
814     cval);
815     wbuffer[n2] += w;
816     }
817     xl += xs;
818     rise2 += rise;
819     cnt--;
820     } else {
821     yl += ys;
822     run2 += run;
823     }
824     }
825     }
826     /* compute final results */
827     for (y = vres; y--; )
828     for (x = hres; x--; ) {
829     n = fndx(x, y);
830     if (wbuffer[n] <= FTINY)
831     continue;
832     w = 1./wbuffer[n];
833     scalecolor(outbuffer[n], w);
834     }
835     } else
836     for (n = hres*vres; n--; )
837     copycolor(outbuffer[n], cbuffer[n]);
838     /*
839     for (n = hres*vres; n--; )
840     if (!sbuffer[n])
841     setcolor(outbuffer[n], 0., 0., 0.);
842     */
843     /* adjust exposure */
844     if ((expval < 0.99 | expval > 1.01))
845     for (n = hres*vres; n--; )
846     scalecolor(outbuffer[n], expval);
847     return;
848     {
849     float *sbuf = (float *)malloc(sizeof(float)*hres*vres);
850     char fnm[256];
851     sprintf(fnm, vval(BASENAME), fcur);
852     strcat(fnm, "_outsamp.pic");
853     for (n = hres*vres; n--; )
854     sbuf[n] = (float)sbuffer[n];
855     write_map(sbuf, fnm);
856     free((void *)sbuf);
857     }
858     }
859    
860    
861     void
862     send_frame() /* send frame to destination */
863     {
864     char pfname[1024];
865     double d;
866     FILE *fp;
867     int y;
868     /* open output picture */
869     sprintf(pfname, vval(BASENAME), fcur);
870     strcat(pfname, ".pic");
871     fp = fopen(pfname, "w");
872     if (fp == NULL) {
873     sprintf(errmsg, "cannot open output frame \"%s\"", pfname);
874     error(SYSTEM, errmsg);
875     }
876     #ifdef MSDOS
877     setmode(fileno(fp), O_BINARY);
878     #endif
879     if (!silent) {
880     printf("\tWriting to \"%s\"\n", pfname);
881     fflush(stdout);
882     }
883     /* write header */
884     newheader("RADIANCE", fp);
885     printargs(gargc, gargv, fp);
886     fprintf(fp, "SOFTWARE= %s\n", VersionID);
887     fprintf(fp, "FRAME=%d\n", fcur);
888     fputnow(fp);
889     fputs(VIEWSTR, fp); fprintview(&vw, fp); fputc('\n', fp);
890     d = expspec_val(getexp(fcur));
891     if ((d < 0.99 | d > 1.01))
892     fputexpos(d, fp);
893     d = viewaspect(&vw) * hres / vres;
894     if ((d < 0.99 | d > 1.01))
895     fputaspect(d, fp);
896     fputformat(COLRFMT, fp);
897     fputc('\n', fp); /* end header */
898     fprtresolu(hres, vres, fp);
899     if (fflush(fp) == EOF)
900     goto writerr;
901     #if (PIXSTANDARD != (YMAJOR|YDECR))
902     error(CONSISTENCY, "bad code in send_frame");
903     #endif
904     for (y = vres; y--; ) /* write scanlines */
905     if (fwritescan(outbuffer+y*hres, hres, fp) < 0)
906     goto writerr;
907     if (fclose(fp) == EOF)
908     goto writerr;
909     return; /* all is well */
910     writerr:
911     sprintf(errmsg, "error writing frame \"%s\"", pfname);
912     error(SYSTEM, errmsg);
913     }
914    
915    
916     void
917     free_frame() /* free frame allocation */
918     {
919     if (cbuffer == NULL)
920     return;
921     free((void *)cbuffer); cbuffer = NULL;
922     free((void *)zbuffer); zbuffer = NULL;
923     free((void *)obuffer); obuffer = NULL;
924     free((void *)xmbuffer); xmbuffer = NULL;
925     free((void *)ymbuffer); ymbuffer = NULL;
926     free((void *)cprev); cprev = NULL;
927     free((void *)zprev); zprev = NULL;
928     free((void *)oprev); oprev = NULL;
929     cerrmap = NULL;
930     val2map = NULL;
931     hres = vres = 0;
932     vw.type = vwprev.type = 0;
933     frm_stop = 0;
934     }