ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/ranimove1.c
Revision: 3.25
Committed: Thu Mar 12 17:19:18 2020 UTC (4 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.24: +2 -2 lines
Log Message:
Added precautionary testing when checking for FHUGE

File Contents

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