home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff397.lzh / DKBTrace / DKBSource.LZH / lighting.c < prev    next >
C/C++ Source or Header  |  1990-08-26  |  19KB  |  547 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 Cos_Angle_Of_Incidence, Halfway_Length, Normal_Length;
  203.    DBL Intensity, RandomNumber, Light_Source_Depth;
  204.    RAY Light_Source_Ray;
  205.    OBJECT *Light_Source, *Blocking_Object;
  206.    int Intersection_Found;
  207.    INTERSECTION *Local_Intersection;
  208.    VECTOR Halfway, REye, Local_Normal, Normal_Projection, Reflect_Direction;
  209.    COLOUR Light_Colour, Blocking_Colour;
  210.    PRIOQ *Local_Queue;
  211.  
  212.    if ((Object -> Object_Texture -> Object_Diffuse == 0.0) &&
  213.        (Object -> Object_Texture -> Object_Specular == 0.0) &&
  214.        (Object -> Object_Texture -> Object_Phong == 0.0))
  215.      return;
  216.  
  217.    if (Object -> Object_Texture -> Object_Specular != 0.0)
  218.       {
  219.       REye.x = -Eye->Direction.x;
  220.       REye.y = -Eye->Direction.y;
  221.       REye.z = -Eye->Direction.z;
  222.       }
  223.  
  224.    Local_Queue = pq_new (128);
  225.  
  226.    for (Light_Source = Frame.Light_Sources ; 
  227.         Light_Source != NULL;
  228.         Light_Source = Light_Source -> Next_Light_Source)
  229.       {
  230.       Intersection_Found = FALSE;  
  231.       Light_Source_Ray.Initial = *Intersection_Point;
  232.       Light_Source_Ray.Quadric_Constants_Cached = FALSE;
  233.       Light_Colour = Light_Source->Object_Colour;
  234.  
  235.       VSub (Light_Source_Ray.Direction,
  236.            Light_Source->Object_Center,
  237.        *Intersection_Point);
  238.  
  239.       VLength (Light_Source_Depth, Light_Source_Ray.Direction);
  240.  
  241.       VScale (Light_Source_Ray.Direction, Light_Source_Ray.Direction,
  242.                 1.0/Light_Source_Depth);
  243.  
  244.     /* What objects does this ray intersect? */
  245.       if (Quality > 3)
  246.          for (Blocking_Object = Frame.Objects ; 
  247.               Blocking_Object != NULL ;
  248.               Blocking_Object = Blocking_Object -> Next_Object) {
  249.  
  250.             Shadow_Ray_Tests++;
  251.             if (Blocking_Object == Light_Source)
  252.                continue;
  253.  
  254.             for (All_Intersections (Blocking_Object, &Light_Source_Ray, Local_Queue) ;
  255.                  (Local_Intersection = pq_get_highest(Local_Queue)) != NULL ;
  256.                  pq_delete_highest(Local_Queue)) {
  257.  
  258.                if ((Local_Intersection -> Depth < Light_Source_Depth-Small_Tolerance)
  259.                     && (Local_Intersection -> Depth > Small_Tolerance))
  260.                   {
  261.                   Shadow_Rays_Succeeded++;
  262.                   if (Blocking_Object->Transparency) {
  263.                      Make_Colour(&Blocking_Colour, 0.0, 0.0, 0.0);
  264.                      Colour_At(&Blocking_Colour, Blocking_Object, &Local_Intersection->Point);
  265.                      Light_Colour.Red *= 
  266.                                     Blocking_Colour.Red * Blocking_Colour.Alpha;
  267.                      Light_Colour.Green *= 
  268.                                     Blocking_Colour.Green * Blocking_Colour.Alpha;
  269.                      Light_Colour.Blue *=
  270.                                     Blocking_Colour.Blue * Blocking_Colour.Alpha;
  271.                      }
  272.                   else {
  273.                      Intersection_Found = TRUE;
  274.                      break;
  275.                      }
  276.                   }
  277.                }
  278.             if (Intersection_Found) {
  279.                while (pq_get_highest(Local_Queue))
  280.                   pq_delete_highest(Local_Queue);
  281.                break;
  282.                }
  283.             }
  284.  
  285.       if (!Intersection_Found)
  286.          {
  287.          if (Object->Object_Texture->Object_Phong)      /* Phong Specular Highlight rtn. */
  288.         {
  289.             VDot(Cos_Angle_Of_Incidence, Eye->Direction, *Surface_Normal);
  290.             if (Cos_Angle_Of_Incidence < 0.0)
  291.                {
  292.                Local_Normal = *Surface_Normal;
  293.                Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  294.                }
  295.             else
  296.                VScale (Local_Normal, *Surface_Normal, -1.0);
  297.  
  298.             VScale (Normal_Projection, Local_Normal, Cos_Angle_Of_Incidence);
  299.             VScale (Normal_Projection, Normal_Projection, 2.0);
  300.             VAdd (Reflect_Direction, Eye->Direction, Normal_Projection);
  301.  
  302.             VDot (Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray.Direction);
  303.             VLength (Normal_Length, Light_Source_Ray.Direction);
  304.             Cos_Angle_Of_Incidence /= Normal_Length;
  305.  
  306.             if (Cos_Angle_Of_Incidence < 0.0)
  307.                Cos_Angle_Of_Incidence = 0;
  308.  
  309.             if (Object -> Object_Texture -> Object_PhongSize != 1.0)
  310.                Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_PhongSize);
  311.             else
  312.                Intensity = Cos_Angle_Of_Incidence;
  313.  
  314.             Intensity *= Object -> Object_Texture -> Object_Phong;
  315.  
  316.             Colour->Red+=Intensity*(Light_Colour.Red);
  317.             Colour->Green+=Intensity*(Light_Colour.Green);
  318.             Colour->Blue+=Intensity*(Light_Colour.Blue);
  319.             }
  320.  
  321.          if (Object->Object_Texture->Object_Specular > 0.0)   /* better specular highlights */
  322.             {
  323.             VHalf (Halfway, REye, Light_Source_Ray.Direction);
  324.             VLength (Normal_Length, *Surface_Normal);
  325.             VLength (Halfway_Length, Halfway);
  326.             VDot (Cos_Angle_Of_Incidence, Halfway, *Surface_Normal);
  327.             Cos_Angle_Of_Incidence /= (Normal_Length * Halfway_Length);
  328.  
  329.             if (Cos_Angle_Of_Incidence < 0.0)
  330.                Cos_Angle_Of_Incidence = 0;
  331.  
  332.             if (Object -> Object_Texture -> Object_Roughness != 1.0)
  333.                Intensity = pow(Cos_Angle_Of_Incidence, 1 / Object->Object_Texture->Object_Roughness);
  334.             else
  335.                Intensity = Cos_Angle_Of_Incidence;
  336.  
  337.             Intensity *= Object->Object_Texture->Object_Specular;
  338.  
  339.             Colour->Red+=Intensity* (Light_Colour.Red);
  340.             Colour->Green+=Intensity* (Light_Colour.Green);
  341.             Colour->Blue+=Intensity* (Light_Colour.Blue);
  342.             }
  343.  
  344.          if (Object->Object_Texture->Object_Diffuse > 0.0)      /* now do normal diffuse */
  345.             {
  346.             VDot (Cos_Angle_Of_Incidence, *Surface_Normal, Light_Source_Ray.Direction);
  347.             if (Cos_Angle_Of_Incidence < 0.0)
  348.                Cos_Angle_Of_Incidence = -Cos_Angle_Of_Incidence;
  349.     
  350.             if (Object -> Object_Texture -> Object_Brilliance != 1.0)
  351.                Intensity = pow(Cos_Angle_Of_Incidence, Object->Object_Texture->Object_Brilliance);
  352.         else
  353.                Intensity = Cos_Angle_Of_Incidence;
  354.  
  355.             Intensity *= Object -> Object_Texture -> Object_Diffuse;
  356.  
  357.             RandomNumber = (rand()&0x7FFF)/(DBL) 0x7FFF;
  358.  
  359.             Intensity -= RandomNumber * Object->Object_Texture->Texture_Randomness;
  360.  
  361.             Intensity *= 1.0 - Surface_Colour->Alpha;
  362.         Colour->Red += Intensity * (Surface_Colour->Red) * (Light_Colour.Red);
  363.             Colour->Green += Intensity * (Surface_Colour->Green) * (Light_Colour.Green);
  364.             Colour->Blue += Intensity * (Surface_Colour->Blue) * (Light_Colour.Blue);
  365.         }
  366.          }
  367.       }
  368.    pq_free (Local_Queue);
  369.    return;
  370.    }
  371.  
  372. void Transmit (Object, Intersection_Point, Ray, Surface_Normal, Surface_Colour, Colour)
  373.    OBJECT *Object;
  374.    VECTOR *Intersection_Point;
  375.    RAY *Ray;
  376.    VECTOR *Surface_Normal;
  377.    COLOUR *Surface_Colour;
  378.    COLOUR *Colour;
  379.    {
  380.    RAY New_Ray;
  381.    COLOUR Temp_Colour;
  382.  
  383.    if (Surface_Colour->Alpha == 0.0)
  384.       return;
  385.  
  386.    New_Ray.Initial = *Intersection_Point;
  387.    New_Ray.Direction = Ray->Direction;
  388.  
  389.    Copy_Ray_Containers (&New_Ray, Ray);
  390.    Trace_Level++;
  391.    Transmitted_Rays_Traced++;
  392.    Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  393.    New_Ray.Quadric_Constants_Cached = FALSE;
  394.    Trace (&New_Ray, &Temp_Colour);
  395.    Trace_Level--;
  396.    (Colour -> Red) += Temp_Colour.Red * Surface_Colour->Red * Surface_Colour->Alpha;
  397.    (Colour -> Green) += Temp_Colour.Green * Surface_Colour->Green * Surface_Colour->Alpha;
  398.    (Colour -> Blue) += Temp_Colour.Blue * Surface_Colour->Blue * Surface_Colour->Alpha;
  399.    }
  400.  
  401.  
  402. void Reflect (Object, Intersection_Point, Ray, Surface_Normal, Colour)
  403.    OBJECT *Object;
  404.    VECTOR *Intersection_Point;
  405.    RAY *Ray;
  406.    VECTOR *Surface_Normal;
  407.    COLOUR *Colour;
  408.    {
  409.    RAY New_Ray;
  410.    COLOUR Temp_Colour;
  411.    VECTOR Local_Normal;
  412.    VECTOR Normal_Projection;
  413.    register DBL Normal_Component;
  414.  
  415.    if (Object -> Object_Texture -> Object_Reflection != 0.0)
  416.       {
  417.       Reflected_Rays_Traced++;
  418.       VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
  419.       if (Normal_Component < 0.0) {
  420.          Local_Normal = *Surface_Normal;
  421.          Normal_Component *= -1.0;
  422.          }
  423.       else
  424.          VScale (Local_Normal, *Surface_Normal, -1.0);
  425.  
  426.       VScale (Normal_Projection, Local_Normal, Normal_Component);
  427.       VScale (Normal_Projection, Normal_Projection, 2.0);
  428.       VAdd (New_Ray.Direction, Ray -> Direction, Normal_Projection);
  429.       New_Ray.Initial = *Intersection_Point;
  430.  
  431.       Copy_Ray_Containers (&New_Ray, Ray);
  432.       Trace_Level++;
  433.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  434.       New_Ray.Quadric_Constants_Cached = FALSE;
  435.       Trace (&New_Ray, &Temp_Colour);
  436.       Trace_Level--;
  437.       (Colour -> Red) += (Temp_Colour.Red) 
  438.                              * (Object -> Object_Texture -> Object_Reflection);
  439.       (Colour -> Green) += (Temp_Colour.Green)
  440.                              * (Object -> Object_Texture -> Object_Reflection);
  441.       (Colour -> Blue) += (Temp_Colour.Blue)
  442.                              * (Object -> Object_Texture -> Object_Reflection);
  443.       }
  444.    }
  445.  
  446. void Refract (Object, Intersection_Point, Ray, Surface_Normal, Colour)
  447.    OBJECT *Object;
  448.    VECTOR *Intersection_Point;
  449.    RAY *Ray;
  450.    VECTOR *Surface_Normal;
  451.    COLOUR *Colour;
  452.    {
  453.    RAY New_Ray;
  454.    COLOUR Temp_Colour;
  455.    VECTOR Local_Normal;
  456.    VECTOR Normal_Projection;
  457.    register DBL Normal_Component, Temp_IOR;
  458.  
  459.    if (Object -> Object_Texture -> Object_Refraction != 0.0)
  460.       {
  461.       Refracted_Rays_Traced++;
  462.       VDot (Normal_Component, Ray -> Direction, *Surface_Normal);
  463.       if (Normal_Component >= 0.0)
  464.          {
  465.          VScale (Local_Normal, *Surface_Normal, -1.0);
  466.          }
  467.       else
  468.          {
  469.          Local_Normal.x = Surface_Normal -> x;
  470.          Local_Normal.y = Surface_Normal -> y;
  471.          Local_Normal.z = Surface_Normal -> z;
  472.  
  473.          Normal_Component *= -1.0;
  474.          }
  475.  
  476.       VScale (Normal_Projection, Local_Normal, Normal_Component);
  477.       VAdd (Normal_Projection, Normal_Projection, Ray -> Direction);
  478.       Copy_Ray_Containers (&New_Ray, Ray);
  479.  
  480.       if (Ray -> Containing_Index == -1)
  481.          {
  482.        /* The ray is entering from the atmosphere */
  483.          Ray_Enter (&New_Ray, Object);
  484.  
  485.          VScale (Normal_Projection, Normal_Projection,
  486.                (Frame.Atmosphere_IOR)/(Object -> Object_Texture -> Object_Index_Of_Refraction));
  487.          }
  488.       else
  489.          {
  490.        /* The ray is currently inside an object */
  491.          if (New_Ray.Containing_Objects [New_Ray.Containing_Index] == Object)
  492.             {
  493.           /* The ray is leaving the current object */
  494.             Ray_Exit (&New_Ray);
  495.             if (New_Ray.Containing_Index == -1)
  496.              /* The ray is leaving into the atmosphere */
  497.                Temp_IOR = Frame.Atmosphere_IOR;
  498.             else
  499.              /* The ray is leaving into another object */
  500.                Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  501.  
  502.             VScale (Normal_Projection, Normal_Projection,
  503.                (Object -> Object_Texture -> Object_Index_Of_Refraction) / Temp_IOR);
  504.             }
  505.          else
  506.             {
  507.             /* The ray is entering a new object */
  508.             Temp_IOR = New_Ray.Containing_IORs [New_Ray.Containing_Index];
  509.             Ray_Enter (&New_Ray, Object);
  510.  
  511.             VScale (Normal_Projection, Normal_Projection,
  512.                  Temp_IOR/(Object -> Object_Texture -> Object_Index_Of_Refraction));
  513.  
  514.             }
  515.          }
  516.  
  517.       VScale (Local_Normal, Local_Normal, -1.0);
  518.       VAdd (New_Ray.Direction, Local_Normal, Normal_Projection);
  519.       VNormalize (New_Ray.Direction, New_Ray.Direction);
  520.       New_Ray.Initial = *Intersection_Point;
  521.       Trace_Level++;
  522.       Make_Colour (&Temp_Colour, 0.0, 0.0, 0.0);
  523.       New_Ray.Quadric_Constants_Cached = FALSE;
  524.       Trace (&New_Ray, &Temp_Colour);
  525.       Trace_Level--;
  526.       (Colour -> Red) += (Temp_Colour.Red)
  527.                         * (Object -> Object_Texture -> Object_Refraction);
  528.       (Colour -> Green) += (Temp_Colour.Green)
  529.                         * (Object -> Object_Texture -> Object_Refraction);
  530.       (Colour -> Blue) += (Temp_Colour.Blue)
  531.                         * (Object -> Object_Texture -> Object_Refraction);
  532.       }  
  533.    }
  534.  
  535. void Fog (Distance, Fog_Colour, Fog_Distance, Colour)
  536.    DBL Distance, Fog_Distance;
  537.    COLOUR *Fog_Colour, *Colour;
  538.    {
  539.    DBL Fog_Factor, Fog_Factor_Inverse;
  540.  
  541.    Fog_Factor = exp(-1.0 * Distance/Fog_Distance);
  542.    Fog_Factor_Inverse = 1.0 - Fog_Factor;
  543.    Colour->Red = Colour->Red*Fog_Factor + Fog_Colour->Red*Fog_Factor_Inverse;
  544.    Colour->Green = Colour->Green*Fog_Factor + Fog_Colour->Green*Fog_Factor_Inverse;
  545.    Colour->Blue = Colour->Blue*Fog_Factor + Fog_Colour->Blue*Fog_Factor_Inverse;
  546.    }
  547.