ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimove1.c
Revision: 3.5
Committed: Mon Jul 21 22:30:19 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 3.4: +6 -5 lines
Log Message:
Eliminated copystruct() macro, which is unnecessary in ANSI.
Reduced ambiguity warnings for nested if/if/else clauses.

File Contents

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