ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimove1.c
Revision: 3.7
Committed: Tue Oct 21 19:19:29 2003 UTC (20 years, 6 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 3.6: +5 -3 lines
Log Message:
Various platform compatibility fixes.

File Contents

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