home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / source / rayce27s / trace.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-02  |  12.5 KB  |  508 lines

  1. /*
  2.  * trace.c -- Important tracing stuff is done here, this is the actual
  3.  * ray-tracing part
  4.  * 
  5.  * (c) 1993, 1994 Han-Wen Nienhuys <hanwen@stack.urc.tue.nl>
  6.  * 
  7.  * originally by George Kyriazis, 1988. Thoroughly rehacked by Han-Wen
  8.  * Nienhuys.
  9.  * 
  10.  * This program is free software; you can redistribute it and/or modify it
  11.  * under the terms of the GNU General Public License as published by the
  12.  * Free Software Foundation;
  13.  * 
  14.  * This program is distributed in the hope that it will be useful, but
  15.  * WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17.  * General Public License for more details.
  18.  * 
  19.  * You should have received a copy of the GNU General Public License along
  20.  * with this program; if not, write to the Free Software Foundation, Inc.,
  21.  * 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  */
  23.  
  24. #include    "ray.h"
  25. #include    "proto.h"
  26. #include    "extern.h"
  27.  
  28.  
  29. #ifdef GNUCC
  30. #error bo
  31. /* Gcc needs this for SEEK_EOF */
  32. #include    <unistd.h>
  33. #endif
  34.  
  35. PRIVATE void    line_stat_update(void);
  36. PRIVATE void    print_endstats(void);
  37. PRIVATE void    write_color(color col);
  38. PRIVATE void    open_TGA(char *fn);
  39. PRIVATE void    open_continueTGA(char *fn);
  40. PRIVATE void    write_line(char *fn);
  41.  
  42. PRIVATE int     cur_x,
  43.                 cur_y;        /* current x,y of pixels we're tracing */
  44. PRIVATE char   *line_buffer,    /* buffer to hold data of the line we're
  45.                  * working on */
  46.                *line_bufp;    /* current buffer position */
  47.  
  48. PRIVATE bool    trace_start;
  49.  
  50.  
  51. /*
  52.  * sample a ray inside specified solid angle
  53.  */
  54. PUBLIC struct ray
  55. sample_ray(struct ray r, double theta)
  56. {
  57.     vector          tmp,
  58.                     hor,
  59.                     ver,
  60.                     dev;
  61.     double          randfact1,
  62.                     randfact2;
  63.  
  64.     if (theta < EPSILON)    /* don't go thru difficult stuff if you
  65.                  * don't have to */
  66.     return r;
  67.  
  68.     setvector(tmp, 1, 0, 0);
  69.     vcross(hor, tmp, r.dir);
  70.  
  71.     if (quickveclen(tmp) < EPSILON) {    /* tmp x r.dir is nullvector */
  72.     setvector(tmp, 0, 1, 0);/* then this won't give nullvector */
  73.     vcross(hor, tmp, r.dir);
  74.     }
  75.     /* hor is orthogonal to r.dir */
  76.     norm(hor, hor);
  77.     vcross(ver, r.dir, hor);
  78.  
  79.     /* pick a point in disc radius 1 */
  80.     do {
  81.     randfact1 = Gauss_rand();    /* maybe use a homogenous rand */
  82.     randfact2 = Gauss_rand();
  83.     }
  84.     while (sqr(randfact1) + sqr(randfact2) > 1);
  85.  
  86.     randfact1 *= theta;
  87.     randfact2 *= theta;
  88.  
  89.     svproduct(hor, randfact1, hor);
  90.     svproduct(ver, randfact2, ver);
  91.  
  92.     vadd(dev, hor, ver);
  93.     vadd(r.dir, dev, r.dir);
  94.     norm(r.dir, r.dir);
  95.  
  96.     return r;
  97. }
  98.  
  99.  
  100. /*
  101.  * trace a single straight ray
  102.  */
  103. PUBLIC color
  104. trace(struct ray r, int n, double importance)
  105. {                /* n = recursion level */
  106.     struct intersect inter;
  107.     color           col;
  108.  
  109.     if (n > line_stats.maxdepth)
  110.     line_stats.maxdepth = n;
  111.  
  112.  
  113.     /* check for intersection with the object */
  114.     inter = intersect(r);
  115.  
  116.  
  117.     /* if no intersection, return some background color */
  118.     if (inter.q_ent.obj == NULL)
  119.     return bgcolor(&r);
  120.  
  121.     /* else calculate the shading function there */
  122.     col = shade(inter, r, n, importance);
  123.     return col;
  124. }
  125.  
  126. /***************************************************************************
  127.  * RAYTRACE():  entry point of trace.c.  raytrace the whole scene       *
  128.  ***************************************************************************/
  129.  
  130. PUBLIC void
  131. raytrace(char *fname)
  132. {
  133.     double          xr,
  134.                     yr,
  135.                     xstep,
  136.                     ystep;
  137.     color
  138.                     pixcol,    /* color gathered sofar for a pixel */
  139.     color;
  140.     struct ray      eyeray;
  141.     double
  142.                     factor,
  143.                     hor_coef,
  144.                     ver_coef;
  145.  
  146.  
  147.     int             i;
  148.     double          pix_width,
  149.                     pix_height;
  150.     vector          camhor,
  151.                     camver,
  152.                     hor,
  153.                     ver;
  154.  
  155.     pix_width = 2 * thecamera->fov / xres;    /* pixel width in radians */
  156.     pix_height = 2 * thecamera->fov / xres;    /* pixel height in radians */
  157.  
  158.  
  159.     /* decide whether to continue or restart */
  160.     if (continue_flag) {
  161.     open_continueTGA(fname);
  162.     } else {
  163.     cur_y = 0;
  164.     open_TGA(fname);
  165.     }
  166.  
  167.     /* init the camera */
  168.     vcross(camhor, thecamera->sky, thecamera->eye_dir);    /* the x screen vector */
  169.     if (isvnull(camhor))
  170.     errormsg("direction vector can't be sky vector.");
  171.     norm(camhor, camhor);
  172.  
  173.     vcross(camver, thecamera->eye_dir, camhor);    /* the y screen vector */
  174.     norm(camver, camver);
  175.  
  176.     eyeray.pos = thecamera->eye;/* eye is the beginning of the ray */
  177.     eyeray.type = R_EYE;    /* this is an eye ray */
  178.  
  179.     xstep = 2.0 / xres;
  180.     ystep = 2.0 / yres;
  181.  
  182.     yr = 1.0 - (double) cur_y *ystep;    /* where should we begin? */
  183.  
  184.     factor = 1 / (double) tries;
  185.  
  186.     trace_start = TRUE;
  187.  
  188.     for (; cur_y < yres; cur_y++) {
  189.     vector          screen;    /* position on imaginary screen in space */
  190.  
  191.     xr = -1.0;
  192.  
  193.     for (cur_x = 0; cur_x < xres; cur_x++) {
  194.         hor_coef = xr * thecamera->fov * thecamera->aspect;
  195.         ver_coef = yr * thecamera->fov;
  196.  
  197.         setcolor(pixcol, 0, 0, 0);    /* init the color */
  198.  
  199.         /*
  200.          * the time blur has to be done in linear time and not
  201.          * randomly
  202.          */
  203.         i = tries;
  204.         while (i--) {
  205.         check_abort();    /* somebody pressed a key? */
  206.  
  207.         /*
  208.          * pick a Time inside time interval randomization is used
  209.          * so we won't get the strobo effect
  210.          */
  211.         Time = (time2 + time1) / 2 +
  212.             (time2 - time1) * (i + rand1()) / tries;
  213.  
  214.         /* ray direction calculations */
  215.         svproduct(hor, hor_coef +
  216.               0.5 * pix_width * Gauss_rand() * Aalias_width,
  217.               camhor);
  218.         svproduct(ver, ver_coef +
  219.          0.5 * pix_height * Gauss_rand() * Aalias_width, camver);
  220.  
  221.         vadd(screen, hor, ver);
  222.         vadd(eyeray.dir, thecamera->eye_dir, screen);
  223.  
  224.         norm(eyeray.dir, eyeray.dir);
  225.  
  226.         /* !!!! this is the important step! */
  227.         color = trace(eyeray, 0, 1.0);
  228.  
  229.         /* sum all the intensities together */
  230.         pixcol.r += color.r * factor;
  231.         pixcol.g += color.g * factor;
  232.         pixcol.b += color.b * factor;
  233.         }
  234.  
  235.         /* normalise color */
  236.         pixcol = normcol(pixcol);
  237.         write_color(pixcol);/* output one pixel */
  238.         xr += xstep;    /* next */
  239.     }
  240.  
  241.     write_line(fname);    /* write image line to output */
  242.     yr -= ystep;        /* next line */
  243.     line_stat_update();    /* and print stats */
  244.     }
  245.  
  246.     print_endstats();        /* global statistics. */
  247. }
  248.  
  249. /* print statistics after abortion */
  250. PUBLIC void
  251. abort_trace(int blubber)
  252. {                /* needed for keeping signal () from
  253.                  * complaining */
  254.     if (trace_start) {
  255.     if (!silent_mode) {
  256.         printf("\nStopped at pixel %d\n", cur_x);
  257.         line_stat_update();
  258.     }
  259.     print_endstats();
  260.  
  261.     } else {
  262.     printf("(interrupt)\n");
  263.     }
  264.  
  265.     exit(0);
  266. }
  267.  
  268.  
  269. /***************************************************************************
  270.  * statistics                                   *
  271.  ***************************************************************************/
  272.  
  273. /* statistics for a line */
  274. PRIVATE void
  275. line_stat_update(void)
  276. {
  277.     if (cur_x == 0)
  278.     return;
  279.     if (!silent_mode)
  280.     printf("line %3d. rays shot: %ld, hits: %ld, rel: %.2lf, ray/pxl: %.2lf\n"
  281.            "          eye: %ld shad: %ld, refl: %ld, refr %ld, depth %d/%d\n",
  282.            cur_y, line_stats.raytest, line_stats.rayintersections, (double) line_stats.rayintersections / line_stats.raytest,
  283.            (double) line_stats.raytest / xres, line_stats.eyerays, line_stats.shadowtest, line_stats.reflected,
  284.          line_stats.refracted, line_stats.maxdepth, max_trace_level);
  285.  
  286.     /* update statistics */
  287.     global_stats.raytest += line_stats.raytest;
  288.     global_stats.rayintersections += line_stats.rayintersections;
  289.     global_stats.shadowtest += line_stats.shadowtest;
  290.     global_stats.reflected += line_stats.reflected;
  291.     global_stats.refracted += line_stats.refracted;
  292.     global_stats.eyerays += line_stats.eyerays;
  293.  
  294.     line_stats.raytest = 0;
  295.     line_stats.rayintersections = 0;
  296.     line_stats.shadowtest = 0;
  297.     line_stats.reflected = 0;
  298.     line_stats.refracted = 0;
  299.     line_stats.maxdepth = 0;
  300.     line_stats.eyerays = 0;
  301.  
  302. }
  303.  
  304.  
  305. #define FMT0 "%-23s\t%12s\t%12s\t%13s\n"
  306. #define FMT1 "%-23s\t%12ld\t%12ld\t%12.2lf%%\n"
  307. #define FMT2 "%-17s%6ld\t%12ld\t%12ld\t%12.2lf%%\n"
  308.  
  309.  
  310. PRIVATE void
  311. print_tot_stat(char *s, long total, long succ)
  312. {
  313.     double          rel;
  314.  
  315.     if (total > 0)
  316.     rel = 100.0 * succ / total;
  317.     else
  318.     rel = 0.0;
  319.  
  320.     printf(FMT1, s, total, succ, rel);
  321. }
  322.  
  323. PRIVATE void
  324. print_shap_stat(char *s, long no, long total, long succ)
  325. {
  326.     double          rel;
  327.  
  328.     if (!no)
  329.     return;
  330.     if (total > 0)
  331.     rel = 100.0 * succ / total;
  332.     else
  333.     rel = 0.0;
  334.  
  335.     printf(FMT2, s, no, total, succ, rel);
  336. }
  337.  
  338.  
  339.  
  340. /* print statistics after finishing */
  341. PRIVATE void
  342. print_endstats(void)
  343. {
  344.     long            sec;
  345.  
  346.     printf(FMT0, "", "tested", "succeeded", "relative");
  347.  
  348.     print_tot_stat("Rays: ", global_stats.raytest, global_stats.rayintersections);
  349.     print_tot_stat("Shadow cache: ", global_stats.cachetest, global_stats.cachehit);
  350.  
  351.     print_shap_stat("Objects: ", global_stats.objects, global_stats.objtest, global_stats.objhit);
  352.     print_all_shape_stats(FMT2, thescene);
  353.  
  354.     print_shap_stat("Bounds: ", global_stats.bounds, global_stats.boundtest, global_stats.boundhit);
  355.     print_shap_stat("Clips: ", global_stats.clips, global_stats.cliptest, global_stats.cliphit);
  356.  
  357.  
  358.     printf("Total reflected rays traced: %ld\n", global_stats.reflected);
  359.     printf("Total refracted rays traced: %ld\n", global_stats.refracted);
  360.     printf("Total eye rays traced: %ld\n", global_stats.eyerays);
  361.  
  362.     if (first_light != NULL)
  363.     printf("light_sources: %ld\n", first_light->methods->howmuch);
  364.     printf("cache misses: %ld\n", global_stats.cachemiss);
  365.  
  366.     if (test_stat)
  367.     printf("\n\nTEST STATISTICS: %ld\n", test_stat);
  368.  
  369.     sec = timer_stop();
  370.     printf("Time for trace: %d:%02d:%02d (%ld seconds)", (int) sec / 36000,
  371.     (int) (sec / 600) % 60, (int) (sec % 600) / 10, (long) sec / 10);
  372.     if (global_stats.raytest > 0)
  373.     printf(" Time per ray: %.3fms\n",
  374.            100.0 * (double) sec / global_stats.raytest);
  375.     else
  376.     printf("\n");
  377.  
  378. }
  379.  
  380. /***************************************************************************
  381.  * FILES                                   *
  382.  ***************************************************************************/
  383.  
  384. PRIVATE char   *
  385. alloc_buf(int xres)
  386. {
  387.     void           *p;
  388.     p = malloc(xres * 3 * sizeof(char));
  389.  
  390.     if (p == NULL)
  391.     alloc_err("line buffer");
  392.  
  393.     return (char *) p;
  394. }
  395.  
  396.  
  397. /* calc the integer value to be put to the file */
  398. /* and store it. NB targa is in bgr form */
  399. PRIVATE void
  400. write_color(color col)
  401. {
  402.     *line_bufp++ = col.b * 255;    /* TGA is BGR */
  403.     *line_bufp++ = col.g * 255;
  404.     *line_bufp++ = col.r * 255;
  405. }
  406.  
  407. /* dump line_buffer to output, and flush buffer (close file) */
  408. PRIVATE void
  409. write_line(char *fn)
  410. {
  411.     int             i;
  412.     char           *cp;
  413.     FILE           *f;
  414.  
  415.     if ((f = fopen(fn, "ab")) == NULL) {
  416.     errormsg("can\'t open %s", fn);
  417.     }
  418.     /* reset buffer */
  419.     cp = line_bufp = line_buffer;
  420.     for (i = 0; i < 3 * xres; i++)
  421.     putc(*cp++, f);
  422.  
  423.     /* now you can press ctl-alt-del */
  424.     fclose(f);
  425. }
  426.  
  427. /* open a file, write TGA header */
  428. PUBLIC void
  429. open_TGA(char *fn)
  430. {
  431.     FILE           *f;
  432.     int             header[18];
  433.     int             i;
  434.  
  435.  
  436.     f = fopen(fn, "wb");
  437.     if (f == NULL)
  438.     errormsg("can\'t open %s", fn);
  439.  
  440.     for (i = 0; i < 18; i++)
  441.     header[i] = 0;
  442.  
  443.     printf("xres %d x yres %d\n", xres, yres);
  444.  
  445.     /* put ID and screen res in header */
  446.     header[2] = 0x02;
  447.     header[12] = xres & 0x00ff;
  448.     header[13] = xres / 256;
  449.     header[14] = yres & 0x00ff;
  450.     header[15] = yres / 256;
  451.     header[16] = 24;
  452.     header[17] = 32;
  453.  
  454.     /* dump header */
  455.     for (i = 0; i < 18; i++)
  456.     putc(header[i], f);
  457.  
  458.     line_bufp = line_buffer = alloc_buf(xres);
  459.  
  460.  
  461.     fclose(f);
  462.  
  463.  
  464. }
  465.  
  466.  
  467. /* open a file for appending */
  468. PRIVATE void
  469. open_continueTGA(char *fn)
  470. {
  471.     FILE           *f;
  472.     int             header[18];
  473.     long            len;
  474.     int             i;
  475.  
  476.     f = fopen(fn, "r+");
  477.     if (f == NULL) {
  478.     printf("error opening continue file, creating a new file\n");
  479.     open_TGA(fn);
  480.     return;
  481.     }
  482.     /* read TGA header */
  483.     for (i = 0; i < 18; i++)
  484.     header[i] = getc(f);
  485.  
  486.     /* check file id */
  487.     if (header[2] != 0x02 || header[16] != 24 || header[17] != 32)
  488.     errormsg("Not a valid TGA!");
  489.  
  490.  
  491.     /* calc resolution */
  492.     xres = header[12] + header[13] * 256;
  493.     yres = header[14] + header[15] * 256;
  494.  
  495.     /* find out where to start. This could be more robust */
  496.     fseek(f, 0, SEEK_END);
  497.     len = ftell(f) - 18;
  498.     if (len % xres * 3)
  499.     errormsg("TGA doesn't end at a scanline");
  500.     cur_y = len / (xres * 3);
  501.  
  502.     printf("xres %d x yres %d, starting at line %d\n", xres, yres, cur_y);
  503.  
  504.     /* set up buffer */
  505.     line_bufp = line_buffer = alloc_buf(xres);
  506.     fclose(f);
  507. }
  508.