| 1 | greg | 3.1 | #ifndef lint | 
| 2 | schorsch | 3.6 | static const char       RCSid[] = "$Id: ranimove1.c,v 3.5 2003/07/21 22:30:19 schorsch Exp $"; | 
| 3 | greg | 3.1 | #endif | 
| 4 |  |  | /* | 
| 5 |  |  | *  ranimove1.c | 
| 6 |  |  | * | 
| 7 |  |  | *  Basic frame rendering routines for ranimate(1). | 
| 8 |  |  | * | 
| 9 |  |  | *  Created by Gregory Ward on Wed Jan 08 2003. | 
| 10 |  |  | */ | 
| 11 |  |  |  | 
| 12 | greg | 3.2 | #include "copyright.h" | 
| 13 | greg | 3.1 |  | 
| 14 | schorsch | 3.4 | #include <string.h> | 
| 15 |  |  |  | 
| 16 | schorsch | 3.3 | #include "platform.h" | 
| 17 | greg | 3.1 | #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 | schorsch | 3.5 | vwprev = vw; | 
| 83 | greg | 3.1 | else if (fcur > 1 && (fv = getview(fcur-1)) != NULL) { | 
| 84 | schorsch | 3.5 | vwprev = *fv; | 
| 85 | greg | 3.1 | 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 | schorsch | 3.5 | vw = *fv; | 
| 94 | greg | 3.1 | 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 | schorsch | 3.6 | if ((hres > 0) & (vres > 0)) | 
| 110 | greg | 3.1 | 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 | schorsch | 3.6 | 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 | greg | 3.1 | 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 | schorsch | 3.4 | memset(abuffer, '\0', sizeof(BYTE)*hres*vres); | 
| 145 |  |  | memset(sbuffer, '\0', sizeof(BYTE)*hres*vres); | 
| 146 | greg | 3.1 | 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 | schorsch | 3.6 | if ((x < SAMPDIST) | (x >= hres-SAMPDIST) | | 
| 228 |  |  | (y < SAMPDIST) | (y >= vres-SAMPDIST)) { | 
| 229 | greg | 3.1 | 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 | schorsch | 3.6 | if ((myobj != OVOID) & (obuffer[i0] != myobj)) | 
| 241 | greg | 3.1 | 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 | schorsch | 3.6 | if ((hres != hro) | (vres != vro)) { | 
| 256 | greg | 3.1 | 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 | schorsch | 3.6 | for (j = 0, nf = 0; (j < NSCHECK) & (nf < nc); j++) { | 
| 275 | greg | 3.1 | i = i0 + ioffs[j]; | 
| 276 | schorsch | 3.6 | if (sbuffer[i] && (myobj == OVOID) | (obuffer[i] == myobj)) | 
| 277 | greg | 3.1 | 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 | schorsch | 3.6 | if ((xp < 0) | (xp >= hres)) | 
| 313 | greg | 3.1 | return; | 
| 314 | schorsch | 3.6 | if ((yp < 0) | (yp >= vres)) | 
| 315 | greg | 3.1 | return; | 
| 316 |  |  | n = fndx(xp, yp); | 
| 317 | schorsch | 3.6 | if ((zprev[n] < 0.97*ovp[2]) | (zprev[n] > 1.03*ovp[2])) | 
| 318 | greg | 3.1 | 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 | schorsch | 3.6 | if ((obuffer[n+1] != OVOID) & (obuffer[n+1] != obj)) { | 
| 411 | greg | 3.1 | obuffer[n] = OVOID; | 
| 412 |  |  | obuffer[n+1] = OVOID; | 
| 413 |  |  | } | 
| 414 | schorsch | 3.6 | if ((obuffer[n+hres] != OVOID) & (obuffer[n+hres] != obj)) { | 
| 415 | greg | 3.1 | 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 | schorsch | 3.6 | if ((op->otype == OBJ_INSTANCE) & (op->omod == OVOID)) | 
| 436 | greg | 3.1 | 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 | schorsch | 3.6 | for (i = 0, ns = 0; (i < nc) & (ns < NSAMPOK); i++) { | 
| 533 | greg | 3.1 | 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 | schorsch | 3.6 | if ((abuffer[n] != ALOWQ) | (obuffer[n] == OVOID)) | 
| 585 | greg | 3.1 | 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 | schorsch | 3.5 | if (restart > 0) { | 
| 644 | greg | 3.1 | if (nprocs > 1) | 
| 645 |  |  | ray_pdone(1); | 
| 646 |  |  | else | 
| 647 |  |  | ray_done(1); | 
| 648 | schorsch | 3.5 | } | 
| 649 | greg | 3.1 | /* 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 | schorsch | 3.4 | memset(outbuffer, '\0', sizeof(COLOR)*hres*vres); | 
| 764 |  |  | memset(wbuffer, '\0', sizeof(float)*hres*vres); | 
| 765 | greg | 3.1 | 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 | schorsch | 3.6 | if ((xl >= 0) & (xl < hres) & | 
| 794 |  |  | (yl >= 0) & (yl < vres)) { | 
| 795 | greg | 3.1 | 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 | schorsch | 3.6 | if ((xl >= 0) & (xl < hres) & | 
| 815 |  |  | (yl >= 0) & (yl < vres)) { | 
| 816 | greg | 3.1 | 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 | schorsch | 3.6 | if ((expval < 0.99) | (expval > 1.01)) | 
| 849 | greg | 3.1 | 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 | schorsch | 3.3 | SET_FILE_BINARY(fp); | 
| 881 | greg | 3.1 | 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 | schorsch | 3.6 | if ((d < 0.99) | (d > 1.01)) | 
| 894 | greg | 3.1 | fputexpos(d, fp); | 
| 895 |  |  | d = viewaspect(&vw) * hres / vres; | 
| 896 | schorsch | 3.6 | if ((d < 0.99) | (d > 1.01)) | 
| 897 | greg | 3.1 | 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 |  |  | } |