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, 1 month 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

# Content
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 #include "copyright.h"
13
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 }