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.1 by greg, Wed Aug 14 20:05:23 2024 UTC vs.
Revision 2.9 by greg, Sun Aug 25 03:13:07 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 50 | Line 52 | PixelAccess::SetPixel(int x, int y, const RAY *rp)
52                  scolor_out(col, primp, rp->rcol);
53                  return SetPixel(x, y, col, zv);
54          default:
55 <                error(INTERNAL, "missing color space type in SetPixel()");
55 >                error(INTERNAL, "botched color space type in SetPixel()");
56          }
57          return false;
58   }
# Line 79 | Line 81 | PixelAccess::SetColorSpace(RenderDataType cs, RGBPRIMP
81          case RDTrgb:
82                  primp = pr ? pr : stdprims;
83                  break;
84 <        default:                        // RDTscolr | RDTscolor
84 >        case RDTscolr:
85 >        case RDTscolor:
86                  primp = NULL;
87                  break;
88 +        default:
89 +                error(INTERNAL, "botched color space type in SetColorSpace()");
90          }
91          dtyp = RDTnewCT(dtyp, cs);
87        if (primp)
88                xyz2myrgbmat[0][0] = 0;
92          return true;
93   }
94  
# Line 138 | Line 141 | int
141   RpictSimulManager::RtCall(RAY *r, void *cd)
142   {
143          RpictSimulManager *     rsp = (RpictSimulManager *)cd;
144 <        const int               ty = r->rno / rsp->TWidth();
145 <        const int               tx = r->rno - (RNUMBER)ty*rsp->TWidth();
144 >        const int               ty = (r->rno-1) / rsp->TWidth();
145 >        const int               tx = r->rno-1 - (RNUMBER)ty*rsp->TWidth();
146  
147          if (ty >= rsp->THeight()) {
148                  error(INTERNAL, "bad pixel calculation position in RtCall()");
# Line 195 | Line 198 | RpictSimulManager::SetTile(const int ti[2])
198   bool
199   RpictSimulManager::ComputePixel(int x, int y)
200   {
201 <        static const SCOLOR     scBlack = {0};
201 >        DCHECK(doneMap.OffBitMap(x,y),
202 >                        CONSISTENCY, "illegal pixel index in ComputPixel()");
203          int     i;
204          FVECT   rodir[2];
205          double  hpos = (x+pixjitter())/TWidth();
206          double  vpos = (y+pixjitter())/THeight();
207          double  dlim = viewray(rodir[0], rodir[1], &tvw, hpos, vpos);
208          if (dlim < -FTINY) {    // off view?
209 <                pacc.SetPixel(x, y, scBlack);
209 >                pacc.SetPixel(x, y, scblack);
210                  doneMap.Set(x, y);
211                  return true;
212          }
# Line 227 | Line 231 | RpictSimulManager::ComputePixel(int x, int y)
231          for (i = (dlim > FTINY)*3; i--; )
232                  rodir[1][i] *= dlim;
233  
234 <        return EnqueueRay(rodir[0], rodir[1], (RNUMBER)y*TWidth()+x);
234 >        return EnqueueRay(rodir[0], rodir[1], (RNUMBER)y*TWidth()+x+1);
235   }
236  
237   // Check if neighbor differences are below pixel sampling threshold
# Line 261 | Line 265 | RpictSimulManager::BelowSampThresh(int x, int y, const
265  
266   // Fill an interior square patch with interpolated values
267   void
268 < RpictSimulManager::FillSquare(int x, int y, const int noff[4][2])
268 > RpictSimulManager::FillSquare(const int x, const int y, const int noff[4][2])
269   {
270          SCOLOR  pval[4];
271          float   dist[4];
272          int     i, j;
273                                          // assumes 4 corners are valid!
274 <        for (i = 4; i--; )
274 >        for (i = 4; i--; ) {
275 >                DCHECK(!doneMap.Check(x+noff[i][0], y+noff[i][1]),
276 >                        CONSISTENCY, "inclusion of bad pixel in FillSquare()");
277                  pacc.GetPixel(x+noff[i][0], y+noff[i][1], pval[i], &dist[i]);
278 <
278 >        }
279          i = abs(noff[1][0]-noff[0][0]);
280 <        j = abs(noff[1][1]-noff[0][1]);
281 <        const int       slen =  i > j ? i : j;
276 <        const double    sf = 1./slen;
280 >        j = abs(noff[1][1]-noff[0][1]); // i==j for diamond fill
281 >        const int       slen =  (i > j) ? i : j;
282          const bool      spectr = (pacc.NC() > 3);
283 <        for (i = 0; i <= slen; i++) {   // bilinear interpolant
284 <            const double        c1 = i*sf;
285 <            for (j = 0; j <= slen; j++) {
286 <                const double    c2 = j*sf;
283 >        for (i = slen+1 + (i==j)*slen; i--; ) {
284 >            const double        c1 = (i>slen ? i-slen-.5 : (double)i)/slen;
285 >            for (j = slen + (i<=slen); j--; ) {
286 >                const double    c2 = (j + (i>slen)*.5)/slen;
287                  const int       px = int(x + (1.-c1)*(1.-c2)*noff[0][0] +
288                                                  c1*(1.-c2)*noff[1][0] +
289                                                  (1.-c1)*c2*noff[2][0] +
# Line 328 | Line 333 | RpictSimulManager::FillSquare(int x, int y, const int
333  
334   // helper function to set up quincunx sampling
335   static void
336 < SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int spc, const bool odd)
336 > SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int spc, bool odd, int x0, int y)
337   {
338 <        for (int y = 0; y < bmp2->Height(); y += spc>>1)
334 <            for (int x = odd*(spc>>1); x < bmp2->Width(); x += spc)
335 <                bmp2->Set(x, y);
336 <                                        // order neighbors CCW
337 <        if (odd) {
338 >        if (odd) {                      // order neighbors CCW
339                  noff[0][0] = spc>>1; noff[0][1] = 0;
340                  noff[1][0] = 0; noff[1][1] = spc>>1;
341                  noff[2][0] = -(spc>>1); noff[2][1] = 0;
# Line 345 | Line 346 | SetQuincunx(ABitMap2 *bmp2, int noff[4][2], const int
346                  noff[2][0] = -(spc>>1); noff[2][1] = -(spc>>1);
347                  noff[3][0] = spc>>1; noff[3][1] = -(spc>>1);
348          }
349 +        int     nsteps;                 // non-negative range
350 +        if (x0 < -(spc>>1)) {
351 +                nsteps = (spc-1 - x0 - (spc>>1))/spc;
352 +                x0 += nsteps*spc;
353 +        }
354 +        if (y < 0) {                    // get past y==0
355 +                nsteps = ((spc>>1)-1 - y)/(spc>>1);
356 +                y += nsteps*(spc>>1);
357 +                odd ^= nsteps&1;
358 +        }
359 +        while (y < bmp2->Height()) {
360 +            for (int x = x0 + odd*(spc>>1); x < bmp2->Width(); x += spc)
361 +                bmp2->Set(x, y);
362 +            y += spc>>1;
363 +            odd = !odd;
364 +        }
365   }
366  
367   // Render (or finish rendering) current tile
368   bool
369 < RpictSimulManager::RenderRect()
369 > RpictSimulManager::RenderRect(const int x0, const int y0)
370   {
371          if (!tvw.type || !Ready()) {
372                  error(INTERNAL, "need octree and view for RenderRect()");
# Line 359 | Line 376 | RpictSimulManager::RenderRect()
376          int             sp2 = ceil(log2((TWidth()>THeight() ? TWidth() : THeight()) - 1.));
377          int             layer = 0;
378          int             x, y;
362 fprintf(stderr, "Rendering %dx%d tile with psample=%d, maxdiff=%.3f ...\n",
363 TWidth(), THeight(), psample, maxdiff);
379          while (sp2 > 0) {
380                  ABitMap2        sampMap(TWidth(), THeight());
381                  int             noff[4][2];
382                  if ((prCB != NULL) & (barPix == NULL))
383                          (*prCB)(100.*doneMap.SumTotal()/doneMap.Width()/doneMap.Height());
384 <                SetQuincunx(&sampMap, noff, 1<<sp2, layer&1);
384 >                SetQuincunx(&sampMap, noff, 1<<sp2, layer&1, x0, y0);
385                  sampMap -= doneSamples; // avoid resampling pixels
386                  // Are we into adaptive sampling realm?
387                  if (noff[0][0]*noff[0][0] + noff[0][1]*noff[0][1] < psample*psample) {
388 <                        if (FlushQueue() < 0)   // need results to check threshold
388 >                        if (FlushQueue() < 0)   // need results to check thresholds
389                                  return false;
390                          ABitMap2        fillMap = sampMap;
391                          for (x = y = 0; sampMap.Find(&x, &y); x++)
392                                  if (BelowSampThresh(x, y, noff))
393                                          sampMap.Reset(x, y);
394 + #if 0
395 + XXX Need to fix directions for spreading!!
396                                          // spread sampling to neighbors...
397                          const ABitMap2  origSampMap = sampMap;
398 <                        for (int yoff = -(1<<(sp2-1));
382 <                                        yoff <= 1<<(sp2-1); yoff += 1<<sp2)
383 <                            for (int xoff = -(1<<(sp2-1));
384 <                                        xoff <= 1<<(sp2-1); xoff += 1<<sp2) {
398 >                        for (x = 4; x--; ) {
399                                  ABitMap2        stamp = origSampMap;
400 <                                stamp.Shift(xoff, yoff);
400 >                                stamp.Shift(noff[x][0], noff[x][1]);
401                                  sampMap |= stamp;
402                          }               // ...but don't resample what's done
403                          sampMap -= doneSamples;
404 + #endif
405                                          // interpolate smooth regions
406                          fillMap -= sampMap;
407                          for (x = y = 0; fillMap.Find(&x, &y); x++)
# Line 397 | Line 412 | TWidth(), THeight(), psample, maxdiff);
412                          if (!ComputePixel(x, y))
413                                  return false;
414                  doneSamples |= sampMap; // samples now done or at least queued
400 fprintf(stderr, "Sampled %ld pixels at (sp2,layer)=(%d,%d)\n",
401 (long)sampMap.SumTotal(), sp2, layer);
402 fprintf(stderr, "\t%ld pixels (%.3f%%) completed (+%ld in process)\n",
403 (long)doneMap.SumTotal(), 100.*doneMap.SumTotal()/doneMap.Width()/doneMap.Height(),
404 (long)(doneSamples.SumTotal()-doneMap.SumTotal()));
415                  sp2 -= layer++ & 1;     // next denser sampling
416          }
417          if (FlushQueue() < 0)           // make sure we got everyone
# Line 436 | Line 446 | RpictSimulManager::RenderTile(COLORV *rp, int ystride,
446                  pacc.SetColorSpace(RDTxyz);
447          else if (prims)
448                  pacc.SetColorSpace(RDTrgb, prims);
449 <                
450 <        return SetTile(tile) && RenderRect();
449 >
450 >        int     x0=0, y0=0;
451 >        if (tile) {
452 >                x0 = -tile[0]*TWidth();
453 >                y0 = -tile[1]*THeight();
454 >        }
455 >        return SetTile(tile) && RenderRect(x0, y0);
456   }
457  
458   // Same but store as common-exponent COLR or SCOLR
# Line 454 | Line 469 | RpictSimulManager::RenderTile(COLRV *bp, int ystride,
469          else if (prims)
470                  pacc.SetColorSpace(RDTrgbe, prims);
471  
472 <        return SetTile(tile) && RenderRect();
472 >        int     x0=0, y0=0;
473 >        if (tile) {
474 >                x0 = -tile[0]*TWidth();
475 >                y0 = -tile[1]*THeight();
476 >        }
477 >        return SetTile(tile) && RenderRect(x0, y0);
478   }
479  
480   // Same but also use 16-bit encoded depth buffer
# Line 471 | Line 491 | RpictSimulManager::RenderTile(COLRV *bp, int ystride,
491          else if (prims)
492                  pacc.SetColorSpace(RDTrgbe, prims);
493  
494 <        return SetTile(tile) && RenderRect();
494 >        int     x0=0, y0=0;
495 >        if (tile) {
496 >                x0 = -tile[0]*TWidth();
497 >                y0 = -tile[1]*THeight();
498 >        }
499 >        return SetTile(tile) && RenderRect(x0, y0);
500   }
501  
502 + // Back to float color with 16-bit depth
503 + bool
504 + RpictSimulManager::RenderTile(COLORV *rp, int ystride, short *dp, const int *tile)
505 + {
506 +        if (!rp | (GetWidth() <= 0) | (GetHeight() <= 0) | !vw.type)
507 +                return false;
508 +        if (!ystride)                   // contiguous rows?
509 +                ystride = TWidth();
510 +        pacc.Init(rp, ystride, dp);
511 +        if (prims == xyzprims)
512 +                pacc.SetColorSpace(RDTxyz);
513 +        else if (prims)
514 +                pacc.SetColorSpace(RDTrgb, prims);
515 +
516 +        int     x0=0, y0=0;
517 +        if (tile) {
518 +                x0 = -tile[0]*TWidth();
519 +                y0 = -tile[1]*THeight();
520 +        }
521 +        return SetTile(tile) && RenderRect(x0, y0);
522 + }
523 +
524   // Allocate a new render bar
525   void
526   RpictSimulManager::NewBar(int ht)
# Line 504 | Line 551 | RpictSimulManager::NewBar(int ht)
551  
552   // Shift render bar area the specified amount down the frame
553   bool
554 < RpictSimulManager::LowerBar(int v)
554 > RpictSimulManager::LowerBar(int v, int ytop)
555   {
509        if (v <= 0) return !v;
556          if (!barPix | !barDepth | (v > THeight()) | !tvw.type)
557                  return false;
558 <        tvw.voff -= double(v)/GetHeight();
559 <        ptvw.voff -= double(v)/GetHeight();
558 >        if (v <= 0) return !v;
559 >        if ((ytop -= v) <= 0)
560 >                return true;
561 >        tvw.voff -= double(v)/THeight();
562 >        ptvw.voff -= double(v)/THeight();
563          if (v == THeight()) {
564                  doneMap.ClearBitMap();
565                  return true;
# Line 521 | Line 570 | RpictSimulManager::LowerBar(int v)
570                          sizeof(COLORV)*NC*TWidth()*(THeight()-v));
571          memmove(barDepth, barDepth + TWidth()*v,
572                          sizeof(float)*TWidth()*(THeight()-v));
573 +        if (ytop < THeight())                   // mark what we won't do as finished
574 +                doneMap.ClearRect(0, 0, TWidth(), THeight()-ytop, true);
575          return true;
576   }
577  
# Line 543 | Line 594 | RpictSimulManager::RenderBelow(int ytop, const int vst
594                          cropview(&ptvw, 0., double(ytop-THeight())/GetHeight(),
595                                                  1., double(ytop)/GetHeight()))
596                  ptvw.type = 0;
597 <                                                // set up spectral sampling
597 >                                                // update spectral sampling
598          if (setspectrsamp(CNDX, WLPART) <= 0) {
599                  error(USER, "unsupported spectral sampling");
600                  return false;
# Line 562 | Line 613 | RpictSimulManager::RenderBelow(int ytop, const int vst
613          }
614          int             lastOut = ytop;         // render down frame
615          while (ytop > 0) {
565                if (ytop < THeight())           // mark what we won't do as finished
566                        doneMap.ClearRect(0, 0, TWidth(), THeight()-ytop, true);
616                  if (prCB)
617                          (*prCB)(100.*(GetHeight()-ytop)/GetHeight());
618 <                if (!RenderRect())              // render this bar
618 >                if (!RenderRect(0, THeight()-ytop))     // render this bar
619                          return false;
620                  int     nlines = lastOut - ytop + THeight();
621                  if (nlines > ytop)
# Line 605 | Line 654 | RpictSimulManager::RenderBelow(int ytop, const int vst
654                                          error(SYSTEM, "cannot write SCOLOR output");
655                                  break;
656                          default:
657 <                                error(INTERNAL, "missing output color type in RenderBelow()");
657 >                                error(INTERNAL, "botched output color type in RenderBelow()");
658                                  break;
659                          }
660                          bpos += pacc.NC()*TWidth();
# Line 614 | Line 663 | RpictSimulManager::RenderBelow(int ytop, const int vst
663                  if (fflush(pfp) == EOF || (dfp && fflush(dfp) == EOF))
664                          error(SYSTEM, "output write error");
665                                                  // advance down the frame
666 <                if (lastOut > 0 && !LowerBar(vstep))
666 >                if (lastOut > 0 && !LowerBar(vstep, ytop))
667                          return false;
668                  ytop -= vstep;
669          }
# Line 625 | Line 674 | RpictSimulManager::RenderBelow(int ytop, const int vst
674          return true;
675   }
676  
677 < /*
629 < * Render and write a frame to the named file
630 < * Include any header lines set prior to call
631 < * Picture file must not already exist
632 < * Picture to stdout if pfname==NULL
633 < * Depth written to a command if dfname[0]=='!'
634 < */
677 > // Open new output picture file (and optional depth file)
678   RenderDataType
679 < RpictSimulManager::RenderFrame(const char *pfname, RenderDataType dt, const char *dfname)
679 > RpictSimulManager::NewOutput(FILE *pdfp[2], const char *pfname,
680 >                                RenderDataType dt, const char *dfname)
681   {
682 <        int     fd = 1;
639 <        FILE *  pfp = NULL;
640 <        FILE *  dfp = NULL;
641 <
682 >        pdfp[0] = pdfp[1] = NULL;
683          if (!RDTcolorT(dt))
684 <                error(INTERNAL, "missing pixel output type in RenderFrame()");
684 >                error(INTERNAL, "missing color output type in NewOutput()");
685          if (NCSAMP == 3) {
686                  if (RDTcolorT(dt) == RDTscolr)
687                          dt = RDTnewCT(dt, prims==xyzprims ? RDTxyze : RDTrgbe);
# Line 648 | Line 689 | RpictSimulManager::RenderFrame(const char *pfname, Ren
689                          dt = RDTnewCT(dt, prims==xyzprims ? RDTxyz : RDTrgb);
690          }
691          if (!RDTdepthT(dt) ^ !dfname)
692 <                error(INTERNAL, "depth output requires file name and type in RenderFrame()");
692 >                error(INTERNAL, "depth output requires file name and type in NewOutput()");
693 >        int     fd = 1;
694          if (pfname) {                           // open picture output file
695                  if (pfname[0] == '!') {
696                          error(INTERNAL, "writing picture to a command not supported");
# Line 661 | Line 703 | RpictSimulManager::RenderFrame(const char *pfname, Ren
703                          sprintf(errmsg, "cannot open picture file '%s'", pfname);
704                          error(SYSTEM, errmsg);
705                  }
706 <                return RDTnone;                 // expected in parallel sequence
706 >                return RDTnone;                 // may be expected in sequence run
707          }
708          if (fd == 1)
709 <                pfp = stdout;
710 <        else if (!(pfp = fdopen(fd, "w")))
709 >                pdfp[0] = stdout;
710 >        else if (!(pdfp[0] = fdopen(fd, "w")))
711                  error(SYSTEM, "failure calling fdopen()");
712 <        SET_FILE_BINARY(pfp);                   // write picture header
713 <        if ((pfp != stdout) | (frameNo <= 1)) {
714 <                newheader("RADIANCE", pfp);
715 <                fputs(GetHeader(), pfp);
712 >        SET_FILE_BINARY(pdfp[0]);               // write picture header
713 >        if ((pdfp[0] != stdout) | (frameNo <= 1)) {
714 >                newheader("RADIANCE", pdfp[0]);
715 >                fputs(GetHeader(), pdfp[0]);
716          }
717 <        fputs(VIEWSTR, pfp); fprintview(&vw, pfp); fputc('\n', pfp);
717 >        fputs(VIEWSTR, pdfp[0]); fprintview(&vw, pdfp[0]); fputc('\n', pdfp[0]);
718          if (frameNo > 0)
719 <                fprintf(pfp, "FRAME=%d\n", frameNo);
719 >                fprintf(pdfp[0], "FRAME=%d\n", frameNo);
720          double  pasp = viewaspect(&vw) * GetWidth() / GetHeight();
721 <        if (!FABSEQ(pasp, 1.0))
722 <                fputaspect(pasp, pfp);
723 <        fputnow(pfp);
721 >        if ((0.99 > pasp) | (pasp > 1.01))
722 >                fputaspect(pasp, pdfp[0]);
723 >        fputnow(pdfp[0]);
724          switch (RDTcolorT(dt)) {                // set primaries and picture format
725          case RDTrgbe:
726                  if (!prims | (prims == xyzprims)) prims = stdprims;
727 <                fputprims(prims, pfp);
728 <                fputformat(COLRFMT, pfp);
727 >                fputprims(prims, pdfp[0]);
728 >                fputformat(COLRFMT, pdfp[0]);
729                  break;
730          case RDTxyze:
731                  prims = xyzprims;
732 <                fputformat(CIEFMT, pfp);
732 >                fputformat(CIEFMT, pdfp[0]);
733                  break;
734          case RDTscolr:
735                  prims = NULL;
736 <                fputwlsplit(WLPART, pfp);
737 <                fputncomp(NCSAMP, pfp);
738 <                fputformat(SPECFMT, pfp);
736 >                fputwlsplit(WLPART, pdfp[0]);
737 >                fputncomp(NCSAMP, pdfp[0]);
738 >                fputformat(SPECFMT, pdfp[0]);
739                  break;
740          case RDTrgb:
741                  if (!prims | (prims == xyzprims)) prims = stdprims;
742 <                fputprims(prims, pfp);
743 <                fputncomp(3, pfp);
744 <                fputendian(pfp);
745 <                fputformat("float", pfp);
742 >                fputprims(prims, pdfp[0]);
743 >                fputncomp(3, pdfp[0]);
744 >                fputendian(pdfp[0]);
745 >                fputformat("float", pdfp[0]);
746                  break;
747          case RDTxyz:
748                  prims = xyzprims;
749 <                fputprims(prims, pfp);
750 <                fputncomp(3, pfp);
751 <                fputendian(pfp);
752 <                fputformat("float", pfp);
749 >                fputprims(prims, pdfp[0]);
750 >                fputncomp(3, pdfp[0]);
751 >                fputendian(pdfp[0]);
752 >                fputformat("float", pdfp[0]);
753                  break;
754          case RDTscolor:
755                  prims = NULL;
756 <                fputwlsplit(WLPART, pfp);
757 <                fputncomp(NCSAMP, pfp);
758 <                fputendian(pfp);
759 <                fputformat("float", pfp);
756 >                fputwlsplit(WLPART, pdfp[0]);
757 >                fputncomp(NCSAMP, pdfp[0]);
758 >                fputendian(pdfp[0]);
759 >                fputformat("float", pdfp[0]);
760                  break;
761 <        default:;
761 >        default:;       // pro forma - caught this above
762          }
763 <        fputc('\n', pfp);                       // end picture header
764 <        fprtresolu(GetWidth(), GetHeight(), pfp);
765 <        if (dfname) {
763 >        fputc('\n', pdfp[0]);                   // flush picture header
764 >        if (fflush(pdfp[0]) == EOF) {
765 >                sprintf(errmsg, "cannot write header to picture '%s'", pfname);
766 >                error(SYSTEM, errmsg);
767 >                fclose(pdfp[0]);
768 >                pdfp[0] = NULL;
769 >                return RDTnone;
770 >        }
771 >        if (dfname) {                           // open depth output
772                  if (dfname[0] == '!')
773 <                        dfp = popen(dfname+1, "w");
773 >                        pdfp[1] = popen(dfname+1, "w");
774                  else
775 <                        dfp = fopen(dfname, "w");
776 <                if (!dfp) {
775 >                        pdfp[1] = fopen(dfname, "w");
776 >                if (!pdfp[1]) {
777                          sprintf(errmsg, "cannot open depth output '%s'", dfname);
778                          error(SYSTEM, errmsg);
779 +                        fclose(pdfp[0]);
780 +                        pdfp[0] = NULL;
781                          return RDTnone;
782                  }
783 <                SET_FILE_BINARY(dfp);
783 >                SET_FILE_BINARY(pdfp[1]);
784          }
785          if (RDTdepthT(dt) == RDTdshort) {       // write header for 16-bit depth?
786 <                newheader("RADIANCE", dfp);
787 <                fputs(GetHeader(), dfp);
788 <                fputs(VIEWSTR, dfp); fprintview(&vw, dfp); fputc('\n', dfp);
789 <                fputs(DEPTHSTR, dfp); fputs(dunit, dfp); fputc('\n', dfp);
790 <                fputformat(DEPTH16FMT, dfp);
791 <                fputc('\n', dfp);               // end-of-info
792 <                fprtresolu(GetWidth(), GetHeight(), dfp);
786 >                newheader("RADIANCE", pdfp[1]);
787 >                fputs(GetHeader(), pdfp[1]);
788 >                fputs(VIEWSTR, pdfp[1]); fprintview(&vw, pdfp[1]); fputc('\n', pdfp[1]);
789 >                fputs(DEPTHSTR, pdfp[1]); fputs(dunit, pdfp[1]); fputc('\n', pdfp[1]);
790 >                fputformat(DEPTH16FMT, pdfp[1]);
791 >                fputc('\n', pdfp[1]);           // end-of-info
792 >                if (fflush(pdfp[1]) == EOF) {
793 >                        sprintf(errmsg, "cannot write header to '%s'", dfname);
794 >                        error(SYSTEM, errmsg);
795 >                        fclose(pdfp[0]); fclose(pdfp[1]);
796 >                        pdfp[0] = pdfp[1] = NULL;
797 >                        return RDTnone;
798 >                }
799          }
800 <        const int       bheight = (psample > 1) ? int(2*psample+.99) : 4;
801 <        const int       vstep =  bheight >> (psample > 1);
800 >        return dt;                              // ready to roll
801 > }
802  
803 + /*
804 + * Render and write a frame to the named file
805 + * Include any header lines set prior to call
806 + * Picture file must not exist
807 + * Write pixels to stdout if !pfname
808 + * Write depth to a command if dfname[0]=='!'
809 + */
810 + RenderDataType
811 + RpictSimulManager::RenderFrame(const char *pfname, RenderDataType dt, const char *dfname)
812 + {
813 +        FILE    *pdfp[2];
814 +                                                // prepare output file(s)
815 +        dt = NewOutput(pdfp, pfname, dt, dfname);
816 +        if (dt == RDTnone)
817 +                return RDTnone;
818 +                                                // add resolution string(s)
819 +        fprtresolu(GetWidth(), GetHeight(), pdfp[0]);
820 +        if (RDTdepthT(dt) == RDTdshort)
821 +                fprtresolu(GetWidth(), GetHeight(), pdfp[1]);
822 +
823 +        const int       bheight = (psample > 1) ? int(4*psample+.99) : 8;
824 +        const int       vstep = bheight >> (psample > 1);
825 +
826          NewBar(bheight);                        // render frame if we can
827 <        if (!RenderBelow(GetHeight(), vstep, pfp, dt, dfp)) {
828 <                fclose(pfp);
829 <                if (dfp) (dfname[0] == '!') ? pclose(dfp) : fclose(dfp);
827 >        if (!RenderBelow(GetHeight(), vstep, pdfp[0], dt, pdfp[1])) {
828 >                fclose(pdfp[0]);
829 >                if (pdfp[1]) (dfname[0] == '!') ? pclose(pdfp[1]) : fclose(pdfp[1]);
830                  Cleanup();
831                  return RDTnone;
832          }
833          NewBar();                               // clean up and return
834 <        if (pfp != stdout)
835 <                fclose(pfp);
836 <        if (dfp) {
834 >        if (pdfp[0] != stdout)
835 >                fclose(pdfp[0]);
836 >        if (pdfp[1]) {
837                  if (dfname[0] == '!') {
838 <                        int     status = pclose(dfp);
838 >                        int     status = pclose(pdfp[1]);
839                          if (status) {
840                                  sprintf(errmsg, "depth output (%s) error status: %d",
841                                                  dfname, status);
# Line 764 | Line 843 | RpictSimulManager::RenderFrame(const char *pfname, Ren
843                                  return RDTnone;
844                          }
845                  } else
846 <                        fclose(dfp);
846 >                        fclose(pdfp[1]);
847          }
848          return dt;
849   }
850  
851   // passed struct for header line callback
852 < struct HeaderInfo {
852 > static struct HeaderInfo {
853          char            fmt[MAXFMTLEN];
854          char            depth_unit[32];
855          int             ncomp;
# Line 791 | Line 870 | struct HeaderInfo {
870                                  gotview = false;
871                                  endianMatch = true;
872                          }
873 < };
873 > }       hinfo;          // XXX single copy to hold custom primitives
874  
875   // helper function checks header line and records req. info.
876   static int
# Line 833 | Line 912 | head_check(char *s, void *p)
912          return 0;
913   }
914  
915 < // Resume partially finished rendering
837 < // Picture file must exist
915 > // Reopen output file(s), leaving pointers at end of (each) header
916   RenderDataType
917 < RpictSimulManager::ResumeFrame(const char *pfname, const char *dfname)
917 > RpictSimulManager::ReopenOutput(FILE *pdfp[2], const char *pfname, const char *dfname)
918   {
919 <        if (!pfname || pfname[0] == '!')
842 <                return RDTnone;
919 >        extern const char       HDRSTR[];
920  
921 +        if (!pfname || pfname[0] == '!') {
922 +                pdfp[0] = pdfp[1] = NULL;
923 +                return RDTnone;
924 +        }
925          RenderDataType  dt = RDTnone;
926 <        FILE *          dfp = NULL;
927 <        FILE *          pfp = fopen(pfname, "r+");
928 <        if (!pfp) {
926 >        pdfp[1] = NULL;
927 >        pdfp[0] = fopen(pfname, "r+");
928 >        if (!pdfp[0]) {
929                  sprintf(errmsg, "cannot reopen output picture '%s'", pfname);
930                  error(SYSTEM, errmsg);
931                  return RDTnone;
932          }
933 <        SET_FILE_BINARY(pfp);
934 <        HeaderInfo      hinfo;          // read header information & dimensions
935 <        RESOLU          res;
936 <        if (getheader(pfp, head_check, &hinfo) < 0) {
856 <                fclose(pfp);
933 >        SET_FILE_BINARY(pdfp[0]);       // read header information
934 >        if (getheader(pdfp[0], head_check, &hinfo) < 0) {
935 >                fclose(pdfp[0]);
936 >                pdfp[0] = NULL;
937                  return RDTnone;
938          }
859        if (!fgetsresolu(&res, pfp) || res.rt != PIXSTANDARD) {
860                sprintf(errmsg, "missing/bad resolution for '%s'", pfname);
861                error(USER, errmsg);
862                fclose(pfp);
863                return RDTnone;
864        }
939          if (!hinfo.gotview) {
940                  sprintf(errmsg, "missing view for '%s'", pfname);
941                  error(USER, errmsg);
942 <                fclose(pfp);
942 >                fclose(pdfp[0]);
943 >                pdfp[0] = NULL;
944                  return RDTnone;
945          }
946          if (hinfo.ncomp < 3) {
947                  sprintf(errmsg, "bad # components (%d) in '%s'", hinfo.ncomp, pfname);
948                  error(USER, errmsg);
949 <                fclose(pfp);
949 >                fclose(pdfp[0]);
950 >                pdfp[0] = NULL;
951                  return RDTnone;
952          }
953 <        int     bytesPer = 0;           // complicated part to set rendering/output space
953 >                                        // set rendering/output space
954          if (!strcmp(hinfo.fmt, COLRFMT)) {
955 <                prims = hinfo.prims;
955 >                prims = hinfo.prims;    // XXX static array
956                  int     n = 8*hinfo.gotprims;
957                  while (n--)
958                          if (!FABSEQ(hinfo.prims[0][n], stdprims[0][n]))
# Line 892 | Line 968 | RpictSimulManager::ResumeFrame(const char *pfname, con
968                          sprintf(errmsg, "incompatible sample count (%d) in '%s'",
969                                          hinfo.ncomp, pfname);
970                          error(USER, errmsg);
971 <                        fclose(pfp);
971 >                        fclose(pdfp[0]);
972 >                        pdfp[0] = NULL;
973                          return RDTnone;
974                  }
975 <                NCSAMP = hinfo.ncomp;   // overrides global setting
975 >                NCSAMP = hinfo.ncomp;           // overrides global setting
976                  prims = NULL;
977                  dt = RDTnewCT(dt, RDTscolr);
901                bytesPer = hinfo.ncomp + 1;     // XXX assumes no compression
978          } else if (!strcmp(hinfo.fmt, "float")) {
979                  if (!hinfo.endianMatch) {
980                          sprintf(errmsg, "incompatible byte ordering in '%s'", pfname);
981                          error(USER, errmsg);
982 <                        fclose(pfp);
982 >                        fclose(pdfp[0]);
983 >                        pdfp[0] = NULL;
984                          return RDTnone;
985                  }
986                  if (hinfo.ncomp == 3) {
987 <                        prims = hinfo.prims;            // custom primaries?
987 >                        prims = hinfo.prims;    // custom primaries?
988                          int     n = 8*hinfo.gotprims;
989                          while (n--)
990                                  if (!FABSEQ(hinfo.prims[0][n], stdprims[0][n]))
991                                          break;
992 <                        if (n < 0)                      // standard primaries?
992 >                        if (n < 0)              // standard primaries?
993                                  prims = stdprims;
994                          else if (hinfo.gotprims) {      // or check if XYZ
995                                  for (n = 8; n--; )
# Line 930 | Line 1007 | RpictSimulManager::ResumeFrame(const char *pfname, con
1007                          prims = NULL;
1008                          dt = RDTnewCT(dt, RDTscolor);
1009                  }
933                bytesPer = sizeof(float)*hinfo.ncomp;
1010          } else {
1011                  sprintf(errmsg, "unknown format (%s) for '%s'", hinfo.fmt, pfname);
1012                  error(USER, errmsg);
1013 <                fclose(pfp);
1013 >                fclose(pdfp[0]);
1014 >                pdfp[0] = NULL;
1015                  return RDTnone;
1016          }
1017 +        if (!dfname)                            // no depth file?
1018 +                return dt;
1019 +
1020 +        if (dfname[0] == '!') {
1021 +                error(USER, "depth data cannot be reloaded from command");
1022 +                fclose(pdfp[0]);
1023 +                pdfp[0] = NULL;
1024 +                return RDTnone;
1025 +        }
1026 +        pdfp[1] = fopen(dfname, "r+");
1027 +        if (!pdfp[1]) {
1028 +                sprintf(errmsg, "cannot reopen depth file '%s'", dfname);
1029 +                error(SYSTEM, errmsg);
1030 +                fclose(pdfp[0]);
1031 +                pdfp[0] = NULL;
1032 +                return RDTnone;
1033 +        }
1034 +        SET_FILE_BINARY(pdfp[1]);
1035 +        int     n, len = strlen(HDRSTR);
1036 +        char    buf[32];                // sniff for 16-bit header
1037 +        if (getbinary(buf, 1, len+1, pdfp[1]) < len+1) {
1038 +                sprintf(errmsg, "empty depth file '%s'", dfname);
1039 +                error(SYSTEM, errmsg);
1040 +                fclose(pdfp[0]); fclose(pdfp[1]);
1041 +                pdfp[0] = pdfp[1] = NULL;
1042 +                return RDTnone;
1043 +        }
1044 +        for (n = 0; n < len; n++)
1045 +                if (buf[n] != HDRSTR[n])
1046 +                        break;          // not a Radiance header
1047 +        rewind(pdfp[1]);
1048 +        if ((n < len) | !isprint(buf[len]))
1049 +                return RDTnewDT(dt, RDTdfloat);
1050 +
1051 +        HeaderInfo      dinfo;          // thinking it's 16-bit encoded
1052 +        if (getheader(pdfp[1], head_check, &dinfo) < 0)
1053 +                sprintf(errmsg, "bad header in encoded depth file '%s'",
1054 +                                dfname);
1055 +        else if (strcmp(dinfo.fmt, DEPTH16FMT))
1056 +                sprintf(errmsg, "wrong format (%s) for depth file '%s'",
1057 +                                dinfo.fmt, dfname);
1058 +        else if (!SetReferenceDepth(dinfo.depth_unit))
1059 +                sprintf(errmsg, "bad/missing reference depth (%s) in '%s'",
1060 +                                dinfo.depth_unit, dfname);
1061 +        else
1062 +                errmsg[0] = '\0';
1063 +
1064 +        if (errmsg[0]) {
1065 +                error(USER, errmsg);
1066 +                fclose(pdfp[1]); fclose(pdfp[0]);
1067 +                pdfp[0] = pdfp[1] = NULL;
1068 +                return RDTnone;
1069 +        }
1070 +        return RDTnewDT(dt, RDTdshort);
1071 + }
1072 +
1073 + // Resume partially finished rendering
1074 + // Picture file must exist
1075 + RenderDataType
1076 + RpictSimulManager::ResumeFrame(const char *pfname, const char *dfname)
1077 + {
1078 +        FILE            *pdfp[2];
1079 +
1080 +        RenderDataType  dt = ReopenOutput(pdfp, pfname, dfname);
1081 +        if (dt == RDTnone)
1082 +                return RDTnone;
1083 +
1084 +        int     bytesPer = 0;           // figure out how far we got...
1085 +        switch (RDTcolorT(dt)) {
1086 +        case RDTrgbe:
1087 +        case RDTxyze:
1088 +                break;
1089 +        case RDTscolr:
1090 +                bytesPer = hinfo.ncomp + 1;     // XXX assumes no compression
1091 +                break;
1092 +        case RDTrgb:
1093 +        case RDTxyz:
1094 +                bytesPer = sizeof(float)*3;
1095 +                break;
1096 +        case RDTscolor:
1097 +                bytesPer = sizeof(float)*hinfo.ncomp;
1098 +                break;
1099 +        default:
1100 +                sprintf(errmsg, "unknown format (%s) for '%s'", hinfo.fmt, pfname);
1101 +                error(USER, errmsg);
1102 +                fclose(pdfp[0]);
1103 +                if (pdfp[1]) fclose(pdfp[1]);
1104 +                return RDTnone;
1105 +        }
1106 +        RESOLU  res;
1107 +        if (!fgetsresolu(&res, pdfp[0]) || res.rt != PIXSTANDARD) {
1108 +                sprintf(errmsg, "missing/bad resolution for '%s'", pfname);
1109 +                error(USER, errmsg);
1110 +                fclose(pdfp[0]);
1111 +                if (pdfp[1]) fclose(pdfp[1]);
1112 +                return RDTnone;
1113 +        }
1114          vw.type = 0;                            // set up new (unreferenced) frame
1115          frameNo = 0;
1116          int     hvdim[2] = {res.xr, res.yr};
1117          double  noAdj = 0;
1118          if (!NewFrame(hinfo.vw, hvdim, &noAdj) ||
1119                          (hvdim[0] != res.xr) | (hvdim[1] != res.yr)) {
1120 <                fclose(pfp);
1120 >                error(CONSISTENCY, "unexpected resolution change in ResumeFrame()");
1121 >                fclose(pdfp[0]);
1122 >                if (pdfp[1]) fclose(pdfp[1]);
1123                  return RDTnone;
1124          }
1125 <        long    dataStart = ftell(pfp);         // picture starting point
1125 >        long    dataStart = ftell(pdfp[0]);     // picture starting point
1126          if (dataStart < 0) {
1127                  sprintf(errmsg, "cannot seek on '%s'", pfname);
1128                  error(SYSTEM, errmsg);
1129 <                fclose(pfp);
1129 >                fclose(pdfp[0]);
1130 >                if (pdfp[1]) fclose(pdfp[1]);
1131                  return RDTnone;
1132          }
1133          long    doneScans = 0;
1134          if (bytesPer) {                         // fixed-width records?
1135 <                fseek(pfp, 0, SEEK_END);
1136 <                long    dataEnd = ftell(pfp);
1135 >                fseek(pdfp[0], 0, SEEK_END);
1136 >                long    dataEnd = ftell(pdfp[0]);
1137                  doneScans = (dataEnd - dataStart)/(bytesPer*GetWidth());
1138                  if (dataEnd-dataStart > bytesPer*GetWidth()*doneScans)
1139 <                        fseek(pfp, dataStart + bytesPer*GetWidth()*doneScans, SEEK_SET);
1139 >                        fseek(pdfp[0], dataStart + bytesPer*GetWidth()*doneScans, SEEK_SET);
1140          } else {                                // else get compressed scanlines
1141                  COLR *  scan = (COLR *)tempbuffer(sizeof(COLR)*GetWidth());
1142 <                while (freadcolrs(scan, GetWidth(), pfp) >= 0)
1142 >                while (freadcolrs(scan, GetWidth(), pdfp[0]) >= 0)
1143                          ++doneScans;
1144 <                if (!feof(pfp)) {
1144 >                if (!feof(pdfp[0])) {
1145                          sprintf(errmsg, "error reading compressed scanline from '%s'", pfname);
1146                          error(USER, errmsg);
1147 <                        fclose(pfp);
1147 >                        fclose(pdfp[0]);
1148 >                        if (pdfp[1]) fclose(pdfp[1]);
1149                          return RDTnone;
1150                  }
1151          }
1152          if (doneScans >= GetHeight()) {         // nothing left to do?
1153                  sprintf(errmsg, "output file '%s' is already complete", pfname);
1154                  error(WARNING, errmsg);
1155 <                fclose(pfp);
1155 >                fclose(pdfp[0]);
1156 >                if (pdfp[1]) fclose(pdfp[1]);
1157                  return dt;
1158          }
1159          if (!doneScans) {
1160                  sprintf(errmsg, "restarting empty frame '%s'", pfname);
1161                  error(WARNING, errmsg);
1162          }
1163 <        if (dfname) {                           // append depth file, too?
1164 <                if (dfname[0] == '!') {
1165 <                        error(USER, "depth data cannot be reloaded from command");
1166 <                        fclose(pfp);
1163 >        long    toSkip = 0;
1164 >        switch (RDTdepthT(dt)) {                // append depth file, too?
1165 >        case RDTdfloat:
1166 >                toSkip = sizeof(float)*GetWidth()*doneScans;
1167 >                break;
1168 >        case RDTdshort:
1169 >                if (!fgetsresolu(&res, pdfp[1]) || (res.rt != PIXSTANDARD) |
1170 >                                (res.xr != GetWidth()) | (res.yr != GetHeight())) {
1171 >                        sprintf(errmsg, "missing/bad resolution for '%s'", dfname);
1172 >                        error(USER, errmsg);
1173 >                        fclose(pdfp[0]); fclose(pdfp[0]);
1174                          return RDTnone;
1175                  }
1176 <                dfp = fopen(dfname, "a");
1177 <                if (!dfp) {
1178 <                        sprintf(errmsg, "cannot reopen depth file '%s'", dfname);
1179 <                        error(SYSTEM, errmsg);
1180 <                        fclose(pfp);
1181 <                        return RDTnone;
1182 <                }
1183 <                SET_FILE_BINARY(dfp);
1184 <                const long      dflen = ftell(dfp);
999 <                if (dflen != sizeof(float)*GetWidth()*doneScans) {
1000 <                        fclose(dfp);
1001 <                        dfp = fopen(dfname, "r+");
1002 <                        if (!dfp) return RDTnone;       // WTH?
1003 <                        SET_FILE_BINARY(dfp);
1004 <                }
1005 <                if (dflen < sizeof(float)*GetWidth()*doneScans) {
1006 <                        HeaderInfo      dinfo;
1007 <                        if (getheader(dfp, head_check, &dinfo) < 0)
1008 <                                sprintf(errmsg, "bad header in encoded depth file '%s'",
1009 <                                                dfname);
1010 <                        else if (strcmp(dinfo.fmt, DEPTH16FMT))
1011 <                                sprintf(errmsg, "wrong format (%s) for depth file '%s'",
1012 <                                                dinfo.fmt, dfname);
1013 <                        else if (!SetReferenceDepth(dinfo.depth_unit))
1014 <                                sprintf(errmsg, "bad/missing reference depth (%s) in '%s'",
1015 <                                                dinfo.depth_unit, dfname);
1016 <                        else if (!fscnresolu(hvdim, hvdim+1, dfp) ||
1017 <                                        (hvdim[0] != GetWidth()) | (hvdim[1] != GetHeight()))
1018 <                                sprintf(errmsg, "bad/mismatched resolution in '%s'",
1019 <                                                dfname);
1020 <                        else
1021 <                                errmsg[0] = '\0';
1022 <
1023 <                        if (errmsg[0]) {
1024 <                                error(USER, errmsg);
1025 <                                fclose(dfp);
1026 <                                fclose(pfp);
1027 <                                return RDTnone;
1028 <                        }
1029 <                        const long      dStart = ftell(dfp);
1030 <                        if (dflen-dStart < 2*GetWidth()*doneScans) {
1031 <                                sprintf(errmsg, "missing %ld depths in '%s'",
1032 <                                        (long)GetWidth()*doneScans - (dflen-dStart)/2,
1033 <                                        dfname);
1034 <                                error(WARNING, errmsg);
1035 <                        }
1036 <                        fseek(dfp, dStart + 2*GetWidth()*doneScans, SEEK_SET);
1037 <                        dt = RDTnewDT(dt, RDTdshort);
1038 <                } else {
1039 <                        if (dflen > sizeof(float)*GetWidth()*doneScans)
1040 <                                fseek(dfp, sizeof(float)*GetWidth()*doneScans, SEEK_SET);
1041 <                        dt = RDTnewDT(dt, RDTdfloat);
1042 <                }
1176 >                toSkip = 2L*GetWidth()*doneScans;
1177 >                break;
1178 >        default:;
1179 >        }                                       // fseek() needed for output
1180 >        if (pdfp[1] && fseek(pdfp[1], toSkip, SEEK_CUR) < 0) {
1181 >                sprintf(errmsg, "cannot seek on depth file '%s'", dfname);
1182 >                error(SYSTEM, errmsg);
1183 >                fclose(pdfp[0]); fclose(pdfp[1]);
1184 >                return RDTnone;
1185          }
1186 <        int     bheight = (psample > 1) ? int(2*psample+.99) : 4;
1186 >        int     bheight = (psample > 1) ? int(4*psample+.99) : 8;
1187          if (bheight > GetHeight()-doneScans)
1188                  bheight = GetHeight()-doneScans;
1189          int     vstep =  bheight >> (psample > 1);
1190          vstep += !vstep;
1191  
1192          NewBar(bheight);                        // render remainder if we can
1193 <        if (!RenderBelow(GetHeight()-doneScans, vstep, pfp, dt, dfp)) {
1194 <                fclose(pfp);
1195 <                if (dfp) fclose(dfp);
1193 >        if (!RenderBelow(GetHeight()-doneScans, vstep, pdfp[0], dt, pdfp[1])) {
1194 >                fclose(pdfp[0]);
1195 >                if (pdfp[1]) fclose(pdfp[1]);
1196                  Cleanup();
1197                  return RDTnone;
1198          }
1199          NewBar();                               // close up and return success
1200 <        fclose(pfp);
1201 <        if (dfp) fclose(dfp);
1200 >        fclose(pdfp[0]);
1201 >        if (pdfp[1]) fclose(pdfp[1]);
1202          return dt;
1203   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines