home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / GRAPHICS / rayshade.lzh / raytrace.c < prev    next >
C/C++ Source or Header  |  1990-05-08  |  20KB  |  757 lines

  1. /*
  2.  * raytrace.c
  3.  *
  4.  * Copyright (C) 1989, Craig E. Kolb
  5.  *
  6.  * This software may be freely copied, modified, and redistributed,
  7.  * provided that this copyright notice is preserved on all copies.
  8.  *
  9.  * There is no warranty or other guarantee of fitness for this software,
  10.  * it is provided solely .  Bug reports or fixes may be sent
  11.  * to the author, who may or may not act on them as he desires.
  12.  *
  13.  * You may not include this software in a program or other software product
  14.  * without supplying the source, or without informing the end-user that the
  15.  * source is available for no extra charge.
  16.  *
  17.  * If you modify this software, you should include a notice giving the
  18.  * name of the person performing the modification, the date of modification,
  19.  * and the reason for such modification.
  20.  *
  21.  * $Id: raytrace.c,v 3.0.1.6 90/02/12 13:29:09 craig Exp $
  22.  *
  23.  * $Log:    raytrace.c,v $
  24.  * Revision 3.0.1.6  90/02/12  13:29:09  craig
  25.  * patch4: Changes to reflect new variable names in linda code.
  26.  * 
  27.  * Revision 3.0.1.5  89/12/07  22:55:25  craig
  28.  * patch2: Renamed utime and stime to avoid name clashes.
  29.  * 
  30.  * Revision 3.0.1.4  89/12/02  16:41:46  craig
  31.  * patch2: Added ReportFreq, reporting of total CPU & split times.
  32.  * 
  33.  * Revision 3.0.1.3  89/12/02  14:42:37  craig
  34.  * patch2: Added call to focus_blur_ray() to support depth of field.
  35.  * 
  36.  * Revision 3.0.1.2  89/11/16  20:35:30  craig
  37.  * patch1: ShadeRay is now called on background rays.
  38.  * 
  39.  * Revision 3.0.1.1  89/11/16  18:27:38  craig
  40.  * patch1: Workers now report statistics to supervisor.
  41.  * patch1: Linda syntax is more up-to-date.
  42.  * 
  43.  * Revision 3.0  89/10/27  02:06:02  craig
  44.  * Baseline for first official release.
  45.  * 
  46.  */
  47.  
  48. /*
  49.  * This module could use some work.  In particular, a better antialiasing
  50.  * scheme would be nice.
  51.  */
  52.  
  53. #ifdef LINDA
  54. /*
  55.  * If you're using linda, be sure to *move* this file to "raytrace.cl"
  56.  * before compiling.
  57.  */
  58. #include "linda.h"
  59. #endif
  60. #include <math.h>
  61. #include <stdio.h>
  62. #include "typedefs.h"
  63. #include "constants.h"
  64. #include "funcdefs.h"
  65. #include "raytrace.h"
  66.  
  67. Color    *pixel_buf[2], background;    /* Point buffer, background color */
  68. Color    *out_buf;            /* Output pixel buffer */
  69. int    pixel_div = UNSET;        /* max times to subdivide pixel */
  70. int    JitSamples = UNSET;        /* sqrt of # jittered samples/pixel */
  71. double    JitterWeight;            /* 1. / (Total Samples Taken) */
  72. int    Jittered;            /* Use distributed raytracing */
  73. int    *SampleNumbers;
  74. int    SampleNumber;
  75. int    StartLine = UNSET;
  76. int    ReportFreq;            /* Frequency of status report */
  77. double    RedContrast = UNSET, GreenContrast = UNSET, BlueContrast = UNSET;
  78. double    SampleSpacing;
  79.  
  80. #ifdef LINDA
  81. extern    int Workers;
  82. int adapt_worker(), dist_worker();
  83. #endif
  84.  
  85. extern    int Xres, Yres;
  86. extern    Vector eyep, firstray;
  87. Ray    TopRay;                /* Top-level ray. */
  88.  
  89. #ifdef LINDA
  90.  
  91. real_main(argc, argv)
  92. int argc;
  93. char **argv;
  94. {
  95.     /*
  96.      * Linda wants all routines, including lmain(), to be in a single
  97.      * file.  So, we have to perform this bit of silliness.
  98.      */
  99.     return rayshade_main(argc, argv);
  100. }
  101.  
  102. #endif
  103.  
  104. raytrace()
  105. {
  106. #ifdef LINDA
  107.     extern unsigned long primtests[], primhits[];
  108.     extern double Utime, Stime;
  109.     extern unsigned long EyeRays, ShadowRays, ReflectRays, RefractRays,
  110.             CacheWorked, CacheFailed, ShadowHits, SuperSampled,
  111.             BVTests, HitRays;
  112.     unsigned long eyerays, shadowrays, reflectrays, refractrays,
  113.             cacheworked, cachefailed, shadowhits, supersampled,
  114.             bvtests, hitrays;
  115.     unsigned long primtmp[PRIMTYPES], hittmp[PRIMTYPES];
  116.     double utmp, stmp;
  117.     int i, j;
  118.     extern FILE *fstats;
  119. #endif
  120.     /*
  121.      * The top-level ray TopRay always has as its origin the
  122.      * eye position and as its medium NULL, indicating that it
  123.      * is passing through a medium with index of refraction
  124.      * equal to DefIndex.
  125.      */
  126.     TopRay.pos = eyep;
  127.     TopRay.media = (SurfaceList *)0;
  128.     TopRay.shadow = FALSE;
  129.  
  130.     out_buf = (Color *)Malloc(Xres * sizeof(Color));
  131.  
  132.     if (Jittered)
  133.         distributed_trace();
  134.     else
  135.         adaptive_trace();
  136. #ifdef LINDA
  137.     /*
  138.      * In statistics & workers.
  139.      */
  140.     for (i = 0; i < Workers; i++) {
  141.         in ("statistics", ? eyerays, ? shadowrays, ? reflectrays,
  142.             ? refractrays, ? cacheworked, ? cachefailed,
  143.             ? shadowhits, ? supersampled, ? bvtests, ? hitrays);
  144.         EyeRays += eyerays;
  145.         ShadowRays += shadowrays;
  146.         ReflectRays += reflectrays;
  147.         RefractRays += refractrays;
  148.         CacheWorked += cacheworked;
  149.         ShadowHits += shadowhits;
  150.         SuperSampled += supersampled;
  151.         BVTests += bvtests;
  152.         HitRays += hitrays;
  153.         in ("counts", ? primtmp, ? hittmp);
  154.         for (j = 0; j < PRIMTYPES; j++) {
  155.             primtests[j] += primtmp[j];
  156.             primhits[j] += hittmp[j];
  157.         }
  158.         in ("timing", ? utmp, ? stmp);
  159.         Utime += utmp / (double)Workers;
  160.         Stime += stmp / (double)Workers;
  161.         in("worker", ? int);
  162.     }
  163. #endif
  164. }
  165.  
  166. /*
  167.  * Raytrace an image using "distributed" raytracing.
  168.  */
  169. distributed_trace()
  170. {
  171.     register int y;
  172.     extern FILE *fstats;
  173.     extern unsigned long EyeRays;
  174. #ifdef LINDA
  175.     extern int VerboseWorker;
  176. #else
  177.     double usertime, systime, lasttime;
  178.     extern int Verbose;
  179. #endif
  180.  
  181.     switch (JitSamples) {
  182.         case 1:
  183.             SampleNumbers = OneSample;
  184.             break;
  185.         case 2:
  186.             SampleNumbers = TwoSamples;
  187.             break;
  188.         case 3:
  189.             SampleNumbers = ThreeSamples;
  190.             break;
  191.         case 4:
  192.             SampleNumbers = FourSamples;
  193.             break;
  194.         case 5:
  195.             SampleNumbers = FiveSamples;
  196.             break;
  197.         default:
  198.             fprintf(stderr,"Sorry, %d rays/pixel not supported.\n",
  199.                 JitSamples*JitSamples);
  200.             exit(2);
  201.     }
  202.  
  203.     JitterWeight= 1. / (JitSamples * JitSamples);
  204.     SampleSpacing = 1. / JitSamples;
  205.  
  206. #ifdef LINDA
  207.     /*
  208.      * Linda strategy:
  209.      * There is one tuple, named "scaninfo", which holds the number of
  210.      * the next line to be worked on.  A worker ins the scaninfo tuple,
  211.      * notes its value, and increments it before outing it again.
  212.      * The supervisor ins finished scanlines in order and writes them to
  213.      * the output file.
  214.      */
  215.     fprintf(fstats,"Using %d workers.\n",Workers);
  216.     fflush(fstats);
  217.     out("scaninfo", StartLine);
  218.     for (y = 0; y < Workers; y++)
  219.         eval("worker", dist_worker());
  220.     for (y = StartLine; y >= 0 ; y--) {
  221.         in("result", y, ? out_buf:);
  222.         if (VerboseWorker)
  223.             fprintf(stderr,"Supervisor: inned %d\n",y);
  224.         if (y % ReportFreq == 0)
  225.             fprintf(fstats, "Finished line %d.\n",y);
  226.         fflush(fstats);
  227.         outline(out_buf);
  228.     }
  229. #else
  230.     /*
  231.      * Trace each scanline, writing results to output file.
  232.      */
  233.     lasttime = 0;
  234.     for (y = StartLine; y >= 0; y--) {
  235.         trace_jit_line(y, out_buf);
  236.         outline(out_buf);
  237.         if (y % ReportFreq == 0) {
  238.             fprintf(fstats,"Finished line %d (%ld rays",y,
  239.                             EyeRays);
  240.             if (Verbose) {
  241.                 /*
  242.                  * Report total CPU and split times.
  243.                  */
  244.                 get_cpu_time(&usertime, &systime);
  245.                 fprintf(fstats,", %2.2lf sec,",
  246.                         usertime+systime);
  247.                 fprintf(fstats," %2.2lf split",
  248.                         usertime+systime-lasttime);
  249.                 lasttime = usertime+systime;
  250.             }
  251.             fprintf(fstats,")\n");
  252.             fflush(fstats);
  253.         }
  254.     }
  255. #endif
  256. }
  257.  
  258. trace_jit_line(line, buf)
  259. int line;
  260. Color *buf;
  261. {
  262.     register int x;
  263.     for (x = 0; x < Xres; x++)
  264.         trace_jit_pixel(x, line, buf++);
  265. }
  266.  
  267. trace_jit_pixel(xp, yp, color)
  268. int xp, yp;
  269. Color *color;
  270. {
  271.     Color tmp;
  272.     double x, y, xpos, ypos;
  273.     int i, j, index;
  274.  
  275.     ypos = (double)yp - 0.5;
  276.     color->r = color->g = color->b = 0.;
  277.     index = 0;
  278.     for (i = 0; i < JitSamples; i++, ypos += SampleSpacing) {
  279.         xpos = (double)xp - 0.5;
  280.         for (j = 0; j < JitSamples; j++, xpos += SampleSpacing) {
  281.             x = xpos + nrand() * SampleSpacing;
  282.             y = ypos + nrand() * SampleSpacing;
  283.             SampleNumber = SampleNumbers[index++];
  284.             trace_point(x, y, &tmp);
  285.             color->r += tmp.r;
  286.             color->g += tmp.g;
  287.             color->b += tmp.b;
  288.         }
  289.     }
  290.     ScaleColor(JitterWeight, *color, color);
  291. }
  292.  
  293. /*
  294.  * Raytrace an image using adaptive supersampling to perform antialising.
  295.  */
  296. adaptive_trace()
  297. {
  298.     register int line;
  299.     extern unsigned long EyeRays;
  300.     extern FILE *fstats;
  301. #ifdef LINDA
  302.     extern int VerboseWorker;
  303. #else
  304.     double usertime, systime, lasttime;
  305.     extern int Verbose;
  306. #endif
  307.  
  308.     /*
  309.      * In the adaptive supersampling case, Jitter, JitterWeight,
  310.      * and SampleSpacing refer are used in sampling extended
  311.      * light sources.  JitterWeight has a -4 in the denominator
  312.      * due to the fact that we don't sample the corners of extended
  313.      * sources when performing adaptive supersampling.
  314.      */
  315.     JitterWeight = 1. / (JitSamples * JitSamples - 4);
  316.     SampleSpacing = 1. / JitSamples;
  317.  
  318.     pixel_buf[0] = (Color *)Malloc(sizeof(Color) *
  319.                 (unsigned)(Xres + 1));
  320.     pixel_buf[1] = (Color *)Malloc(sizeof(Color) *
  321.                 (unsigned)(Xres + 1));
  322.     /*
  323.      * Minimum pixel square size.
  324.      */
  325.     Minsquare = 1./pow(2.,(double)pixel_div);
  326.     /*
  327.      * At any time, there can be a maximum of 3 * pixel_div + 1
  328.      * pixel squares on the stack.
  329.      */
  330.     SquareStack = (pixel_square *)Malloc((unsigned)(3 * pixel_div + 1) *
  331.                 sizeof(pixel_square));
  332.     /*
  333.      * A pixel is treated as a square through whose corners rays
  334.      * are traced.  If the color values at the corners are
  335.      * "too different" (as measured by pixel_ok()), the square is
  336.      * divided into four squares (tracing 5 additional rays)
  337.      * and the process is repeated on the four new squares.
  338.      * The color assigned to a square is the average of the 4 corners.
  339.      * Note that this means that adjacent super-sampled pixels
  340.      * cause the same ray to be traced more than once.
  341.      * This scheme is adequate but far from wonderful.
  342.      */
  343. #ifdef LINDA
  344.     /*
  345.      * This is a bit more complicated than 'jittered' sampling,
  346.      * as workers must know about other scanlines.
  347.      *
  348.      * The basic idea is to have a "scanline" tuple which
  349.      * holds the last pixline handed out and the last scanline
  350.      * completed.  This should be improved by keeping a tuple
  351.      * containing the last completed scanline/pixline, and not
  352.      * just the last ones assigned.  (The problem being that a
  353.      * worker can try to in a pixline while another worker
  354.      * is still working on it.)
  355.      */
  356.     fprintf(fstats,"Using %d workers.\n",Workers);
  357.     fflush(fstats);
  358.     out("scaninfo", StartLine+1, StartLine+2);
  359.     for (line = 0; line < Workers; line++)
  360.         eval("worker", adapt_worker());
  361.  
  362.     /*
  363.      * in() the scanlines in order, writing to output file as we go.
  364.      * This loop can easily be modified to make the supervisor
  365.      * do some work, too.
  366.      */
  367.     for (line = StartLine; line >= 0;) {
  368.         if (!adapt_job(TRUE))
  369.             sleep(5);
  370.         while (inp("result", line, ? out_buf:)) {
  371.             if (VerboseWorker)
  372.                 fprintf(stderr,"Supervisor: inned %d\n",line);
  373.             if (line % ReportFreq == 0) {
  374.                 fprintf(fstats, "Finished line %d.\n",line);
  375.                 fflush(fstats);
  376.             }
  377.             outline(out_buf);
  378.             if (--line < 0)
  379.                 break;
  380.         }
  381.     }
  382. #else
  383.     line = StartLine + 1;
  384.     trace_line(line, &pixel_buf[line & 01][0]);
  385.     lasttime = 0;
  386.     /*
  387.      * Work bottom-to-top, as that's the way Utah-raster wants to
  388.      * operate.
  389.      */
  390.     for(line--;line >= 0;line--) {
  391.         trace_line(line, &pixel_buf[line & 01][0]);
  392.         subdivide_line(line, pixel_buf[line & 01],
  393.                      pixel_buf[(line+1) & 01],
  394.                      out_buf);
  395.         outline(out_buf);
  396.         if(line % ReportFreq == 0) {
  397.             fprintf(fstats,"Finished line %d (%ld rays",line,
  398.                                 EyeRays);
  399.             if (Verbose) {
  400.                 /*
  401.                  * Report total CPU and split times.
  402.                  */
  403.                 get_cpu_time(&usertime, &systime);
  404.                 fprintf(fstats,", %2.2lf sec,",
  405.                         usertime+systime);
  406.                 fprintf(fstats," %2.2lf split",
  407.                         usertime+systime-lasttime);
  408.                 lasttime = usertime+systime;
  409.             }
  410.             fprintf(fstats,")\n");
  411.             fflush(fstats);
  412.         }
  413.     }
  414. #endif
  415. }
  416.  
  417. /*
  418.  * Trace a line of sample points along "line".
  419.  */
  420. trace_line(line, buf)
  421. int line;
  422. Color *buf;
  423. {
  424.     register int x;
  425.     /*
  426.      * We need to trace Xres + 1 rays.
  427.      */
  428.     for(x = 0; x <= Xres;x++)
  429.         trace_point((double)x, (double)line, buf + x);
  430. }
  431.  
  432. /*
  433.  * Given the two arrays of sample points which define the upper and
  434.  * lower edges of all the pixel squares in line "y," push each
  435.  * square in turn on the pixelsquare stack and determine a color value
  436.  * for the pixel by calling subdivide_square().
  437.  */
  438. subdivide_line(y, upper, lower, buf)
  439. int y;
  440. Color *upper, *lower, *buf;
  441. {
  442.     register int x;
  443.  
  444.     /*
  445.      * Upper is the array of
  446.      * sample values which define the "upper" part (corners) of this
  447.      * row, while lower are the "lower" corners.  For the
  448.      * next (lower) row, the current "upper" becomes "lower".
  449.      */
  450.     for(x = 0; x < Xres;x++) {
  451.         SquareStack[0].x = (float)x;
  452.         SquareStack[0].y = (float)y;
  453.         SquareStack[0].size = 1.0;
  454.         SquareStack[0].ul = upper[x];
  455.         SquareStack[0].ur = upper[x+1];
  456.         SquareStack[0].ll = lower[x];
  457.         SquareStack[0].lr = lower[x+1];
  458.         subdivide_square(&buf[x]);
  459.     }
  460. }
  461.  
  462. /*
  463.  * Bleck, but it saves us a function call and keeps the code much cleaner.
  464.  */
  465. #define push_square(u,v,s,a,b,c,d) {\
  466.             Stackp->x = u; \
  467.             Stackp->y = v; \
  468.             Stackp->size = s; \
  469.             Stackp->ul = a; \
  470.             Stackp->ur = b; \
  471.             Stackp->ll = c; \
  472.             Stackp->lr = d; \
  473.             Stackp++;}
  474.  
  475. /*
  476.  * Subdivide a pixel square.
  477.  */
  478. subdivide_square(color)
  479. Color *color;
  480. {
  481.     register pixel_square *Stackp;
  482.     register float x, y;
  483.     float size, halfsize;
  484.     double avfact, xdelta, ydelta;
  485.     Color ul, ur, ll, lr, u, d, l, r, c;
  486.     extern unsigned long SuperSampled;
  487.  
  488.     color->r = color->g = color->b = 0.;
  489.     Stackp = SquareStack + 1;
  490.  
  491.     do {
  492.         Stackp--;
  493.         size = Stackp->size;
  494.         ul = Stackp->ul;
  495.         ur = Stackp->ur;
  496.         ll = Stackp->ll;
  497.         lr = Stackp->lr;
  498.  
  499.         if(size <= Minsquare || pixel_ok(&ul,&ur,&ll,&lr)) {
  500.             /*
  501.              * The square is either the smallest allowed, or
  502.              * the four corners of the square are similar.
  503.              * Average the four corners (weighted by the
  504.              * size of the square) to get this square's
  505.              * contribution to the whole pixel's color.
  506.              */
  507.             avfact = (size * size) * 0.25;
  508.             color->r += (ul.r + ur.r + ll.r + lr.r) * avfact;
  509.             color->g += (ul.g + ur.g + ll.g + lr.g) * avfact;
  510.             color->b += (ul.b + ur.b + ll.b + lr.b) * avfact;
  511.             continue;
  512.         }
  513.         /*
  514.          * Subdivide into four squares -- trace 5 additional
  515.          * rays and push the appropriate squares on the pixelsquare
  516.          * stack.
  517.          */
  518.         x = Stackp->x;
  519.         y = Stackp->y;
  520.         halfsize = size * 0.5;
  521.         xdelta = (double)(x + halfsize);
  522.         ydelta = (double)(y + halfsize);
  523.         trace_point(xdelta, (double)y, &u);
  524.         trace_point((double)x, ydelta, &l);
  525.         trace_point(xdelta, ydelta, &c);
  526.         trace_point((double)(x + size),ydelta, &r);
  527.         trace_point(xdelta, (double)(y + size), &d);
  528.         if(size == 1.)
  529.             SuperSampled++;
  530.         push_square(x, y, halfsize, ul, u, l, c);
  531.         push_square((float)xdelta, y, halfsize, u, ur, c, r);
  532.         push_square(x, (float)ydelta, halfsize, l, c, ll, d);
  533.         push_square((float)xdelta, (float)ydelta, halfsize,
  534.                     c, r, d, lr);
  535.     } while (Stackp != SquareStack);
  536. }
  537.  
  538. /*
  539.  * Trace a ray through x, y on the screen, placing the result in "color."
  540.  */
  541. trace_point(x, y, color)
  542. double x, y;
  543. Color *color;
  544. {
  545.     double dist;
  546.     HitInfo hitinfo;
  547.     extern Vector scrnx, scrny;
  548.     extern double aperture;
  549.     extern unsigned long EyeRays;
  550.     extern double TraceRay();
  551.  
  552.     /*
  553.      * Calculate ray direction.
  554.      */
  555.     EyeRays++;
  556.     TopRay.dir.x = firstray.x + x*scrnx.x - y*scrny.x;
  557.     TopRay.dir.y = firstray.y + x*scrnx.y - y*scrny.y;
  558.     TopRay.dir.z = firstray.z + x*scrnx.z - y*scrny.z;
  559.  
  560.     (void)normalize(&TopRay.dir);
  561.  
  562.     if (aperture > 0.0) {
  563.         /*
  564.          * If the aperture is open, adjust the initial ray
  565.          * to account for depth of field.  
  566.          */
  567.         focus_blur_ray(&TopRay);
  568.     }
  569.  
  570.     /*
  571.      * Do the actual ray trace.
  572.      */
  573.     dist = TraceRay((Primitive *)NULL, &TopRay, &hitinfo);
  574.     ShadeRay(&hitinfo, &TopRay, dist, &background, color, 1.0);
  575. }
  576.  
  577. /*
  578.  * Return TRUE if this pixel is okay and doesn't need to be supersampled,
  579.  * FALSE otherwise.
  580.  */
  581. pixel_ok(w,x,y,z)
  582. Color *w, *x, *y, *z;
  583. {
  584.     double rmax, rmin, gmax, gmin, bmax, bmin;
  585.     double rsum, gsum, bsum;
  586.  
  587.     /*
  588.      * Find min & max R, G, & B.
  589.      */
  590.     rmax = max(w->r, max(x->r, max(y->r, z->r)));
  591.     rmin = min(w->r, min(x->r, min(y->r, z->r)));
  592.     gmax = max(w->g, max(x->g, max(y->g, z->g)));
  593.     gmin = min(w->g, min(x->g, min(y->g, z->g)));
  594.     bmax = max(w->b, max(x->b, max(y->b, z->b)));
  595.     bmin = min(w->b, min(x->b, min(y->b, z->b)));
  596.  
  597.     /*
  598.      * Contrast is defined as (Max - Min) / (Max + Min) for each
  599.      * of RG&B.  If any of these values is greater than the maximum
  600.      * allowed, we have to supersample.
  601.      */
  602.     rsum = rmax + rmin;
  603.     gsum = gmax + gmin;
  604.     bsum = bmax + bmin;
  605.     if ((rsum == 0. || (rmax - rmin) / rsum < RedContrast) &&
  606.         (gsum == 0. || (bmax - bmin) / gsum < BlueContrast) &&
  607.         (bsum == 0. || (gmax - gmin) / bsum < GreenContrast))
  608.         return TRUE;
  609.  
  610.     return FALSE;
  611. }
  612.  
  613. #ifdef LINDA
  614. dist_worker()
  615. {
  616.     extern unsigned long EyeRays, ShadowRays, ReflectRays, RefractRays;
  617.     extern unsigned long CacheWorked, CacheFailed, ShadowHits;
  618.     extern unsigned long SuperSampled, BVTests, HitRays;
  619.     extern unsigned long primtests[PRIMTYPES], primhits[PRIMTYPES];
  620.     extern int VerboseWorker;
  621.     extern FILE *fstats;
  622.     double user, sys;
  623.  
  624.     while (dist_job())
  625.         ;
  626.     /*
  627.      * Out statistics.
  628.      */
  629.     out ("statistics", EyeRays, ShadowRays, ReflectRays, RefractRays,
  630.         CacheWorked, CacheFailed, ShadowHits, SuperSampled, BVTests,
  631.         HitRays);
  632.     /*
  633.      * Out ray/primitive intersection counts.
  634.      */
  635.     out ("counts", primtests, primhits);
  636.     /*
  637.      * Compute running time.
  638.      */
  639.     get_cpu_time(&user, &sys);
  640.     out ("timing", user, sys);
  641.     return;
  642. }
  643.  
  644. /*
  645.  * Worker trained to perform distributed ray-tracing.
  646.  */
  647. dist_job()
  648. {
  649.     int y;
  650.     extern int VerboseWorker;
  651.  
  652.     in("scaninfo", ? y);
  653.     if (y < 0) {
  654.         out("scaninfo", y);
  655.         return 0;
  656.     }
  657.     if (VerboseWorker)
  658.         fprintf(stderr,"Worker: inned %d\n",y);
  659.     out("scaninfo", y-1);
  660.     trace_jit_line(y, out_buf);
  661.     if (VerboseWorker)
  662.         fprintf(stderr,"Worker: outing %d\n",y);
  663.     out("result", y, out_buf : Xres);
  664.     return 1;
  665. }
  666.  
  667. adapt_worker()
  668. {
  669.  
  670.     extern unsigned long EyeRays, ShadowRays, ReflectRays, RefractRays;
  671.     extern unsigned long CacheWorked, CacheFailed, ShadowHits;
  672.     extern unsigned long SuperSampled, BVTests, HitRays;
  673.     extern unsigned long primtests[PRIMTYPES], primhits[PRIMTYPES];
  674.     double user, sys;
  675.  
  676.     while (adapt_job(FALSE))
  677.         ;
  678.     /*
  679.      * Out statistics.
  680.      */
  681.     out ("statistics", EyeRays, ShadowRays, ReflectRays, RefractRays,
  682.         CacheWorked, CacheFailed, ShadowHits, SuperSampled, BVTests,
  683.         HitRays);
  684.     /*
  685.      * Out ray/primitive intersection counts.
  686.      */
  687.     out ("counts", primtests, primhits);
  688.  
  689.     /*
  690.      * Compute running time.
  691.      */
  692.     get_cpu_time(&user, &sys);
  693.     out ("timing", user, sys);
  694.  
  695.     return;
  696. }
  697.  
  698. adapt_job(supervisor)
  699. int supervisor;
  700. {
  701.     int lastpix, lastscan;
  702.     extern int VerboseWorker;
  703.  
  704.     in("scaninfo", ? lastpix, ? lastscan);
  705.     if (lastpix <= 0) {
  706.         out("scaninfo", lastpix, lastscan);
  707.         if (VerboseWorker)
  708.             fprintf(stderr,"Worker:  all finished!\n");
  709.         return FALSE;
  710.     }
  711.  
  712.     if (rdp("scanline", lastpix -1, ? pixel_buf[0]:) &&
  713.         inp("scanline", lastpix, ? pixel_buf[1]:)) {
  714.         lastpix--;
  715.         out("scaninfo", lastpix, lastscan);
  716.         if (VerboseWorker)
  717.             fprintf(stderr,"%s: doing pixline %d\n",
  718.                 supervisor ? "Supervisor" : "Worker",
  719.                     lastpix);
  720.         subdivide_line(lastpix, pixel_buf[0], pixel_buf[1],
  721.                     out_buf);
  722.         out("result", lastpix, out_buf : Xres);
  723.     } else if (supervisor) {
  724.         /*
  725.          * Don't let the supervisor get caught up in
  726.          * ray-tracing a whole scanline.  It might take
  727.          * a long, long time, causing tuple-space to get
  728.          * jammed with finished pixlines, and...
  729.          */
  730.         if (VerboseWorker)
  731.             fprintf(stderr,"Supervisor: nothing to do...\n");
  732.         out ("scaninfo", lastpix, lastscan);
  733.         return FALSE;
  734.     } else if (lastscan > 0) {
  735.         lastscan--;
  736.         out("scaninfo", lastpix, lastscan);
  737.         if (VerboseWorker)
  738.             fprintf(stderr,"Worker: doing scan %d\n",
  739.                     lastscan);
  740.         trace_line(lastscan, pixel_buf[0]);
  741.         out("scanline", lastscan, pixel_buf[0] : Xres + 1);
  742.     } else {
  743.         /*
  744.          * Nothing to do until somebody finishes a scanline.
  745.          */
  746.         if (VerboseWorker) {
  747.             fprintf(stderr,"Worker idle... ");
  748.             fprintf(stderr,"pix = %d, scan = %d\n",
  749.                     lastpix, lastscan);
  750.         }
  751.         out("scaninfo", lastpix, lastscan);
  752.         sleep(2);
  753.     }
  754.     return 1;
  755. }
  756. #endif
  757.