| 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" | 
| 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 | 
  | 
        } | 
| 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]); // i==j for diamond fill | 
| 281 | 
  | 
        const int       slen =  (i > j) ? i : j; | 
| 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^(y&1))*(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; | 
| 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()"); | 
| 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) { | 
| 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 (x = 4; x--; ) { | 
| 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++) | 
| 412 | 
  | 
                        if (!ComputePixel(x, y)) | 
| 413 | 
  | 
                                return false; | 
| 414 | 
  | 
                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())); | 
| 415 | 
  | 
                sp2 -= layer++ & 1;     // next denser sampling | 
| 416 | 
  | 
        } | 
| 417 | 
  | 
        if (FlushQueue() < 0)           // make sure we got everyone | 
| 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 | 
| 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 | 
| 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 | 
| 513 | 
  | 
        else if (prims) | 
| 514 | 
  | 
                pacc.SetColorSpace(RDTrgb, prims); | 
| 515 | 
  | 
 | 
| 516 | 
< | 
        return SetTile(tile) && RenderRect(); | 
| 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 | 
| 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 | 
| 573 | 
> | 
        if (ytop < THeight())                   // mark what we won't do as finished | 
| 574 | 
  | 
                doneMap.ClearRect(0, 0, TWidth(), THeight()-ytop, true); | 
| 542 | 
– | 
                memset(barPix, 0, sizeof(COLORV)*NC*TWidth()*(THeight()-ytop)); | 
| 543 | 
– | 
                memset(barDepth, 0, sizeof(float)*TWidth()*(THeight()-ytop)); | 
| 544 | 
– | 
        } | 
| 575 | 
  | 
        return true; | 
| 576 | 
  | 
} | 
| 577 | 
  | 
 | 
| 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; | 
| 613 | 
  | 
        } | 
| 614 | 
  | 
        int             lastOut = ytop;         // render down frame | 
| 615 | 
  | 
        while (ytop > 0) { | 
| 586 | 
– | 
// fprintf(stderr, "At y=%d, source drawing %s...\n", ytop, parr ? "ON" : "OFF"); | 
| 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) | 
| 681 | 
  | 
{ | 
| 682 | 
  | 
        pdfp[0] = pdfp[1] = NULL; | 
| 683 | 
  | 
        if (!RDTcolorT(dt)) | 
| 684 | 
< | 
                error(INTERNAL, "botched color output type in NewOutput()"); | 
| 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); | 
| 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 | 
  | 
                pdfp[0] = stdout; | 
| 758 | 
  | 
                fputendian(pdfp[0]); | 
| 759 | 
  | 
                fputformat("float", pdfp[0]); | 
| 760 | 
  | 
                break; | 
| 761 | 
< | 
        default:; | 
| 761 | 
> | 
        default:;       // pro forma - caught this above | 
| 762 | 
  | 
        } | 
| 763 | 
< | 
        fputc('\n', pdfp[0]);                   // flush picture header + resolution | 
| 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); | 
| 820 | 
  | 
        if (RDTdepthT(dt) == RDTdshort) | 
| 821 | 
  | 
                fprtresolu(GetWidth(), GetHeight(), pdfp[1]); | 
| 822 | 
  | 
 | 
| 823 | 
< | 
        const int       bheight = (psample > 1) ? int(2*psample+.99) : 4; | 
| 824 | 
< | 
        const int       vstep =  bheight >> (psample > 1); | 
| 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, pdfp[0], dt, pdfp[1])) { | 
| 1034 | 
  | 
        SET_FILE_BINARY(pdfp[1]); | 
| 1035 | 
  | 
        int     n, len = strlen(HDRSTR); | 
| 1036 | 
  | 
        char    buf[32];                // sniff for 16-bit header | 
| 1037 | 
< | 
        if (read(fileno(pdfp[1]), buf, len+1) < len+1) { | 
| 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]); | 
| 1044 | 
  | 
        for (n = 0; n < len; n++) | 
| 1045 | 
  | 
                if (buf[n] != HDRSTR[n]) | 
| 1046 | 
  | 
                        break;          // not a Radiance header | 
| 1047 | 
< | 
        lseek(fileno(pdfp[1]), 0, SEEK_SET); | 
| 1047 | 
> | 
        rewind(pdfp[1]); | 
| 1048 | 
  | 
        if ((n < len) | !isprint(buf[len])) | 
| 1049 | 
  | 
                return RDTnewDT(dt, RDTdfloat); | 
| 1050 | 
  | 
 | 
| 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); |