home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / inetray / irtrace.c < prev    next >
C/C++ Source or Header  |  1992-05-18  |  12KB  |  473 lines

  1. /*======================================================================
  2.                     I R T R A C E . C 
  3.                     doc: Tue Mar  3 10:50:23 1992
  4.                     dlm: Tue May 19 11:21:08 1992
  5.                     (c) 1992 ant@julia
  6.                     uE-Info: 9 39 T 0 0 72 2 2 8 ofnI
  7. ======================================================================*/
  8.  
  9. /*#define        FULL_SAMPLING*/
  10.  
  11. #include "rayshade.h"
  12. #include "libsurf/atmosphere.h"
  13. #include "libsurf/surface.h"
  14. #include "libcommon/sampling.h"
  15. #include "options.h"
  16. #include "stats.h"
  17. #include "viewing.h"
  18. #include "picture.h"
  19. #include "irtrace.h"
  20.  
  21. #define UNSAMPLED    -1
  22. #define SUPERSAMPLED    -2
  23.  
  24. static void    FullySamplePixel();        /* private routines */
  25. static void    AdaptiveRefineScanline();
  26. static void     FullySampleScanline();
  27. static void    SingleSampleScanline();
  28. static int    ExcessiveContrast();
  29. static Float    SampleTime();
  30.  
  31. static Ray    TopRay;                /* Top-level ray. */
  32. static int    *SampleNumbers;
  33. static Scanline *scan;
  34.  
  35. /*
  36.  * "Dither matrices" used to encode the 'number' of a ray that samples a
  37.  * particular portion of a pixel.  Hand-coding is ugly, but...
  38.  */
  39. static int OneSample[1] =     {0};
  40. static int TwoSamples[4] =    {0, 2,
  41.                  3, 1};
  42. static int ThreeSamples[9] =    {0, 2, 7,
  43.                  6, 5, 1,
  44.                  3, 8, 4};
  45. static int FourSamples[16] =    { 0,  8,  2, 10,
  46.                  12,  4, 14,  6,
  47.                   3, 11,  1,  9,
  48.                  15,  7, 13,  5};
  49. static int FiveSamples[25] =    { 0,  8, 23, 17,  2,
  50.                  19, 12,  4, 20, 15,
  51.                   3, 21, 16,  9,  6,
  52.                  14, 10, 24,  1, 13,
  53.                  22,  7, 18, 11,  5};
  54. static int SixSamples[36] =    { 6, 32,  3, 34, 35,  1,
  55.                   7, 11, 27, 28,  8, 30,
  56.                  24, 14, 16, 15, 23, 19,
  57.                  13, 20, 22, 21, 17, 18,
  58.                  25, 29, 10,  9, 26, 12,
  59.                  36,  5, 33,  4,  2, 31};
  60. static int SevenSamples[49] =    {22, 47, 16, 41, 10, 35,  4,
  61.                   5, 23, 48, 17, 42, 11, 29,
  62.                  30,  6, 24, 49, 18, 36, 12,
  63.                  13, 31,  7, 25, 43, 19, 37,
  64.                  38, 14, 32,  1, 26, 44, 20,
  65.                  21, 39,  8, 33,  2, 27, 45,
  66.                  46, 15, 40,  9, 34,  3, 28};
  67. static int EightSamples[64] =    { 8, 58, 59,  5,  4, 62, 63,  1,
  68.                  49, 15, 14, 52, 53, 11, 10, 56,
  69.                  41, 23, 22, 44, 45, 19, 18, 48,
  70.                  32, 34, 35, 29, 28, 38, 39, 25,
  71.                  40, 26, 27, 37, 36, 30, 31, 33,
  72.                  17, 47, 46, 20, 21, 43, 42, 24,
  73.                   9, 55, 54, 12, 13, 51, 50, 16,
  74.                  64,  2,  3, 61, 60,  6,  7, 57};
  75.  
  76. RaytraceInit(argc, argv)
  77. int argc;
  78. char **argv;
  79. {
  80.     RSInitialize(argc,argv);
  81.     switch (Sampling.sidesamples) {
  82.         case 1:
  83.             SampleNumbers = OneSample;
  84.             break;
  85.         case 2:
  86.             SampleNumbers = TwoSamples;
  87.             break;
  88.         case 3:
  89.             SampleNumbers = ThreeSamples;
  90.             break;
  91.         case 4:
  92.             SampleNumbers = FourSamples;
  93.             break;
  94.         case 5:
  95.             SampleNumbers = FiveSamples;
  96.             break;
  97.         case 6:
  98.             SampleNumbers = SixSamples;
  99.             break;
  100.         case 7:
  101.             SampleNumbers = SevenSamples;
  102.             break;
  103.         case 8:
  104.             SampleNumbers = EightSamples;
  105.             break;
  106.         default:
  107.             RLerror(RL_PANIC,
  108.                 "Sorry, %d rays/pixel not supported.\n",
  109.                     Sampling.totsamples);
  110.     }
  111.     return Screen.xsize;
  112. }
  113.  
  114. Scanline *Raytrace(bSz,lNr)
  115. int bSz,lNr;
  116. {
  117.     int x,y,i;
  118.  
  119.     /* ----------- */
  120.     /* alloc stuff */
  121.     /* ----------- */
  122.     scan = (Scanline *)Malloc((bSz+2)*sizeof(Scanline));
  123.     if (scan == NULL) {
  124.         fprintf(stderr,"Malloc() failed\n");
  125.         exit(1);
  126.     }
  127.     for (y=0; y<bSz+2; y++) {
  128.         scan[y].pix = (Pixel *)Malloc(Screen.xsize * sizeof(Pixel));
  129.             if (scan[y].pix == NULL) {
  130.                     fprintf(stderr,"Malloc() failed\n");
  131.                     exit(1);
  132.         }
  133.             scan[y].samp = (int *)Malloc(Screen.xsize * sizeof(int));
  134.             if (scan[y].samp == NULL) {
  135.                     fprintf(stderr,"Malloc() failed\n");
  136.                     exit(1);
  137.         }
  138.     }
  139.  
  140.     /* ------- */
  141.     /* Top Ray */
  142.     /* ------- */
  143.     TopRay.pos = Camera.pos;
  144.     TopRay.media = (Medium *)0;
  145.     TopRay.depth = 0;
  146.  
  147.     /* ----------- */
  148.     /* Trace Block */
  149.     /* ----------- */
  150. #ifdef FULL_SAMPLING
  151.     for (y=0; y<bSz; y++)
  152.         FullySampleScanline(y+lNr,&scan[y+1]);
  153. #else
  154.     x = Screen.xsize-1;
  155.     SingleSampleScanline(lNr+1,&scan[2]);
  156.     FullySamplePixel(0, lNr+1, &scan[2].pix[0],
  157.                    &scan[2].samp[0]);
  158.     FullySamplePixel(x, lNr+1, &scan[2].pix[x],
  159.                    &scan[2].samp[x]); 
  160.     if (lNr == 0) {                    /* first block */
  161.         FullySampleScanline(0,&scan[1]);
  162.     } else {                    /* 2nd to last */
  163.         SingleSampleScanline(lNr-1,&scan[0]);
  164.         FullySamplePixel(0, lNr-1, &scan[0].pix[0],
  165.                        &scan[0].samp[0]);
  166.         FullySamplePixel(x, lNr-1, &scan[0].pix[x],
  167.                        &scan[0].samp[x]); 
  168.         SingleSampleScanline(lNr,&scan[1]);
  169.         FullySamplePixel(0, lNr, &scan[1].pix[0],
  170.                      &scan[1].samp[0]);
  171.         FullySamplePixel(x, lNr, &scan[1].pix[x],
  172.                      &scan[1].samp[x]);
  173.         if (Sampling.sidesamples > 1)
  174.             AdaptiveRefineScanline(lNr,
  175.                 &scan[0],
  176.                 &scan[1],
  177.                 &scan[2]); 
  178.     }
  179.     
  180.     for (y=lNr+1,i=3; i<bSz; y++,i++) {        /* main part */
  181.         SingleSampleScanline(y+1,&scan[i]);
  182.         FullySamplePixel(0, y+1, &scan[i].pix[0],
  183.                      &scan[i].samp[0]);
  184.         FullySamplePixel(x, y+1, &scan[i].pix[x],
  185.                      &scan[i].samp[x]);
  186.         if (Sampling.sidesamples > 1)
  187.             AdaptiveRefineScanline(y,
  188.                 &scan[i-2],
  189.                 &scan[i-1],
  190.                 &scan[i]); 
  191.     }
  192.  
  193.     if (lNr+bSz == Screen.ysize) {            /* last block */
  194.         FullySampleScanline(lNr+bSz-1,&scan[bSz]);
  195.         if (Sampling.sidesamples > 1)
  196.             AdaptiveRefineScanline(lNr+bSz-1,
  197.                 &scan[bSz-2],
  198.                 &scan[bSz-1],
  199.                 &scan[bSz]); 
  200.     } else {                    /* 1st - 2nd to last */
  201.          y = lNr+bSz-1;
  202.         SingleSampleScanline(y,&scan[bSz]);
  203.         FullySamplePixel(0, y, &scan[bSz].pix[0],
  204.                        &scan[bSz].samp[0]);
  205.         FullySamplePixel(x, y, &scan[bSz].pix[x],
  206.                        &scan[bSz].samp[x]);
  207.         if (Sampling.sidesamples > 1)
  208.             AdaptiveRefineScanline(y-1,
  209.                 &scan[bSz-2],
  210.                 &scan[bSz-1],
  211.                 &scan[bSz]); 
  212.         y = lNr+bSz;
  213.         SingleSampleScanline(y,&scan[bSz+1]);
  214.         FullySamplePixel(0, y, &scan[bSz+1].pix[0],
  215.                        &scan[bSz+1].samp[0]);
  216.         FullySamplePixel(x, y, &scan[bSz+1].pix[x],
  217.                        &scan[bSz+1].samp[x]);
  218.         if (Sampling.sidesamples > 1)
  219.             AdaptiveRefineScanline(y-1,
  220.                 &scan[bSz-1],
  221.                 &scan[bSz],
  222.                 &scan[bSz+1]);
  223.     }
  224. #endif
  225.     return scan;
  226. }
  227.  
  228. static void
  229. SingleSampleScanline(line, data)
  230. int line;
  231. Scanline *data;
  232. {
  233.     Float upos, vpos, yp;
  234.     int x, usamp, vsamp;
  235.     Pixel tmp;
  236.  
  237.     yp = line + Screen.miny - 0.5*Sampling.filterwidth;
  238.     for (x = 0; x < Screen.xsize; x++) {
  239.         /*
  240.          * Pick a sample number...
  241.          */
  242.         data->samp[x] = nrand() * Sampling.totsamples;
  243.         /*
  244.          * Take sample corresponding to sample #.
  245.          */
  246.         usamp = data->samp[x] % Sampling.sidesamples;
  247.         vsamp = data->samp[x] / Sampling.sidesamples;
  248.  
  249.         vpos = yp + vsamp * Sampling.filterdelta;
  250.         upos = x + Screen.minx - 0.5*Sampling.filterwidth +
  251.                 usamp*Sampling.filterdelta;
  252.         if (Options.jitter) {
  253.             vpos += nrand()*Sampling.filterdelta;
  254.             upos += nrand()*Sampling.filterdelta;
  255.         }
  256.         TopRay.time = SampleTime(SampleNumbers[data->samp[x]]);
  257.         SampleScreen(upos, vpos, &TopRay,
  258.             &data->pix[x], SampleNumbers[data->samp[x]]);
  259.         if (Options.samplemap)
  260.             data->pix[x].alpha = 0;
  261.     }
  262. }
  263.  
  264. static void
  265. FullySampleScanline(line, data)
  266. int line;
  267. Scanline *data;
  268. {
  269.     int x;
  270.  
  271.     for (x = 0; x < Screen.xsize; x++) {
  272.         data->samp[x] = UNSAMPLED;
  273.         FullySamplePixel(x, line, &data->pix[x], &data->samp[x]);
  274.     }
  275. }
  276.  
  277. static void
  278. FullySamplePixel(xp, yp, pix, prevsamp)
  279. int xp, yp;
  280. Pixel *pix;
  281. int *prevsamp;
  282. {
  283.     Float upos, vpos, u, v;
  284.     int x, y, sampnum;
  285.     Pixel ctmp;
  286.  
  287.     if (*prevsamp == SUPERSAMPLED)
  288.         return;    /* already done */
  289.  
  290.     Stats.SuperSampled++;
  291.     if (*prevsamp == UNSAMPLED) {
  292.         /*
  293.          * No previous sample; initialize to black.
  294.          */
  295.         pix->r = pix->g = pix->b = pix->alpha = 0.;
  296.     } else {
  297.         if (Sampling.sidesamples == 1) {
  298.             *prevsamp = SUPERSAMPLED;
  299.             return;
  300.         }
  301.         x = *prevsamp % Sampling.sidesamples;
  302.         y = *prevsamp / Sampling.sidesamples;
  303.         pix->r *= Sampling.filter[x][y];
  304.         pix->g *= Sampling.filter[x][y];
  305.         pix->b *= Sampling.filter[x][y];
  306.         pix->alpha *= Sampling.filter[x][y];
  307.     }
  308.  
  309.     sampnum = 0;
  310.     xp += Screen.minx;
  311.     vpos = Screen.miny + yp - 0.5*Sampling.filterwidth;
  312.     for (y = 0; y < Sampling.sidesamples; y++,
  313.          vpos += Sampling.filterdelta) {
  314.         upos = xp - 0.5*Sampling.filterwidth;
  315.         for (x = 0; x < Sampling.sidesamples; x++,
  316.              upos += Sampling.filterdelta) {
  317.             if (sampnum != *prevsamp) {
  318.                 if (Options.jitter) {
  319.                     u = upos + nrand()*Sampling.filterdelta;
  320.                     v = vpos + nrand()*Sampling.filterdelta;
  321.                 } else {
  322.                     u = upos;
  323.                     v = vpos;
  324.                 }
  325.                 TopRay.time = SampleTime(SampleNumbers[sampnum]);
  326.                 SampleScreen(u, v, &TopRay, &ctmp,
  327.                     SampleNumbers[sampnum]);
  328.                 pix->r += ctmp.r*Sampling.filter[x][y];
  329.                 pix->g += ctmp.g*Sampling.filter[x][y];
  330.                 pix->b += ctmp.b*Sampling.filter[x][y];
  331.                 pix->alpha += ctmp.alpha*Sampling.filter[x][y];
  332.             }
  333.             if (++sampnum == Sampling.totsamples)
  334.                 sampnum = 0;
  335.         }
  336.     }
  337.  
  338.     if (Options.samplemap)
  339.         pix->alpha = 255;
  340.  
  341.     *prevsamp = SUPERSAMPLED;
  342. }
  343.  
  344. static void
  345. AdaptiveRefineScanline(y, scan0, scan1, scan2)
  346. int y;
  347. Scanline *scan0, *scan1, *scan2;
  348. {
  349.     int x, done;
  350.  
  351.     /*
  352.      * Walk down scan1, looking at 4-neighbors for excessive contrast.
  353.      * If found, supersample *all* neighbors not already supersampled.
  354.      * The process is repeated until either there are no
  355.      * high-contrast regions or all such regions are already supersampled.
  356.      */
  357.  
  358.     do {
  359.         done = TRUE;
  360.         for (x = 1; x < Screen.xsize -1; x++) {
  361.             /*
  362.               * Find min and max RGB for area we care about
  363.              */
  364.             if (ExcessiveContrast(x, scan0->pix, scan1->pix,
  365.                 scan2->pix)) {
  366.                 if (scan1->samp[x-1] != SUPERSAMPLED) {
  367.                     done = FALSE;
  368.                     FullySamplePixel(x-1, y,
  369.                         &scan1->pix[x-1],
  370.                         &scan1->samp[x-1]);
  371.                 }
  372.                 if (scan0->samp[x] != SUPERSAMPLED) {
  373.                     done = FALSE;
  374.                     FullySamplePixel(x, y-1,
  375.                         &scan0->pix[x],
  376.                         &scan0->samp[x]);
  377.                 }
  378.                 if (scan1->samp[x+1] != SUPERSAMPLED) {
  379.                     done = FALSE;
  380.                     FullySamplePixel(x+1, y,
  381.                         &scan1->pix[x+1],
  382.                         &scan1->samp[x+1]);
  383.                 }
  384.                 if (scan2->samp[x] != SUPERSAMPLED) {
  385.                     done = FALSE;
  386.                     FullySamplePixel(x, y+1,
  387.                         &scan2->pix[x],
  388.                         &scan2->samp[x]);
  389.                 }
  390.                 if (scan1->samp[x] != SUPERSAMPLED) {
  391.                     done = FALSE;
  392.                     FullySamplePixel(x, y,
  393.                         &scan1->pix[x],
  394.                         &scan1->samp[x]);
  395.                 }
  396.             }
  397.         }
  398.     } while (!done);
  399. }
  400.  
  401. static int
  402. ExcessiveContrast(x, pix0, pix1, pix2)
  403. int x;
  404. Pixel *pix0, *pix1, *pix2;
  405. {
  406.     Float mini, maxi, sum, diff;
  407.  
  408.     maxi = max(pix0[x].r, pix1[x-1].r);
  409.     if (pix1[x].r > maxi) maxi = pix1[x].r;
  410.     if (pix1[x+1].r > maxi) maxi = pix1[x+1].r;
  411.     if (pix2[x].r > maxi) maxi = pix2[x].r;
  412.  
  413.     mini = min(pix0[x].r, pix1[x-1].r);
  414.     if (pix1[x].r < mini) mini = pix1[x].r;
  415.     if (pix1[x+1].r < mini) mini = pix1[x+1].r;
  416.     if (pix2[x].r < mini) mini = pix2[x].r;
  417.  
  418.     diff = maxi - mini;
  419.     sum = maxi + mini;
  420.     if (sum > EPSILON && diff/sum > Options.contrast.r)
  421.         return TRUE;
  422.  
  423.     maxi = max(pix0[x].g, pix1[x-1].g);
  424.     if (pix1[x].g > maxi) maxi = pix1[x].g;
  425.     if (pix1[x+1].g > maxi) maxi = pix1[x+1].g;
  426.     if (pix2[x].g > maxi) maxi = pix2[x].g;
  427.  
  428.     mini = min(pix0[x].g, pix1[x-1].g);
  429.     if (pix1[x].g < mini) mini = pix1[x].g;
  430.     if (pix1[x+1].g < mini) mini = pix1[x+1].g;
  431.     if (pix2[x].g < mini) mini = pix2[x].g;
  432.  
  433.     diff = maxi - mini;
  434.     sum = maxi + mini;
  435.  
  436.     if (sum > EPSILON && diff/sum > Options.contrast.g)
  437.         return TRUE;
  438.  
  439.     maxi = max(pix0[x].b, pix1[x-1].b);
  440.     if (pix1[x].b > maxi) maxi = pix1[x].b;
  441.     if (pix1[x+1].b > maxi) maxi = pix1[x+1].b;
  442.     if (pix2[x].b > maxi) maxi = pix2[x].b;
  443.  
  444.     mini = min(pix0[x].b, pix1[x-1].b);
  445.     if (pix1[x].b < mini) mini = pix1[x].b;
  446.     if (pix1[x+1].b < mini) mini = pix1[x+1].b;
  447.     if (pix2[x].b < mini) mini = pix2[x].b;
  448.  
  449.     diff = maxi - mini;
  450.     sum = maxi + mini;
  451.     if (sum > EPSILON && diff/sum > Options.contrast.b)
  452.         return TRUE;
  453.  
  454.     return FALSE;
  455. }
  456.  
  457. static Float
  458. SampleTime(sampnum)
  459. int sampnum;
  460. {
  461.     Float window, jitter = 0.0, res;
  462.  
  463.     if (Options.shutterspeed <= 0.)
  464.         return Options.framestart;
  465.     if (Options.jitter)
  466.         jitter = nrand();
  467.     window = Options.shutterspeed / Sampling.totsamples;
  468.     res = Options.framestart + window * (sampnum + jitter);
  469.     TimeSet(res);
  470.     return res;
  471. }
  472.  
  473.