home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / graphic / csg_rt / rt.c < prev    next >
C/C++ Source or Header  |  1993-02-07  |  54KB  |  2,310 lines

  1. /*
  2.  
  3. RT.C  CSG Ray Tracer
  4.  
  5. */
  6.  
  7. /*...sincludes:0:*/
  8. #include <stdio.h>
  9. #include <ctype.h>
  10. #include <stdlib.h>
  11. #include <stddef.h>
  12. #include <stdarg.h>
  13. #include <string.h>
  14. #include <memory.h>
  15. #include <malloc.h>
  16. #include <math.h>
  17. #include "standard.h"
  18. /*...e*/
  19.  
  20. static char progname [] = "rt";
  21. static char sccs_id [] = "@(#)CSG Ray Tracer  1/3/93";
  22.  
  23. /*...susefull:0:*/
  24. /*...sfatal:0:*/
  25. static void fatal(const char *fmt, ...)
  26.     {
  27.     va_list    vars;
  28.     char    s [256+1];
  29.  
  30.     va_start(vars, fmt);
  31.     vsprintf(s, fmt, vars);
  32.     va_end(vars);
  33.     fprintf(stderr, "%s: %s\n", progname, s);
  34.     exit(1);
  35.     }
  36. /*...e*/
  37. /*...susage:0:*/
  38. static void usage(void)
  39.     {
  40.     fprintf(stderr, "usage: %s scriptfile\n", progname);
  41.     fprintf(stderr, "flags: scriptfile  contains scene and view definition\n");
  42.     exit(1);
  43.     }
  44. /*...e*/
  45. /*...sget_opt_value:0:*/
  46. static int get_opt_value(char *s, char *name)
  47.     {
  48.     int    v;
  49.  
  50.     if ( s == NULL )
  51.         fatal("missing %s argument", name);
  52.     if ( !isdigit(s [0]) )
  53.         fatal("bad %s argument", name);
  54.     if ( s [0] == '0' && tolower(s [1]) == 'x' )
  55.         sscanf(s + 2, "%x", &v);
  56.     else
  57.         v = atoi(s);
  58.  
  59.     return ( v );
  60.     }
  61. /*...e*/
  62. /*...smemcheck:0:*/
  63. static void *memcheck(void *p)
  64.     {
  65.     if ( p == NULL )
  66.         fatal("out of memory");
  67.     return ( p );
  68.     }
  69. /*...e*/
  70. /*...sstrsave:0:*/
  71. static char *strsave(char *s)
  72.     {
  73.     int    len = strlen(s);
  74.     char    *t = memcheck(malloc(len + 1));
  75.  
  76.     return ( strcpy(t, s) );
  77.     }
  78. /*...e*/
  79. /*...e*/
  80. /*...smain:0:*/
  81. /*...sincludes:0:*/
  82. #include "rt.h"
  83. #include "fio.h"
  84. #include "tex.h"
  85. #include "vector.h"
  86. #include "rgbvec.h"
  87. #include "col.h"
  88. #include "surf.h"
  89. #include "sil.h"
  90. #include "plane.h"
  91. #include "sphere.h"
  92. #include "quad.h"
  93. #include "shape.h"
  94.  
  95. /*...vrt\46\h:0:*/
  96. /*...vfio\46\h:0:*/
  97. /*...vtex\46\h:0:*/
  98. /*...vvector\46\h:0:*/
  99. /*...vrgbvec\46\h:0:*/
  100. /*...vcol\46\h:0:*/
  101. /*...vsurf\46\h:0:*/
  102. /*...vsil\46\h:0:*/
  103. /*...vplane\46\h:0:*/
  104. /*...vsphere\46\h:0:*/
  105. /*...vquad\46\h:0:*/
  106. /*...vshape\46\h:0:*/
  107. /*...e*/
  108.  
  109. #ifdef OS2_V2
  110. #include <signal.h>
  111. #include <float.h>
  112. /*...vd\58\\92\ibmc\92\include\92\signal\46\h:0:*/
  113. /*...vd\58\\92\ibmc\92\include\92\float\46\h:0:*/
  114. #endif
  115.  
  116. /*...slighting:0:*/
  117. /*
  118. Surfaces do not emit light of their own. They only reflect and refract light
  119. from the light sources in the scene. The lighting/shading model used is the
  120. one defined in F,vD,F,H p734.
  121.  
  122. Global parameters :-
  123.     Ia = ambient intensity (rgb vector)
  124.  
  125. Parameters defined per surface :-
  126.     ka               = ambient-reflection-coefficient
  127.     kd               = diffuse coefficient, range 0.0 to 1.0
  128.     ks               = specular coefficient, range 0.0 to 1.0
  129.     kt               = transmission coefficent, range 0.0 to 1.0
  130.     od               = diffuse colour (rgb vector)
  131.     os               = specular colour (rgb vector)
  132.     phong_number     = Phong power
  133.     rinx = inside relative to outside of surface
  134.  
  135. Ambient contribution is :-
  136.     Ia * ka * od
  137.  
  138. Diffuse for light of intensity Ip, attenuated by distance by fatt, using
  139. Lamberts law gives :-
  140.     fatt * Ip * kd * od * cos_nl
  141.  
  142. Specular for light of intensity Ip, attenuated by distance by fatt, using
  143. the Phong shading model gives :-
  144.     fatt * Ip * ks * os * pow(cos_rv, phong_number)
  145.  
  146. Reflective component (specular only), using recursion (if depth not too deep) :-
  147.     intensity_from_looking_along_reflected_ray * ks * os
  148.  
  149. Refractive component (transmissive), given no total internal reflection,
  150. using recursion (if depth not too deep) :-
  151.     intensity_from_refractive_ray * kt
  152.  
  153. Before returning intensity, scale down by distance to origin of ray (eye).
  154. */
  155.  
  156. typedef struct { VECTOR posn; RGBVEC i; } LIGHT;
  157.  
  158. #define    N_LIGHTS    10
  159. static LIGHT lights [N_LIGHTS];
  160. static int n_lights = 0;
  161.  
  162. static RGBVEC i_background = { 0.0, 0.0, 0.0 };
  163. static RGBVEC i_ambient = { 0.0, 0.0, 0.0 };
  164. static double af1 = 1.0, af2 = 0.9;
  165.  
  166. /*...sscale_by_distance:0:*/
  167. /*
  168. The further light travels (from light source to surface, or from surface to
  169. eye etc.) the fainter it gets. Therefore as t increases, the amount intensity
  170. is reduced by should increase.
  171. */
  172.  
  173. static RGBVEC scale_by_distance(RGBVEC i, double t)
  174.     {
  175.     double    scalar = af1 * pow(af2, t);
  176.  
  177.     if ( scalar > 1.0 )
  178.         scalar = 1.0;
  179.  
  180.     i.r *= scalar;
  181.     i.g *= scalar;
  182.     i.b *= scalar;
  183.  
  184.     return ( i );
  185.     }
  186. /*...e*/
  187. /*...e*/
  188. /*...srender:0:*/
  189. /*...strace:0:*/
  190. #define    EPSILON        (1.0e-8)        /* A tiny number             */
  191.  
  192. /*...sshadow_calc:0:*/
  193. /*
  194.  
  195. In a CSG system without refraction, no rays can pass through any solid.
  196. Hence this code would return 1.0 or 0.0 depending on whether il is empty.
  197. Actually we are only interested in the range of t from 0 to dist_l being empty.
  198. This is because the light is dist_l away, things further don't cause shadows.
  199.  
  200. With refraction, things can be lit through glass-like solids.
  201. Let me admit, from the start, that refraction in a CSG system is a kludge!
  202. Glass-like solids transmit kt of the light coming from their other side.
  203. So we look along the intersections for transmissive surfaces and work out the
  204. combined transmissiveness.
  205.  
  206. We assume that pathalogical shapes (transmissive on one side, non-transmissive
  207. on the the other) do not exist. We also assume the kt coefficients match for
  208. a given shape on its entry and exit. We only use kt once (on entry) per shape.
  209.  
  210. Actually, to correctly handle illumination through refractive shapes is a
  211. nightmare, and requires that we calculate a full multi-part path back to the
  212. light. This is horrendous, and we will assume that refraction does not alter
  213. the path (much) back to the light.
  214.  
  215. In doing so, we will prevent glass causing shadows, which is the main goal.
  216.  
  217. */
  218.  
  219. static double shadow_calc(ISECTL *il, double dist_l)
  220.     {
  221.     int    j = 0;
  222.     double    kt_accum = 1.0;
  223.  
  224.     while ( j < il -> n_isects && il -> isects [j].t < dist_l )
  225.         {
  226.         double    kt = il -> isects [j].shape -> surf -> kt;
  227.  
  228.         if ( kt == 0.0 )
  229.             return ( 0.0 );
  230.         kt_accum *= kt;
  231.         j += 2;
  232.         }
  233.  
  234.     return ( kt_accum );
  235.     }
  236. /*...e*/
  237.  
  238. /*...sreflect:0:*/
  239. static VECTOR reflect(VECTOR unit_v, VECTOR unit_n, double cos_vn)
  240.     {
  241.     return ( vector_difference(scale_vector(vector_sum(unit_n, unit_n), cos_vn), unit_v) );
  242.     }
  243. /*...e*/
  244. /*...srefract:0:*/
  245. /*
  246.           ^ N             Given an incident unit vector I, approaching a
  247.           | -             surface with unit normal vector N, compute the
  248.   \       |               transmitted ray T. This ray will not necessarily
  249.    \      |               be a unit vector.
  250.     \     |               
  251.      \  0 |               If the term under the square root is negative
  252.       \  i|               then this indicates total internal reflection.
  253.        \  |               
  254.      I  \||               n_it is the relative refractive index of the
  255.      -  -\|               incident medium relative the the transmissive
  256. ----------+----------> S  medium. Thus for air (1.0) entering crown glass
  257.           |\           -  (1.5) this number would be 1.0/1.5 = 0.66 approx.
  258.           | \             
  259.           |  \            We use the equation given in Byte Magazine Dec 90.
  260.           | 0 \           
  261.           |  t \          
  262.           |     \         
  263.           |   T  \|       
  264.           |   -  -\       
  265.           |               
  266. */
  267.  
  268. static BOOLEAN refract(
  269.     VECTOR unit_i,
  270.     VECTOR unit_n,
  271.     double n_it,
  272.     VECTOR *t
  273.     )
  274.     {
  275.     double    cos_ni = -scalar_product(unit_n, unit_i);
  276.     double    under_root = 1.0 + n_it*n_it * (cos_ni*cos_ni - 1.0);
  277.     double    n_comp;
  278.  
  279.     if ( under_root < 0.0 )
  280.         return ( FALSE ); /* Total internal reflection */
  281.  
  282.     n_comp = n_it * cos_ni - sqrt(under_root);
  283.  
  284.     *t = unit_vector(vector_sum(scale_vector(unit_i, n_it),
  285.                         scale_vector(unit_n, n_comp)));
  286.  
  287.     return ( TRUE );
  288.     }
  289. /*...e*/
  290.  
  291. static RGBVEC trace(
  292.     SHAPE *root_shape,
  293.     VECTOR start, VECTOR direction,
  294.     int depth,
  295.     ISECTL *ils []
  296.     )
  297.     {
  298.     ISECTL    *il = *ils;
  299.     double    t;
  300.     SHAPE    *shape;
  301.     SURF    *surf;
  302.     RGBVEC    i, od, os;
  303.     VECTOR    unit_direction, unit_v, isect_posn, unit_n;
  304.     int    j;
  305.  
  306.     unit_direction = unit_vector(direction);
  307.     unit_v = negate_vector(unit_direction);
  308.  
  309.     intersect_shape(root_shape, start, unit_direction, ils);
  310.     t_after_isectl(il, EPSILON);
  311.  
  312.     if ( is_empty_isectl(il) )
  313.         return ( i_background );
  314.  
  315.     /* Hit something */
  316.  
  317.     t          = il -> isects [0].t;
  318.     shape      = il -> isects [0].shape;
  319.     surf       = shape -> surf;
  320.     isect_posn = t_along_pq(start, unit_direction, t);
  321.     unit_n     = unit_vector(normal_to_shape(shape, isect_posn));
  322.  
  323.     if ( il -> isects [0].negate_normal )
  324.         unit_n = negate_vector(unit_n);
  325.  
  326.     /* Calculate colours at intersection position */
  327.  
  328.     od = evaluate_col(surf -> od, isect_posn.x, isect_posn.y, isect_posn.z);
  329.     os = evaluate_col(surf -> os, isect_posn.x, isect_posn.y, isect_posn.z);
  330.  
  331.     /* Ambient light */
  332.  
  333.     i.r = i_ambient.r * surf -> ka * od.r;
  334.     i.g = i_ambient.g * surf -> ka * od.g;
  335.     i.b = i_ambient.b * surf -> ka * od.b;
  336.  
  337.     /* For each light source */
  338.  
  339.     for ( j = 0; j < n_lights; j++ )
  340. /*...shandle contribution of this light source:16:*/
  341. /*
  342. l is the vector from the intersection point to the light.
  343. dist_l is the distance to l.
  344. unit_l is a unit vector pointing to the light.
  345. We can reuse the intersection list used to hit the object for the shadow calc.
  346. */
  347.  
  348. {
  349. VECTOR    l, unit_l;
  350. double    dist_l, kt_accum;
  351.  
  352. l      = vector_difference(lights [j].posn, isect_posn);
  353. dist_l = magnitude(l);
  354. unit_l = inv_scale_vector(l, dist_l);
  355.  
  356. /* Can we see the light from the point of intersection */
  357.  
  358. intersect_shape(root_shape, isect_posn, unit_l, ils);
  359. t_after_isectl(il, EPSILON);
  360.  
  361. if ( (kt_accum = shadow_calc(il, dist_l)) > 0.0 )
  362.     {
  363.     RGBVEC    i_light;
  364.     VECTOR    unit_r;
  365.     double    cos_ln, cos_rv;
  366.  
  367.     i_light = scale_rgbvec(scale_by_distance(lights [j].i, dist_l), kt_accum);
  368.  
  369.     /* Diffuse lighting, using Lambert's law */
  370.  
  371.     if ( (cos_ln = scalar_product(unit_l, unit_n)) > 0.0 )
  372.         {
  373.         double    kd_cos_ln = surf -> kd * cos_ln;
  374.  
  375.         i.r += i_light.r * od.r * kd_cos_ln;
  376.         i.g += i_light.g * od.g * kd_cos_ln;
  377.         i.b += i_light.b * od.b * kd_cos_ln;
  378.         }
  379.  
  380.     /* Specular lighting by light source, using Phong model */
  381.  
  382.     unit_r = reflect(unit_l, unit_n, cos_ln);
  383.  
  384.     if ( (cos_rv = scalar_product(unit_r, unit_v)) > 0.0 )
  385.         {
  386.         double    ks_cos_rv_n = surf -> ks * pow(cos_rv, surf -> phong);
  387.  
  388.         i.r += i_light.r * os.r * ks_cos_rv_n;
  389.         i.g += i_light.g * os.g * ks_cos_rv_n;
  390.         i.b += i_light.b * os.b * ks_cos_rv_n;
  391.         }
  392.     }
  393. }
  394. /*...e*/
  395.  
  396.     if ( depth > 0 )
  397.         {
  398.         if ( surf -> ks > 0.0 )
  399. /*...sreflection:24:*/
  400. {
  401. double    cos_nv;
  402.  
  403. if ( (cos_nv = scalar_product(unit_n, unit_v)) > 0.0 )
  404.     {
  405.     VECTOR unit_r;
  406.     RGBVEC i_r;
  407.  
  408.     unit_r = reflect(unit_v, unit_n, cos_nv);
  409.     i_r    = trace(root_shape, isect_posn, unit_r, depth - 1, ils);
  410.  
  411.     i.r += surf -> ks * os.r * i_r.r;
  412.     i.g += surf -> ks * os.g * i_r.g;
  413.     i.b += surf -> ks * os.b * i_r.b;
  414.     }
  415. }
  416. /*...e*/
  417.         if ( surf -> kt > 0.0 )
  418. /*...srefraction:24:*/
  419. /*
  420. Refractive index of outside medium is assumed to be 1.0.
  421. Bend the ray into the medium, work out where it comes out, and bend it again.
  422. Then trace the emerging ray and accumulate its effect.
  423. If total internal reflection occurs, entering the shape, treat as reflection.
  424. If it occurs leaving, bounce the ray inside the shape and try to exit again.
  425. */
  426.  
  427. #define    MAX_BOUNCE    10
  428.  
  429. {
  430. VECTOR    unit_r;                /* Unit refracted ray at entry       */
  431.  
  432. if ( refract(unit_direction, unit_n, 1.0 / surf -> rinx, &unit_r) )
  433.     /* Refraction has occurred */
  434.     {
  435.     double    t_out;            /* Value of t where leave solid      */
  436.     SHAPE    *shape_out;        /* Shape where leave solid           */
  437.     SURF    *surf_out;        /* Surface of shape where leave      */
  438.     VECTOR    isect_posn_out;        /* Place where leave solid           */
  439.     VECTOR    unit_n_out;        /* Unit inward pointing normal       */
  440.     VECTOR    unit_r_out;        /* Unit leaving refracted ray        */
  441.     double    kt_comp = surf -> kt;    /* Composite scale down factor       */
  442.     double    t_comp = 0.0;        /* Composite/total distance inside   */
  443.     int    n_bounce = 0;        /* # of internal bounces             */
  444.  
  445.     isect_posn_out = isect_posn;
  446.     unit_r_out     = unit_r;
  447.     for ( ;; )
  448.         {
  449.         double    cos_rn;
  450.  
  451.         intersect_shape(root_shape, isect_posn_out, unit_r_out, ils);
  452.         t_after_isectl(il, EPSILON);
  453.  
  454.         t_out          = il -> isects [1].t;
  455.         shape_out      = il -> isects [1].shape;
  456.         surf_out       = shape_out -> surf;
  457.         isect_posn_out = t_along_pq(isect_posn_out, unit_r_out, t_out);
  458.         unit_n_out     = unit_vector(normal_to_shape(shape_out, isect_posn_out));
  459.  
  460.         if ( !il -> isects [1].negate_normal )
  461.             unit_n_out = negate_vector(unit_n_out);
  462.  
  463.         t_comp += t_out;
  464.  
  465.         if ( refract(unit_r_out, unit_n_out, surf_out -> rinx, &unit_r_out) )
  466.             break; /* Refracted out of solid */
  467.  
  468.         /* Total internal reflection trying to leave solid */
  469.         /* This implies the solid has an index > 1.0 */
  470.  
  471.         if ( ++n_bounce == MAX_BOUNCE )
  472.             break; /* Reached our bounce limit, give up! */
  473.  
  474.         cos_rn = scalar_product(unit_r_out, unit_n_out);
  475.         unit_r_out = reflect(negate_vector(unit_r_out), unit_n_out, -cos_rn);
  476.         kt_comp *= surf_out -> kt; /* Accumulate this as we effectively re-enter solid */
  477.         }
  478.  
  479.     if ( n_bounce < MAX_BOUNCE )
  480.         {
  481.         RGBVEC i_r;
  482.  
  483.         i_r = trace(root_shape, isect_posn_out, unit_r_out, depth - 1, ils);
  484.         i_r = scale_by_distance(i_r, t_comp);
  485.  
  486.         i.r += kt_comp * i_r.r;
  487.         i.g += kt_comp * i_r.g;
  488.         i.b += kt_comp * i_r.b;
  489.         }
  490.     }
  491. else
  492.     /* Total internal reflection trying to enter solid */
  493.     /* This implies the solid has an index < 1.0 */
  494.     /* This is not actually very likely (glass is 1.5, water 1.3 etc) */
  495.     {
  496.     double    cos_nv;
  497.  
  498.     if ( (cos_nv = scalar_product(unit_n, unit_v)) > 0.0 )
  499.         {
  500.         VECTOR u_r;
  501.         RGBVEC i_r;
  502.  
  503.         u_r = reflect(unit_v, unit_n, cos_nv);
  504.         i_r = trace(root_shape, isect_posn, u_r, depth - 1, ils);
  505.  
  506.         i.r += surf -> kt * i_r.r;
  507.         i.g += surf -> kt * i_r.g;
  508.         i.b += surf -> kt * i_r.b;
  509.         }
  510.     }
  511. }
  512. /*...e*/
  513.         }
  514.  
  515.     return ( scale_by_distance(i, t) );
  516.     }
  517. /*...e*/
  518. /*...slogging:0:*/
  519. #include <time.h>
  520.  
  521. static time_t t_start;
  522.  
  523. static void bs(int n)
  524.     {
  525.     while ( n-- )
  526.         fputc('\b', stdout);
  527.     }
  528.  
  529. static char *str_of_time(time_t t)
  530.     {
  531.     static char buf [30+1];
  532.  
  533.     strcpy(buf, ctime(&t));
  534.     buf [19] = '\0';
  535.     return ( buf + 11 );
  536.     }
  537.  
  538. static void log_init(char *fn)
  539.     {
  540.     t_start = time(NULL);
  541.  
  542.     printf("%s, started %8s,   0.0%% done, etc ________, max int 0.00 ", fn, str_of_time(t_start));
  543.     fflush(stdout);
  544.     }
  545.  
  546. static void log_done_so_far(int done, int total, double m)
  547.     {
  548.     double    percent = (100.0 * (double) done) / (double) total;
  549.     time_t    t_fin = t_start + (((time(NULL) - t_start) * total) / done);
  550.  
  551.     bs(40);
  552.     printf("%5.1lf%% done, etc %8s, max int %4.2lf ",
  553.         percent, str_of_time(t_fin), m);
  554.     fflush(stdout);
  555.     }
  556.  
  557. static void log_done(double m)
  558.     {
  559.     time_t    t_now = time(NULL);
  560.  
  561.     bs(40);
  562.     printf("done %8s, max int %4.2lf                \n",
  563.         str_of_time(t_now), m);
  564.     fflush(stdout);
  565.     }
  566. /*...e*/
  567.  
  568. static void render(
  569.     SHAPE *shape,                /* Root of shape tree        */
  570.     VECTOR eye,                /* Eye position vector       */
  571.     VECTOR forward,                /* Forward vector            */
  572.     VECTOR up,                /* Up vector                 */
  573.     double hangle, double vangle,        /* Veiwing angles            */
  574.     int hpixels, int vpixels,        /* No of pixels to render    */
  575.     int depth,                /* Depth to recurse to       */
  576.     char *fn                /* Output filename           */
  577.     )
  578.     {
  579.     BITMAP    *bitmap;
  580.     VECTOR    unit_forward, unit_up, unit_right, vis_up, vis_right;
  581.     double    hpixels2 = (double) (hpixels >> 1);
  582.     double    vpixels2 = (double) (vpixels >> 1);
  583.     int    h, v;
  584.     double    m = 0.0;
  585.     int    n_isectls, n_isects, i;
  586.     ISECTL    **ils;
  587.  
  588.     unit_forward = unit_vector(forward);
  589.     unit_up      = unit_vector(up);
  590.     unit_right   = vector_product(unit_forward, unit_up);
  591.     vis_up       = scale_vector(unit_up, tan(vangle));
  592.     vis_right    = scale_vector(unit_right, tan(hangle));
  593.  
  594.     if ( (bitmap = fio_create_bitmap(hpixels, vpixels)) == NULL )
  595.         fatal("out of memory for bitmap %dx%d", hpixels, vpixels);
  596.  
  597.     preprocess_shape(shape, &n_isectls, &n_isects);
  598.  
  599.     /* Now allocate intersection lists, for use in tracing */
  600.  
  601.     printf("Require %d intersection lists, each of %d intersections\n",
  602.         n_isectls, n_isects);
  603.     if ( (ils = malloc(n_isectls * sizeof(ISECTL *))) == NULL )
  604.         fatal("out of memory");
  605.     for ( i = 0; i < n_isectls; i++ )
  606.         if ( (ils [i] = create_isectl(n_isects)) == NULL )
  607.             fatal("out of memory");
  608.  
  609.     log_init(fn);
  610.  
  611.     for ( v = 0; v < vpixels; v++ )
  612.         {
  613.         double    vfactor = (v - vpixels2) / vpixels2;
  614.         VECTOR    comp_up, ray_plane;
  615.  
  616.         comp_up   = scale_vector(vis_up, vfactor);
  617.         ray_plane = vector_sum(unit_forward, comp_up);
  618.  
  619.         for ( h = 0; h < hpixels; h++ )
  620.             {
  621.             double    hfactor = (h - hpixels2) / hpixels2;
  622.             VECTOR    comp_right, ray;
  623.             RGBVEC    rgb;
  624.  
  625.             comp_right = scale_vector(vis_right, hfactor);
  626.             ray        = vector_sum(ray_plane, comp_right);
  627.             rgb        = trace(shape, eye, ray, depth, ils);
  628.  
  629.             if ( rgb.r > m ) m = rgb.r;
  630.             if ( rgb.g > m ) m = rgb.g;
  631.             if ( rgb.b > m ) m = rgb.b;
  632.  
  633.             if ( rgb.r > 1.0 ) rgb.r = 1.0;
  634.             if ( rgb.g > 1.0 ) rgb.g = 1.0;
  635.             if ( rgb.b > 1.0 ) rgb.b = 1.0;
  636.  
  637.             fio_set_pixel(bitmap, h, v, (byte) (rgb.r * 255.0),
  638.                             (byte) (rgb.g * 255.0),
  639.                             (byte) (rgb.b * 255.0));
  640.             }
  641.  
  642.         log_done_so_far(v + 1, vpixels, m);
  643.         }
  644.  
  645.     log_done(m);
  646.  
  647.     for ( i = 0; i < n_isectls; i++ )
  648.         destroy_isectl(ils [i]);
  649.     free(ils);
  650.  
  651.     if ( !fio_write_bitmap(bitmap, fn) )
  652.         fatal("unable to write %s", fn);
  653.  
  654.     fio_destroy_bitmap(bitmap);
  655.     }
  656. /*...e*/
  657. /*...sread_data_file:0:*/
  658. /*...slexical stuff:0:*/
  659. #define    S_EOF        0
  660. #define    S_ID        1
  661. #define    S_VALUE        2
  662. #define    S_STRING    3
  663. #define    S_COMMA        4
  664. #define    S_LPAR        5
  665. #define    S_RPAR        6
  666. #define    S_RAD        7
  667. #define    S_VECTOR    8
  668. #define    S_RGBVEC    9
  669. #define    S_COL_CONST    10
  670. #define    S_COL_NO_MOVE    11
  671. #define    S_COL_INTERP0    12
  672. #define    S_COL_INTERP1    13
  673. #define    S_COL_INTERP2    14
  674. #define    S_COL_FIELD2D    15
  675. #define    S_COL_FIELD3D    16
  676. #define    S_COL_REMAP    17
  677. #define    S_COL_CYLPOLAR    18
  678. #define    S_COL_SPHPOLAR    19
  679. #define    S_COL_MATRIX2D    20
  680. #define    S_COL_MATRIX3D    21
  681. #define    S_SURF        22
  682. #define    S_RESURF    23
  683. #define    S_PLANE        24
  684. #define    S_X_LT        25
  685. #define    S_X_GT        26
  686. #define    S_Y_LT        27
  687. #define    S_Y_GT        28
  688. #define    S_Z_LT        29
  689. #define    S_Z_GT        30
  690. #define    S_QUAD        31
  691. #define    S_ELLIPSOID    32
  692. #define    S_SPHERE    33
  693. #define    S_X_ELL_CYL    34
  694. #define    S_Y_ELL_CYL    35
  695. #define    S_Z_ELL_CYL    36
  696. #define    S_X_CYL        37
  697. #define    S_Y_CYL        38
  698. #define    S_Z_CYL        39
  699. #define    S_X_ELL_CONE    40
  700. #define    S_Y_ELL_CONE    41
  701. #define    S_Z_ELL_CONE    42
  702. #define    S_X_CONE    43
  703. #define    S_Y_CONE    44
  704. #define    S_Z_CONE    45
  705. #define    S_TRANS        46
  706. #define    S_TRANS_X    47
  707. #define    S_TRANS_Y    48
  708. #define    S_TRANS_Z    49
  709. #define    S_SCALE        50
  710. #define    S_SCALE_X    51
  711. #define    S_SCALE_Y    52
  712. #define    S_SCALE_Z    53
  713. #define    S_ROTATE_X    54
  714. #define    S_ROTATE_Y    55
  715. #define    S_ROTATE_Z    56
  716. #define    S_UNION        57
  717. #define    S_ISECT        58
  718. #define    S_DIFF        59
  719. #define    S_SDIFF        60
  720. #define    S_EXTENT    61
  721. #define    S_SET_VALUE    62
  722. #define    S_SET_VECTOR    63
  723. #define    S_SET_RGBVEC    64
  724. #define    S_SET_COL    65
  725. #define    S_SET_SURF    66
  726. #define    S_SET_SHAPE    67
  727. #define    S_SET_BKGND    68
  728. #define    S_SET_AMBIENT    69
  729. #define    S_SET_ATTEN    70
  730. #define    S_ADD_LIGHT    71
  731. #define    S_RENDER    72
  732. #define    S_INCLUDE    73
  733.  
  734. typedef struct { char *id_name; int id; } RESERVED_WORD;
  735.  
  736. static RESERVED_WORD my_reserved_words [] =
  737.     {
  738.     "rad",        S_RAD,
  739.     "xyz",        S_VECTOR,
  740.     "rgb",        S_RGBVEC,
  741.     "col",        S_COL_CONST,
  742.     "col_nomove",    S_COL_NO_MOVE,
  743.     "col_interp0",    S_COL_INTERP0,
  744.     "col_interp1",    S_COL_INTERP1,
  745.     "col_interp2",    S_COL_INTERP2,
  746.     "col_field2d",    S_COL_FIELD2D,
  747.     "col_field3d",    S_COL_FIELD3D,
  748.     "col_remap",    S_COL_REMAP,
  749.     "col_cyl",    S_COL_CYLPOLAR,
  750.     "col_sph",    S_COL_SPHPOLAR,
  751.     "col_mat2d",    S_COL_MATRIX2D,
  752.     "col_mat3d",    S_COL_MATRIX3D,
  753.     "surf",        S_SURF,
  754.     "resurf",    S_RESURF,
  755.     "plane",    S_PLANE,
  756.     "x_lt",        S_X_LT,
  757.     "x_gt",        S_X_GT,
  758.     "y_lt",        S_Y_LT,
  759.     "y_gt",        S_Y_GT,
  760.     "z_lt",        S_Z_LT,
  761.     "z_gt",        S_Z_GT,
  762.     "quad",        S_QUAD,
  763.     "ellipsoid",    S_ELLIPSOID,
  764.     "sphere",    S_SPHERE,
  765.     "x_ell_cyl",     S_X_ELL_CYL,
  766.     "y_ell_cyl",     S_Y_ELL_CYL,
  767.     "z_ell_cyl",     S_Z_ELL_CYL,
  768.     "x_cyl",     S_X_CYL,
  769.     "y_cyl",     S_Y_CYL,
  770.     "z_cyl",     S_Z_CYL,
  771.     "x_ell_cone",     S_X_ELL_CONE,
  772.     "y_ell_cone",     S_Y_ELL_CONE,
  773.     "z_ell_cone",     S_Z_ELL_CONE,
  774.     "x_cone",     S_X_CONE,
  775.     "y_cone",     S_Y_CONE,
  776.     "z_cone",     S_Z_CONE,
  777.     "trans",    S_TRANS,
  778.     "trans_x",    S_TRANS_X,
  779.     "trans_y",    S_TRANS_Y,
  780.     "trans_z",    S_TRANS_Z,
  781.     "scale",    S_SCALE,
  782.     "scale_x",    S_SCALE_X,
  783.     "scale_y",    S_SCALE_Y,
  784.     "scale_z",    S_SCALE_Z,
  785.     "rot_x",    S_ROTATE_X,
  786.     "rot_y",    S_ROTATE_Y,
  787.     "rot_z",    S_ROTATE_Z,
  788.     "union",    S_UNION,
  789.     "isect",    S_ISECT,
  790.     "diff",        S_DIFF,
  791.     "sdiff",    S_SDIFF,
  792.     "extent",    S_EXTENT,
  793.     "set_value",    S_SET_VALUE,
  794.     "set_xyz",    S_SET_VECTOR,
  795.     "set_rgb",    S_SET_RGBVEC,
  796.     "set_col",    S_SET_COL,
  797.     "set_surf",    S_SET_SURF,
  798.     "set_shape",    S_SET_SHAPE,
  799.     "set_background",S_SET_BKGND,
  800.     "set_ambient",    S_SET_AMBIENT,
  801.     "set_attenuation",S_SET_ATTEN,
  802.     "add_light",    S_ADD_LIGHT,
  803.     "render",    S_RENDER,
  804.     "include",    S_INCLUDE,
  805.     };
  806.  
  807. #define    N_RESERVED_WORDS (sizeof(my_reserved_words)/sizeof(my_reserved_words [0]))
  808.  
  809. typedef struct
  810.     {
  811.     FILE *fp;
  812.     char fn [500+1];
  813.     unsigned long line_num;
  814.     int chr;
  815.     char str [100+1];
  816.     char id_name [100+1];
  817.     double id_value;
  818.     } F;
  819.  
  820. /*...sopen_stream:0:*/
  821. static F *open_stream(FILE *fp, char *fn)
  822.     {
  823.     F *f = (F *) memcheck(malloc(sizeof(F)));
  824.  
  825.     f -> fp = fp;
  826.     f -> line_num = 1UL;
  827.     strcpy(f -> fn, fn);
  828.     f -> chr = getc(f -> fp);
  829.     return ( f );
  830.     }
  831. /*...e*/
  832. /*...sclose_stream:0:*/
  833. static FILE *close_stream(F *f)
  834.     {
  835.     FILE    *fp = f -> fp;
  836.  
  837.     free(f);
  838.     return ( fp );
  839.     }
  840. /*...e*/
  841. /*...sreaderr:0:*/
  842. static void readerr(F *f, const char *fmt, ...)
  843.     {
  844.     va_list    vars;
  845.     char    s [256+1];
  846.  
  847.     va_start(vars, fmt);
  848.     vsprintf(s, fmt, vars);
  849.     va_end(vars);
  850.     fprintf(stderr, "%s(%lu): %s\n", f -> fn, f -> line_num, s);
  851.     exit(1);
  852.     }
  853. /*...e*/
  854. /*...sgetsym:0:*/
  855. static int getsym(F *f)
  856.     {
  857.     int    i = 0;
  858.  
  859.     for ( ;; )
  860.         {
  861.         while ( f -> chr != EOF && isspace(f -> chr) )
  862.             {
  863.             if ( f -> chr == '\n' )
  864.                 f -> line_num++;
  865.             f -> chr = getc(f -> fp);
  866.             }
  867.  
  868.         if ( f -> chr == EOF )
  869.             return ( S_EOF );
  870.  
  871.         if ( f -> chr != ';' )
  872.             break;
  873.  
  874.         while ( (f -> chr = getc(f -> fp)) != EOF && f -> chr != '\n' )
  875.             if ( f -> chr == '\n' )
  876.                 f -> line_num++;
  877.         }
  878.  
  879.     if ( f -> chr == ',' )
  880.         {
  881.         f -> chr = getc(f -> fp);
  882.         return ( S_COMMA );
  883.         }
  884.  
  885.     if ( f -> chr == '(' )
  886.         {
  887.         f -> chr = getc(f -> fp);
  888.         return ( S_LPAR );
  889.         }
  890.  
  891.     if ( f -> chr == ')' )
  892.         {
  893.         f -> chr = getc(f -> fp);
  894.         return ( S_RPAR );
  895.         }
  896.  
  897.     if ( isdigit(f -> chr) || f -> chr == '+' || f -> chr == '-' || f -> chr == '.' )
  898.         {
  899.         char    num [50+1];
  900.  
  901.         do
  902.             {
  903.             num [i++] = (char) f -> chr;
  904.             f -> chr = getc(f -> fp);
  905.             }
  906.         while ( isdigit(f -> chr) || f -> chr == '+' || f -> chr == '-' ||
  907.             f -> chr == '.' || f -> chr == 'e' || f -> chr == 'E' );
  908.         num [i] = (char) '\0';
  909.  
  910.         sscanf(num, "%lf", &(f -> id_value));
  911.  
  912.         return ( S_VALUE );
  913.         }
  914.  
  915.     if ( f -> chr == '"' )
  916.         {
  917.         int    j = 0;
  918.  
  919.         while ( (f -> chr = getc(f -> fp)) != EOF && f -> chr != '"' )
  920.             f -> str [j++] = (char) f -> chr;
  921.         f -> str [j] = '\0';
  922.         if ( f -> chr == '"' )
  923.             f -> chr = getc(f -> fp);
  924.         return ( S_STRING );
  925.         }
  926.  
  927.     if ( !(isalnum(f -> chr) || f -> chr != '_') )
  928.         readerr(f, "character 0x%02x not expected", f -> chr);
  929.  
  930.     while ( f -> chr != EOF && (isalnum(f -> chr) || f -> chr == '_') )
  931.         {
  932.         f -> id_name [i++] = (char) f -> chr;
  933.         f -> chr = getc(f -> fp);
  934.         }
  935.     f -> id_name [i] = '\0';
  936.  
  937.     for ( i = 0; i < N_RESERVED_WORDS; i++ )
  938.         if ( !strcmp(f -> id_name, my_reserved_words [i].id_name) )
  939.             return ( my_reserved_words [i].id );
  940.  
  941.     return ( S_ID );
  942.     }
  943. /*...e*/
  944. /*...sskip:0:*/
  945. static void skip(F *f, int symbol, char *symbol_name)
  946.     {
  947.     if ( getsym(f) != symbol )
  948.         readerr(f, "expected %s", symbol_name);
  949.     }
  950. /*...e*/
  951. /*...e*/
  952. /*...suser variables:0:*/
  953. typedef byte VTYPE;
  954. #define    VTYPE_VALUE    ((VTYPE) 0)
  955. #define    VTYPE_VECTOR    ((VTYPE) 1)
  956. #define    VTYPE_RGBVEC    ((VTYPE) 2)
  957. #define    VTYPE_COL    ((VTYPE) 3)
  958. #define    VTYPE_SURF    ((VTYPE) 4)
  959. #define    VTYPE_SHAPE    ((VTYPE) 5)
  960.  
  961. static char *vtype_names [] =
  962.     {
  963.     "value",
  964.     "xyz_vector",
  965.     "rgb_vector",
  966.     "colour",
  967.     "surface",
  968.     "shape",
  969.     };
  970.  
  971. typedef struct
  972.     {
  973.     char    *name;
  974.     VTYPE    vtype;
  975.     union
  976.         {
  977.         double    value;
  978.         VECTOR    vector;
  979.         RGBVEC    rgb;
  980.         COL    *col;
  981.         SURF    *surf;
  982.         SHAPE    *shape;
  983.         } u;
  984.     } VAR;
  985.  
  986. #define    N_VARS        500
  987. static VAR vars [N_VARS];
  988. static int n_vars = 0;
  989.  
  990. /*...slookup_var:0:*/
  991. static int lookup_var(char *name)
  992.     {
  993.     int    i;
  994.  
  995.     for ( i = 0; i < n_vars; i++ )
  996.         if ( !strcmp(name, vars [i].name) )
  997.             return ( i );
  998.     return ( -1 );
  999.     }
  1000. /*...e*/
  1001. /*...slookup_defined_var:0:*/
  1002. static int lookup_defined_var(F *f, char *name)
  1003.     {
  1004.     int    i;
  1005.  
  1006.     if ( (i = lookup_var(name)) == -1 )
  1007.         readerr(f, "undefined variable %s", name);
  1008.     return ( i );
  1009.     }
  1010. /*...e*/
  1011. /*...slookup_defined_var_vtype:0:*/
  1012. static int lookup_defined_var_vtype(F *f, char *name, VTYPE vtype)
  1013.     {
  1014.     int    i = lookup_defined_var(f, name);
  1015.  
  1016.     if ( vars [i].vtype != vtype )
  1017.         readerr(f, "expected %s variable", vtype_names [vtype]);
  1018.     return ( i );
  1019.     }
  1020. /*...e*/
  1021.  
  1022. /*...sadd_value_var:0:*/
  1023. static void add_value_var(F *f, char *name, double value)
  1024.     {
  1025.     if ( n_vars == N_VARS )
  1026.         readerr(f, "too many variables");
  1027.  
  1028.     vars [n_vars  ].name    = strsave(name);
  1029.     vars [n_vars  ].vtype   = VTYPE_VALUE;
  1030.     vars [n_vars++].u.value = value;
  1031.     }
  1032. /*...e*/
  1033. /*...sadd_vector_var:0:*/
  1034. static void add_vector_var(F *f, char *name, VECTOR vector)
  1035.     {
  1036.     if ( n_vars == N_VARS )
  1037.         readerr(f, "too many variables");
  1038.  
  1039.     vars [n_vars  ].name     = strsave(name);
  1040.     vars [n_vars  ].vtype    = VTYPE_VECTOR;
  1041.     vars [n_vars++].u.vector = vector;
  1042.     }
  1043. /*...e*/
  1044. /*...sadd_rgb_var:0:*/
  1045. static void add_rgb_var(F *f, char *name, RGBVEC rgb)
  1046.     {
  1047.     if ( n_vars == N_VARS )
  1048.         readerr(f, "too many variables");
  1049.  
  1050.     vars [n_vars  ].name  = strsave(name);
  1051.     vars [n_vars  ].vtype = VTYPE_RGBVEC;
  1052.     vars [n_vars++].u.rgb = rgb;
  1053.     }
  1054. /*...e*/
  1055. /*...sadd_col_var:0:*/
  1056. static void add_col_var(F *f, char *name, COL *col)
  1057.     {
  1058.     if ( n_vars == N_VARS )
  1059.         readerr(f, "too many variables");
  1060.  
  1061.     vars [n_vars  ].name  = strsave(name);
  1062.     vars [n_vars  ].vtype = VTYPE_COL;
  1063.     vars [n_vars++].u.col = col;
  1064.     }
  1065. /*...e*/
  1066. /*...sadd_surf_var:0:*/
  1067. static void add_surf_var(F *f, char *name, SURF *surf)
  1068.     {
  1069.     if ( n_vars == N_VARS )
  1070.         readerr(f, "too many variables");
  1071.  
  1072.     vars [n_vars  ].name   = strsave(name);
  1073.     vars [n_vars  ].vtype  = VTYPE_SURF;
  1074.     vars [n_vars++].u.surf = surf;
  1075.     }
  1076. /*...e*/
  1077. /*...sadd_shape_var:0:*/
  1078. static void add_shape_var(F *f, char *name, SHAPE *shape)
  1079.     {
  1080.     if ( n_vars == N_VARS )
  1081.         readerr(f, "too many variables");
  1082.  
  1083.     vars [n_vars  ].name    = strsave(name);
  1084.     vars [n_vars  ].vtype   = VTYPE_SHAPE;
  1085.     vars [n_vars++].u.shape = shape;
  1086.     }
  1087. /*...e*/
  1088. /*...e*/
  1089.  
  1090. static void read_data_file(char *fn);
  1091.  
  1092. /*...sget_file:0:*/
  1093. /*...sget_new_id:0:*/
  1094. static void get_new_id(F *f, char *name)
  1095.     {
  1096.     if ( getsym(f) != S_ID )
  1097.         readerr(f, "expected new identifier");
  1098.  
  1099.     strncpy(name, f -> id_name, 30);
  1100.  
  1101.     if ( lookup_var(name) != -1 )
  1102.         readerr(f, "redefinition of identifier %s", name);
  1103.     }
  1104. /*...e*/
  1105. /*...sget_value:0:*/
  1106. static double get_value(F *f)
  1107.     {
  1108.     switch ( getsym(f) )
  1109.         {
  1110.         case S_VALUE:
  1111.             return ( f -> id_value );
  1112.         case S_ID:
  1113.             return ( vars [lookup_defined_var_vtype(f, f -> id_name, VTYPE_VALUE)].u.value );
  1114.         case S_RAD:
  1115.             {
  1116.             double    value;
  1117.  
  1118.             skip(f, S_LPAR, "(");
  1119.             value = get_value(f);
  1120.             skip(f, S_RPAR, ")");
  1121.             return ( value * PI / 180.0 );
  1122.             }
  1123.         default:
  1124.             readerr(f, "number or numeric variable expected");
  1125.         }
  1126.     return ( 0.0 ); /* Keep fussy C compiler happy */
  1127.     }
  1128. /*...e*/
  1129. /*...sget_vector:0:*/
  1130. static VECTOR get_vector(F *f)
  1131.     {
  1132.     static VECTOR dummy_vector = { 0.0, 0.0, 0.0 };
  1133.  
  1134.     switch ( getsym(f) )
  1135.         {
  1136. /*...sS_VECTOR:16:*/
  1137. case S_VECTOR:
  1138.     {
  1139.     VECTOR    vector;
  1140.  
  1141.     skip(f, S_LPAR , "("); vector.x = get_value(f);
  1142.     skip(f, S_COMMA, ","); vector.y = get_value(f);
  1143.     skip(f, S_COMMA, ","); vector.z = get_value(f);
  1144.     skip(f, S_RPAR , ")");
  1145.     return ( vector );
  1146.     }
  1147. /*...e*/
  1148. /*...sS_TRANS:16:*/
  1149. case S_TRANS:
  1150.     {
  1151.     VECTOR v, t;
  1152.  
  1153.     skip(f, S_LPAR , "("); v = get_vector(f);
  1154.     skip(f, S_COMMA, ","); t = get_vector(f);
  1155.     skip(f, S_RPAR , ")");
  1156.     return ( vector_sum(v, t) );
  1157.     }
  1158. /*...e*/
  1159. /*...sS_TRANS_X:16:*/
  1160. case S_TRANS_X:
  1161.     {
  1162.     VECTOR v;
  1163.     double t;
  1164.  
  1165.     skip(f, S_LPAR , "("); v = get_vector(f);
  1166.     skip(f, S_COMMA, ","); t = get_value(f);
  1167.     skip(f, S_RPAR , ")");
  1168.     v.x += t;
  1169.     return ( v );
  1170.     }
  1171. /*...e*/
  1172. /*...sS_TRANS_Y:16:*/
  1173. case S_TRANS_Y:
  1174.     {
  1175.     VECTOR v;
  1176.     double t;
  1177.  
  1178.     skip(f, S_LPAR , "("); v = get_vector(f);
  1179.     skip(f, S_COMMA, ","); t = get_value(f);
  1180.     skip(f, S_RPAR , ")");
  1181.     v.y += t;
  1182.     return ( v );
  1183.     }
  1184. /*...e*/
  1185. /*...sS_TRANS_Z:16:*/
  1186. case S_TRANS_Z:
  1187.     {
  1188.     VECTOR v;
  1189.     double t;
  1190.  
  1191.     skip(f, S_LPAR , "("); v = get_vector(f);
  1192.     skip(f, S_COMMA, ","); t = get_value(f);
  1193.     skip(f, S_RPAR , ")");
  1194.     v.z += t;
  1195.     return ( v );
  1196.     }
  1197. /*...e*/
  1198. /*...sS_SCALE:16:*/
  1199. case S_SCALE:
  1200.     {
  1201.     VECTOR v, factor;
  1202.  
  1203.     skip(f, S_LPAR , "("); v      = get_vector(f);
  1204.     skip(f, S_COMMA, ","); factor = get_vector(f);
  1205.     skip(f, S_RPAR , ")");
  1206.     v.x *= factor.x;
  1207.     v.y *= factor.y;
  1208.     v.z *= factor.z;
  1209.     return ( v );
  1210.     }
  1211. /*...e*/
  1212. /*...sS_SCALE_X:16:*/
  1213. case S_SCALE_X:
  1214.     {
  1215.     VECTOR v;
  1216.     double factor;
  1217.  
  1218.     skip(f, S_LPAR , "("); v      = get_vector(f);
  1219.     skip(f, S_COMMA, ","); factor = get_value(f);
  1220.     skip(f, S_RPAR , ")");
  1221.     v.x *= factor;
  1222.     return ( v );
  1223.     }
  1224. /*...e*/
  1225. /*...sS_SCALE_Y:16:*/
  1226. case S_SCALE_Y:
  1227.     {
  1228.     VECTOR v;
  1229.     double factor;
  1230.  
  1231.     skip(f, S_LPAR , "("); v      = get_vector(f);
  1232.     skip(f, S_COMMA, ","); factor = get_value(f);
  1233.     skip(f, S_RPAR , ")");
  1234.     v.y *= factor;
  1235.     return ( v );
  1236.     }
  1237. /*...e*/
  1238. /*...sS_SCALE_Z:16:*/
  1239. case S_SCALE_Z:
  1240.     {
  1241.     VECTOR v;
  1242.     double factor;
  1243.  
  1244.     skip(f, S_LPAR , "("); v      = get_vector(f);
  1245.     skip(f, S_COMMA, ","); factor = get_value(f);
  1246.     skip(f, S_RPAR , ")");
  1247.     v.z *= factor;
  1248.     return ( v );
  1249.     }
  1250. /*...e*/
  1251. /*...sS_ROTATE_X:16:*/
  1252. case S_ROTATE_X:
  1253.     {
  1254.     VECTOR v;
  1255.     double angle;
  1256.  
  1257.     skip(f, S_LPAR , "("); v = get_vector(f);
  1258.     skip(f, S_COMMA, ","); angle = get_value(f);
  1259.     skip(f, S_RPAR , ")");
  1260.     return ( rot_x_vector(v, angle) );
  1261.     }
  1262. /*...e*/
  1263. /*...sS_ROTATE_Y:16:*/
  1264. case S_ROTATE_Y:
  1265.     {
  1266.     VECTOR v;
  1267.     double angle;
  1268.  
  1269.     skip(f, S_LPAR , "("); v = get_vector(f);
  1270.     skip(f, S_COMMA, ","); angle = get_value(f);
  1271.     skip(f, S_RPAR , ")");
  1272.     return ( rot_y_vector(v, angle) );
  1273.     }
  1274. /*...e*/
  1275. /*...sS_ROTATE_Z:16:*/
  1276. case S_ROTATE_Z:
  1277.     {
  1278.     VECTOR v;
  1279.     double angle;
  1280.  
  1281.     skip(f, S_LPAR , "("); v = get_vector(f);
  1282.     skip(f, S_COMMA, ","); angle = get_value(f);
  1283.     skip(f, S_RPAR , ")");
  1284.     return ( rot_z_vector(v, angle) );
  1285.     }
  1286. /*...e*/
  1287. /*...sS_ID:16:*/
  1288. case S_ID:
  1289.     return ( vars [lookup_defined_var_vtype(f, f -> id_name, VTYPE_VECTOR)].u.vector );
  1290. /*...e*/
  1291. /*...sdefault:16:*/
  1292. default:
  1293.     readerr(f, "vector expected");
  1294. /*...e*/
  1295.         }
  1296.     return ( dummy_vector ); /* Keep fussy C compiler happy */
  1297.     }
  1298. /*...e*/
  1299. /*...sget_rgb:0:*/
  1300. static RGBVEC get_rgb(F *f)
  1301.     {
  1302.     static RGBVEC dummy_rgbvec = { 0.0, 0.0, 0.0 };
  1303.  
  1304.     switch ( getsym(f) )
  1305.         {
  1306.         case S_RGBVEC:
  1307.             {
  1308.             RGBVEC    rgb;
  1309.  
  1310.             skip(f, S_LPAR , "("); rgb.r = get_value(f);
  1311.             skip(f, S_COMMA, ","); rgb.g = get_value(f);
  1312.             skip(f, S_COMMA, ","); rgb.b = get_value(f);
  1313.             skip(f, S_RPAR , ")");
  1314.             return ( rgb );
  1315.             }
  1316.         case S_ID:
  1317.             return ( vars [lookup_defined_var_vtype(f, f -> id_name, VTYPE_RGBVEC)].u.rgb );
  1318.         default:
  1319.             readerr(f, "rgb colour vector expected");
  1320.         }
  1321.  
  1322.     return ( dummy_rgbvec ); /* Keep fussy C compiler happy */
  1323.     }
  1324. /*...e*/
  1325. /*...sget_col:0:*/
  1326. /*
  1327. This returns a colour.
  1328. If it comes from a user variable, then a copy of the variable is returned.
  1329. If not, then the new datastructure is returned.
  1330. */
  1331.  
  1332. static COL *get_col(F *f)
  1333.     {
  1334.     switch ( getsym(f) )
  1335.         {
  1336. /*...sS_COL_CONST:16:*/
  1337. case S_COL_CONST:
  1338.     {
  1339.     RGBVEC rgbvec;
  1340.  
  1341.     skip(f, S_LPAR , "("); rgbvec = get_rgb(f);
  1342.     skip(f, S_RPAR , ")");
  1343.     return ( memcheck(create_const_col(rgbvec)) );
  1344.     }
  1345. /*...e*/
  1346. /*...sS_COL_NO_MOVE:16:*/
  1347. case S_COL_NO_MOVE:
  1348.     {
  1349.     COL *col;
  1350.  
  1351.     skip(f, S_LPAR , "("); col = get_col(f);
  1352.     skip(f, S_RPAR , ")");
  1353.  
  1354.     return ( memcheck(create_no_move_col(col)) );
  1355.     }
  1356. /*...e*/
  1357. /*...sS_COL_INTERP0:16:*/
  1358. case S_COL_INTERP0:
  1359.     {
  1360.     COL *col;
  1361.  
  1362.     skip(f, S_LPAR , "("); col = get_col(f);
  1363.     skip(f, S_RPAR , ")");
  1364.  
  1365.     return ( memcheck(create_interp0_col(col)) );
  1366.     }
  1367. /*...e*/
  1368. /*...sS_COL_INTERP1:16:*/
  1369. case S_COL_INTERP1:
  1370.     {
  1371.     COL *col;
  1372.  
  1373.     skip(f, S_LPAR , "("); col = get_col(f);
  1374.     skip(f, S_RPAR , ")");
  1375.  
  1376.     return ( memcheck(create_interp1_col(col)) );
  1377.     }
  1378. /*...e*/
  1379. /*...sS_COL_INTERP2:16:*/
  1380. case S_COL_INTERP2:
  1381.     {
  1382.     COL *col;
  1383.  
  1384.     skip(f, S_LPAR , "("); col = get_col(f);
  1385.     skip(f, S_RPAR , ")");
  1386.  
  1387.     return ( memcheck(create_interp2_col(col)) );
  1388.     }
  1389. /*...e*/
  1390. /*...sS_COL_FIELD2D:16:*/
  1391. case S_COL_FIELD2D:
  1392.     {
  1393.     double bx, by;
  1394.     BITMAP *bitmap;
  1395.  
  1396.     skip(f, S_LPAR , "("); bx = get_value(f);
  1397.     skip(f, S_COMMA, ","); by = get_value(f);
  1398.     skip(f, S_COMMA, ",");
  1399.  
  1400.     if ( getsym(f) != S_STRING )
  1401.         readerr(f, "expected input bitmap filename");
  1402.  
  1403.     if ( (bitmap = fio_read_bitmap(f -> str)) == NULL )
  1404.         readerr(f, "unable to read bitmap %s", f -> str);
  1405.  
  1406.     skip(f, S_RPAR , ")");
  1407.     return ( memcheck(create_2d_field_col(bx, by, bitmap)) );
  1408.     }
  1409. /*...e*/
  1410. /*...sS_COL_FIELD3D:16:*/
  1411. case S_COL_FIELD3D:
  1412.     {
  1413.     double bx, by, bz;
  1414.     TEX *tex;
  1415.  
  1416.     skip(f, S_LPAR , "("); bx = get_value(f);
  1417.     skip(f, S_COMMA, ","); by = get_value(f);
  1418.     skip(f, S_COMMA, ","); bz = get_value(f);
  1419.     skip(f, S_COMMA, ",");
  1420.  
  1421.     if ( getsym(f) != S_STRING )
  1422.         readerr(f, "expected input 3d texture-map filename");
  1423.  
  1424.     if ( (tex = read_tex(f -> str)) == NULL )
  1425.         readerr(f, "unable to read 3d texture-map %s", f -> str);
  1426.  
  1427.     skip(f, S_RPAR , ")");
  1428.     return ( memcheck(create_3d_field_col(bx, by, bz, tex)) );
  1429.     }
  1430. /*...e*/
  1431. /*...sS_COL_REMAP:16:*/
  1432. case S_COL_REMAP:
  1433.     {
  1434.     VECTOR base, v0, v1, v2;
  1435.     COL *col;
  1436.  
  1437.     skip(f, S_LPAR , "("); base = get_vector(f);
  1438.     skip(f, S_COMMA, ","); v0   = get_vector(f);
  1439.     skip(f, S_COMMA, ","); v1   = get_vector(f);
  1440.     skip(f, S_COMMA, ","); v2   = get_vector(f);
  1441.     skip(f, S_COMMA, ","); col  = get_col(f);
  1442.     skip(f, S_RPAR , ")");
  1443.     return ( memcheck(create_remap_col(base, v0, v1, v2, col)) );
  1444.     }
  1445. /*...e*/
  1446. /*...sS_COL_CYLPOLAR:16:*/
  1447. case S_COL_CYLPOLAR:
  1448.     {
  1449.     double lond, rd, hd;
  1450.     COL *col;
  1451.  
  1452.     skip(f, S_LPAR , "("); lond = get_value(f);
  1453.     skip(f, S_COMMA, ","); rd   = get_value(f);
  1454.     skip(f, S_COMMA, ","); hd   = get_value(f);
  1455.     skip(f, S_COMMA, ","); col  = get_col(f);
  1456.     skip(f, S_RPAR , ")");
  1457.  
  1458.     return ( memcheck(create_cyl_polar_col(lond, rd, hd, col)) );
  1459.     }
  1460. /*...e*/
  1461. /*...sS_COL_SPHPOLAR:16:*/
  1462. case S_COL_SPHPOLAR:
  1463.     {
  1464.     double lond, latd, rd;
  1465.     COL *col;
  1466.  
  1467.     skip(f, S_LPAR , "("); lond = get_value(f);
  1468.     skip(f, S_COMMA, ","); latd = get_value(f);
  1469.     skip(f, S_COMMA, ","); rd   = get_value(f);
  1470.     skip(f, S_COMMA, ","); col  = get_col(f);
  1471.     skip(f, S_RPAR , ")");
  1472.  
  1473.     return ( memcheck(create_sph_polar_col(lond, latd, rd, col)) );
  1474.     }
  1475. /*...e*/
  1476. /*...sS_COL_MATRIX2D:16:*/
  1477. case S_COL_MATRIX2D:
  1478.     {
  1479.     double m [2][2];
  1480.     int i, j;
  1481.     COL *col;
  1482.  
  1483.     skip(f, S_LPAR , "(");
  1484.     for ( j = 0; j < 2; j++ )
  1485.         for ( i = 0; i < 2; i++ )
  1486.             {
  1487.             m [j][i] = get_value(f);
  1488.             skip(f, S_COMMA, ",");
  1489.             }
  1490.     col = get_col(f);
  1491.     skip(f, S_RPAR , ")");
  1492.  
  1493.     return ( memcheck(create_2d_matrix_col(m, col)) );
  1494.     }
  1495. /*...e*/
  1496. /*...sS_COL_MATRIX3D:16:*/
  1497. case S_COL_MATRIX3D:
  1498.     {
  1499.     double m [3][3];
  1500.     int i, j;
  1501.     COL *col;
  1502.  
  1503.     skip(f, S_LPAR , "(");
  1504.     for ( j = 0; j < 3; j++ )
  1505.         for ( i = 0; i < 3; i++ )
  1506.             {
  1507.             m [j][i] = get_value(f);
  1508.             skip(f, S_COMMA, ",");
  1509.             }
  1510.     col = get_col(f);
  1511.     skip(f, S_RPAR , ")");
  1512.  
  1513.     return ( memcheck(create_3d_matrix_col(m, col)) );
  1514.     }
  1515. /*...e*/
  1516. /*...sS_ID:16:*/
  1517. case S_ID:
  1518.     {
  1519.     COL *col = vars [lookup_defined_var_vtype(f, f -> id_name, VTYPE_COL)].u.col;
  1520.  
  1521.     return ( memcheck(copy_col(col)) );
  1522.     }
  1523. /*...e*/
  1524. /*...sdefault:16:*/
  1525. default:
  1526.     readerr(f, "colour definition or colour variable expected");
  1527. /*...e*/
  1528.         }
  1529.     return ( NULL ); /* Keep fussy C compiler happy */
  1530.     }
  1531. /*...e*/
  1532. /*...sget_surf:0:*/
  1533. /*
  1534. This returns a surface.
  1535. If it comes from a user variable, then a copy of the variable is returned.
  1536. If not, then the new datastructure is returned.
  1537. */
  1538.  
  1539. static SURF *get_surf(F *f)
  1540.     {
  1541.     switch ( getsym(f) )
  1542.         {
  1543.         case S_SURF:
  1544.             {
  1545.             double    ka, kd, ks, kt;
  1546.             COL    *od, *os;
  1547.             double    phong, rinx;
  1548.  
  1549.             skip(f, S_LPAR , "("); ka    = get_value(f);
  1550.             skip(f, S_COMMA, ","); kd    = get_value(f);
  1551.             skip(f, S_COMMA, ","); ks    = get_value(f);
  1552.             skip(f, S_COMMA, ","); kt    = get_value(f);
  1553.             skip(f, S_COMMA, ","); od    = get_col(f);
  1554.             skip(f, S_COMMA, ","); os    = get_col(f);
  1555.             skip(f, S_COMMA, ","); phong = get_value(f);
  1556.             skip(f, S_COMMA, ","); rinx  = get_value(f);
  1557.             skip(f, S_RPAR , ")");
  1558.  
  1559.             return ( memcheck(create_surf(ka, kd, ks, kt, od, os, phong, rinx)) );
  1560.             }
  1561.         case S_ID:
  1562.             {
  1563.             SURF *surf = vars [lookup_defined_var_vtype(f, f -> id_name, VTYPE_SURF)].u.surf;
  1564.  
  1565.             return ( memcheck(copy_surf(surf)) );
  1566.             }
  1567.         default:
  1568.             readerr(f, "surface definition or surface variable expected");
  1569.         }
  1570.     return ( NULL ); /* Keep fussy C compiler happy */
  1571.     }
  1572. /*...e*/
  1573. /*...sget_shape:0:*/
  1574. /*
  1575. This returns a shape.
  1576. If it comes from a user variable, then a copy of the variable is returned.
  1577. If not, then the new datastructure is returned.
  1578. */
  1579.  
  1580. static SHAPE *get_shape(F *f)
  1581.     {
  1582.     switch ( getsym(f) )
  1583.         {
  1584. /*...sS_PLANE:16:*/
  1585. case S_PLANE:
  1586.     {
  1587.     double    a, b, c, d;
  1588.     SURF    *surf;
  1589.  
  1590.     skip(f, S_LPAR , "("); a = get_value(f);
  1591.     skip(f, S_COMMA, ","); b = get_value(f);
  1592.     skip(f, S_COMMA, ","); c = get_value(f);
  1593.     skip(f, S_COMMA, ","); d = get_value(f);
  1594.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1595.     skip(f, S_RPAR , ")");
  1596.     return ( memcheck(create_plane_shape(memcheck(create_plane(a, b, c, d)), surf)) );
  1597.     }
  1598. /*...e*/
  1599. /*...sS_X_LT:16:*/
  1600. case S_X_LT:
  1601.     {
  1602.     double    x;
  1603.     SURF    *surf;
  1604.  
  1605.     skip(f, S_LPAR , "("); x = get_value(f);
  1606.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1607.     skip(f, S_RPAR , ")");
  1608.     return ( memcheck(create_plane_shape(memcheck(create_x_lt_plane(x)), surf)) );
  1609.     }
  1610. /*...e*/
  1611. /*...sS_X_GT:16:*/
  1612. case S_X_GT:
  1613.     {
  1614.     double    x;
  1615.     SURF    *surf;
  1616.  
  1617.     skip(f, S_LPAR , "("); x = get_value(f);
  1618.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1619.     skip(f, S_RPAR , ")");
  1620.     return ( memcheck(create_plane_shape(memcheck(create_x_gt_plane(x)), surf)) );
  1621.     }
  1622. /*...e*/
  1623. /*...sS_Y_LT:16:*/
  1624. case S_Y_LT:
  1625.     {
  1626.     double    y;
  1627.     SURF    *surf;
  1628.  
  1629.     skip(f, S_LPAR , "("); y = get_value(f);
  1630.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1631.     skip(f, S_RPAR , ")");
  1632.     return ( memcheck(create_plane_shape(memcheck(create_y_lt_plane(y)), surf)) );
  1633.     }
  1634. /*...e*/
  1635. /*...sS_Y_GT:16:*/
  1636. case S_Y_GT:
  1637.     {
  1638.     double    y;
  1639.     SURF    *surf;
  1640.  
  1641.     skip(f, S_LPAR , "("); y = get_value(f);
  1642.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1643.     skip(f, S_RPAR , ")");
  1644.     return ( memcheck(create_plane_shape(memcheck(create_y_gt_plane(y)), surf)) );
  1645.     }
  1646. /*...e*/
  1647. /*...sS_Z_LT:16:*/
  1648. case S_Z_LT:
  1649.     {
  1650.     double    z;
  1651.     SURF    *surf;
  1652.  
  1653.     skip(f, S_LPAR , "("); z = get_value(f);
  1654.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1655.     skip(f, S_RPAR , ")");
  1656.     return ( memcheck(create_plane_shape(memcheck(create_z_lt_plane(z)), surf)) );
  1657.     }
  1658. /*...e*/
  1659. /*...sS_Z_GT:16:*/
  1660. case S_Z_GT:
  1661.     {
  1662.     double    z;
  1663.     SURF    *surf;
  1664.  
  1665.     skip(f, S_LPAR , "("); z = get_value(f);
  1666.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1667.     skip(f, S_RPAR , ")");
  1668.     return ( memcheck(create_plane_shape(memcheck(create_z_gt_plane(z)), surf)) );
  1669.     }
  1670. /*...e*/
  1671. /*...sS_SPHERE:16:*/
  1672. case S_SPHERE:
  1673.     {
  1674.     double    r;
  1675.     SURF    *surf;
  1676.  
  1677.     skip(f, S_LPAR , "("); r = get_value(f);
  1678.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1679.     skip(f, S_RPAR , ")");
  1680.     return ( memcheck(create_sphere_shape(memcheck(create_sphere(r)), surf)) );
  1681.     }
  1682. /*...e*/
  1683. /*...sS_QUAD:16:*/
  1684. case S_QUAD:
  1685.     {
  1686.     double    a, b, c, d, e, ff, g, h, i, j;
  1687.     SURF    *surf;
  1688.  
  1689.     skip(f, S_LPAR , "("); a  = get_value(f);
  1690.     skip(f, S_COMMA, ","); b  = get_value(f);
  1691.     skip(f, S_COMMA, ","); c  = get_value(f);
  1692.     skip(f, S_COMMA, ","); d  = get_value(f);
  1693.     skip(f, S_COMMA, ","); e  = get_value(f);
  1694.     skip(f, S_COMMA, ","); ff = get_value(f);
  1695.     skip(f, S_COMMA, ","); g  = get_value(f);
  1696.     skip(f, S_COMMA, ","); h  = get_value(f);
  1697.     skip(f, S_COMMA, ","); i  = get_value(f);
  1698.     skip(f, S_COMMA, ","); j  = get_value(f);
  1699.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1700.     skip(f, S_RPAR , ")");
  1701.     return ( memcheck(create_quad_shape(memcheck(create_quad(a, b, c, d, e, ff, g, h, i, j)), surf)) );
  1702.     }
  1703. /*...e*/
  1704. /*...sS_ELLIPSOID:16:*/
  1705. case S_ELLIPSOID:
  1706.     {
  1707.     double    rx, ry, rz;
  1708.     SURF    *surf;
  1709.  
  1710.     skip(f, S_LPAR , "("); rx = get_value(f);
  1711.     skip(f, S_COMMA, ","); ry = get_value(f);
  1712.     skip(f, S_COMMA, ","); rz = get_value(f);
  1713.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1714.     skip(f, S_RPAR , ")");
  1715.     return ( memcheck(create_quad_shape(memcheck(create_ellipsoid(rx, ry, rz)), surf)) );
  1716.     }
  1717. /*...e*/
  1718. /*...sS_X_ELL_CYL:16:*/
  1719. case S_X_ELL_CYL:
  1720.     {
  1721.     double    ry, rz;
  1722.     SURF    *surf;
  1723.  
  1724.     skip(f, S_LPAR , "("); ry = get_value(f);
  1725.     skip(f, S_COMMA, ","); rz = get_value(f);
  1726.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1727.     skip(f, S_RPAR , ")");
  1728.     return ( memcheck(create_quad_shape(memcheck(create_x_ell_cyl(ry, rz)), surf)) );
  1729.     }
  1730. /*...e*/
  1731. /*...sS_Y_ELL_CYL:16:*/
  1732. case S_Y_ELL_CYL:
  1733.     {
  1734.     double    rx, rz;
  1735.     SURF    *surf;
  1736.  
  1737.     skip(f, S_LPAR , "("); rx = get_value(f);
  1738.     skip(f, S_COMMA, ","); rz = get_value(f);
  1739.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1740.     skip(f, S_RPAR , ")");
  1741.     return ( memcheck(create_quad_shape(memcheck(create_y_ell_cyl(rx, rz)), surf)) );
  1742.     }
  1743. /*...e*/
  1744. /*...sS_Z_ELL_CYL:16:*/
  1745. case S_Z_ELL_CYL:
  1746.     {
  1747.     double    rx, ry;
  1748.     SURF    *surf;
  1749.  
  1750.     skip(f, S_LPAR , "("); rx = get_value(f);
  1751.     skip(f, S_COMMA, ","); ry = get_value(f);
  1752.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1753.     skip(f, S_RPAR , ")");
  1754.     return ( memcheck(create_quad_shape(memcheck(create_z_ell_cyl(rx, ry)), surf)) );
  1755.     }
  1756. /*...e*/
  1757. /*...sS_X_CYL:16:*/
  1758. case S_X_CYL:
  1759.     {
  1760.     double    r;
  1761.     SURF    *surf;
  1762.  
  1763.     skip(f, S_LPAR , "("); r = get_value(f);
  1764.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1765.     skip(f, S_RPAR , ")");
  1766.     return ( memcheck(create_quad_shape(memcheck(create_x_cyl(r)), surf)) );
  1767.     }
  1768. /*...e*/
  1769. /*...sS_Y_CYL:16:*/
  1770. case S_Y_CYL:
  1771.     {
  1772.     double    r;
  1773.     SURF    *surf;
  1774.  
  1775.     skip(f, S_LPAR , "("); r = get_value(f);
  1776.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1777.     skip(f, S_RPAR , ")");
  1778.     return ( memcheck(create_quad_shape(memcheck(create_y_cyl(r)), surf)) );
  1779.     }
  1780. /*...e*/
  1781. /*...sS_Z_CYL:16:*/
  1782. case S_Z_CYL:
  1783.     {
  1784.     double    r;
  1785.     SURF    *surf;
  1786.  
  1787.     skip(f, S_LPAR , "("); r = get_value(f);
  1788.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1789.     skip(f, S_RPAR , ")");
  1790.     return ( memcheck(create_quad_shape(memcheck(create_z_cyl(r)), surf)) );
  1791.     }
  1792. /*...e*/
  1793. /*...sS_X_ELL_CONE:16:*/
  1794. case S_X_ELL_CONE:
  1795.     {
  1796.     double    ky, kz;
  1797.     SURF    *surf;
  1798.  
  1799.     skip(f, S_LPAR , "("); ky = get_value(f);
  1800.     skip(f, S_COMMA, ","); kz = get_value(f);
  1801.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1802.     skip(f, S_RPAR , ")");
  1803.     return ( memcheck(create_quad_shape(memcheck(create_x_ell_cone(ky, kz)), surf)) );
  1804.     }
  1805. /*...e*/
  1806. /*...sS_Y_ELL_CONE:16:*/
  1807. case S_Y_ELL_CONE:
  1808.     {
  1809.     double    kx, kz;
  1810.     SURF    *surf;
  1811.  
  1812.     skip(f, S_LPAR , "("); kx = get_value(f);
  1813.     skip(f, S_COMMA, ","); kz = get_value(f);
  1814.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1815.     skip(f, S_RPAR , ")");
  1816.     return ( memcheck(create_quad_shape(memcheck(create_y_ell_cone(kx, kz)), surf)) );
  1817.     }
  1818. /*...e*/
  1819. /*...sS_Z_ELL_CONE:16:*/
  1820. case S_Z_ELL_CONE:
  1821.     {
  1822.     double    kx, ky;
  1823.     SURF    *surf;
  1824.  
  1825.     skip(f, S_LPAR , "("); kx = get_value(f);
  1826.     skip(f, S_COMMA, ","); ky = get_value(f);
  1827.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1828.     skip(f, S_RPAR , ")");
  1829.     return ( memcheck(create_quad_shape(memcheck(create_z_ell_cone(kx, ky)), surf)) );
  1830.     }
  1831. /*...e*/
  1832. /*...sS_X_CONE:16:*/
  1833. case S_X_CONE:
  1834.     {
  1835.     double    k;
  1836.     SURF    *surf;
  1837.  
  1838.     skip(f, S_LPAR , "("); k = get_value(f);
  1839.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1840.     skip(f, S_RPAR , ")");
  1841.     return ( memcheck(create_quad_shape(memcheck(create_x_cone(k)), surf)) );
  1842.     }
  1843. /*...e*/
  1844. /*...sS_Y_CONE:16:*/
  1845. case S_Y_CONE:
  1846.     {
  1847.     double    k;
  1848.     SURF    *surf;
  1849.  
  1850.     skip(f, S_LPAR , "("); k = get_value(f);
  1851.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1852.     skip(f, S_RPAR , ")");
  1853.     return ( memcheck(create_quad_shape(memcheck(create_y_cone(k)), surf)) );
  1854.     }
  1855. /*...e*/
  1856. /*...sS_Z_CONE:16:*/
  1857. case S_Z_CONE:
  1858.     {
  1859.     double    k;
  1860.     SURF    *surf;
  1861.  
  1862.     skip(f, S_LPAR , "("); k = get_value(f);
  1863.     skip(f, S_COMMA, ","); surf = get_surf(f);
  1864.     skip(f, S_RPAR , ")");
  1865.     return ( memcheck(create_quad_shape(memcheck(create_z_cone(k)), surf)) );
  1866.     }
  1867. /*...e*/
  1868. /*...sS_TRANS:16:*/
  1869. case S_TRANS:
  1870.     {
  1871.     SHAPE    *shape;
  1872.     VECTOR    t;
  1873.  
  1874.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1875.     skip(f, S_COMMA, ","); t = get_vector(f);
  1876.     skip(f, S_RPAR , ")");
  1877.     trans(shape, t);
  1878.     return ( shape );
  1879.     }
  1880. /*...e*/
  1881. /*...sS_TRANS_X:16:*/
  1882. case S_TRANS_X:
  1883.     {
  1884.     SHAPE    *shape;
  1885.     double    t;
  1886.  
  1887.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1888.     skip(f, S_COMMA, ","); t = get_value(f);
  1889.     skip(f, S_RPAR , ")");
  1890.     trans_x(shape, t);
  1891.     return ( shape );
  1892.     }
  1893. /*...e*/
  1894. /*...sS_TRANS_Y:16:*/
  1895. case S_TRANS_Y:
  1896.     {
  1897.     SHAPE    *shape;
  1898.     double    t;
  1899.  
  1900.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1901.     skip(f, S_COMMA, ","); t = get_value(f);
  1902.     skip(f, S_RPAR , ")");
  1903.     trans_y(shape, t);
  1904.     return ( shape );
  1905.     }
  1906. /*...e*/
  1907. /*...sS_TRANS_Z:16:*/
  1908. case S_TRANS_Z:
  1909.     {
  1910.     SHAPE    *shape;
  1911.     double    t;
  1912.  
  1913.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1914.     skip(f, S_COMMA, ","); t = get_value(f);
  1915.     skip(f, S_RPAR , ")");
  1916.     trans_z(shape, t);
  1917.     return ( shape );
  1918.     }
  1919. /*...e*/
  1920. /*...sS_SCALE:16:*/
  1921. case S_SCALE:
  1922.     {
  1923.     SHAPE    *shape;
  1924.     VECTOR    factor;
  1925.  
  1926.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1927.     skip(f, S_COMMA, ","); factor = get_vector(f);
  1928.     if ( factor.x == 0.0 || factor.y == 0.0 || factor.z == 0 )
  1929.         readerr(f, "at least one component of factor is zero");
  1930.     skip(f, S_RPAR , ")");
  1931.     if ( !scale(shape, factor) )
  1932.         readerr(f, "can't scale shape");
  1933.     return ( shape );
  1934.     }
  1935. /*...e*/
  1936. /*...sS_SCALE_X:16:*/
  1937. case S_SCALE_X:
  1938.     {
  1939.     SHAPE    *shape;
  1940.     double    factor;
  1941.  
  1942.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1943.     skip(f, S_COMMA, ","); factor = get_value(f);
  1944.     if ( factor == 0.0 )
  1945.         readerr(f, "factor is zero");
  1946.     skip(f, S_RPAR , ")");
  1947.     if ( !scale_x(shape, factor) )
  1948.         readerr(f, "can't scale_x shape");
  1949.     return ( shape );
  1950.     }
  1951. /*...e*/
  1952. /*...sS_SCALE_Y:16:*/
  1953. case S_SCALE_Y:
  1954.     {
  1955.     SHAPE    *shape;
  1956.     double    factor;
  1957.  
  1958.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1959.     skip(f, S_COMMA, ","); factor = get_value(f);
  1960.     if ( factor == 0.0 )
  1961.         readerr(f, "factor is zero");
  1962.     skip(f, S_RPAR , ")");
  1963.     if ( !scale_y(shape, factor) )
  1964.         readerr(f, "can't scale_y shape");
  1965.     return ( shape );
  1966.     }
  1967. /*...e*/
  1968. /*...sS_SCALE_Z:16:*/
  1969. case S_SCALE_Z:
  1970.     {
  1971.     SHAPE    *shape;
  1972.     double    factor;
  1973.  
  1974.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1975.     skip(f, S_COMMA, ","); factor = get_value(f);
  1976.     if ( factor == 0.0 )
  1977.         readerr(f, "factor is zero");
  1978.     skip(f, S_RPAR , ")");
  1979.     if ( !scale_z(shape, factor) )
  1980.         readerr(f, "can't scale_z shape");
  1981.     return ( shape );
  1982.     }
  1983. /*...e*/
  1984. /*...sS_ROTATE_X:16:*/
  1985. case S_ROTATE_X:
  1986.     {
  1987.     SHAPE    *shape;
  1988.     double    angle;
  1989.  
  1990.     skip(f, S_LPAR , "("); shape = get_shape(f);
  1991.     skip(f, S_COMMA, ","); angle = get_value(f);
  1992.     skip(f, S_RPAR , ")");
  1993.     rot_x(shape, angle);
  1994.     return ( shape );
  1995.     }
  1996. /*...e*/
  1997. /*...sS_ROTATE_Y:16:*/
  1998. case S_ROTATE_Y:
  1999.     {
  2000.     SHAPE    *shape;
  2001.     double    angle;
  2002.  
  2003.     skip(f, S_LPAR , "("); shape = get_shape(f);
  2004.     skip(f, S_COMMA, ","); angle = get_value(f);
  2005.     skip(f, S_RPAR , ")");
  2006.     rot_y(shape, angle);
  2007.     return ( shape );
  2008.     }
  2009. /*...e*/
  2010. /*...sS_ROTATE_Z:16:*/
  2011. case S_ROTATE_Z:
  2012.     {
  2013.     SHAPE    *shape;
  2014.     double    angle;
  2015.  
  2016.     skip(f, S_LPAR , "("); shape = get_shape(f);
  2017.     skip(f, S_COMMA, ","); angle = get_value(f);
  2018.     skip(f, S_RPAR , ")");
  2019.     rot_z(shape, angle);
  2020.     return ( shape );
  2021.     }
  2022. /*...e*/
  2023. /*...sS_UNION:16:*/
  2024. case S_UNION:
  2025.     {
  2026.     SHAPE    *shape;
  2027.     int    sym;
  2028.  
  2029.     skip(f, S_LPAR, "(");
  2030.     shape = get_shape(f);
  2031.     while ( (sym = getsym(f)) == S_COMMA )
  2032.         shape = memcheck(create_bin_shape(STYPE_UNION, shape, get_shape(f)));
  2033.     if ( sym != S_RPAR )
  2034.         readerr(f, "expected )");
  2035.  
  2036.     return ( shape );
  2037.     }
  2038. /*...e*/
  2039. /*...sS_ISECT:16:*/
  2040. case S_ISECT:
  2041.     {
  2042.     SHAPE    *shape;
  2043.     int    sym;
  2044.  
  2045.     skip(f, S_LPAR, "(");
  2046.     shape = get_shape(f);
  2047.     while ( (sym = getsym(f)) == S_COMMA )
  2048.         shape = memcheck(create_bin_shape(STYPE_ISECT, shape, get_shape(f)));
  2049.     if ( sym != S_RPAR )
  2050.         readerr(f, "expected )");
  2051.  
  2052.     return ( shape );
  2053.     }
  2054. /*...e*/
  2055. /*...sS_DIFF:16:*/
  2056. case S_DIFF:
  2057.     {
  2058.     SHAPE    *shape;
  2059.     int    sym;
  2060.  
  2061.     skip(f, S_LPAR, "(");
  2062.     shape = get_shape(f);
  2063.     while ( (sym = getsym(f)) == S_COMMA )
  2064.         shape = memcheck(create_bin_shape(STYPE_DIFF, shape, get_shape(f)));
  2065.     if ( sym != S_RPAR )
  2066.         readerr(f, "expected )");
  2067.  
  2068.     return ( shape );
  2069.     }
  2070. /*...e*/
  2071. /*...sS_SDIFF:16:*/
  2072. case S_SDIFF:
  2073.     {
  2074.     SHAPE    *shape;
  2075.     int    sym;
  2076.  
  2077.     skip(f, S_LPAR, "(");
  2078.     shape = get_shape(f);
  2079.     while ( (sym = getsym(f)) == S_COMMA )
  2080.         shape = memcheck(create_bin_shape(STYPE_SDIFF, shape, get_shape(f)));
  2081.     if ( sym != S_RPAR )
  2082.         readerr(f, "expected )");
  2083.  
  2084.     return ( shape );
  2085.     }
  2086. /*...e*/
  2087. /*...sS_EXTENT:16:*/
  2088. case S_EXTENT:
  2089.     {
  2090.     SHAPE    *shape;
  2091.     int    sym;
  2092.  
  2093.     skip(f, S_LPAR, "(");
  2094.     shape = get_shape(f);
  2095.     while ( (sym = getsym(f)) == S_COMMA )
  2096.         shape = memcheck(create_bin_shape(STYPE_EXTENT, shape, get_shape(f)));
  2097.     if ( sym != S_RPAR )
  2098.         readerr(f, "expected )");
  2099.  
  2100.     return ( shape );
  2101.     }
  2102. /*...e*/
  2103. /*...sS_RESURF:16:*/
  2104. case S_RESURF:
  2105.     {
  2106.     SHAPE    *shape;
  2107.     SURF    *surf;
  2108.  
  2109.     skip(f, S_LPAR , "("); shape = get_shape(f);
  2110.     skip(f, S_COMMA, ","); surf  = get_surf(f);
  2111.     skip(f, S_RPAR , ")");
  2112.  
  2113.     if ( !resurf(shape, surf) )
  2114.         readerr(f, "unable to resurface shape");
  2115.     destroy_surf(surf);
  2116.  
  2117.     return ( shape );
  2118.     }
  2119. /*...e*/
  2120. /*...sS_ID:16:*/
  2121. case S_ID:
  2122.     {
  2123.     SHAPE *shape = vars [lookup_defined_var_vtype(f, f -> id_name, VTYPE_SHAPE)].u.shape;
  2124.  
  2125.     return ( memcheck(copy_shape(shape)) );
  2126.     }
  2127. /*...e*/
  2128. /*...sdefault:16:*/
  2129. default:
  2130.     readerr(f, "expected a shape specification");
  2131. /*...e*/
  2132.         }
  2133.     return ( NULL ); /* Keep fussy C compiler happy */
  2134.     }
  2135. /*...e*/
  2136. /*...sget_set_value:0:*/
  2137. static void get_set_value(F *f)
  2138.     {
  2139.     char    name [30+1];
  2140.  
  2141.     get_new_id(f, name);
  2142.     add_value_var(f, name, get_value(f));
  2143.     }
  2144.  
  2145. /*...e*/
  2146. /*...sget_set_vector:0:*/
  2147. static void get_set_vector(F *f)
  2148.     {
  2149.     char    name [30+1];
  2150.  
  2151.     get_new_id(f, name);
  2152.     add_vector_var(f, name, get_vector(f));
  2153.     }
  2154. /*...e*/
  2155. /*...sget_set_rgb:0:*/
  2156. static void get_set_rgb(F *f)
  2157.     {
  2158.     char    name [30+1];
  2159.  
  2160.     get_new_id(f, name);
  2161.     add_rgb_var(f, name, get_rgb(f));
  2162.     }
  2163. /*...e*/
  2164. /*...sget_set_col:0:*/
  2165. static void get_set_col(F *f)
  2166.     {
  2167.     char    name [30+1];
  2168.  
  2169.     get_new_id(f, name);
  2170.     add_col_var(f, name, get_col(f));
  2171.     }
  2172. /*...e*/
  2173. /*...sget_set_surf:0:*/
  2174. static void get_set_surf(F *f)
  2175.     {
  2176.     char    name [30+1];
  2177.  
  2178.     get_new_id(f, name);
  2179.     add_surf_var(f, name, get_surf(f));
  2180.     }
  2181. /*...e*/
  2182. /*...sget_set_shape:0:*/
  2183. static void get_set_shape(F *f)
  2184.     {
  2185.     char    name [30+1];
  2186.  
  2187.     get_new_id(f, name);
  2188.     add_shape_var(f, name, get_shape(f));
  2189.     }
  2190. /*...e*/
  2191. /*...sget_set_background:0:*/
  2192. static void get_set_background(F *f)
  2193.     {
  2194.     i_background = get_rgb(f);
  2195.     }
  2196. /*...e*/
  2197. /*...sget_set_ambient:0:*/
  2198. static void get_set_ambient(F *f)
  2199.     {
  2200.     i_ambient = get_rgb(f);
  2201.     }
  2202. /*...e*/
  2203. /*...sget_set_atten:0:*/
  2204. static void get_set_atten(F *f)
  2205.     {
  2206.     af1 = get_value(f);
  2207.     af2 = get_value(f);
  2208.     }
  2209. /*...e*/
  2210. /*...sget_add_light:0:*/
  2211. static void get_add_light(F *f)
  2212.     {
  2213.     if ( n_lights == N_LIGHTS )
  2214.         readerr(f, "maximum of %d lights exceeded", N_LIGHTS);
  2215.  
  2216.     lights [n_lights  ].posn = get_vector(f);
  2217.     lights [n_lights++].i    = get_rgb(f);
  2218.     }
  2219. /*...e*/
  2220. /*...sget_render:0:*/
  2221. static void get_render(F *f)
  2222.     {
  2223.     SHAPE    *shape;
  2224.     VECTOR    eye, forward, up;
  2225.     double    hangle, vangle;
  2226.     int    hpixels, vpixels, depth;
  2227.  
  2228.     shape   = get_shape(f);
  2229.     eye     = get_vector(f);
  2230.     forward = get_vector(f);
  2231.     up      = get_vector(f);
  2232.     hangle  = get_value(f);
  2233.     vangle  = get_value(f);
  2234.     hpixels = (int) get_value(f);
  2235.     vpixels = (int) get_value(f);
  2236.     depth   = (int) get_value(f);
  2237.  
  2238.     if ( getsym(f) != S_STRING )
  2239.         readerr(f, "expected output filename");
  2240.  
  2241.     render(shape, eye, forward, up, hangle, vangle, hpixels, vpixels, depth, f -> str);
  2242.  
  2243.     destroy_shape(shape);
  2244.     }
  2245. /*...e*/
  2246. /*...sget_include:0:*/
  2247. static void get_include(F *f)
  2248.     {
  2249.     if ( getsym(f) != S_STRING )
  2250.         readerr(f, "expected filename");
  2251.  
  2252.     read_data_file(f -> str);
  2253.     }
  2254. /*...e*/
  2255.  
  2256. static void get_file(F *f)
  2257.     {
  2258.     int    sym;
  2259.  
  2260.     while ( (sym = getsym(f)) != S_EOF )
  2261.         switch ( sym )
  2262.             {
  2263.             case S_SET_VALUE:    get_set_value(f);    break;
  2264.             case S_SET_VECTOR:    get_set_vector(f);    break;
  2265.             case S_SET_RGBVEC:    get_set_rgb(f);        break;
  2266.             case S_SET_COL:        get_set_col(f);        break;
  2267.             case S_SET_SURF:    get_set_surf(f);    break;
  2268.             case S_SET_SHAPE:    get_set_shape(f);    break;
  2269.             case S_SET_BKGND:    get_set_background(f);    break;
  2270.             case S_SET_AMBIENT:    get_set_ambient(f);    break;
  2271.             case S_SET_ATTEN:    get_set_atten(f);    break;
  2272.             case S_ADD_LIGHT:    get_add_light(f);    break;
  2273.             case S_RENDER:        get_render(f);        break;
  2274.             case S_INCLUDE:        get_include(f);        break;
  2275.             default:        readerr(f, "expected assignment, set_ambient, set_attenuation, add_light, render or include statement");
  2276.             }
  2277.     }
  2278. /*...e*/
  2279.  
  2280. static void read_data_file(char *fn)
  2281.     {
  2282.     FILE    *fp;
  2283.     F    *f;
  2284.  
  2285.     if ( (fp = fopen(fn, "r")) == NULL )
  2286.         fatal("can't open %s", fn);
  2287.  
  2288.     f = open_stream(fp, fn);
  2289.     get_file(f);
  2290.     fp = close_stream(f);
  2291.     fclose(fp);
  2292.     }
  2293. /*...e*/
  2294.  
  2295. int main(int argc, char *argv [])
  2296.     {
  2297.     if ( argc != 2 )
  2298.         exit(1);
  2299.  
  2300. #ifdef OS2_V2
  2301.     /* Prevent numeric exceptions from terminating this program */
  2302.     _control87(EM_UNDERFLOW|EM_DENORMAL, EM_UNDERFLOW|EM_DENORMAL);
  2303. #endif
  2304.  
  2305.     read_data_file(argv [1]);
  2306.  
  2307.     return ( 0 );
  2308.     }
  2309. /*...e*/
  2310.