home *** CD-ROM | disk | FTP | other *** search
- /*======================================================================
- I R T R A C E . C
- doc: Tue Mar 3 10:50:23 1992
- dlm: Sun Jul 5 15:41:44 1992
- (c) 1992 ant@julia
- uE-Info: 154 74 T 0 0 72 2 2 8 ofnI
- ======================================================================*/
-
- /*#define FULL_SAMPLING*/
-
- #include "rayshade.h"
- #include "libsurf/atmosphere.h"
- #include "libsurf/surface.h"
- #include "libcommon/sampling.h"
- #include "options.h"
- #include "stats.h"
- #include "viewing.h"
- #include "picture.h"
- #include "irtrace.h"
-
- #define UNSAMPLED -1
- #define SUPERSAMPLED -2
-
- static void FullySamplePixel(); /* private routines */
- static void AdaptiveRefineScanline();
- static void FullySampleScanline();
- static void SingleSampleScanline();
- static int ExcessiveContrast();
- static Float SampleTime();
-
- static Ray TopRay; /* Top-level ray. */
- static int *SampleNumbers;
- static Scanline *scan;
-
- /*
- * "Dither matrices" used to encode the 'number' of a ray that samples a
- * particular portion of a pixel. Hand-coding is ugly, but...
- */
- static int OneSample[1] = {0};
- static int TwoSamples[4] = {0, 2,
- 3, 1};
- static int ThreeSamples[9] = {0, 2, 7,
- 6, 5, 1,
- 3, 8, 4};
- static int FourSamples[16] = { 0, 8, 2, 10,
- 12, 4, 14, 6,
- 3, 11, 1, 9,
- 15, 7, 13, 5};
- static int FiveSamples[25] = { 0, 8, 23, 17, 2,
- 19, 12, 4, 20, 15,
- 3, 21, 16, 9, 6,
- 14, 10, 24, 1, 13,
- 22, 7, 18, 11, 5};
- static int SixSamples[36] = { 6, 32, 3, 34, 35, 1,
- 7, 11, 27, 28, 8, 30,
- 24, 14, 16, 15, 23, 19,
- 13, 20, 22, 21, 17, 18,
- 25, 29, 10, 9, 26, 12,
- 36, 5, 33, 4, 2, 31};
- static int SevenSamples[49] = {22, 47, 16, 41, 10, 35, 4,
- 5, 23, 48, 17, 42, 11, 29,
- 30, 6, 24, 49, 18, 36, 12,
- 13, 31, 7, 25, 43, 19, 37,
- 38, 14, 32, 1, 26, 44, 20,
- 21, 39, 8, 33, 2, 27, 45,
- 46, 15, 40, 9, 34, 3, 28};
- static int EightSamples[64] = { 8, 58, 59, 5, 4, 62, 63, 1,
- 49, 15, 14, 52, 53, 11, 10, 56,
- 41, 23, 22, 44, 45, 19, 18, 48,
- 32, 34, 35, 29, 28, 38, 39, 25,
- 40, 26, 27, 37, 36, 30, 31, 33,
- 17, 47, 46, 20, 21, 43, 42, 24,
- 9, 55, 54, 12, 13, 51, 50, 16,
- 64, 2, 3, 61, 60, 6, 7, 57};
-
- RaytraceInit(argc, argv)
- int argc;
- char **argv;
- {
- RSInitialize(argc,argv);
- switch (Sampling.sidesamples) {
- case 1:
- SampleNumbers = OneSample;
- break;
- case 2:
- SampleNumbers = TwoSamples;
- break;
- case 3:
- SampleNumbers = ThreeSamples;
- break;
- case 4:
- SampleNumbers = FourSamples;
- break;
- case 5:
- SampleNumbers = FiveSamples;
- break;
- case 6:
- SampleNumbers = SixSamples;
- break;
- case 7:
- SampleNumbers = SevenSamples;
- break;
- case 8:
- SampleNumbers = EightSamples;
- break;
- default:
- RLerror(RL_PANIC,
- "Sorry, %d rays/pixel not supported.\n",
- Sampling.totsamples);
- }
- return Screen.xsize;
- }
-
- Scanline *Raytrace(bSz,lNr)
- int bSz,lNr;
- {
- int x,y,i;
-
- /* ----------- */
- /* alloc stuff */
- /* ----------- */
- scan = (Scanline *)Malloc((bSz+2)*sizeof(Scanline));
- if (scan == NULL) {
- fprintf(stderr,"Malloc() failed\n");
- exit(1);
- }
- for (y=0; y<bSz+2; y++) {
- scan[y].pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
- if (scan[y].pix == NULL) {
- fprintf(stderr,"Malloc() failed\n");
- exit(1);
- }
- scan[y].samp = (int *)Malloc(Screen.xsize * sizeof(int));
- if (scan[y].samp == NULL) {
- fprintf(stderr,"Malloc() failed\n");
- exit(1);
- }
- }
-
- /* ------- */
- /* Top Ray */
- /* ------- */
- TopRay.pos = Camera.pos;
- TopRay.media = (Medium *)0;
- TopRay.depth = 0;
-
- /* ----------- */
- /* Trace Block */
- /* ----------- */
- #ifdef FULL_SAMPLING
- for (y=0; y<bSz; y++)
- FullySampleScanline(y+lNr,&scan[y+1]);
- #else
- if (bSz == 1) { /* special case */
- FullySampleScanline(lNr,&scan[1]);
- return scan;
- }
- x = Screen.xsize-1;
- SingleSampleScanline(lNr+1,&scan[2]);
- FullySamplePixel(0, lNr+1, &scan[2].pix[0],
- &scan[2].samp[0]);
- FullySamplePixel(x, lNr+1, &scan[2].pix[x],
- &scan[2].samp[x]);
- if (lNr == 0) { /* first block */
- FullySampleScanline(0,&scan[1]);
- } else { /* 2nd to last */
- SingleSampleScanline(lNr-1,&scan[0]);
- FullySamplePixel(0, lNr-1, &scan[0].pix[0],
- &scan[0].samp[0]);
- FullySamplePixel(x, lNr-1, &scan[0].pix[x],
- &scan[0].samp[x]);
- SingleSampleScanline(lNr,&scan[1]);
- FullySamplePixel(0, lNr, &scan[1].pix[0],
- &scan[1].samp[0]);
- FullySamplePixel(x, lNr, &scan[1].pix[x],
- &scan[1].samp[x]);
- if (Sampling.sidesamples > 1)
- AdaptiveRefineScanline(lNr,
- &scan[0],
- &scan[1],
- &scan[2]);
- }
-
- for (y=lNr+1,i=3; i<bSz; y++,i++) { /* main part */
- SingleSampleScanline(y+1,&scan[i]);
- FullySamplePixel(0, y+1, &scan[i].pix[0],
- &scan[i].samp[0]);
- FullySamplePixel(x, y+1, &scan[i].pix[x],
- &scan[i].samp[x]);
- if (Sampling.sidesamples > 1)
- AdaptiveRefineScanline(y,
- &scan[i-2],
- &scan[i-1],
- &scan[i]);
- }
-
- if (lNr+bSz == Screen.ysize) { /* last block */
- FullySampleScanline(lNr+bSz-1,&scan[bSz]);
- if (Sampling.sidesamples > 1)
- AdaptiveRefineScanline(lNr+bSz-1,
- &scan[bSz-2],
- &scan[bSz-1],
- &scan[bSz]);
- } else { /* 1st - 2nd to last */
- y = lNr+bSz-1;
- SingleSampleScanline(y,&scan[bSz]);
- FullySamplePixel(0, y, &scan[bSz].pix[0],
- &scan[bSz].samp[0]);
- FullySamplePixel(x, y, &scan[bSz].pix[x],
- &scan[bSz].samp[x]);
- if (Sampling.sidesamples > 1)
- AdaptiveRefineScanline(y-1,
- &scan[bSz-2],
- &scan[bSz-1],
- &scan[bSz]);
- y = lNr+bSz;
- SingleSampleScanline(y,&scan[bSz+1]);
- FullySamplePixel(0, y, &scan[bSz+1].pix[0],
- &scan[bSz+1].samp[0]);
- FullySamplePixel(x, y, &scan[bSz+1].pix[x],
- &scan[bSz+1].samp[x]);
- if (Sampling.sidesamples > 1)
- AdaptiveRefineScanline(y-1,
- &scan[bSz-1],
- &scan[bSz],
- &scan[bSz+1]);
- }
- #endif
- return scan;
- }
-
- static void
- SingleSampleScanline(line, data)
- int line;
- Scanline *data;
- {
- Float upos, vpos, yp;
- int x, usamp, vsamp;
- Pixel tmp;
-
- yp = line + Screen.miny - 0.5*Sampling.filterwidth;
- for (x = 0; x < Screen.xsize; x++) {
- /*
- * Pick a sample number...
- */
- data->samp[x] = nrand() * Sampling.totsamples;
- /*
- * Take sample corresponding to sample #.
- */
- usamp = data->samp[x] % Sampling.sidesamples;
- vsamp = data->samp[x] / Sampling.sidesamples;
-
- vpos = yp + vsamp * Sampling.filterdelta;
- upos = x + Screen.minx - 0.5*Sampling.filterwidth +
- usamp*Sampling.filterdelta;
- if (Options.jitter) {
- vpos += nrand()*Sampling.filterdelta;
- upos += nrand()*Sampling.filterdelta;
- }
- TopRay.time = SampleTime(SampleNumbers[data->samp[x]]);
- SampleScreen(upos, vpos, &TopRay,
- &data->pix[x], SampleNumbers[data->samp[x]]);
- if (Options.samplemap)
- data->pix[x].alpha = 0;
- }
- }
-
- static void
- FullySampleScanline(line, data)
- int line;
- Scanline *data;
- {
- int x;
-
- for (x = 0; x < Screen.xsize; x++) {
- data->samp[x] = UNSAMPLED;
- FullySamplePixel(x, line, &data->pix[x], &data->samp[x]);
- }
- }
-
- static void
- FullySamplePixel(xp, yp, pix, prevsamp)
- int xp, yp;
- Pixel *pix;
- int *prevsamp;
- {
- Float upos, vpos, u, v;
- int x, y, sampnum;
- Pixel ctmp;
-
- if (*prevsamp == SUPERSAMPLED)
- return; /* already done */
-
- Stats.SuperSampled++;
- if (*prevsamp == UNSAMPLED) {
- /*
- * No previous sample; initialize to black.
- */
- pix->r = pix->g = pix->b = pix->alpha = 0.;
- } else {
- if (Sampling.sidesamples == 1) {
- *prevsamp = SUPERSAMPLED;
- return;
- }
- x = *prevsamp % Sampling.sidesamples;
- y = *prevsamp / Sampling.sidesamples;
- pix->r *= Sampling.filter[x][y];
- pix->g *= Sampling.filter[x][y];
- pix->b *= Sampling.filter[x][y];
- pix->alpha *= Sampling.filter[x][y];
- }
-
- sampnum = 0;
- xp += Screen.minx;
- vpos = Screen.miny + yp - 0.5*Sampling.filterwidth;
- for (y = 0; y < Sampling.sidesamples; y++,
- vpos += Sampling.filterdelta) {
- upos = xp - 0.5*Sampling.filterwidth;
- for (x = 0; x < Sampling.sidesamples; x++,
- upos += Sampling.filterdelta) {
- if (sampnum != *prevsamp) {
- if (Options.jitter) {
- u = upos + nrand()*Sampling.filterdelta;
- v = vpos + nrand()*Sampling.filterdelta;
- } else {
- u = upos;
- v = vpos;
- }
- TopRay.time = SampleTime(SampleNumbers[sampnum]);
- SampleScreen(u, v, &TopRay, &ctmp,
- SampleNumbers[sampnum]);
- pix->r += ctmp.r*Sampling.filter[x][y];
- pix->g += ctmp.g*Sampling.filter[x][y];
- pix->b += ctmp.b*Sampling.filter[x][y];
- pix->alpha += ctmp.alpha*Sampling.filter[x][y];
- }
- if (++sampnum == Sampling.totsamples)
- sampnum = 0;
- }
- }
-
- if (Options.samplemap)
- pix->alpha = 255;
-
- *prevsamp = SUPERSAMPLED;
- }
-
- static void
- AdaptiveRefineScanline(y, scan0, scan1, scan2)
- int y;
- Scanline *scan0, *scan1, *scan2;
- {
- int x, done;
-
- /*
- * Walk down scan1, looking at 4-neighbors for excessive contrast.
- * If found, supersample *all* neighbors not already supersampled.
- * The process is repeated until either there are no
- * high-contrast regions or all such regions are already supersampled.
- */
-
- do {
- done = TRUE;
- for (x = 1; x < Screen.xsize -1; x++) {
- /*
- * Find min and max RGB for area we care about
- */
- if (ExcessiveContrast(x, scan0->pix, scan1->pix,
- scan2->pix)) {
- if (scan1->samp[x-1] != SUPERSAMPLED) {
- done = FALSE;
- FullySamplePixel(x-1, y,
- &scan1->pix[x-1],
- &scan1->samp[x-1]);
- }
- if (scan0->samp[x] != SUPERSAMPLED) {
- done = FALSE;
- FullySamplePixel(x, y-1,
- &scan0->pix[x],
- &scan0->samp[x]);
- }
- if (scan1->samp[x+1] != SUPERSAMPLED) {
- done = FALSE;
- FullySamplePixel(x+1, y,
- &scan1->pix[x+1],
- &scan1->samp[x+1]);
- }
- if (scan2->samp[x] != SUPERSAMPLED) {
- done = FALSE;
- FullySamplePixel(x, y+1,
- &scan2->pix[x],
- &scan2->samp[x]);
- }
- if (scan1->samp[x] != SUPERSAMPLED) {
- done = FALSE;
- FullySamplePixel(x, y,
- &scan1->pix[x],
- &scan1->samp[x]);
- }
- }
- }
- } while (!done);
- }
-
- static int
- ExcessiveContrast(x, pix0, pix1, pix2)
- int x;
- Pixel *pix0, *pix1, *pix2;
- {
- Float mini, maxi, sum, diff;
-
- maxi = max(pix0[x].r, pix1[x-1].r);
- if (pix1[x].r > maxi) maxi = pix1[x].r;
- if (pix1[x+1].r > maxi) maxi = pix1[x+1].r;
- if (pix2[x].r > maxi) maxi = pix2[x].r;
-
- mini = min(pix0[x].r, pix1[x-1].r);
- if (pix1[x].r < mini) mini = pix1[x].r;
- if (pix1[x+1].r < mini) mini = pix1[x+1].r;
- if (pix2[x].r < mini) mini = pix2[x].r;
-
- diff = maxi - mini;
- sum = maxi + mini;
- if (sum > EPSILON && diff/sum > Options.contrast.r)
- return TRUE;
-
- maxi = max(pix0[x].g, pix1[x-1].g);
- if (pix1[x].g > maxi) maxi = pix1[x].g;
- if (pix1[x+1].g > maxi) maxi = pix1[x+1].g;
- if (pix2[x].g > maxi) maxi = pix2[x].g;
-
- mini = min(pix0[x].g, pix1[x-1].g);
- if (pix1[x].g < mini) mini = pix1[x].g;
- if (pix1[x+1].g < mini) mini = pix1[x+1].g;
- if (pix2[x].g < mini) mini = pix2[x].g;
-
- diff = maxi - mini;
- sum = maxi + mini;
-
- if (sum > EPSILON && diff/sum > Options.contrast.g)
- return TRUE;
-
- maxi = max(pix0[x].b, pix1[x-1].b);
- if (pix1[x].b > maxi) maxi = pix1[x].b;
- if (pix1[x+1].b > maxi) maxi = pix1[x+1].b;
- if (pix2[x].b > maxi) maxi = pix2[x].b;
-
- mini = min(pix0[x].b, pix1[x-1].b);
- if (pix1[x].b < mini) mini = pix1[x].b;
- if (pix1[x+1].b < mini) mini = pix1[x+1].b;
- if (pix2[x].b < mini) mini = pix2[x].b;
-
- diff = maxi - mini;
- sum = maxi + mini;
- if (sum > EPSILON && diff/sum > Options.contrast.b)
- return TRUE;
-
- return FALSE;
- }
-
- static Float
- SampleTime(sampnum)
- int sampnum;
- {
- Float window, jitter = 0.0, res;
-
- if (Options.shutterspeed <= 0.)
- return Options.framestart;
- if (Options.jitter)
- jitter = nrand();
- window = Options.shutterspeed / Sampling.totsamples;
- res = Options.framestart + window * (sampnum + jitter);
- TimeSet(res);
- return res;
- }
-
-