ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/RpictSimulManager.cpp
(Generate patch)

Comparing ray/src/rt/RpictSimulManager.cpp (file contents):
Revision 2.3 by greg, Sun Aug 18 17:24:48 2024 UTC vs.
Revision 2.12 by greg, Mon Sep 16 23:49:13 2024 UTC

# Line 9 | Line 9 | static const char RCSid[] = "$Id$";
9   *  Created by Greg Ward on 07/11/2024.
10   */
11  
12 + #define DEBUG   1       // XXX temporary!
13 +
14   #include <ctype.h>
15   #include "platform.h"
16   #include "RpictSimulManager.h"
# Line 103 | Line 105 | RpictSimulManager::NewFrame(const VIEW &v, int xydim[2
105  
106          if (!xydim) return false;
107          if (!ap) ap = &pasp;
108 <        pvw = vw;                       // save previous view for motion blur
109 <        vw = v;
108 >        if (&v == &vw) {
109 >                pvw.type = 0;
110 >        } else {
111 >                pvw = vw;               // save previous view for motion blur
112 >                vw = v;
113 >        }
114          const char *    verr = setview(&vw);
115          if (verr) {
116                  error(WARNING, verr);
# Line 196 | Line 202 | RpictSimulManager::SetTile(const int ti[2])
202   bool
203   RpictSimulManager::ComputePixel(int x, int y)
204   {
205 <        static const SCOLOR     scBlack = {0};
205 >        DCHECK(doneMap.OffBitMap(x,y),
206 >                        CONSISTENCY, "illegal pixel index in ComputPixel()");
207          int     i;
208          FVECT   rodir[2];
209          double  hpos = (x+pixjitter())/TWidth();
210          double  vpos = (y+pixjitter())/THeight();
211          double  dlim = viewray(rodir[0], rodir[1], &tvw, hpos, vpos);
212          if (dlim < -FTINY) {    // off view?
213 <                pacc.SetPixel(x, y, scBlack);
213 >                pacc.SetPixel(x, y, scblack);
214                  doneMap.Set(x, y);
215                  return true;
216          }
# Line 233 | Line 240 | RpictSimulManager::ComputePixel(int x, int y)
240  
241   // Check if neighbor differences are below pixel sampling threshold
242   bool
243 < RpictSimulManager::BelowSampThresh(int x, int y, const int noff[4][2]) const
243 > RpictSimulManager::BelowSampThresh(const int x, const int y, const int noff[4][2]) const
244   {
245          SCOLOR  pval[4];
246          float   dist[4];
247          int     i, j;
248  
249          for (i = 4; i--; ) {            // get pixels from tile store
250 <                int     px = x + noff[i][0];
251 <                int     py = y + noff[i][1];
250 >                const int       px = x + noff[i][0];
251 >                const int       py = y + noff[i][1];
252                  if (!doneMap.Check(px, py) ||
253                                  !pacc.GetPixel(px, py, pval[i], &dist[i]))
254                          return false;
255          }
256 <        const bool      spectr = (pacc.NC() > 3);
257 <        for (i = 4; --i; )              // do pairwise comparisons
258 <            for (j = i; j--; ) {
259 <                if (pacc.DepthType() &&
253 <                                (dist[i] - dist[j] > maxdiff*dist[j]) |
256 >                                        // do pairwise comparisons
257 >        for (i = (pacc.DepthType() != RDTnone)*4; --i > 0; )
258 >            for (j = i; j--; )
259 >                if ((dist[i] - dist[j] > maxdiff*dist[j]) |
260                                  (dist[j] - dist[i] > maxdiff*dist[i]))
261                          return false;
262 <                if (spectr ? sbigsdiff(pval[i], pval[j], maxdiff) :
263 <                                bigdiff(pval[i], pval[j], maxdiff))
262 >        if (pacc.NC() > 3) {
263 >            for (i = 4; --i; )
264 >                for (j = i; j--; )
265 >                    if (sbigsdiff(pval[i], pval[j], maxdiff))
266                          return false;
267 <            }
268 <        return true;                    // linear interpolation OK
267 >        } else {
268 >            for (i = 4; --i; )
269 >                for (j = i; j--; )
270 >                    if (bigdiff(pval[i], pval[j], maxdiff))
271 >                        return false;
272 >        }
273 >        return true;
274   }
275  
276   // Fill an interior square patch with interpolated values
# Line 268 | Line 281 | RpictSimulManager::FillSquare(const int x, const int y
281          float   dist[4];
282          int     i, j;
283                                          // assumes 4 corners are valid!
284 <        for (i = 4; i--; )
284 >        for (i = 4; i--; ) {
285 >                DCHECK(!doneMap.Check(x+noff[i][0], y+noff[i][1]),
286 >                        CONSISTENCY, "inclusion of bad pixel in FillSquare()");
287                  pacc.GetPixel(x+noff[i][0], y+noff[i][1], pval[i], &dist[i]);
288 <
288 >        }
289          i = abs(noff[1][0]-noff[0][0]);
290          j = abs(noff[1][1]-noff[0][1]); // i==j for diamond fill
291          const int       slen =  (i > j) ? i : j;
# Line 328 | Line 343 | RpictSimulManager::FillSquare(const int x, const int y
343  
344   // helper function to set up quincunx sampling
345   static void
346 < SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int spc, const bool odd)
346 > SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int spc, bool odd, int x0, int y)
347   {
348 <        for (int y = 0; y < bmp2->Height(); y += spc>>1)
334 <            for (int x = (odd^(y&1))*(spc>>1); x < bmp2->Width(); x += spc)
335 <                bmp2->Set(x, y);
336 <                                        // order neighbors CCW
337 <        if (odd) {
348 >        if (odd) {                      // order neighbors CCW
349                  noff[0][0] = spc>>1; noff[0][1] = 0;
350                  noff[1][0] = 0; noff[1][1] = spc>>1;
351                  noff[2][0] = -(spc>>1); noff[2][1] = 0;
# Line 345 | Line 356 | SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int
356                  noff[2][0] = -(spc>>1); noff[2][1] = -(spc>>1);
357                  noff[3][0] = spc>>1; noff[3][1] = -(spc>>1);
358          }
359 +        int     nsteps;                 // non-negative range
360 +        if (x0 < -(spc>>1)) {
361 +                nsteps = (spc-1 - x0 - (spc>>1))/spc;
362 +                x0 += nsteps*spc;
363 +        }
364 +        if (y < 0) {                    // get past y==0
365 +                nsteps = ((spc>>1)-1 - y)/(spc>>1);
366 +                y += nsteps*(spc>>1);
367 +                odd ^= nsteps&1;
368 +        }
369 +        while (y < bmp2->Height()) {
370 +            for (int x = x0 + odd*(spc>>1); x < bmp2->Width(); x += spc)
371 +                bmp2->Set(x, y);
372 +            y += spc>>1;
373 +            odd = !odd;
374 +        }
375   }
376  
377   // Render (or finish rendering) current tile
378   bool
379 < RpictSimulManager::RenderRect()
379 > RpictSimulManager::RenderRect(const int x0, const int y0)
380   {
381          if (!tvw.type || !Ready()) {
382                  error(INTERNAL, "need octree and view for RenderRect()");
# Line 359 | Line 386 | RpictSimulManager::RenderRect()
386          int             sp2 = ceil(log2((TWidth()>THeight() ? TWidth() : THeight()) - 1.));
387          int             layer = 0;
388          int             x, y;
362 // fprintf(stderr, "Rendering %dx%d tile with psample=%d, maxdiff=%.3f ...\n",
363 // TWidth(), THeight(), psample, maxdiff);
389          while (sp2 > 0) {
390                  ABitMap2        sampMap(TWidth(), THeight());
391                  int             noff[4][2];
392                  if ((prCB != NULL) & (barPix == NULL))
393                          (*prCB)(100.*doneMap.SumTotal()/doneMap.Width()/doneMap.Height());
394 <                SetQuincunx(&sampMap, noff, 1<<sp2, layer&1);
394 >                SetQuincunx(&sampMap, noff, 1<<sp2, layer&1, x0, y0);
395                  sampMap -= doneSamples; // avoid resampling pixels
396                  // Are we into adaptive sampling realm?
397                  if (noff[0][0]*noff[0][0] + noff[0][1]*noff[0][1] < psample*psample) {
# Line 380 | Line 405 | RpictSimulManager::RenderRect()
405                          const ABitMap2  origSampMap = sampMap;
406                          for (x = 4; x--; ) {
407                                  ABitMap2        stamp = origSampMap;
408 <                                stamp.Shift(noff[x][0], noff[x][1]);
408 >                                stamp.Shift(noff[x][0] + noff[(x+1)&3][0],
409 >                                                noff[x][1] + noff[(x+1)&3][1]);
410                                  sampMap |= stamp;
411                          }               // ...but don't resample what's done
412                          sampMap -= doneSamples;
413                                          // interpolate smooth regions
414                          fillMap -= sampMap;
415 +                        fillMap -= doneSamples;
416                          for (x = y = 0; fillMap.Find(&x, &y); x++)
417                                  FillSquare(x, y, noff);
418                          doneSamples |= doneMap;
# Line 394 | Line 421 | RpictSimulManager::RenderRect()
421                          if (!ComputePixel(x, y))
422                                  return false;
423                  doneSamples |= sampMap; // samples now done or at least queued
397 // 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()));
424                  sp2 -= layer++ & 1;     // next denser sampling
425          }
426          if (FlushQueue() < 0)           // make sure we got everyone
427                  return false;
428          x = y = 0;
429          if (doneMap.Find(&x, &y, false)) {
430 <                sprintf(errmsg, "missed %ld tile pixels, e.g. (%d,%d)",
431 <                                (long)doneMap.Width()*doneMap.Height() -
432 <                                        doneMap.SumTotal(), x, y);
430 >                sprintf(errmsg, "missed %.4f%% of pixels in rectangle\n",
431 >                                100. - 100.*doneMap.SumTotal() /
432 >                                        doneMap.Width() / doneMap.Height());
433                  error(WARNING, errmsg);
434          }
435          if ((prCB != NULL) & (barPix == NULL))
# Line 433 | Line 455 | RpictSimulManager::RenderTile(COLORV *rp, int ystride,
455                  pacc.SetColorSpace(RDTxyz);
456          else if (prims)
457                  pacc.SetColorSpace(RDTrgb, prims);
458 <                
458 >
459          return SetTile(tile) && RenderRect();
460   }
461  
# Line 471 | Line 493 | RpictSimulManager::RenderTile(COLRV *bp, int ystride,
493          return SetTile(tile) && RenderRect();
494   }
495  
496 + // Back to float color with 16-bit depth
497 + bool
498 + RpictSimulManager::RenderTile(COLORV *rp, int ystride, short *dp, const int *tile)
499 + {
500 +        if (!rp | (GetWidth() <= 0) | (GetHeight() <= 0) | !vw.type)
501 +                return false;
502 +        if (!ystride)                   // contiguous rows?
503 +                ystride = TWidth();
504 +        pacc.Init(rp, ystride, dp);
505 +        if (prims == xyzprims)
506 +                pacc.SetColorSpace(RDTxyz);
507 +        else if (prims)
508 +                pacc.SetColorSpace(RDTrgb, prims);
509 +
510 +        return SetTile(tile) && RenderRect();
511 + }
512 +
513   // Allocate a new render bar
514   void
515   RpictSimulManager::NewBar(int ht)
# Line 520 | Line 559 | RpictSimulManager::LowerBar(int v, int ytop)
559                          sizeof(COLORV)*NC*TWidth()*(THeight()-v));
560          memmove(barDepth, barDepth + TWidth()*v,
561                          sizeof(float)*TWidth()*(THeight()-v));
562 <        if (ytop < THeight()) {                 // mark what we won't do as finished
562 >        if (ytop < THeight())                   // mark what we won't do as finished
563                  doneMap.ClearRect(0, 0, TWidth(), THeight()-ytop, true);
525                memset(barPix, 0, sizeof(COLORV)*NC*TWidth()*(THeight()-ytop));
526                memset(barDepth, 0, sizeof(float)*TWidth()*(THeight()-ytop));
527        }
564          return true;
565   }
566  
# Line 547 | Line 583 | RpictSimulManager::RenderBelow(int ytop, const int vst
583                          cropview(&ptvw, 0., double(ytop-THeight())/GetHeight(),
584                                                  1., double(ytop)/GetHeight()))
585                  ptvw.type = 0;
586 <                                                // set up spectral sampling
587 <        if (setspectrsamp(CNDX, WLPART) <= 0) {
586 >                                                // update spectral sampling
587 >        int     rv = setspectrsamp(CNDX, WLPART);
588 >        if (rv < 0) {
589                  error(USER, "unsupported spectral sampling");
590                  return false;
591          }
592 +        if (!rv & (RDTcolorT(dt) != RDTscolor) & (RDTcolorT(dt) != RDTscolr))
593 +                error(WARNING, "spectral range incompatible with color output");
594          COLORV **       parr = NULL;            // set up tiny source drawing
595          float **        zarr = NULL;
596          if (!ptvw.type && directvis && dblur <= FTINY) {
# Line 566 | Line 605 | RpictSimulManager::RenderBelow(int ytop, const int vst
605          }
606          int             lastOut = ytop;         // render down frame
607          while (ytop > 0) {
569 // fprintf(stderr, "At y=%d, source drawing %s...\n", ytop, parr ? "ON" : "OFF");
608                  if (prCB)
609                          (*prCB)(100.*(GetHeight()-ytop)/GetHeight());
610 <                if (!RenderRect())              // render this bar
610 >                if (!RenderRect(0, THeight()-ytop))     // render this bar
611                          return false;
612                  int     nlines = lastOut - ytop + THeight();
613                  if (nlines > ytop)
# Line 628 | Line 666 | RpictSimulManager::RenderBelow(int ytop, const int vst
666          return true;
667   }
668  
669 < /*
632 < * Render and write a frame to the named file
633 < * Include any header lines set prior to call
634 < * Picture file must not already exist
635 < * Write pixels to stdout if !pfname
636 < * Write depth to a command if dfname[0]=='!'
637 < */
669 > // Open new output picture file (and optional depth file)
670   RenderDataType
671 < RpictSimulManager::RenderFrame(const char *pfname, RenderDataType dt, const char *dfname)
671 > RpictSimulManager::NewOutput(FILE *pdfp[2], const char *pfname,
672 >                                RenderDataType dt, const char *dfname)
673   {
674 <        int     fd = 1;
642 <        FILE *  pfp = NULL;
643 <        FILE *  dfp = NULL;
644 <
674 >        pdfp[0] = pdfp[1] = NULL;
675          if (!RDTcolorT(dt))
676 <                error(INTERNAL, "botched color output type in RenderFrame()");
676 >                error(INTERNAL, "missing color output type in NewOutput()");
677          if (NCSAMP == 3) {
678                  if (RDTcolorT(dt) == RDTscolr)
679                          dt = RDTnewCT(dt, prims==xyzprims ? RDTxyze : RDTrgbe);
# Line 651 | Line 681 | RpictSimulManager::RenderFrame(const char *pfname, Ren
681                          dt = RDTnewCT(dt, prims==xyzprims ? RDTxyz : RDTrgb);
682          }
683          if (!RDTdepthT(dt) ^ !dfname)
684 <                error(INTERNAL, "depth output requires file name and type in RenderFrame()");
684 >                error(INTERNAL, "depth output requires file name and type in NewOutput()");
685 >        int     fd = 1;
686          if (pfname) {                           // open picture output file
687                  if (pfname[0] == '!') {
688                          error(INTERNAL, "writing picture to a command not supported");
689                          return RDTnone;
690                  }
691 <                fd = open(pfname, O_WRONLY|O_CREAT|O_EXCL, 0666);
691 >                fd = open(pfname, O_RDWR|O_CREAT|O_EXCL, 0666);
692          }
693          if (fd < 0) {
694                  if ((frameNo <= 0) | (errno != EEXIST)) {
695                          sprintf(errmsg, "cannot open picture file '%s'", pfname);
696                          error(SYSTEM, errmsg);
697                  }
698 <                return RDTnone;                 // expected in parallel sequence
698 >                return RDTnone;                 // may be expected in sequence run
699          }
700          if (fd == 1)
701 <                pfp = stdout;
702 <        else if (!(pfp = fdopen(fd, "w")))
701 >                pdfp[0] = stdout;
702 >        else if (!(pdfp[0] = fdopen(fd, "w+")))
703                  error(SYSTEM, "failure calling fdopen()");
704 <        SET_FILE_BINARY(pfp);                   // write picture header
705 <        if ((pfp != stdout) | (frameNo <= 1)) {
706 <                newheader("RADIANCE", pfp);
707 <                fputs(GetHeader(), pfp);
704 >        SET_FILE_BINARY(pdfp[0]);               // write picture header
705 >        if ((pdfp[0] != stdout) | (frameNo <= 1)) {
706 >                newheader("RADIANCE", pdfp[0]);
707 >                fputs(GetHeadStr(), pdfp[0]);
708          }
709 <        fputs(VIEWSTR, pfp); fprintview(&vw, pfp); fputc('\n', pfp);
709 >        fputs(VIEWSTR, pdfp[0]); fprintview(&vw, pdfp[0]); fputc('\n', pdfp[0]);
710          if (frameNo > 0)
711 <                fprintf(pfp, "FRAME=%d\n", frameNo);
711 >                fprintf(pdfp[0], "FRAME=%d\n", frameNo);
712          double  pasp = viewaspect(&vw) * GetWidth() / GetHeight();
713          if ((0.99 > pasp) | (pasp > 1.01))
714 <                fputaspect(pasp, pfp);
715 <        fputnow(pfp);
714 >                fputaspect(pasp, pdfp[0]);
715 >        fputnow(pdfp[0]);
716          switch (RDTcolorT(dt)) {                // set primaries and picture format
717          case RDTrgbe:
718                  if (!prims | (prims == xyzprims)) prims = stdprims;
719 <                fputprims(prims, pfp);
720 <                fputformat(COLRFMT, pfp);
719 >                fputprims(prims, pdfp[0]);
720 >                fputformat(COLRFMT, pdfp[0]);
721                  break;
722          case RDTxyze:
723                  prims = xyzprims;
724 <                fputformat(CIEFMT, pfp);
724 >                fputformat(CIEFMT, pdfp[0]);
725                  break;
726          case RDTscolr:
727                  prims = NULL;
728 <                fputwlsplit(WLPART, pfp);
729 <                fputncomp(NCSAMP, pfp);
730 <                fputformat(SPECFMT, pfp);
728 >                fputwlsplit(WLPART, pdfp[0]);
729 >                fputncomp(NCSAMP, pdfp[0]);
730 >                fputformat(SPECFMT, pdfp[0]);
731                  break;
732          case RDTrgb:
733                  if (!prims | (prims == xyzprims)) prims = stdprims;
734 <                fputprims(prims, pfp);
735 <                fputncomp(3, pfp);
736 <                fputendian(pfp);
737 <                fputformat("float", pfp);
734 >                fputprims(prims, pdfp[0]);
735 >                fputncomp(3, pdfp[0]);
736 >                fputendian(pdfp[0]);
737 >                fputformat("float", pdfp[0]);
738                  break;
739          case RDTxyz:
740                  prims = xyzprims;
741 <                fputprims(prims, pfp);
742 <                fputncomp(3, pfp);
743 <                fputendian(pfp);
744 <                fputformat("float", pfp);
741 >                fputprims(prims, pdfp[0]);
742 >                fputncomp(3, pdfp[0]);
743 >                fputendian(pdfp[0]);
744 >                fputformat("float", pdfp[0]);
745                  break;
746          case RDTscolor:
747                  prims = NULL;
748 <                fputwlsplit(WLPART, pfp);
749 <                fputncomp(NCSAMP, pfp);
750 <                fputendian(pfp);
751 <                fputformat("float", pfp);
748 >                fputwlsplit(WLPART, pdfp[0]);
749 >                fputncomp(NCSAMP, pdfp[0]);
750 >                fputendian(pdfp[0]);
751 >                fputformat("float", pdfp[0]);
752                  break;
753 <        default:;
753 >        default:;       // pro forma - caught this above
754          }
755 <        fputc('\n', pfp);                       // end picture header
756 <        fprtresolu(GetWidth(), GetHeight(), pfp);
757 <        if (dfname) {
755 >        fputc('\n', pdfp[0]);                   // flush picture header
756 >        if (fflush(pdfp[0]) == EOF) {
757 >                sprintf(errmsg, "cannot write header to picture '%s'", pfname);
758 >                error(SYSTEM, errmsg);
759 >                fclose(pdfp[0]);
760 >                pdfp[0] = NULL;
761 >                return RDTnone;
762 >        }
763 >        if (dfname) {                           // open depth output
764                  if (dfname[0] == '!')
765 <                        dfp = popen(dfname+1, "w");
765 >                        pdfp[1] = popen(dfname+1, "w");
766                  else
767 <                        dfp = fopen(dfname, "w");
768 <                if (!dfp) {
767 >                        pdfp[1] = fopen(dfname, "w+");
768 >                if (!pdfp[1]) {
769                          sprintf(errmsg, "cannot open depth output '%s'", dfname);
770                          error(SYSTEM, errmsg);
771 +                        fclose(pdfp[0]);
772 +                        pdfp[0] = NULL;
773                          return RDTnone;
774                  }
775 <                SET_FILE_BINARY(dfp);
775 >                SET_FILE_BINARY(pdfp[1]);
776          }
777          if (RDTdepthT(dt) == RDTdshort) {       // write header for 16-bit depth?
778 <                newheader("RADIANCE", dfp);
779 <                fputs(GetHeader(), dfp);
780 <                fputs(VIEWSTR, dfp); fprintview(&vw, dfp); fputc('\n', dfp);
781 <                fputs(DEPTHSTR, dfp); fputs(dunit, dfp); fputc('\n', dfp);
782 <                fputformat(DEPTH16FMT, dfp);
783 <                fputc('\n', dfp);               // end-of-info
784 <                fprtresolu(GetWidth(), GetHeight(), dfp);
778 >                newheader("RADIANCE", pdfp[1]);
779 >                fputs(GetHeadStr(), pdfp[1]);
780 >                fputs(VIEWSTR, pdfp[1]); fprintview(&vw, pdfp[1]); fputc('\n', pdfp[1]);
781 >                fputs(DEPTHSTR, pdfp[1]); fputs(dunit, pdfp[1]); fputc('\n', pdfp[1]);
782 >                fputformat(DEPTH16FMT, pdfp[1]);
783 >                fputc('\n', pdfp[1]);           // end-of-info
784 >                if (fflush(pdfp[1]) == EOF) {
785 >                        sprintf(errmsg, "cannot write header to '%s'", dfname);
786 >                        error(SYSTEM, errmsg);
787 >                        fclose(pdfp[0]); fclose(pdfp[1]);
788 >                        pdfp[0] = pdfp[1] = NULL;
789 >                        return RDTnone;
790 >                }
791          }
792 <        const int       bheight = (psample > 1) ? int(2*psample+.99) : 4;
793 <        const int       vstep =  bheight >> (psample > 1);
792 >        return dt;                              // ready to roll
793 > }
794  
795 + /*
796 + * Render and write a frame to the named file
797 + * Include any header lines set prior to call
798 + * Picture file must not exist
799 + * Write pixels to stdout if !pfname
800 + * Write depth to a command if dfname[0]=='!'
801 + */
802 + RenderDataType
803 + RpictSimulManager::RenderFrame(const char *pfname, RenderDataType dt, const char *dfname)
804 + {
805 +        FILE    *pdfp[2];
806 +                                                // prepare output file(s)
807 +        dt = NewOutput(pdfp, pfname, dt, dfname);
808 +        if (dt == RDTnone)
809 +                return RDTnone;
810 +                                                // add resolution string(s)
811 +        fprtresolu(GetWidth(), GetHeight(), pdfp[0]);
812 +        if (RDTdepthT(dt) == RDTdshort)
813 +                fprtresolu(GetWidth(), GetHeight(), pdfp[1]);
814 +
815 +        const int       bheight = (psample > 1) ? int(8*psample+.99) : 16;
816 +        const int       vstep = bheight >> (psample > 1);
817 +
818          NewBar(bheight);                        // render frame if we can
819 <        if (!RenderBelow(GetHeight(), vstep, pfp, dt, dfp)) {
820 <                fclose(pfp);
821 <                if (dfp) (dfname[0] == '!') ? pclose(dfp) : fclose(dfp);
819 >        if (!RenderBelow(GetHeight(), vstep, pdfp[0], dt, pdfp[1])) {
820 >                fclose(pdfp[0]);
821 >                if (pdfp[1]) (dfname[0] == '!') ? pclose(pdfp[1]) : fclose(pdfp[1]);
822                  Cleanup();
823                  return RDTnone;
824          }
825          NewBar();                               // clean up and return
826 <        if (pfp != stdout)
827 <                fclose(pfp);
828 <        if (dfp) {
826 >        if (pdfp[0] != stdout)
827 >                fclose(pdfp[0]);
828 >        if (pdfp[1]) {
829                  if (dfname[0] == '!') {
830 <                        int     status = pclose(dfp);
830 >                        int     status = pclose(pdfp[1]);
831                          if (status) {
832                                  sprintf(errmsg, "depth output (%s) error status: %d",
833                                                  dfname, status);
# Line 767 | Line 835 | RpictSimulManager::RenderFrame(const char *pfname, Ren
835                                  return RDTnone;
836                          }
837                  } else
838 <                        fclose(dfp);
838 >                        fclose(pdfp[1]);
839          }
840          return dt;
841   }
842  
843   // passed struct for header line callback
844 < struct HeaderInfo {
844 > static struct HeaderInfo {
845          char            fmt[MAXFMTLEN];
846          char            depth_unit[32];
847          int             ncomp;
# Line 794 | Line 862 | struct HeaderInfo {
862                                  gotview = false;
863                                  endianMatch = true;
864                          }
865 < };
865 > }       hinfo;          // XXX single copy to hold custom primitives
866  
867   // helper function checks header line and records req. info.
868   static int
# Line 836 | Line 904 | head_check(char *s, void *p)
904          return 0;
905   }
906  
907 < // Resume partially finished rendering
840 < // Picture file must exist
907 > // Reopen output file(s), leaving pointers at end of (each) header
908   RenderDataType
909 < RpictSimulManager::ResumeFrame(const char *pfname, const char *dfname)
909 > RpictSimulManager::ReopenOutput(FILE *pdfp[2], const char *pfname, const char *dfname)
910   {
911 <        if (!pfname || pfname[0] == '!')
845 <                return RDTnone;
911 >        extern const char       HDRSTR[];
912  
913 +        if (!pfname || pfname[0] == '!') {
914 +                pdfp[0] = pdfp[1] = NULL;
915 +                return RDTnone;
916 +        }
917          RenderDataType  dt = RDTnone;
918 <        FILE *          dfp = NULL;
919 <        FILE *          pfp = fopen(pfname, "r+");
920 <        if (!pfp) {
918 >        pdfp[1] = NULL;
919 >        pdfp[0] = fopen(pfname, "r+");
920 >        if (!pdfp[0]) {
921                  sprintf(errmsg, "cannot reopen output picture '%s'", pfname);
922                  error(SYSTEM, errmsg);
923                  return RDTnone;
924          }
925 <        SET_FILE_BINARY(pfp);
926 <        HeaderInfo      hinfo;          // read header information & dimensions
927 <        RESOLU          res;
928 <        if (getheader(pfp, head_check, &hinfo) < 0) {
859 <                fclose(pfp);
925 >        SET_FILE_BINARY(pdfp[0]);       // read header information
926 >        if (getheader(pdfp[0], head_check, &hinfo) < 0) {
927 >                fclose(pdfp[0]);
928 >                pdfp[0] = NULL;
929                  return RDTnone;
930          }
862        if (!fgetsresolu(&res, pfp) || res.rt != PIXSTANDARD) {
863                sprintf(errmsg, "missing/bad resolution for '%s'", pfname);
864                error(USER, errmsg);
865                fclose(pfp);
866                return RDTnone;
867        }
931          if (!hinfo.gotview) {
932                  sprintf(errmsg, "missing view for '%s'", pfname);
933                  error(USER, errmsg);
934 <                fclose(pfp);
934 >                fclose(pdfp[0]);
935 >                pdfp[0] = NULL;
936                  return RDTnone;
937          }
938          if (hinfo.ncomp < 3) {
939                  sprintf(errmsg, "bad # components (%d) in '%s'", hinfo.ncomp, pfname);
940                  error(USER, errmsg);
941 <                fclose(pfp);
941 >                fclose(pdfp[0]);
942 >                pdfp[0] = NULL;
943                  return RDTnone;
944          }
945 <        int     bytesPer = 0;           // complicated part to set rendering/output space
945 >                                        // set rendering/output space
946          if (!strcmp(hinfo.fmt, COLRFMT)) {
947 <                prims = hinfo.prims;
947 >                prims = hinfo.prims;    // XXX static array
948                  int     n = 8*hinfo.gotprims;
949                  while (n--)
950                          if (!FABSEQ(hinfo.prims[0][n], stdprims[0][n]))
# Line 895 | Line 960 | RpictSimulManager::ResumeFrame(const char *pfname, con
960                          sprintf(errmsg, "incompatible sample count (%d) in '%s'",
961                                          hinfo.ncomp, pfname);
962                          error(USER, errmsg);
963 <                        fclose(pfp);
963 >                        fclose(pdfp[0]);
964 >                        pdfp[0] = NULL;
965                          return RDTnone;
966                  }
967 <                NCSAMP = hinfo.ncomp;   // overrides global setting
967 >                NCSAMP = hinfo.ncomp;           // overrides global setting
968                  prims = NULL;
969                  dt = RDTnewCT(dt, RDTscolr);
904                bytesPer = hinfo.ncomp + 1;     // XXX assumes no compression
970          } else if (!strcmp(hinfo.fmt, "float")) {
971                  if (!hinfo.endianMatch) {
972                          sprintf(errmsg, "incompatible byte ordering in '%s'", pfname);
973                          error(USER, errmsg);
974 <                        fclose(pfp);
974 >                        fclose(pdfp[0]);
975 >                        pdfp[0] = NULL;
976                          return RDTnone;
977                  }
978                  if (hinfo.ncomp == 3) {
979 <                        prims = hinfo.prims;            // custom primaries?
979 >                        prims = hinfo.prims;    // custom primaries?
980                          int     n = 8*hinfo.gotprims;
981                          while (n--)
982                                  if (!FABSEQ(hinfo.prims[0][n], stdprims[0][n]))
983                                          break;
984 <                        if (n < 0)                      // standard primaries?
984 >                        if (n < 0)              // standard primaries?
985                                  prims = stdprims;
986                          else if (hinfo.gotprims) {      // or check if XYZ
987                                  for (n = 8; n--; )
# Line 933 | Line 999 | RpictSimulManager::ResumeFrame(const char *pfname, con
999                          prims = NULL;
1000                          dt = RDTnewCT(dt, RDTscolor);
1001                  }
936                bytesPer = sizeof(float)*hinfo.ncomp;
1002          } else {
1003                  sprintf(errmsg, "unknown format (%s) for '%s'", hinfo.fmt, pfname);
1004                  error(USER, errmsg);
1005 <                fclose(pfp);
1005 >                fclose(pdfp[0]);
1006 >                pdfp[0] = NULL;
1007                  return RDTnone;
1008          }
1009 <        vw.type = 0;                            // set up new (unreferenced) frame
1010 <        frameNo = 0;
1009 >        if (hinfo.gotview) {                    // header view overrides
1010 >                pvw = vw;
1011 >                vw = hinfo.vw;
1012 >        }
1013 >        if (!dfname)                            // no depth file?
1014 >                return dt;
1015 >
1016 >        if (dfname[0] == '!') {
1017 >                error(USER, "depth data cannot be reloaded from command");
1018 >                fclose(pdfp[0]);
1019 >                pdfp[0] = NULL;
1020 >                return RDTnone;
1021 >        }
1022 >        pdfp[1] = fopen(dfname, "r+");
1023 >        if (!pdfp[1]) {
1024 >                sprintf(errmsg, "cannot reopen depth file '%s'", dfname);
1025 >                error(SYSTEM, errmsg);
1026 >                fclose(pdfp[0]);
1027 >                pdfp[0] = NULL;
1028 >                return RDTnone;
1029 >        }
1030 >        SET_FILE_BINARY(pdfp[1]);
1031 >        int     n, len = strlen(HDRSTR);
1032 >        char    buf[32];                        // sniff for 16-bit header
1033 >        if (getbinary(buf, 1, len+1, pdfp[1]) < len+1) {
1034 >                sprintf(errmsg, "empty depth file '%s'", dfname);
1035 >                error(SYSTEM, errmsg);
1036 >                fclose(pdfp[0]); fclose(pdfp[1]);
1037 >                pdfp[0] = pdfp[1] = NULL;
1038 >                return RDTnone;
1039 >        }
1040 >        for (n = 0; n < len; n++)
1041 >                if (buf[n] != HDRSTR[n])
1042 >                        break;                  // not a Radiance header
1043 >        rewind(pdfp[1]);
1044 >        if ((n < len) | !isprint(buf[len]))
1045 >                return RDTnewDT(dt, RDTdfloat);
1046 >
1047 >        HeaderInfo      dinfo;                  // thinking it's 16-bit encoded
1048 >        if (getheader(pdfp[1], head_check, &dinfo) < 0)
1049 >                sprintf(errmsg, "bad header in encoded depth file '%s'",
1050 >                                dfname);
1051 >        else if (strcmp(dinfo.fmt, DEPTH16FMT))
1052 >                sprintf(errmsg, "wrong format (%s) for depth file '%s'",
1053 >                                dinfo.fmt, dfname);
1054 >        else if (!SetReferenceDepth(dinfo.depth_unit))
1055 >                sprintf(errmsg, "bad/missing reference depth (%s) in '%s'",
1056 >                                dinfo.depth_unit, dfname);
1057 >        else
1058 >                errmsg[0] = '\0';
1059 >
1060 >        if (errmsg[0]) {
1061 >                error(USER, errmsg);
1062 >                fclose(pdfp[1]); fclose(pdfp[0]);
1063 >                pdfp[0] = pdfp[1] = NULL;
1064 >                return RDTnone;
1065 >        }
1066 >        return RDTnewDT(dt, RDTdshort);
1067 > }
1068 >
1069 > // Resume partially finished rendering
1070 > // Picture file must exist
1071 > RenderDataType
1072 > RpictSimulManager::ResumeFrame(const char *pfname, const char *dfname)
1073 > {
1074 >        FILE            *pdfp[2];
1075 >
1076 >        RenderDataType  dt = ReopenOutput(pdfp, pfname, dfname);
1077 >        if (dt == RDTnone)
1078 >                return RDTnone;
1079 >
1080 >        int     bytesPer = 0;           // figure out how far we got...
1081 >        switch (RDTcolorT(dt)) {
1082 >        case RDTrgbe:
1083 >        case RDTxyze:
1084 >                break;
1085 >        case RDTscolr:
1086 >                bytesPer = NCSAMP + 1;  // XXX assumes no compression
1087 >                break;
1088 >        case RDTrgb:
1089 >        case RDTxyz:
1090 >                bytesPer = sizeof(float)*3;
1091 >                break;
1092 >        case RDTscolor:
1093 >                bytesPer = sizeof(float)*NCSAMP;
1094 >                break;
1095 >        default:
1096 >                sprintf(errmsg, "unknown format for '%s'", pfname);
1097 >                error(USER, errmsg);
1098 >                fclose(pdfp[0]);
1099 >                if (pdfp[1]) fclose(pdfp[1]);
1100 >                return RDTnone;
1101 >        }
1102 >        RESOLU  res;
1103 >        if (!fgetsresolu(&res, pdfp[0]) || res.rt != PIXSTANDARD) {
1104 >                sprintf(errmsg, "missing/bad resolution for '%s'", pfname);
1105 >                error(USER, errmsg);
1106 >                fclose(pdfp[0]);
1107 >                if (pdfp[1]) fclose(pdfp[1]);
1108 >                return RDTnone;
1109 >        }
1110 >        frameNo = 0;                            // set up unreferenced frame
1111          int     hvdim[2] = {res.xr, res.yr};
1112          double  noAdj = 0;
1113 <        if (!NewFrame(hinfo.vw, hvdim, &noAdj) ||
1113 >        if (!NewFrame(vw, hvdim, &noAdj) ||
1114                          (hvdim[0] != res.xr) | (hvdim[1] != res.yr)) {
1115 <                fclose(pfp);
1115 >                error(CONSISTENCY, "unexpected resolution change in ResumeFrame()");
1116 >                fclose(pdfp[0]);
1117 >                if (pdfp[1]) fclose(pdfp[1]);
1118                  return RDTnone;
1119          }
1120 <        long    dataStart = ftell(pfp);         // picture starting point
1120 >        long    dataStart = ftell(pdfp[0]);     // picture starting point
1121          if (dataStart < 0) {
1122                  sprintf(errmsg, "cannot seek on '%s'", pfname);
1123                  error(SYSTEM, errmsg);
1124 <                fclose(pfp);
1124 >                fclose(pdfp[0]);
1125 >                if (pdfp[1]) fclose(pdfp[1]);
1126                  return RDTnone;
1127          }
1128          long    doneScans = 0;
1129          if (bytesPer) {                         // fixed-width records?
1130 <                fseek(pfp, 0, SEEK_END);
1131 <                long    dataEnd = ftell(pfp);
1130 >                fseek(pdfp[0], 0, SEEK_END);
1131 >                long    dataEnd = ftell(pdfp[0]);
1132                  doneScans = (dataEnd - dataStart)/(bytesPer*GetWidth());
1133                  if (dataEnd-dataStart > bytesPer*GetWidth()*doneScans)
1134 <                        fseek(pfp, dataStart + bytesPer*GetWidth()*doneScans, SEEK_SET);
1134 >                        fseek(pdfp[0], dataStart + bytesPer*GetWidth()*doneScans, SEEK_SET);
1135          } else {                                // else get compressed scanlines
1136                  COLR *  scan = (COLR *)tempbuffer(sizeof(COLR)*GetWidth());
1137 <                while (freadcolrs(scan, GetWidth(), pfp) >= 0)
1137 >                while (freadcolrs(scan, GetWidth(), pdfp[0]) >= 0)
1138                          ++doneScans;
1139 <                if (!feof(pfp)) {
1139 >                if (!feof(pdfp[0])) {
1140                          sprintf(errmsg, "error reading compressed scanline from '%s'", pfname);
1141                          error(USER, errmsg);
1142 <                        fclose(pfp);
1142 >                        fclose(pdfp[0]);
1143 >                        if (pdfp[1]) fclose(pdfp[1]);
1144                          return RDTnone;
1145                  }
1146          }
1147          if (doneScans >= GetHeight()) {         // nothing left to do?
1148                  sprintf(errmsg, "output file '%s' is already complete", pfname);
1149                  error(WARNING, errmsg);
1150 <                fclose(pfp);
1150 >                fclose(pdfp[0]);
1151 >                if (pdfp[1]) fclose(pdfp[1]);
1152                  return dt;
1153          }
1154          if (!doneScans) {
1155                  sprintf(errmsg, "restarting empty frame '%s'", pfname);
1156                  error(WARNING, errmsg);
1157          }
1158 <        if (dfname) {                           // append depth file, too?
1159 <                if (dfname[0] == '!') {
1160 <                        error(USER, "depth data cannot be reloaded from command");
1161 <                        fclose(pfp);
1158 >        long    toSkip = 0;
1159 >        switch (RDTdepthT(dt)) {                // append depth file, too?
1160 >        case RDTdfloat:
1161 >                toSkip = sizeof(float)*GetWidth()*doneScans;
1162 >                break;
1163 >        case RDTdshort:
1164 >                if (!fgetsresolu(&res, pdfp[1]) || (res.rt != PIXSTANDARD) |
1165 >                                (res.xr != GetWidth()) | (res.yr != GetHeight())) {
1166 >                        sprintf(errmsg, "missing/bad resolution for '%s'", dfname);
1167 >                        error(USER, errmsg);
1168 >                        fclose(pdfp[0]); fclose(pdfp[0]);
1169                          return RDTnone;
1170                  }
1171 <                dfp = fopen(dfname, "a");
1172 <                if (!dfp) {
1173 <                        sprintf(errmsg, "cannot reopen depth file '%s'", dfname);
1174 <                        error(SYSTEM, errmsg);
1175 <                        fclose(pfp);
1176 <                        return RDTnone;
1177 <                }
1178 <                SET_FILE_BINARY(dfp);
1179 <                const long      dflen = ftell(dfp);
1002 <                if (dflen != sizeof(float)*GetWidth()*doneScans) {
1003 <                        fclose(dfp);
1004 <                        dfp = fopen(dfname, "r+");
1005 <                        if (!dfp) return RDTnone;       // WTH?
1006 <                        SET_FILE_BINARY(dfp);
1007 <                }
1008 <                if (dflen < sizeof(float)*GetWidth()*doneScans) {
1009 <                        HeaderInfo      dinfo;
1010 <                        if (getheader(dfp, head_check, &dinfo) < 0)
1011 <                                sprintf(errmsg, "bad header in encoded depth file '%s'",
1012 <                                                dfname);
1013 <                        else if (strcmp(dinfo.fmt, DEPTH16FMT))
1014 <                                sprintf(errmsg, "wrong format (%s) for depth file '%s'",
1015 <                                                dinfo.fmt, dfname);
1016 <                        else if (!SetReferenceDepth(dinfo.depth_unit))
1017 <                                sprintf(errmsg, "bad/missing reference depth (%s) in '%s'",
1018 <                                                dinfo.depth_unit, dfname);
1019 <                        else if (!fscnresolu(hvdim, hvdim+1, dfp) ||
1020 <                                        (hvdim[0] != GetWidth()) | (hvdim[1] != GetHeight()))
1021 <                                sprintf(errmsg, "bad/mismatched resolution in '%s'",
1022 <                                                dfname);
1023 <                        else
1024 <                                errmsg[0] = '\0';
1025 <
1026 <                        if (errmsg[0]) {
1027 <                                error(USER, errmsg);
1028 <                                fclose(dfp);
1029 <                                fclose(pfp);
1030 <                                return RDTnone;
1031 <                        }
1032 <                        const long      dStart = ftell(dfp);
1033 <                        if (dflen-dStart < 2*GetWidth()*doneScans) {
1034 <                                sprintf(errmsg, "missing %ld depths in '%s'",
1035 <                                        (long)GetWidth()*doneScans - (dflen-dStart)/2,
1036 <                                        dfname);
1037 <                                error(WARNING, errmsg);
1038 <                        }
1039 <                        fseek(dfp, dStart + 2*GetWidth()*doneScans, SEEK_SET);
1040 <                        dt = RDTnewDT(dt, RDTdshort);
1041 <                } else {
1042 <                        if (dflen > sizeof(float)*GetWidth()*doneScans)
1043 <                                fseek(dfp, sizeof(float)*GetWidth()*doneScans, SEEK_SET);
1044 <                        dt = RDTnewDT(dt, RDTdfloat);
1045 <                }
1171 >                toSkip = 2L*GetWidth()*doneScans;
1172 >                break;
1173 >        default:;
1174 >        }                                       // fseek() needed for output
1175 >        if (pdfp[1] && fseek(pdfp[1], toSkip, SEEK_CUR) < 0) {
1176 >                sprintf(errmsg, "cannot seek on depth file '%s'", dfname);
1177 >                error(SYSTEM, errmsg);
1178 >                fclose(pdfp[0]); fclose(pdfp[1]);
1179 >                return RDTnone;
1180          }
1181 <        int     bheight = (psample > 1) ? int(2*psample+.99) : 4;
1181 >        int     bheight = (psample > 1) ? int(8*psample+.99) : 16;
1182          if (bheight > GetHeight()-doneScans)
1183                  bheight = GetHeight()-doneScans;
1184          int     vstep =  bheight >> (psample > 1);
1185          vstep += !vstep;
1186  
1187          NewBar(bheight);                        // render remainder if we can
1188 <        if (!RenderBelow(GetHeight()-doneScans, vstep, pfp, dt, dfp)) {
1189 <                fclose(pfp);
1190 <                if (dfp) fclose(dfp);
1188 >        if (!RenderBelow(GetHeight()-doneScans, vstep, pdfp[0], dt, pdfp[1])) {
1189 >                fclose(pdfp[0]);
1190 >                if (pdfp[1]) fclose(pdfp[1]);
1191                  Cleanup();
1192                  return RDTnone;
1193          }
1194          NewBar();                               // close up and return success
1195 <        fclose(pfp);
1196 <        if (dfp) fclose(dfp);
1195 >        fclose(pdfp[0]);
1196 >        if (pdfp[1]) fclose(pdfp[1]);
1197          return dt;
1198   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines