home *** CD-ROM | disk | FTP | other *** search
/ Archive Magazine 1996 / ARCHIVE_96.iso / discs / shareware / share_43 / source / c / LIGHTING < prev    next >
Text File  |  1991-08-22  |  20KB  |  597 lines

  1. /*****************************************************************************
  2. *
  3. *                                    lighting.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module calculates lighting properties like ambient, diffuse, specular,
  8. *  reflection, refraction, etc.
  9. *
  10. *
  11. * This software is freely distributable. The source and/or object code may be
  12. * copied or uploaded to communications services so long as this notice remains
  13. * at the top of each file.  If any changes are made to the program, you must
  14. * clearly indicate in the documentation and in the programs startup message
  15. * who it was who made the changes. The documentation should also describe what
  16. * those changes were. This software may not be included in whole or in
  17. * part into any commercial package without the express written consent of the
  18. * author.  It may, however, be included in other public domain or freely
  19. * distributed software so long as the proper credit for the software is given.
  20. *
  21. * This software is provided as is without any guarantees or warranty. Although
  22. * the author has attempted to find and correct any bugs in the software, he
  23. * is not responsible for any damage caused by the use of the software.  The
  24. * author is under no obligation to provide service, corrections, or upgrades
  25. * to this package.
  26. *
  27. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  28. * about them.  Also, if you have any comments or questions, you may contact me
  29. * at the following address:
  30. *
  31. *     David Buck
  32. *     22C Sonnet Cres.
  33. *     Nepean Ontario
  34. *     Canada, K2H 8W7
  35. *
  36. *  I can also be reached on the following bulleton boards:
  37. *
  38. *     ATX              (613) 526-4141
  39. *     OMX              (613) 731-3419
  40. *     Mystic           (613) 731-0088 or (613) 731-6698
  41. *
  42. *  Fidonet:   1:163/109.9
  43. *  Internet:  David_Buck@Carleton.CA
  44. *
  45. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  46. *
  47. *     Lattice BBS                      (708) 916-1200
  48. *     The Information Exchange BBS     (708) 945-5575
  49. *     Stillwaters BBS                  (708) 403-2826
  50. *
  51. *****************************************************************************/
  52.  
  53.  
  54. #include "frame.h"
  55. #include "vector.h"
  56. #include "dkbproto.h"
  57.  
  58. extern int Trace_Level;
  59. extern FRAME Frame;
  60. extern unsigned long Options;
  61. extern int Quality;
  62. extern long Shadow_Ray_Tests, Shadow_Rays_Succeeded;
  63. extern long Reflected_Rays_Traced, Refracted_Rays_Traced;
  64. extern long Transmitted_Rays_Traced;
  65.  
  66. #define Small_Tolerance 0.001
  67.  
  68. void Colour_At (Colour, Object, Intersection_Point)
  69.    COLOUR *Colour;
  70.    OBJECT *Object;
  71.    VECTOR *Intersection_Point;
  72.    {
  73.    register DBL x, y, z;
  74.    VECTOR Transformed_Point;
  75.  
  76.    if (Object -> Object_Texture->Texture_Transformation) {
  77.       MInverseTransformVector (&Transformed_Point,
  78.                                Intersection_Point,
  79.                    Object -> Object_Texture->Texture_Transformation);
  80.       }
  81.    else
  82.       Transformed_Point = *Intersection_Point;
  83.  
  84.    x = Transformed_Point.x;
  85.    y = Transformed_Point.y;
  86.    z = Transformed_Point.z;
  87.      
  88.    switch (Object -> Object_Texture->Texture_Number) {
  89.       case BOZO_TEXTURE: 
  90.            Bozo (x, y, z, Object, Colour);
  91.            break;
  92.  
  93.       case MARBLE_TEXTURE:
  94.            marble (x, y, z, Object, Colour);
  95.            break;
  96.  
  97.       case WOOD_TEXTURE:
  98.            wood (x, y, z, Object, Colour);
  99.            break;
  100.  
  101.       case CHECKER_TEXTURE:
  102.            checker (x, y, z, Object, Colour);
  103.            break;
  104.  
  105.       case SPOTTED_TEXTURE:
  106.            spotted (x, y, z, Object, Colour);
  107.            break;
  108.  
  109.       case AGATE_TEXTURE:
  110.            agate (x, y, z, Object, Colour);
  111.            break;
  112.  
  113.       case GRANITE_TEXTURE:
  114.            granite (x, y, z, Object, Colour);
  115.            break;
  116.  
  117.      case GRADIENT_TEXTURE:
  118.            gradient (x, y, z, Object, Colour);
  119.            break;
  120.  
  121.       case IMAGEMAP_TEXTURE:
  122.            texture_map (x, y, z, Object, Colour);
  123.        break;
  124.  
  125.       default:
  126.            *Colour = Object -> Object_Colour;
  127.            break;
  128.       }
  129.    }
  130.  
  131.  
  132. void Perturb_Normal(New_Normal, Object, Intersection_Point, Surface_Normal)
  133.    VECTOR *New_Normal, *Intersection_Point, *Surface_Normal;
  134.    OBJECT *Object;
  135.    {
  136.    VECTOR Transformed_Point;
  137.    register DBL x, y, z;
  138.  
  139.    if (Object -> Object_Texture->Bump_Number == NO_BUMPS) {
  140.       *New_Normal = *Surface_Normal;
  141.       return;
  142.       }
  143.  
  144.    if (Object -> Object_Texture->Texture_Transformation)
  145.       MInverseTransformVector (&Transformed_Point,
  146.                                Intersection_Point,
  147.                                Object -> Object_Texture->Texture_Transformation);
  148.    else
  149.       Transformed_Point = *Intersection_Point;
  150.  
  151.    x = Transformed_Point.x;
  152.    y = Transformed_Point.y;
  153.    z = Transformed_Point.z;
  154.  
  155.    switch (Object -> Object_Texture->Bump_Number) {
  156.       case NO_BUMPS: break;
  157.  
  158.       case WAVES: waves (x, y, z, Object, New_Normal);
  159.                   break;
  160.  
  161.       case RIPPLES: ripples (x, y, z, Object, New_Normal);
  162.                   break;
  163.  
  164.       case WRINKLES: wrinkles (x, y, z, Object, New_Normal);
  165.                   break;
  166.  
  167.       case BUMPS: bumps (x, y, z, Object, New_Normal);
  168.                   break;
  169.  
  170.       case DENTS: dents (x, y, z, Object, New_Normal);
  171.                   break;
  172.       }
  173.    return;
  174.    }
  175.  
  176. void Ambient (Object, Intersection_Point, Surface_Colour, Colour)
  177.    OBJECT *Object;
  178.    VECTOR *Intersection_Point;
  179.    COLOUR *Surface_Colour;
  180.    COLOUR *Colour;
  181.    {
  182.    DBL t;
  183.  
  184.    if (Object -> Object_Texture -> Object_Ambient == 0.0)
  185.       return;
  186.  
  187.    t = 1.0 - Surface_Colour->Alpha;
  188.    Colour->Red += Surface_Colour->Red * t * Object->Object_Texture->Object_Ambient;
  189.    Colour->Green += Surface_Colour->Green * t * Object->Object_Texture->Object_Ambient;
  190.    Colour->Blue += Surface_Colour->Blue * t * Object->Object_Texture->Object_Ambient;
  191.    return;
  192.    }
  193.  
  194.  
  195. void Diffuse (Object, Intersection_Point, Eye, Surface_Normal, Surface_Colour, Colour)
  196.    OBJECT *Object;
  197.    VECTOR *Intersection_Point, *Surface_Normal;
  198.    COLOUR *Surface_Colour;
  199.    COLOUR *Colour;
  200.    RAY *Eye;
  201.    {
  202.    DBL Light_Source_Depth;
  203.    RAY Light_Source_Ray;
  204.    OBJECT *Light_Source, *Blocking_Object;
  205.    int Intersection_Found;
  206.    INTERSECTION *Local_Intersection;
  207.    VECTOR REye;
  208.    COLOUR Light_Colour, Blocking_Colour;
  209.    PRIOQ *Local_Queue;
  210.  
  211.    if ((Object -> Object_Texture -> Object_Diffuse == 0.0) &&
  212.        (Object -> Object_Texture -> Object_Specular == 0.0) &&
  213.        (Object -> Object_Texture -> Object_Phong == 0.0))
  214.      return;
  215.  
  216.    if (Object -> Object_Texture -> Object_Specular != 0.0)
  217.       {
  218.       REye.x = -Eye->Direction.x;
  219.       REye.y = -Eye->Direction.y;
  220.       REye.z = -Eye->Direction.z;
  221.       }
  222.  
  223.    Local_Queue = pq_new (128);
  224.  
  225.    for (Light_Source = Frame.Light_Sources ; 
  226.         Light_Source != NULL;
  227.         Light_Source = Light_Source -> Next_Light_Source)
  228.       {
  229.       Light_Colour = Light_Source->Object_Colour;
  230.       Intersection_Found = FALSE;  
  231.  
  232.       do_light(Light_Source, &Light_Source_Depth, &Light_Source_Ray, Intersection_Point);
  233.  
  234.       /* What objects does this ray intersect? */
  235.       if (Quality > 3)
  236.          for (Blocking_Object = Frame.Objects ; 
  237.               Blocking_Object != NULL ;
  238.               Blocking_Object = Blocking_Object -> Next_Object) {
  239.  
  240.             Shadow_Ray_Tests++;
  241.             if (Blocking_Object == Light_Source)
  242.                continue;
  243.  
  244.             for (All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Queue) ;
  245.                  (Local_Intersection = pq_get_highest(Local_Queue)) != NULL ;
  246.                  pq_delete_highest(Local_Queue)) {
  247.  
  248.                if ((Local_Intersection -> Depth < Light_Source_Depth-Small_Tolerance)
  249.                     && (Local_Intersection -> Depth > Small_Tolerance))
  250.                   {
  251.                   Shadow_Rays_Succeeded++;
  252.                   if (Blocking_Object->Transparency)
  253.              do_blocking(Blocking_Object, &Blocking_Colour, Local_Intersection, &Light_Colour);
  254.                   else {
  255.                      Intersection_Found = TRUE;
  256.                      break;
  257.                      }
  258.                   }
  259.                }
  260.             if (Intersection_Found) {
  261.                while (pq_get_highest(Local_Queue))
  262.                   pq_delete_highest(Local_Queue);
  263.                break;
  264.                }
  265.             }
  266.  
  267.       if (!Intersection_Found)
  268.          {
  269.      if (Object->Object_Texture->Object_Phong >0.0) /*Phong Spec. Hilite*/
  270.         do_phong(Object, &Light_Source_Ray, Eye, Surface_Normal, Colour, &Light_Colour);
  271.  
  272.          if (Object->Object_Texture->Object_Specular >0.0) /*specular hilite*/
  273.         do_specular(Object,&Light_Source_Ray,&REye,Surface_Normal,Colour, &Light_Colour);
  274.  
  275.          if (Object->Object_Texture->Object_Diffuse > 0.0) /*normal diffuse */
  276.         do_diffuse(Object, &Light_Source_Ray, Surface_Normal, Colour, &Light_Colour, Surface_Colour);
  277.          }
  278.       }
  279.    pq_free (Local_Queue);
  280.    return;
  281.    }
  282.  
  283. void do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Intersection_Point)
  284. OBJECT *Light_Source;
  285. DBL *Light_Source_Depth;
  286. RAY *Light_Source_Ray;
  287. VECTOR *Intersection_Point;
  288. {
  289.       Light_Source_Ray->Initial = *Intersection_Point;
  290.       Light_Source_Ray->Quadric_Constants_Cached = FALSE;
  291.  
  292.       VSub (Light_Source_Ray->Direction,
  293.            Light_Source->Object_Center,
  294.        *Intersection_Point);
  295.  
  296.       VLength (*Light_Source_Depth, Light_Source_Ray->Direction);
  297.  
  298.       VScale (Light_Source_Ray->Direction, Light_Source_Ray->Direction,
  299.                 1.0/(*Light_Source_Depth));
  300.       return;
  301. }
  302.  
  303. void do_blocking(Blocking_Object, Blocking_Colour, Local_Intersection, Light_Colour)
  304. OBJECT *Blocking_Object;
  305. COLOUR *Blocking_Colour, *Light_Colour;
  306. INTERSECTION *Local_Intersection;
  307. {
  308.     Make_Colour(Blocking_Colour, 0.0, 0.0, 0.0);
  309.     Colour_At(Blocking_Colour,Blocking_Object,&Local_Intersection->Point);
  310.  
  311.     Light_Colour->Red *= 
  312.         Blocking_Colour->Red * Blocking_Colour->Alpha;
  313.     Light_Colour->Green *= 
  314.         Blocking_Colour->Green * Blocking_Colour->Alpha;
  315.     Light_Colour->Blue *=
  316.         Blocking_Colour->Blue * Blocking_Colour->Alpha;
  317.     return;
  318. }
  319.  
  320. void do_phong(Object, Light_Source_Ray, Eye, Surface_Normal, Colour, Light_Colour)
  321. OBJECT *Object;
  322. RAY *Light_Source_Ray, *Eye;
  323. VECTOR *Surface_Normal;
  324. COLOUR *Colour, *Light_Colour;
  325. {
  326.     DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity;
  327.     VECTOR Local_Normal, Normal_Projection, Reflect_Direction;
  328.  
  329.     VDot(Cos_Angle_Of_Incidence, Eye->Direction, *Surface_Normal);
  330.     if (Cos_Angle_Of_Incidence < 0.0)
  331.     {
  332.         Local_Normal = *Surface_Normal;
  333.         Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  334.     }
  335.     else
  336.         VScale (Local_Normal, *Surface_Normal, -1.0);
  337.  
  338.     VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
  339.     VScale (Normal_Projection, Normal_Projection, 2.0);
  340.     VAdd (Reflect_Direction, Eye->Direction, Normal_Projection);
  341.  
  342.     VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
  343.     VLength (Normal_Length, Light_Source_Ray->Direction);
  344.     Cos_Angle_Of_Incidence /= Normal_Length;
  345.  
  346.     if (Cos_Angle_Of_Incidence < 0.0)
  347.         Cos_Angle_Of_Incidence = 0;
  348.  
  349.     if (Object -> Object_Texture -> Object_PhongSize != 1.0)
  350.         Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_PhongSize);
  351.     else
  352.         Intensity = Cos_Angle_Of_Incidence;
  353.  
  354.     Intensity *= Object -> Object_Texture -> Object_Phong;
  355.  
  356.     Colour->Red+=Intensity*(Light_Colour->Red);
  357.     Colour->Green+=Intensity*(Light_Colour->Green);
  358.     Colour->Blue+=Intensity*(Light_Colour->Blue);
  359.     return;
  360. }
  361.  
  362. void do_specular(Object, Light_Source_Ray, REye, Surface_Normal, Colour, Light_Colour)
  363. OBJECT *Object;
  364. RAY *Light_Source_Ray;
  365. VECTOR *Surface_Normal, *REye;
  366. COLOUR *Colour, *Light_Colour;
  367. {
  368.     DBL Cos_Angle_Of_Incidence, Normal_Length, Intensity, Halfway_Length;
  369.     VECTOR Halfway;
  370.  
  371.     VHalf (Halfway, *REye, Light_Source_Ray->Direction);
  372.     VLength (Normal_Length, *Surface_Normal);
  373.     VLength (Halfway_Length, Halfway);
  374.     VDot (Cos_Angle_Of_Incidence, Halfway, *Surface_Normal);
  375.     Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
  376.     
  377.     if (Cos_Angle_Of_Incidence < 0.0)
  378.         Cos_Angle_Of_Incidence = 0;
  379.     
  380.     if (Object -> Object_Texture -> Object_Roughness != 1.0)
  381.         Intensity = pow(Cos_Angle_Of_Incidence, 1 / Object->Object_Texture->Object_Roughness);
  382.     else
  383.         Intensity = Cos_Angle_Of_Incidence;
  384.  
  385.     Intensity *= Object->Object_Texture->Object_Specular;
  386.  
  387.     Colour->Red+=Intensity* (Light_Colour->Red);
  388.     Colour->Green+=Intensity* (Light_Colour->Green);
  389.     Colour->Blue+=Intensity* (Light_Colour->Blue);
  390.     return;
  391. }
  392.  
  393. void do_diffuse(Object, Light_Source_Ray, Surface_Normal, Colour, Light_Colour, Surface_Colour)
  394. OBJECT *Object;
  395. RAY *Light_Source_Ray;
  396. VECTOR *Surface_Normal;
  397. COLOUR *Colour, *Light_Colour, *Surface_Colour;
  398. {
  399.     DBL Cos_Angle_Of_Incidence, Intensity, RandomNumber;
  400.  
  401.     VDot (Cos_Angle_Of_Incidence, *Surface_Normal, Light_Source_Ray->Direction);
  402.     if (Cos_Angle_Of_Incidence < 0.0)
  403.         Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  404.  
  405.     if (Object -> Object_Texture -> Object_Brilliance != 1.0)
  406.         Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_Brilliance);
  407.     else
  408.         Intensity = Cos_Angle_Of_Incidence;
  409.  
  410.     Intensity *= Object -> Object_Texture -> Object_Diffuse;
  411.  
  412.     RandomNumber = (rand()&0x7FFF)/(DBL) 0x7FFF;
  413.  
  414.     Intensity -= RandomNumber * Object->Object_Texture->Texture_Randomness;
  415.     Intensity *= 1.0 - Surface_Colour->Alpha;
  416.     Colour->Red += Intensity * (Surface_Colour->Red) * (Light_Colour->Red);
  417.     Colour->Green += Intensity * (Surface_Colour->Green) * (Light_Colour->Green);
  418.     Colour->Blue += Intensity * (Surface_Colour->Blue) * (Light_Colour->Blue);
  419.     return;
  420. }
  421.  
  422. void Transmit (Object, Intersection_Point, Ray, Surface_Normal, Surface_Colour, Colour)
  423.    OBJECT *Object;
  424.    VECTOR *Intersection_Point;
  425.    RAY *Ray;
  426.    VECTOR *Surface_Normal;
  427.    COLOUR *Surface_Colour;
  428.    COLOUR *Colour;
  429.    {
  430.    RAY New_Ray;
  431.    COLOUR Temp_Colour;
  432.  
  433.    if (Surface_Colour->Alpha == 0.0)
  434.       return;
  435.  
  436.    New_Ray.Initial = *Intersection_Point;
  437.    New_Ray.Direction = Ray->Direction;
  438.  
  439.    Copy_Ray_Containers (&New_Ray, Ray);
  440.    Trace_Level++;
  441.    Transmitted_Rays_Traced++;
  442.    Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  443.    New_Ray.Quadric_Constants_Cached = FALSE;
  444.    Trace (&New_Ray, &Temp_Colour);
  445.    Trace_Level--;
  446.    (Colour -> Red) += Temp_Colour.Red * Surface_Colour->Red * Surface_Colour->Alpha;
  447.    (Colour -> Green) += Temp_Colour.Green * Surface_Colour->Green * Surface_Colour->Alpha;
  448.    (Colour -> Blue) += Temp_Colour.Blue * Surface_Colour->Blue * Surface_Colour->Alpha;
  449.    }
  450.  
  451.  
  452. void Reflect (Object, Intersection_Point, Ray, Surface_Normal, Colour)
  453.    OBJECT *Object;
  454.    VECTOR *Intersection_Point;
  455.    RAY *Ray;
  456.    VECTOR *Surface_Normal;
  457.    COLOUR *Colour;
  458.    {
  459.    RAY New_Ray;
  460.    COLOUR Temp_Colour;
  461.    VECTOR Local_Normal;
  462.    VECTOR Normal_Projection;
  463.    register DBL Normal_Component;
  464.  
  465.    if (Object -> Object_Texture -> Object_Reflection != 0.0)
  466.       {
  467.       Reflected_Rays_Traced++;
  468.       VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
  469.       if (Normal_Component < 0.0) {
  470.          Local_Normal = *Surface_Normal;
  471.          Normal_Component *= -1.0;
  472.          }
  473.       else
  474.          VScale (Local_Normal, *Surface_Normal, -1.0);
  475.  
  476.       VScale (Normal_Projection, Local_Normal, Normal_Component);
  477.       VScale (Normal_Projection, Normal_Projection, 2.0);
  478.       VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
  479.       New_Ray.Initial = *Intersection_Point;
  480.  
  481.       Copy_Ray_Containers (&New_Ray, Ray);
  482.       Trace_Level++;
  483.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  484.       New_Ray.Quadric_Constants_Cached = FALSE;
  485.       Trace (&New_Ray, &Temp_Colour);
  486.       Trace_Level--;
  487.       (Colour -> Red) += (Temp_Colour.Red) 
  488.                              * (Object -> Object_Texture -> Object_Reflection);
  489.       (Colour -> Green) += (Temp_Colour.Green)
  490.                              * (Object -> Object_Texture -> Object_Reflection);
  491.       (Colour -> Blue) += (Temp_Colour.Blue)
  492.                              * (Object -> Object_Texture -> Object_Reflection);
  493.       }
  494.    }
  495.  
  496. void Refract (Object, Intersection_Point, Ray, Surface_Normal, Colour)
  497.    OBJECT *Object;
  498.    VECTOR *Intersection_Point;
  499.    RAY *Ray;
  500.    VECTOR *Surface_Normal;
  501.    COLOUR *Colour;
  502.    {
  503.    RAY New_Ray;
  504.    COLOUR Temp_Colour;
  505.    VECTOR Local_Normal;
  506.    VECTOR Normal_Projection;
  507.    register DBL Normal_Component, Temp_IOR;
  508.  
  509.    if (Object -> Object_Texture -> Object_Refraction != 0.0)
  510.       {
  511.       Refracted_Rays_Traced++;
  512.       VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
  513.       if (Normal_Component >= 0.0)
  514.          {
  515.          VScale (Local_Normal, *Surface_Normal, -1.0);
  516.          }
  517.       else
  518.          {
  519.          Local_Normal.x = Surface_Normal -> x;
  520.          Local_Normal.y = Surface_Normal -> y;
  521.          Local_Normal.z = Surface_Normal -> z;
  522.  
  523.          Normal_Component *= -1.0;
  524.          }
  525.  
  526.       VScale (Normal_Projection, Local_Normal, Normal_Component);
  527.       VAdd (Normal_Projection, Normal_Projection, Ray -> Direction);
  528.       Copy_Ray_Containers (&New_Ray, Ray);
  529.  
  530.       if (Ray -> Containing_Index == -1)
  531.          {
  532.        /* The ray is entering from the atmosphere */
  533.          Ray_Enter (&New_Ray, Object);
  534.  
  535.          VScale (Normal_Projection, Normal_Projection,
  536.                (Frame.Atmosphere_IOR)/(Object -> Object_Texture -> Object_Index_Of_Refraction));
  537.          }
  538.       else
  539.          {
  540.        /* The ray is currently inside an object */
  541.          if (New_Ray.Containing_Objects [New_Ray.Containing_Index] == Object)
  542.             {
  543.           /* The ray is leaving the current object */
  544.             Ray_Exit (&New_Ray);
  545.             if (New_Ray.Containing_Index == -1)
  546.              /* The ray is leaving into the atmosphere */
  547.                Temp_IOR = Frame.Atmosphere_IOR;
  548.             else
  549.              /* The ray is leaving into another object */
  550.                Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  551.  
  552.             VScale (Normal_Projection, Normal_Projection,
  553.                (Object -> Object_Texture -> Object_Index_Of_Refraction) / Temp_IOR);
  554.             }
  555.          else
  556.             {
  557.             /* The ray is entering a new object */
  558.             Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  559.             Ray_Enter (&New_Ray, Object);
  560.  
  561.             VScale (Normal_Projection, Normal_Projection,
  562.                  Temp_IOR/(Object -> Object_Texture -> Object_Index_Of_Refraction));
  563.  
  564.             }
  565.          }
  566.  
  567.       VScale (Local_Normal, Local_Normal, -1.0);
  568.       VAdd (New_Ray.Direction, Local_Normal, Normal_Projection);
  569.       VNormalize (New_Ray.Direction, New_Ray.Direction);
  570.       New_Ray.Initial = *Intersection_Point;
  571.       Trace_Level++;
  572.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  573.       New_Ray.Quadric_Constants_Cached = FALSE;
  574.       Trace (&New_Ray, &Temp_Colour);
  575.       Trace_Level--;
  576.       (Colour -> Red) += (Temp_Colour.Red)
  577.                         * (Object -> Object_Texture -> Object_Refraction);
  578.       (Colour -> Green) += (Temp_Colour.Green)
  579.                         * (Object -> Object_Texture -> Object_Refraction);
  580.       (Colour -> Blue) += (Temp_Colour.Blue)
  581.                         * (Object -> Object_Texture -> Object_Refraction);
  582.       }  
  583.    }
  584.  
  585. void Fog (Distance, Fog_Colour, Fog_Distance, Colour)
  586.    DBL Distance, Fog_Distance;
  587.    COLOUR *Fog_Colour, *Colour;
  588.    {
  589.    DBL Fog_Factor, Fog_Factor_Inverse;
  590.  
  591.    Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
  592.    Fog_Factor_Inverse = 1.0 - Fog_Factor;
  593.    Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
  594.    Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
  595.    Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
  596.    }
  597.