ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RpictSimulManager.cpp
Revision: 2.7
Committed: Thu Aug 22 00:44:02 2024 UTC (8 months, 1 week ago) by greg
Branch: MAIN
Changes since 2.6: +3 -3 lines
Log Message:
perf(rxpict): Minor optimization calling getbinary() rather than read()

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.7 static const char RCSid[] = "$Id: RpictSimulManager.cpp,v 2.6 2024/08/21 23:52:24 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * RpictSimulManager.cpp
6     *
7     * Rpict simulation manager implementation
8     *
9     * Created by Greg Ward on 07/11/2024.
10     */
11    
12     #include <ctype.h>
13     #include "platform.h"
14     #include "RpictSimulManager.h"
15     #include "depthcodec.h"
16     #include "random.h"
17    
18     /************* Imported globals from rxpmain.c *************/
19    
20     extern VIEW ourview; /* viewing parameters */
21     extern int hres, vres; /* current image resolution */
22    
23     extern int psample; /* pixel sample size */
24     extern double maxdiff; /* max. sample difference */
25     extern double dstrpix; /* square pixel distribution */
26    
27     extern double mblur; /* motion blur parameter */
28    
29     extern double dblur; /* depth-of-field blur parameter */
30    
31     // Assign a pixel value (& depth) from rendered ray value
32     bool
33     PixelAccess::SetPixel(int x, int y, const RAY *rp)
34     {
35     if (!rp) return false;
36    
37     COLOR col;
38     float zv = 0; // get depth if needed
39     if (DepthType())
40     zv = raydistance(rp);
41    
42     switch (ColorSpace()) {
43     case RDTscolor: // keeping rendered spectrum?
44     case RDTscolr:
45     return SetPixel(x, y, rp->rcol, zv);
46     case RDTrgb:
47     case RDTrgbe:
48     case RDTxyz:
49     case RDTxyze:
50     scolor_out(col, primp, rp->rcol);
51     return SetPixel(x, y, col, zv);
52     default:
53 greg 2.2 error(INTERNAL, "botched color space type in SetPixel()");
54 greg 2.1 }
55     return false;
56     }
57    
58     // Set color space after non-empty initialization
59     bool
60     PixelAccess::SetColorSpace(RenderDataType cs, RGBPRIMP pr)
61     {
62     if (!dtyp) return false;
63    
64     if (!(cs = RDTcolorT(cs)))
65     cs = RDTcolorT(dtyp);
66     else if (RDTcommonE(cs) ^ RDTcommonE(dtyp))
67     return false;
68    
69     if (NCSAMP == 3) {
70     if (cs == RDTscolr) cs = RDTrgbe;
71     else if (cs == RDTscolor) cs = RDTrgb;
72     }
73     switch (cs) {
74     case RDTxyze:
75     case RDTxyz:
76     primp = xyzprims;
77     break;
78     case RDTrgbe:
79     case RDTrgb:
80     primp = pr ? pr : stdprims;
81     break;
82 greg 2.2 case RDTscolr:
83     case RDTscolor:
84 greg 2.1 primp = NULL;
85     break;
86 greg 2.2 default:
87     error(INTERNAL, "botched color space type in SetColorSpace()");
88 greg 2.1 }
89     dtyp = RDTnewCT(dtyp, cs);
90     return true;
91     }
92    
93     /*
94     * Set up rendering frame (call after octree loaded)
95     * Overall dimensions may be adjusted for view,
96     * optional pixel aspect ratio and tile grid
97     * Increments frameNo if >0
98     */
99     bool
100     RpictSimulManager::NewFrame(const VIEW &v, int xydim[2], double *ap, const int *tgrid)
101     {
102     double pasp = 1.;
103    
104     if (!xydim) return false;
105     if (!ap) ap = &pasp;
106     pvw = vw; // save previous view for motion blur
107     vw = v;
108     const char * verr = setview(&vw);
109     if (verr) {
110     error(WARNING, verr);
111     vw = pvw;
112     return false;
113     }
114     const double va = viewaspect(&vw);
115     normaspect(va, ap, &xydim[0], &xydim[1]);
116     // set up tiling?
117     if (tgrid && (tgrid[0] > 0) & (tgrid[1] > 0) & (tgrid[0]*tgrid[1] > 1)) {
118     if ((8*tgrid[0] >= xydim[0]) | (8*tgrid[1] >= xydim[1])) {
119     error(WARNING, "Excessive tiling for image size");
120     return false;
121     }
122     xydim[0] -= xydim[0] % (tgsize[0] = tgrid[0]);
123     xydim[1] -= xydim[1] % (tgsize[1] = tgrid[1]);
124     *ap = va * xydim[0] / xydim[1];
125     } else
126     tgsize[0] = tgsize[1] = 1;
127    
128     if (vw.vaft > FTINY) rtFlags |= RTlimDist;
129     else rtFlags &= ~RTlimDist;
130     hvres[0] = xydim[0]; hvres[1] = xydim[1];
131     thvres[0] = hvres[0]/tgsize[0]; // presumed tile width
132     thvres[1] = hvres[1]/tgsize[1]; // ...and height
133     frameNo += (frameNo > 0); // caller may override after
134     return true;
135     }
136    
137     // Call-back for rendered pixel
138     int
139     RpictSimulManager::RtCall(RAY *r, void *cd)
140     {
141     RpictSimulManager * rsp = (RpictSimulManager *)cd;
142 greg 2.2 const int ty = (r->rno-1) / rsp->TWidth();
143     const int tx = r->rno-1 - (RNUMBER)ty*rsp->TWidth();
144 greg 2.1
145     if (ty >= rsp->THeight()) {
146     error(INTERNAL, "bad pixel calculation position in RtCall()");
147     return -1;
148     }
149     if (!rsp->doneMap.TestAndSet(tx, ty)) {
150     error(WARNING, "duplicate pixel calculation");
151     return 0;
152     }
153     return rsp->pacc.SetPixel(tx, ty, r);
154     }
155    
156     // Set up the specified tile (or entire image if NULL)
157     bool
158     RpictSimulManager::SetTile(const int ti[2])
159     {
160     tvw = vw; ptvw = pvw;
161    
162     if (ti) {
163     if ((ti[0] < 0) | (ti[0] >= tgsize[0]) |
164     (ti[1] < 0) | (ti[1] >= tgsize[1])) {
165     error(INTERNAL, "illegal tile specification in SetTile()");
166     return false;
167     }
168     const char * verr = cropview(&tvw,
169     (double)ti[0]/tgsize[0],
170     (double)ti[1]/tgsize[1],
171     (ti[0]+1.)/tgsize[0],
172     (ti[1]+1.)/tgsize[1]);
173     if (verr) {
174     sprintf(errmsg, "crop failure @ tile (%d,%d)/(%d,%d): %s",
175     ti[0], ti[1], tgsize[0], tgsize[1], verr);
176     error(USER, errmsg);
177     return false;
178     } // previous tile view for blur
179     if (!ptvw.type | (mblur <= FTINY) ||
180     cropview(&ptvw, (double)ti[0]/tgsize[0],
181     (double)ti[1]/tgsize[1],
182     (ti[0]+1.)/tgsize[0],
183     (ti[1]+1.)/tgsize[1]))
184     ptvw.type = 0;
185    
186     } else if ((tgsize[0] > 1) | (tgsize[1] > 1)) {
187     error(INTERNAL, "missing tile specification in SetTile()");
188     return false;
189     }
190     return doneMap.NewBitMap(TWidth(), THeight());
191     }
192    
193     #define pixjitter() (.5+dstrpix*(.5-frandom()))
194    
195     // Send the indicated pixel to ray tracer
196     bool
197     RpictSimulManager::ComputePixel(int x, int y)
198     {
199     static const SCOLOR scBlack = {0};
200     int i;
201     FVECT rodir[2];
202     double hpos = (x+pixjitter())/TWidth();
203     double vpos = (y+pixjitter())/THeight();
204     double dlim = viewray(rodir[0], rodir[1], &tvw, hpos, vpos);
205     if (dlim < -FTINY) { // off view?
206     pacc.SetPixel(x, y, scBlack);
207     doneMap.Set(x, y);
208     return true;
209     }
210     if (ptvw.type) { // add motion blur if requested
211     FVECT rorg2, rdir2;
212     double dlim2 = viewray(rorg2, rdir2, &ptvw, hpos, vpos);
213     if (dlim2 >= -FTINY) {
214     const double d = mblur*(.5-frandom());
215     dlim = (1.-d)*dlim + d*dlim2;
216     for (i = 3; i--; ) {
217     rodir[0][i] = (1.-d)*rodir[0][i] + d*rorg2[i];
218     rodir[1][i] = (1.-d)*rodir[1][i] + d*rdir2[i];
219     }
220     if (normalize(rodir[1]) == 0)
221     return false;
222     }
223     }
224     // depth-of-field blur if any
225     if (!jitteraperture(rodir[0], rodir[1], &tvw, dblur))
226     return false;
227     // include aft clipping distance?
228     for (i = (dlim > FTINY)*3; i--; )
229     rodir[1][i] *= dlim;
230    
231 greg 2.2 return EnqueueRay(rodir[0], rodir[1], (RNUMBER)y*TWidth()+x+1);
232 greg 2.1 }
233    
234     // Check if neighbor differences are below pixel sampling threshold
235     bool
236     RpictSimulManager::BelowSampThresh(int x, int y, const int noff[4][2]) const
237     {
238     SCOLOR pval[4];
239     float dist[4];
240     int i, j;
241    
242     for (i = 4; i--; ) { // get pixels from tile store
243     int px = x + noff[i][0];
244     int py = y + noff[i][1];
245     if (!doneMap.Check(px, py) ||
246     !pacc.GetPixel(px, py, pval[i], &dist[i]))
247     return false;
248     }
249     const bool spectr = (pacc.NC() > 3);
250     for (i = 4; --i; ) // do pairwise comparisons
251     for (j = i; j--; ) {
252     if (pacc.DepthType() &&
253     (dist[i] - dist[j] > maxdiff*dist[j]) |
254     (dist[j] - dist[i] > maxdiff*dist[i]))
255     return false;
256     if (spectr ? sbigsdiff(pval[i], pval[j], maxdiff) :
257     bigdiff(pval[i], pval[j], maxdiff))
258     return false;
259     }
260     return true; // linear interpolation OK
261     }
262    
263     // Fill an interior square patch with interpolated values
264     void
265 greg 2.2 RpictSimulManager::FillSquare(const int x, const int y, const int noff[4][2])
266 greg 2.1 {
267     SCOLOR pval[4];
268     float dist[4];
269     int i, j;
270     // assumes 4 corners are valid!
271     for (i = 4; i--; )
272     pacc.GetPixel(x+noff[i][0], y+noff[i][1], pval[i], &dist[i]);
273    
274     i = abs(noff[1][0]-noff[0][0]);
275 greg 2.2 j = abs(noff[1][1]-noff[0][1]); // i==j for diamond fill
276     const int slen = (i > j) ? i : j;
277 greg 2.1 const bool spectr = (pacc.NC() > 3);
278 greg 2.2 for (i = slen+1 + (i==j)*slen; i--; ) {
279     const double c1 = (i>slen ? i-slen-.5 : (double)i)/slen;
280     for (j = slen + (i<=slen); j--; ) {
281     const double c2 = (j + (i>slen)*.5)/slen;
282 greg 2.1 const int px = int(x + (1.-c1)*(1.-c2)*noff[0][0] +
283     c1*(1.-c2)*noff[1][0] +
284     (1.-c1)*c2*noff[2][0] +
285     c1*c2*noff[3][0] + .5);
286     const int py = int(y + (1.-c1)*(1.-c2)*noff[0][1] +
287     c1*(1.-c2)*noff[1][1] +
288     (1.-c1)*c2*noff[2][1] +
289     c1*c2*noff[3][1] + .5);
290     if (!doneMap.TestAndSet(px, py))
291     continue;
292     float zval = 0;
293     if (pacc.DepthType())
294     zval = (1.-c1)*(1.-c2)*dist[0] + c1*(1.-c2)*dist[1] +
295     (1.-c1)*c2*dist[2] + c1*c2*dist[3];
296     if (spectr) { // XXX assumes pacc.NC() == NCSAMP
297     SCOLOR ipval, tpval;
298     copyscolor(ipval, pval[0]);
299     scalescolor(ipval, (1.-c1)*(1.-c2));
300     copyscolor(tpval, pval[1]);
301     scalescolor(tpval, c1*(1.-c2));
302     saddscolor(ipval, tpval);
303     copyscolor(tpval, pval[2]);
304     scalescolor(tpval, (1.-c1)*c2);
305     saddscolor(ipval, tpval);
306     copyscolor(tpval, pval[3]);
307     scalescolor(tpval, c1*c2);
308     saddscolor(ipval, tpval);
309     pacc.SetPixel(px, py, ipval, zval);
310     } else { // tristimulus interpolation
311     COLOR ipval, tpval;
312     copycolor(ipval, pval[0]);
313     scalecolor(ipval, (1.-c1)*(1.-c2));
314     copycolor(tpval, pval[1]);
315     scalecolor(tpval, c1*(1.-c2));
316     addcolor(ipval, tpval);
317     copycolor(tpval, pval[2]);
318     scalecolor(tpval, (1.-c1)*c2);
319     addcolor(ipval, tpval);
320     copycolor(tpval, pval[3]);
321     scalecolor(tpval, c1*c2);
322     addcolor(ipval, tpval);
323     pacc.SetPixel(px, py, ipval, zval);
324     }
325     }
326     }
327     }
328    
329     // helper function to set up quincunx sampling
330     static void
331     SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int spc, const bool odd)
332     {
333     for (int y = 0; y < bmp2->Height(); y += spc>>1)
334 greg 2.2 for (int x = (odd^(y&1))*(spc>>1); x < bmp2->Width(); x += spc)
335 greg 2.1 bmp2->Set(x, y);
336     // order neighbors CCW
337     if (odd) {
338     noff[0][0] = spc>>1; noff[0][1] = 0;
339     noff[1][0] = 0; noff[1][1] = spc>>1;
340     noff[2][0] = -(spc>>1); noff[2][1] = 0;
341     noff[3][0] = 0; noff[3][1] = -(spc>>1);
342     } else {
343     noff[0][0] = spc>>1; noff[0][1] = spc>>1;
344     noff[1][0] = -(spc>>1); noff[1][1] = spc>>1;
345     noff[2][0] = -(spc>>1); noff[2][1] = -(spc>>1);
346     noff[3][0] = spc>>1; noff[3][1] = -(spc>>1);
347     }
348     }
349    
350     // Render (or finish rendering) current tile
351     bool
352     RpictSimulManager::RenderRect()
353     {
354     if (!tvw.type || !Ready()) {
355     error(INTERNAL, "need octree and view for RenderRect()");
356     return false;
357     }
358     ABitMap2 doneSamples = doneMap;
359     int sp2 = ceil(log2((TWidth()>THeight() ? TWidth() : THeight()) - 1.));
360     int layer = 0;
361     int x, y;
362 greg 2.3 // fprintf(stderr, "Rendering %dx%d tile with psample=%d, maxdiff=%.3f ...\n",
363     // TWidth(), THeight(), psample, maxdiff);
364 greg 2.1 while (sp2 > 0) {
365     ABitMap2 sampMap(TWidth(), THeight());
366     int noff[4][2];
367     if ((prCB != NULL) & (barPix == NULL))
368     (*prCB)(100.*doneMap.SumTotal()/doneMap.Width()/doneMap.Height());
369     SetQuincunx(&sampMap, noff, 1<<sp2, layer&1);
370     sampMap -= doneSamples; // avoid resampling pixels
371     // Are we into adaptive sampling realm?
372     if (noff[0][0]*noff[0][0] + noff[0][1]*noff[0][1] < psample*psample) {
373 greg 2.2 if (FlushQueue() < 0) // need results to check thresholds
374 greg 2.1 return false;
375     ABitMap2 fillMap = sampMap;
376     for (x = y = 0; sampMap.Find(&x, &y); x++)
377     if (BelowSampThresh(x, y, noff))
378     sampMap.Reset(x, y);
379     // spread sampling to neighbors...
380     const ABitMap2 origSampMap = sampMap;
381 greg 2.2 for (x = 4; x--; ) {
382 greg 2.1 ABitMap2 stamp = origSampMap;
383 greg 2.2 stamp.Shift(noff[x][0], noff[x][1]);
384 greg 2.1 sampMap |= stamp;
385     } // ...but don't resample what's done
386     sampMap -= doneSamples;
387     // interpolate smooth regions
388     fillMap -= sampMap;
389     for (x = y = 0; fillMap.Find(&x, &y); x++)
390     FillSquare(x, y, noff);
391     doneSamples |= doneMap;
392     } // compute required ray samples
393     for (x = y = 0; sampMap.Find(&x, &y); x++)
394     if (!ComputePixel(x, y))
395     return false;
396     doneSamples |= sampMap; // samples now done or at least queued
397 greg 2.3 // fprintf(stderr, "Sampled %ld pixels at (sp2,layer)=(%d,%d)\n",
398     // (long)sampMap.SumTotal(), sp2, layer);
399     // fprintf(stderr, "\t%ld pixels (%.3f%%) completed (+%ld in process)\n",
400     // (long)doneMap.SumTotal(), 100.*doneMap.SumTotal()/doneMap.Width()/doneMap.Height(),
401     // (long)(doneSamples.SumTotal()-doneMap.SumTotal()));
402 greg 2.1 sp2 -= layer++ & 1; // next denser sampling
403     }
404     if (FlushQueue() < 0) // make sure we got everyone
405     return false;
406     x = y = 0;
407     if (doneMap.Find(&x, &y, false)) {
408     sprintf(errmsg, "missed %ld tile pixels, e.g. (%d,%d)",
409     (long)doneMap.Width()*doneMap.Height() -
410     doneMap.SumTotal(), x, y);
411     error(WARNING, errmsg);
412     }
413     if ((prCB != NULL) & (barPix == NULL))
414     (*prCB)(100.);
415     return true;
416     }
417    
418     /*
419     * Render the specified tile in frame
420     * Tile pixels are contiguous unless ystride != 0
421     * Tiles numbered from upper-left at (0,0)
422     * Pixel type influenced by this->prims assignment
423     */
424     bool
425     RpictSimulManager::RenderTile(COLORV *rp, int ystride, float *zp, const int *tile)
426     {
427     if (!rp | (GetWidth() <= 0) | (GetHeight() <= 0) | !vw.type)
428     return false;
429     if (!ystride) // contiguous rows?
430     ystride = TWidth();
431     pacc.Init(rp, ystride, zp);
432     if (prims == xyzprims)
433     pacc.SetColorSpace(RDTxyz);
434     else if (prims)
435     pacc.SetColorSpace(RDTrgb, prims);
436    
437     return SetTile(tile) && RenderRect();
438     }
439    
440     // Same but store as common-exponent COLR or SCOLR
441     bool
442     RpictSimulManager::RenderTile(COLRV *bp, int ystride, float *zp, const int *tile)
443     {
444     if (!bp | (GetWidth() <= 0) | (GetHeight() <= 0) | !vw.type)
445     return false;
446     if (!ystride) // contiguous rows?
447     ystride = TWidth();
448     pacc.Init(bp, ystride, zp);
449     if (prims == xyzprims)
450     pacc.SetColorSpace(RDTxyze);
451     else if (prims)
452     pacc.SetColorSpace(RDTrgbe, prims);
453    
454     return SetTile(tile) && RenderRect();
455     }
456    
457     // Same but also use 16-bit encoded depth buffer
458     bool
459     RpictSimulManager::RenderTile(COLRV *bp, int ystride, short *dp, const int *tile)
460     {
461     if (!bp | (GetWidth() <= 0) | (GetHeight() <= 0) | !vw.type)
462     return false;
463     if (!ystride) // contiguous rows?
464     ystride = TWidth();
465     pacc.Init(bp, ystride, dp);
466     if (prims == xyzprims)
467     pacc.SetColorSpace(RDTxyze);
468     else if (prims)
469     pacc.SetColorSpace(RDTrgbe, prims);
470    
471     return SetTile(tile) && RenderRect();
472     }
473    
474 greg 2.4 // Back to float color with 16-bit depth
475     bool
476     RpictSimulManager::RenderTile(COLORV *rp, int ystride, short *dp, const int *tile)
477     {
478     if (!rp | (GetWidth() <= 0) | (GetHeight() <= 0) | !vw.type)
479     return false;
480     if (!ystride) // contiguous rows?
481     ystride = TWidth();
482     pacc.Init(rp, ystride, dp);
483     if (prims == xyzprims)
484     pacc.SetColorSpace(RDTxyz);
485     else if (prims)
486     pacc.SetColorSpace(RDTrgb, prims);
487    
488     return SetTile(tile) && RenderRect();
489     }
490    
491 greg 2.1 // Allocate a new render bar
492     void
493     RpictSimulManager::NewBar(int ht)
494     {
495     delete [] barPix;
496     delete [] barDepth;
497     if (ht > GetHeight()) ht = GetHeight();
498     if ((ht <= 0) | (GetWidth() <= 0)) {
499     doneMap.NewBitMap(0,0);
500     pacc.Init();
501     barPix = NULL; barDepth = NULL;
502     return;
503     }
504     thvres[0] = GetWidth();
505     thvres[1] = ht;
506     const int NC = prims ? 3 : NCSAMP;
507     barPix = new COLORV [ht*thvres[0]*NC];
508     barDepth = new float [ht*thvres[0]];
509     pacc.Init(barPix + (ht-1)*thvres[0]*NC,
510     -thvres[0], barDepth + (ht-1)*thvres[0]);
511     if (prims == xyzprims)
512     pacc.SetColorSpace(RDTxyz);
513     else if (prims)
514     pacc.SetColorSpace(RDTrgb, prims);
515    
516     doneMap.NewBitMap(TWidth(), THeight());
517     }
518    
519     // Shift render bar area the specified amount down the frame
520     bool
521 greg 2.3 RpictSimulManager::LowerBar(int v, int ytop)
522 greg 2.1 {
523     if (!barPix | !barDepth | (v > THeight()) | !tvw.type)
524     return false;
525 greg 2.3 if (v <= 0) return !v;
526     if ((ytop -= v) <= 0)
527     return true;
528 greg 2.2 tvw.voff -= double(v)/THeight();
529     ptvw.voff -= double(v)/THeight();
530 greg 2.1 if (v == THeight()) {
531     doneMap.ClearBitMap();
532     return true;
533     }
534     const int NC = pacc.NC();
535     doneMap.Shift(0, v, false); // lift finished pixel samples
536     memmove(barPix, barPix + NC*TWidth()*v,
537     sizeof(COLORV)*NC*TWidth()*(THeight()-v));
538     memmove(barDepth, barDepth + TWidth()*v,
539     sizeof(float)*TWidth()*(THeight()-v));
540 greg 2.3 if (ytop < THeight()) { // mark what we won't do as finished
541     doneMap.ClearRect(0, 0, TWidth(), THeight()-ytop, true);
542     memset(barPix, 0, sizeof(COLORV)*NC*TWidth()*(THeight()-ytop));
543     memset(barDepth, 0, sizeof(float)*TWidth()*(THeight()-ytop));
544     }
545 greg 2.1 return true;
546     }
547    
548     // Continue rendering from the specified position
549     bool
550     RpictSimulManager::RenderBelow(int ytop, const int vstep, FILE *pfp, const int dt, FILE *dfp)
551     {
552     if (ytop <= 0)
553     return true;
554     ptvw = pvw; // set starting bar's view
555     tvw = vw;
556     const char * verr = cropview(&tvw, 0., double(ytop-THeight())/GetHeight(),
557     1., double(ytop)/GetHeight());
558     if (verr) {
559     sprintf(errmsg, "illegal render bar below y=%d: %s", ytop, verr);
560     error(INTERNAL, errmsg);
561     return false;
562     }
563     if (!ptvw.type | (mblur <= FTINY) ||
564     cropview(&ptvw, 0., double(ytop-THeight())/GetHeight(),
565     1., double(ytop)/GetHeight()))
566     ptvw.type = 0;
567     // set up spectral sampling
568     if (setspectrsamp(CNDX, WLPART) <= 0) {
569     error(USER, "unsupported spectral sampling");
570     return false;
571     }
572     COLORV ** parr = NULL; // set up tiny source drawing
573     float ** zarr = NULL;
574     if (!ptvw.type && directvis && dblur <= FTINY) {
575     parr = new COLORV * [THeight()];
576     zarr = new float * [THeight()];
577     for (int n = THeight(); n-- > 0; ) {
578     parr[THeight()-1-n] = barPix + pacc.NC()*TWidth()*n;
579     zarr[THeight()-1-n] = barDepth + TWidth()*n;
580     }
581     ourview = vw; hres = GetWidth(); vres = GetHeight();
582     init_drawsources(psample);
583     }
584     int lastOut = ytop; // render down frame
585     while (ytop > 0) {
586 greg 2.3 // fprintf(stderr, "At y=%d, source drawing %s...\n", ytop, parr ? "ON" : "OFF");
587 greg 2.1 if (prCB)
588     (*prCB)(100.*(GetHeight()-ytop)/GetHeight());
589     if (!RenderRect()) // render this bar
590     return false;
591     int nlines = lastOut - ytop + THeight();
592     if (nlines > ytop)
593     nlines = ytop;
594     else if (parr) // drawing sources?
595     drawsources(parr, prims, zarr,
596     0, hres, lastOut-nlines, nlines);
597    
598     if (dfp) { // write out depth scanlines?
599     const float * dp = barDepth + TWidth()*(ytop-lastOut);
600     if (RDTdepthT(dt) == RDTdshort) {
601     for (int n = TWidth()*nlines; n-- > 0; dp++)
602     if (putint(depth2code(*dp, pacc.refDepth), 2, dfp) == EOF)
603     error(SYSTEM, "cannot write 16-bit depth buffer");
604     } else if (putbinary(dp, sizeof(float), TWidth()*nlines, dfp)
605     != TWidth()*nlines)
606     error(SYSTEM, "cannot write raw depth buffer");
607     }
608     COLORV * bpos = barPix + pacc.NC()*TWidth()*(ytop-lastOut);
609     while (nlines-- > 0) { // write pixel scanlines
610     switch (RDTcolorT(dt)) {
611     case RDTrgbe:
612     case RDTxyze:
613     if (fwritescan((COLOR *)bpos, TWidth(), pfp) < 0)
614     error(SYSTEM, "cannot write RGBE/XYZE output");
615     break;
616     case RDTscolr:
617     if (fwritesscan(bpos, pacc.NC(), TWidth(), pfp) < 0)
618     error(SYSTEM, "cannot write SCOLOR output");
619     break;
620     case RDTrgb:
621     case RDTxyz:
622     case RDTscolor:
623     if (putbinary(bpos, sizeof(COLORV)*pacc.NC(), TWidth(), pfp)
624     != TWidth())
625     error(SYSTEM, "cannot write SCOLOR output");
626     break;
627     default:
628 greg 2.2 error(INTERNAL, "botched output color type in RenderBelow()");
629 greg 2.1 break;
630     }
631     bpos += pacc.NC()*TWidth();
632     --lastOut;
633     } // flush each scan bar
634     if (fflush(pfp) == EOF || (dfp && fflush(dfp) == EOF))
635     error(SYSTEM, "output write error");
636     // advance down the frame
637 greg 2.3 if (lastOut > 0 && !LowerBar(vstep, ytop))
638 greg 2.1 return false;
639     ytop -= vstep;
640     }
641     delete [] parr;
642     delete [] zarr;
643     if (prCB)
644     (*prCB)(100.);
645     return true;
646     }
647    
648 greg 2.5 // Open new output picture file (and optional depth file)
649 greg 2.1 RenderDataType
650 greg 2.5 RpictSimulManager::NewOutput(FILE *pdfp[2], const char *pfname,
651     RenderDataType dt, const char *dfname)
652 greg 2.1 {
653 greg 2.5 pdfp[0] = pdfp[1] = NULL;
654 greg 2.1 if (!RDTcolorT(dt))
655 greg 2.5 error(INTERNAL, "botched color output type in NewOutput()");
656 greg 2.1 if (NCSAMP == 3) {
657     if (RDTcolorT(dt) == RDTscolr)
658     dt = RDTnewCT(dt, prims==xyzprims ? RDTxyze : RDTrgbe);
659     else if (RDTcolorT(dt) == RDTscolor)
660     dt = RDTnewCT(dt, prims==xyzprims ? RDTxyz : RDTrgb);
661     }
662     if (!RDTdepthT(dt) ^ !dfname)
663 greg 2.5 error(INTERNAL, "depth output requires file name and type in NewOutput()");
664     int fd = 1;
665 greg 2.1 if (pfname) { // open picture output file
666     if (pfname[0] == '!') {
667     error(INTERNAL, "writing picture to a command not supported");
668     return RDTnone;
669     }
670     fd = open(pfname, O_WRONLY|O_CREAT|O_EXCL, 0666);
671     }
672     if (fd < 0) {
673     if ((frameNo <= 0) | (errno != EEXIST)) {
674     sprintf(errmsg, "cannot open picture file '%s'", pfname);
675     error(SYSTEM, errmsg);
676     }
677     return RDTnone; // expected in parallel sequence
678     }
679     if (fd == 1)
680 greg 2.5 pdfp[0] = stdout;
681     else if (!(pdfp[0] = fdopen(fd, "w")))
682 greg 2.1 error(SYSTEM, "failure calling fdopen()");
683 greg 2.5 SET_FILE_BINARY(pdfp[0]); // write picture header
684     if ((pdfp[0] != stdout) | (frameNo <= 1)) {
685     newheader("RADIANCE", pdfp[0]);
686     fputs(GetHeader(), pdfp[0]);
687 greg 2.1 }
688 greg 2.5 fputs(VIEWSTR, pdfp[0]); fprintview(&vw, pdfp[0]); fputc('\n', pdfp[0]);
689 greg 2.1 if (frameNo > 0)
690 greg 2.5 fprintf(pdfp[0], "FRAME=%d\n", frameNo);
691 greg 2.1 double pasp = viewaspect(&vw) * GetWidth() / GetHeight();
692 greg 2.2 if ((0.99 > pasp) | (pasp > 1.01))
693 greg 2.5 fputaspect(pasp, pdfp[0]);
694     fputnow(pdfp[0]);
695 greg 2.1 switch (RDTcolorT(dt)) { // set primaries and picture format
696     case RDTrgbe:
697     if (!prims | (prims == xyzprims)) prims = stdprims;
698 greg 2.5 fputprims(prims, pdfp[0]);
699     fputformat(COLRFMT, pdfp[0]);
700 greg 2.1 break;
701     case RDTxyze:
702     prims = xyzprims;
703 greg 2.5 fputformat(CIEFMT, pdfp[0]);
704 greg 2.1 break;
705     case RDTscolr:
706     prims = NULL;
707 greg 2.5 fputwlsplit(WLPART, pdfp[0]);
708     fputncomp(NCSAMP, pdfp[0]);
709     fputformat(SPECFMT, pdfp[0]);
710 greg 2.1 break;
711     case RDTrgb:
712     if (!prims | (prims == xyzprims)) prims = stdprims;
713 greg 2.5 fputprims(prims, pdfp[0]);
714     fputncomp(3, pdfp[0]);
715     fputendian(pdfp[0]);
716     fputformat("float", pdfp[0]);
717 greg 2.1 break;
718     case RDTxyz:
719     prims = xyzprims;
720 greg 2.5 fputprims(prims, pdfp[0]);
721     fputncomp(3, pdfp[0]);
722     fputendian(pdfp[0]);
723     fputformat("float", pdfp[0]);
724 greg 2.1 break;
725     case RDTscolor:
726     prims = NULL;
727 greg 2.5 fputwlsplit(WLPART, pdfp[0]);
728     fputncomp(NCSAMP, pdfp[0]);
729     fputendian(pdfp[0]);
730     fputformat("float", pdfp[0]);
731 greg 2.1 break;
732     default:;
733     }
734 greg 2.5 fputc('\n', pdfp[0]); // flush picture header + resolution
735     if (fflush(pdfp[0]) == EOF) {
736     sprintf(errmsg, "cannot write header to picture '%s'", pfname);
737     error(SYSTEM, errmsg);
738     fclose(pdfp[0]);
739     pdfp[0] = NULL;
740     return RDTnone;
741     }
742 greg 2.6 if (dfname) { // open depth output
743 greg 2.1 if (dfname[0] == '!')
744 greg 2.5 pdfp[1] = popen(dfname+1, "w");
745 greg 2.1 else
746 greg 2.5 pdfp[1] = fopen(dfname, "w");
747     if (!pdfp[1]) {
748 greg 2.1 sprintf(errmsg, "cannot open depth output '%s'", dfname);
749     error(SYSTEM, errmsg);
750 greg 2.5 fclose(pdfp[0]);
751     pdfp[0] = NULL;
752 greg 2.1 return RDTnone;
753     }
754 greg 2.5 SET_FILE_BINARY(pdfp[1]);
755 greg 2.1 }
756     if (RDTdepthT(dt) == RDTdshort) { // write header for 16-bit depth?
757 greg 2.5 newheader("RADIANCE", pdfp[1]);
758     fputs(GetHeader(), pdfp[1]);
759     fputs(VIEWSTR, pdfp[1]); fprintview(&vw, pdfp[1]); fputc('\n', pdfp[1]);
760     fputs(DEPTHSTR, pdfp[1]); fputs(dunit, pdfp[1]); fputc('\n', pdfp[1]);
761     fputformat(DEPTH16FMT, pdfp[1]);
762     fputc('\n', pdfp[1]); // end-of-info
763     if (fflush(pdfp[1]) == EOF) {
764     sprintf(errmsg, "cannot write header to '%s'", dfname);
765     error(SYSTEM, errmsg);
766     fclose(pdfp[0]); fclose(pdfp[1]);
767     pdfp[0] = pdfp[1] = NULL;
768     return RDTnone;
769     }
770 greg 2.1 }
771 greg 2.5 return dt; // ready to roll
772     }
773    
774     /*
775     * Render and write a frame to the named file
776     * Include any header lines set prior to call
777     * Picture file must not exist
778     * Write pixels to stdout if !pfname
779     * Write depth to a command if dfname[0]=='!'
780     */
781     RenderDataType
782     RpictSimulManager::RenderFrame(const char *pfname, RenderDataType dt, const char *dfname)
783     {
784     FILE *pdfp[2];
785     // prepare output file(s)
786     dt = NewOutput(pdfp, pfname, dt, dfname);
787     if (dt == RDTnone)
788     return RDTnone;
789 greg 2.6 // add resolution string(s)
790     fprtresolu(GetWidth(), GetHeight(), pdfp[0]);
791     if (RDTdepthT(dt) == RDTdshort)
792     fprtresolu(GetWidth(), GetHeight(), pdfp[1]);
793 greg 2.5
794 greg 2.1 const int bheight = (psample > 1) ? int(2*psample+.99) : 4;
795     const int vstep = bheight >> (psample > 1);
796    
797     NewBar(bheight); // render frame if we can
798 greg 2.5 if (!RenderBelow(GetHeight(), vstep, pdfp[0], dt, pdfp[1])) {
799     fclose(pdfp[0]);
800     if (pdfp[1]) (dfname[0] == '!') ? pclose(pdfp[1]) : fclose(pdfp[1]);
801 greg 2.1 Cleanup();
802     return RDTnone;
803     }
804     NewBar(); // clean up and return
805 greg 2.5 if (pdfp[0] != stdout)
806     fclose(pdfp[0]);
807     if (pdfp[1]) {
808 greg 2.1 if (dfname[0] == '!') {
809 greg 2.5 int status = pclose(pdfp[1]);
810 greg 2.1 if (status) {
811     sprintf(errmsg, "depth output (%s) error status: %d",
812     dfname, status);
813     error(USER, errmsg);
814     return RDTnone;
815     }
816     } else
817 greg 2.5 fclose(pdfp[1]);
818 greg 2.1 }
819     return dt;
820     }
821    
822     // passed struct for header line callback
823 greg 2.5 static struct HeaderInfo {
824 greg 2.1 char fmt[MAXFMTLEN];
825     char depth_unit[32];
826     int ncomp;
827     RGBPRIMS prims;
828     VIEW vw;
829     bool gotWL;
830     bool gotprims;
831     bool gotview;
832     bool endianMatch;
833    
834     HeaderInfo() {
835     strcpy(fmt, "MISSING");
836     depth_unit[0] = '\0';
837     ncomp = 3;
838     vw = stdview;
839     gotWL = false;
840     gotprims = false;
841     gotview = false;
842     endianMatch = true;
843     }
844 greg 2.5 } hinfo; // XXX single copy to hold custom primitives
845 greg 2.1
846     // helper function checks header line and records req. info.
847     static int
848     head_check(char *s, void *p)
849     {
850     HeaderInfo * hp = (HeaderInfo *)p;
851     int rval;
852    
853     if (isncomp(s)) {
854     hp->ncomp = ncompval(s);
855     return 1;
856     }
857     if (iswlsplit(s)) {
858     hp->gotWL = wlsplitval(WLPART, s);
859     return 1;
860     }
861     if (isprims(s)) {
862     hp->gotprims = primsval(hp->prims, s);
863     return 1;
864     }
865     if (isview(s)) {
866     hp->gotview |= (sscanview(&hp->vw, s) > 0);
867     return 1;
868     }
869     if (!strncmp(s, DEPTHSTR, LDEPTHSTR)) {
870     strlcpy(hp->depth_unit, s+LDEPTHSTR, sizeof(hp->depth_unit));
871     char * cp = hp->depth_unit;
872     while (*cp) cp++;
873     while (cp > hp->depth_unit && isspace(cp[-1])) cp--;
874     *cp = '\0';
875     return 1;
876     }
877     if ((rval = isbigendian(s)) >= 0) {
878     hp->endianMatch = (rval == nativebigendian());
879     return 1;
880     }
881     if (formatval(hp->fmt, s))
882     return 1;
883     return 0;
884     }
885    
886 greg 2.5 // Reopen output file(s), leaving pointers at end of (each) header
887 greg 2.1 RenderDataType
888 greg 2.5 RpictSimulManager::ReopenOutput(FILE *pdfp[2], const char *pfname, const char *dfname)
889 greg 2.1 {
890 greg 2.5 extern const char HDRSTR[];
891    
892     if (!pfname || pfname[0] == '!') {
893     pdfp[0] = pdfp[1] = NULL;
894 greg 2.1 return RDTnone;
895 greg 2.5 }
896 greg 2.1 RenderDataType dt = RDTnone;
897 greg 2.5 pdfp[1] = NULL;
898     pdfp[0] = fopen(pfname, "r+");
899     if (!pdfp[0]) {
900 greg 2.1 sprintf(errmsg, "cannot reopen output picture '%s'", pfname);
901     error(SYSTEM, errmsg);
902     return RDTnone;
903     }
904 greg 2.5 SET_FILE_BINARY(pdfp[0]); // read header information
905     if (getheader(pdfp[0], head_check, &hinfo) < 0) {
906     fclose(pdfp[0]);
907     pdfp[0] = NULL;
908 greg 2.1 return RDTnone;
909     }
910     if (!hinfo.gotview) {
911     sprintf(errmsg, "missing view for '%s'", pfname);
912     error(USER, errmsg);
913 greg 2.5 fclose(pdfp[0]);
914     pdfp[0] = NULL;
915 greg 2.1 return RDTnone;
916     }
917     if (hinfo.ncomp < 3) {
918     sprintf(errmsg, "bad # components (%d) in '%s'", hinfo.ncomp, pfname);
919     error(USER, errmsg);
920 greg 2.5 fclose(pdfp[0]);
921     pdfp[0] = NULL;
922 greg 2.1 return RDTnone;
923     }
924 greg 2.5 // set rendering/output space
925 greg 2.1 if (!strcmp(hinfo.fmt, COLRFMT)) {
926 greg 2.5 prims = hinfo.prims; // XXX static array
927 greg 2.1 int n = 8*hinfo.gotprims;
928     while (n--)
929     if (!FABSEQ(hinfo.prims[0][n], stdprims[0][n]))
930     break;
931     if (n < 0)
932     prims = stdprims;
933     dt = RDTnewCT(dt, RDTrgbe);
934     } else if (!strcmp(hinfo.fmt, CIEFMT)) {
935     prims = xyzprims;
936     dt = RDTnewCT(dt, RDTxyze);
937     } else if (!strcmp(hinfo.fmt, SPECFMT)) {
938     if ((hinfo.ncomp <= 3) | (hinfo.ncomp > MAXCSAMP)) {
939     sprintf(errmsg, "incompatible sample count (%d) in '%s'",
940     hinfo.ncomp, pfname);
941     error(USER, errmsg);
942 greg 2.5 fclose(pdfp[0]);
943     pdfp[0] = NULL;
944 greg 2.1 return RDTnone;
945     }
946 greg 2.5 NCSAMP = hinfo.ncomp; // overrides global setting
947 greg 2.1 prims = NULL;
948     dt = RDTnewCT(dt, RDTscolr);
949     } else if (!strcmp(hinfo.fmt, "float")) {
950     if (!hinfo.endianMatch) {
951     sprintf(errmsg, "incompatible byte ordering in '%s'", pfname);
952     error(USER, errmsg);
953 greg 2.5 fclose(pdfp[0]);
954     pdfp[0] = NULL;
955 greg 2.1 return RDTnone;
956     }
957     if (hinfo.ncomp == 3) {
958 greg 2.5 prims = hinfo.prims; // custom primaries?
959 greg 2.1 int n = 8*hinfo.gotprims;
960     while (n--)
961     if (!FABSEQ(hinfo.prims[0][n], stdprims[0][n]))
962     break;
963 greg 2.5 if (n < 0) // standard primaries?
964 greg 2.1 prims = stdprims;
965     else if (hinfo.gotprims) { // or check if XYZ
966     for (n = 8; n--; )
967     if (!FABSEQ(prims[0][n], xyzprims[0][n]))
968     break;
969     if (n < 0)
970     prims = xyzprims;
971     }
972     if (prims == xyzprims)
973     dt = RDTnewCT(dt, RDTxyz);
974     else
975     dt = RDTnewCT(dt, RDTrgb);
976     } else {
977     NCSAMP = hinfo.ncomp; // overrides global setting
978     prims = NULL;
979     dt = RDTnewCT(dt, RDTscolor);
980     }
981 greg 2.5 } else {
982     sprintf(errmsg, "unknown format (%s) for '%s'", hinfo.fmt, pfname);
983     error(USER, errmsg);
984     fclose(pdfp[0]);
985     pdfp[0] = NULL;
986     return RDTnone;
987     }
988     if (!dfname) // no depth file?
989     return dt;
990    
991     if (dfname[0] == '!') {
992     error(USER, "depth data cannot be reloaded from command");
993     fclose(pdfp[0]);
994     pdfp[0] = NULL;
995     return RDTnone;
996     }
997     pdfp[1] = fopen(dfname, "r+");
998     if (!pdfp[1]) {
999     sprintf(errmsg, "cannot reopen depth file '%s'", dfname);
1000     error(SYSTEM, errmsg);
1001     fclose(pdfp[0]);
1002     pdfp[0] = NULL;
1003     return RDTnone;
1004     }
1005     SET_FILE_BINARY(pdfp[1]);
1006     int n, len = strlen(HDRSTR);
1007     char buf[32]; // sniff for 16-bit header
1008 greg 2.7 if (getbinary(buf, 1, len+1, pdfp[1]) < len+1) {
1009 greg 2.5 sprintf(errmsg, "empty depth file '%s'", dfname);
1010     error(SYSTEM, errmsg);
1011     fclose(pdfp[0]); fclose(pdfp[1]);
1012     pdfp[0] = pdfp[1] = NULL;
1013     return RDTnone;
1014     }
1015     for (n = 0; n < len; n++)
1016     if (buf[n] != HDRSTR[n])
1017     break; // not a Radiance header
1018 greg 2.7 rewind(pdfp[1]);
1019 greg 2.5 if ((n < len) | !isprint(buf[len]))
1020     return RDTnewDT(dt, RDTdfloat);
1021    
1022     HeaderInfo dinfo; // thinking it's 16-bit encoded
1023     if (getheader(pdfp[1], head_check, &dinfo) < 0)
1024     sprintf(errmsg, "bad header in encoded depth file '%s'",
1025     dfname);
1026     else if (strcmp(dinfo.fmt, DEPTH16FMT))
1027     sprintf(errmsg, "wrong format (%s) for depth file '%s'",
1028     dinfo.fmt, dfname);
1029     else if (!SetReferenceDepth(dinfo.depth_unit))
1030     sprintf(errmsg, "bad/missing reference depth (%s) in '%s'",
1031     dinfo.depth_unit, dfname);
1032     else
1033     errmsg[0] = '\0';
1034    
1035     if (errmsg[0]) {
1036     error(USER, errmsg);
1037     fclose(pdfp[1]); fclose(pdfp[0]);
1038     pdfp[0] = pdfp[1] = NULL;
1039     return RDTnone;
1040     }
1041     return RDTnewDT(dt, RDTdshort);
1042     }
1043    
1044     // Resume partially finished rendering
1045     // Picture file must exist
1046     RenderDataType
1047     RpictSimulManager::ResumeFrame(const char *pfname, const char *dfname)
1048     {
1049     FILE *pdfp[2];
1050    
1051     RenderDataType dt = ReopenOutput(pdfp, pfname, dfname);
1052     if (dt == RDTnone)
1053     return RDTnone;
1054    
1055     int bytesPer = 0; // figure out how far we got...
1056     switch (RDTcolorT(dt)) {
1057     case RDTrgbe:
1058     case RDTxyze:
1059     break;
1060     case RDTscolr:
1061     bytesPer = hinfo.ncomp + 1; // XXX assumes no compression
1062     break;
1063     case RDTrgb:
1064     case RDTxyz:
1065     bytesPer = sizeof(float)*3;
1066     break;
1067     case RDTscolor:
1068 greg 2.1 bytesPer = sizeof(float)*hinfo.ncomp;
1069 greg 2.5 break;
1070     default:
1071 greg 2.1 sprintf(errmsg, "unknown format (%s) for '%s'", hinfo.fmt, pfname);
1072     error(USER, errmsg);
1073 greg 2.5 fclose(pdfp[0]);
1074     if (pdfp[1]) fclose(pdfp[1]);
1075     return RDTnone;
1076     }
1077     RESOLU res;
1078     if (!fgetsresolu(&res, pdfp[0]) || res.rt != PIXSTANDARD) {
1079     sprintf(errmsg, "missing/bad resolution for '%s'", pfname);
1080     error(USER, errmsg);
1081     fclose(pdfp[0]);
1082     if (pdfp[1]) fclose(pdfp[1]);
1083 greg 2.1 return RDTnone;
1084     }
1085     vw.type = 0; // set up new (unreferenced) frame
1086     frameNo = 0;
1087     int hvdim[2] = {res.xr, res.yr};
1088     double noAdj = 0;
1089     if (!NewFrame(hinfo.vw, hvdim, &noAdj) ||
1090     (hvdim[0] != res.xr) | (hvdim[1] != res.yr)) {
1091 greg 2.5 error(CONSISTENCY, "unexpected resolution change in ResumeFrame()");
1092     fclose(pdfp[0]);
1093     if (pdfp[1]) fclose(pdfp[1]);
1094 greg 2.1 return RDTnone;
1095     }
1096 greg 2.5 long dataStart = ftell(pdfp[0]); // picture starting point
1097 greg 2.1 if (dataStart < 0) {
1098     sprintf(errmsg, "cannot seek on '%s'", pfname);
1099     error(SYSTEM, errmsg);
1100 greg 2.5 fclose(pdfp[0]);
1101     if (pdfp[1]) fclose(pdfp[1]);
1102 greg 2.1 return RDTnone;
1103     }
1104     long doneScans = 0;
1105     if (bytesPer) { // fixed-width records?
1106 greg 2.5 fseek(pdfp[0], 0, SEEK_END);
1107     long dataEnd = ftell(pdfp[0]);
1108 greg 2.1 doneScans = (dataEnd - dataStart)/(bytesPer*GetWidth());
1109     if (dataEnd-dataStart > bytesPer*GetWidth()*doneScans)
1110 greg 2.5 fseek(pdfp[0], dataStart + bytesPer*GetWidth()*doneScans, SEEK_SET);
1111 greg 2.1 } else { // else get compressed scanlines
1112     COLR * scan = (COLR *)tempbuffer(sizeof(COLR)*GetWidth());
1113 greg 2.5 while (freadcolrs(scan, GetWidth(), pdfp[0]) >= 0)
1114 greg 2.1 ++doneScans;
1115 greg 2.5 if (!feof(pdfp[0])) {
1116 greg 2.1 sprintf(errmsg, "error reading compressed scanline from '%s'", pfname);
1117     error(USER, errmsg);
1118 greg 2.5 fclose(pdfp[0]);
1119     if (pdfp[1]) fclose(pdfp[1]);
1120 greg 2.1 return RDTnone;
1121     }
1122     }
1123     if (doneScans >= GetHeight()) { // nothing left to do?
1124     sprintf(errmsg, "output file '%s' is already complete", pfname);
1125     error(WARNING, errmsg);
1126 greg 2.5 fclose(pdfp[0]);
1127     if (pdfp[1]) fclose(pdfp[1]);
1128 greg 2.1 return dt;
1129     }
1130     if (!doneScans) {
1131     sprintf(errmsg, "restarting empty frame '%s'", pfname);
1132     error(WARNING, errmsg);
1133     }
1134 greg 2.5 long toSkip = 0;
1135 greg 2.6 switch (RDTdepthT(dt)) { // append depth file, too?
1136 greg 2.5 case RDTdfloat:
1137     toSkip = sizeof(float)*GetWidth()*doneScans;
1138     break;
1139     case RDTdshort:
1140     if (!fgetsresolu(&res, pdfp[1]) || (res.rt != PIXSTANDARD) |
1141     (res.xr != GetWidth()) | (res.yr != GetHeight())) {
1142     sprintf(errmsg, "missing/bad resolution for '%s'", dfname);
1143     error(USER, errmsg);
1144     fclose(pdfp[0]); fclose(pdfp[0]);
1145 greg 2.1 return RDTnone;
1146     }
1147 greg 2.5 toSkip = 2L*GetWidth()*doneScans;
1148     break;
1149     default:;
1150 greg 2.6 } // fseek() needed for output
1151     if (pdfp[1] && fseek(pdfp[1], toSkip, SEEK_CUR) < 0) {
1152 greg 2.5 sprintf(errmsg, "cannot seek on depth file '%s'", dfname);
1153     error(SYSTEM, errmsg);
1154     fclose(pdfp[0]); fclose(pdfp[1]);
1155     return RDTnone;
1156 greg 2.1 }
1157     int bheight = (psample > 1) ? int(2*psample+.99) : 4;
1158     if (bheight > GetHeight()-doneScans)
1159     bheight = GetHeight()-doneScans;
1160     int vstep = bheight >> (psample > 1);
1161     vstep += !vstep;
1162    
1163     NewBar(bheight); // render remainder if we can
1164 greg 2.5 if (!RenderBelow(GetHeight()-doneScans, vstep, pdfp[0], dt, pdfp[1])) {
1165     fclose(pdfp[0]);
1166     if (pdfp[1]) fclose(pdfp[1]);
1167 greg 2.1 Cleanup();
1168     return RDTnone;
1169     }
1170     NewBar(); // close up and return success
1171 greg 2.5 fclose(pdfp[0]);
1172     if (pdfp[1]) fclose(pdfp[1]);
1173 greg 2.1 return dt;
1174     }