home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Graphics / Graphics.zip / povsrc31.zip / lighting.c < prev    next >
C/C++ Source or Header  |  2001-01-21  |  209KB  |  6,907 lines

  1. /****************************************************************************
  2. *                   lighting.c
  3. *
  4. *  -------------------------------------------------------
  5. *  ATTENTION:
  6. *  This is an unofficial version of lighting.c modified by
  7. *  Ryoichi Suzuki, rsuzuki@etl.go.jp for use with
  8. *  "isosurface" shape type.
  9. *  -------------------------------------------------------
  10. *  This module calculates lighting properties like ambient, diffuse, specular,
  11. *  reflection, refraction, etc.
  12. *
  13. *  from Persistence of Vision(tm) Ray Tracer
  14. *  Copyright 1996,1999 Persistence of Vision Team
  15. *---------------------------------------------------------------------------
  16. *  NOTICE: This source code file is provided so that users may experiment
  17. *  with enhancements to POV-Ray and to port the software to platforms other
  18. *  than those supported by the POV-Ray Team.  There are strict rules under
  19. *  which you are permitted to use this file.  The rules are in the file
  20. *  named POVLEGAL.DOC which should be distributed with this file.
  21. *  If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  22. *  Team Coordinator by email to team-coord@povray.org or visit us on the web at
  23. *  http://www.povray.org. The latest version of POV-Ray may be found at this site.
  24. *
  25. * This program is based on the popular DKB raytracer version 2.12.
  26. * DKBTrace was originally written by David K. Buck.
  27. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  28. *
  29. * Modifications by Robert G. Smith & Andreas Dilger, March 1999, used with
  30. * permission
  31. *
  32. *****************************************************************************/
  33.  
  34. #include "frame.h"
  35. #include "vector.h"
  36. #include "povproto.h"
  37. #include "blob.h"
  38. #include "bbox.h"
  39. #include "colour.h"
  40. #include "image.h"
  41. #include "interior.h"
  42. #ifdef IsoBlobPatch
  43. #include "isoblob.h"  /* Lummox JR, July 1999 */
  44. #endif
  45. #include "lbuffer.h"
  46. #include "lighting.h"
  47. #include "media.h"
  48. #include "mesh.h"
  49. #include "normal.h"
  50. #include "objects.h"
  51. #include "octree.h"
  52. #include "pattern.h"  /* [CEY 10/94] */
  53. #include "pigment.h"
  54. #include "povray.h"
  55. #include "radiosit.h"
  56. #include "ray.h"
  57. #include "render.h"
  58. #include "texture.h"
  59. #include "lightgrp.h"
  60.  
  61. /*YS april 2000 cache */
  62. #ifdef UseMediaAndLightCache
  63.  
  64. /* ------- cache init / reinit / deinit -------- */
  65. static void InitMallocCaches(void);
  66. static void DeInitMallocCaches(void);
  67. static void ReInitMallocCaches(void);
  68.  
  69. /* ------- cache sizes for statistics gathering ------- */
  70. long TotalMallocCacheSize=0;
  71. long MediaMallocCacheSize=0;
  72.  
  73. /* ------- Caches for DetermineApparantColour ------- */
  74. long MaxLightCacheDepth = 0;
  75. long LightingCacheIndex = -1;
  76.  
  77. DBL **WeightListCache = NULL;          /* cache weight list - each is fixed size */
  78. TEXTURE ***TextureListCache = NULL;    /* cache texture list - each is fixed size */
  79. LIGHT_TESTED **LightListCache = NULL;  /* cache for light_list - each is fixed size */
  80.  
  81.  
  82. /* ------- Caches for media calculations ------- */
  83. long MaxMediaCacheDepth = 0;
  84.  
  85. /* caches for all & lit intervals */
  86. long MediaCacheIndex=-1;
  87. LIGHT_LIST **MediaLightListCache = NULL;     /* cache for light_list - each is fixed size */
  88. LIT_INTERVAL **MediaLitIntervalCache = NULL; /* cache for lit_interval - each is fixed size */
  89. MEDIA_INTERVAL **MediaIntervalCache = NULL;  /* cache for media_interval */
  90. long *MediaIntervalCacheSize = NULL;         /* interval array sizes vary */
  91.  
  92. /* cache for media list in shadow calculations */
  93. long ShadowMediaListIndex=-1;
  94. IMEDIA ***ShadowMediaListCache = NULL;
  95. long *ShadowMediaListCacheSize = NULL;
  96.  
  97. /* cache for media list in lighting calculations */
  98. long LightingMediaListIndex=-1;
  99. IMEDIA ***LightingMediaListCache = NULL;
  100. long *LightingMediaListCacheSize = NULL;
  101.  
  102. /* s0 and s1 - always the same size - just malloc once and keep the arrays */
  103. DBL *s0 = NULL;
  104. DBL *s1 = NULL;
  105.  
  106. #ifdef AccumulateCacheStatistics
  107. long MaxAppColourRecCntr=-1;
  108. long MaxSimMediatRecCntr=-1;
  109. long MaxShadowTextRecCntr=-1;
  110. long MaxLightedTexture=-1;
  111. #endif
  112.  
  113. #endif
  114. /*YS*/
  115.  
  116. /* NK phmap */
  117. #include "photons.h"
  118. /* NK ---- */
  119. #include "matrices.h"
  120. #ifdef PostProcessPatch
  121. #include "postproc.h"
  122. #endif
  123. #ifdef MultiTextureCsgPatch
  124. #include "csg.h"
  125. #endif
  126.  
  127. #ifdef MotionBlurPatch
  128. extern int TimeStamp;
  129. #endif
  130.  
  131. #ifdef PostProcessPatch
  132. extern DBL savedRefractDepth;
  133. #endif
  134.  
  135. /* Global vars to remember which colour component is being traced */
  136. int disp_elem;        /* not thread safe */ /* 0=normal, 1..nelems=we're tracing elements */
  137. int disp_nelems;      /* not thread safe */
  138.  
  139. int alreadyBlurred;
  140.  
  141. /* NK rad */
  142. extern int firstRadiosityPass;
  143. /* NK ---- */
  144.  
  145. /*****************************************************************************
  146. * Local preprocessor defines
  147. ******************************************************************************/
  148.  
  149. #define BLACK_LEVEL 0.003
  150.  
  151. /*
  152.  * "Small_Tolerance" is just too tight for higher order polynomial equations.
  153.  * this value should probably be a variable of some sort, but for now just
  154.  * use a reasonably small value.  If people render real small objects real
  155.  * close to each other then there may be some shading problems.  Otherwise
  156.  * having SHADOW_TOLERANCE as large as this won't affect images.
  157.  */
  158.  
  159. #define SHADOW_TOLERANCE 1.0e-3
  160.  
  161. /* Number of inital entries in the texture and weight list. */
  162.  
  163. #define NUMBER_OF_ENTRIES 16
  164.  
  165.  
  166.  
  167. /*****************************************************************************
  168. * Local typedefs
  169. ******************************************************************************/
  170.  
  171.  
  172.  
  173. /*****************************************************************************
  174. * Local variables
  175. ******************************************************************************/
  176.  
  177. /* static variables for multi-layer speedups */
  178. /* this is a hack and should be done in a cleaner way in the future */
  179. /* NOT THREAD SAFE */
  180. static int photonsAlreadyGathered;
  181. static DBL previousRad;
  182.  
  183. static LIGHT_TESTED *Light_List; /* not thread safe */
  184. static TEXTURE **Texture_List; /* not thread safe */
  185. static DBL *Weight_List; /* not thread safe */
  186.  
  187. static int Number_Of_Textures_And_Weights; /* not thread safe */
  188.  
  189.  
  190. /** poviso:. July 14 '96 R.S. **/
  191. #ifdef POVISO
  192. int    Shadow_Test_Flag = FALSE;
  193. #endif
  194. /** --- **/
  195.  
  196. #ifdef NormalBugFix
  197. #define MAX_NESTED_TEXTURES 100
  198. static TEXTURE *warpNormalTextureList[MAX_NESTED_TEXTURES];
  199. int warpNormalTextures;
  200. #endif
  201.  
  202. /*****************************************************************************
  203. * Static functions
  204. ******************************************************************************/
  205.  
  206. static void block_area_light (LIGHT_SOURCE *Light_Source,
  207.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray,
  208.   VECTOR IPoint, COLOUR Light_Colour, int u1, int v1, int u2, int v2, int Level);
  209.  
  210. static void block_point_light (LIGHT_SOURCE *Light_Source,
  211.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour);
  212.  
  213. static void block_point_light_LBuffer (LIGHT_SOURCE *Light_Source,
  214.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour);
  215.  
  216. static void do_light (LIGHT_SOURCE *Light_Source,
  217.   DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR IPoint,
  218.   COLOUR Light_Colour);
  219.  
  220. static int do_blocking (INTERSECTION *Local_Intersection,
  221.   RAY *Light_Source_Ray, COLOUR Light_Colour, ISTACK *Local_Stack);
  222.  
  223. static void do_phong (FINISH *Finish, RAY *Light_Source_Ray,
  224.   VECTOR Eye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
  225.   COLOUR Layer_Texture_Colour);
  226.  
  227. static void do_specular (FINISH *Finish, RAY *Light_Source_Ray,
  228.   VECTOR REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
  229.   COLOUR Layer_Pigment_Colour);
  230.  
  231. static void do_diffuse (FINISH *Finish, RAY *Light_Source_Ray,
  232.   VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
  233.   COLOUR Layer_Pigment_Colour, DBL Attenuation);
  234.  
  235. static void do_irid (FINISH *Finish, RAY *Light_Source_Ray,
  236.   VECTOR Layer_Normal, VECTOR IPoint, COLOUR Colour);
  237.  
  238. static void Diffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR Layer_Normal,
  239.   COLOUR Layer_Pigment_Colour, COLOUR Colour,DBL Attenuation, OBJECT *Object);
  240.  
  241. static void Reflect (VECTOR, RAY*, VECTOR, VECTOR, COLOUR, DBL, DBL, int);
  242.  
  243. static int Refract (INTERIOR*, VECTOR, RAY*, VECTOR, VECTOR, COLOUR, DBL);
  244.  
  245. static void filter_shadow_ray (INTERSECTION *Ray_Intersection,
  246.   RAY *Light_Source_Ray, COLOUR Colour);
  247.  
  248. #ifdef InteriorTexturePatch
  249. static int create_texture_list (INTERSECTION *Ray_Intersection, DBL realNormDir);
  250. #else
  251. static int create_texture_list (INTERSECTION *Ray_Intersection);
  252. #endif
  253. static void do_texture_map (COLOUR Result_Colour,
  254.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
  255.   INTERSECTION *Ray_Intersection, int Shadow_Flag);
  256.  
  257. static void average_textures (COLOUR Result_Colour,
  258.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
  259.   INTERSECTION *Ray_Intersection, int Shadow_Flag);
  260.  
  261. static void compute_lighted_texture (COLOUR Result_Colour,
  262.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
  263.   INTERSECTION *Ray_Intersection);
  264.  
  265. static void compute_shadow_texture (COLOUR Filter_Colour,
  266.   TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray,
  267.   INTERSECTION *Ray_Intersection);
  268.  
  269. static void block_light_source (LIGHT_SOURCE *Light,
  270.   DBL Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR P, COLOUR Colour);
  271.  
  272. static void do_light_ray_atmosphere (RAY *Light_Source_Ray,
  273.   INTERSECTION *Ray_Intersection, COLOUR Colour, int Valid_Object);
  274.  
  275. static void determine_reflectivity (DBL *weight,
  276.   RGB reflectivity, COLOUR Reflection_Max, COLOUR Reflection_Min,
  277.   int Reflection_Type, DBL Reflection_Falloff, DBL cos_angle, RAY *Ray, INTERIOR *Interior);
  278.  
  279. /* NK phmap */
  280. static void compute_backtrace_texture(COLOUR LightCol, 
  281.   TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal, RAY *Ray, DBL Weight,
  282.   INTERSECTION *Intersection);
  283.  
  284. static void backtrace_average_textures (COLOUR Result_Colour,
  285.   TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal, RAY *Ray, DBL Weight,
  286.   INTERSECTION *Ray_Intersection, int Shadow_Flag);
  287.  
  288. static void GlobalPhotonDiffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR  Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object);
  289. /* NK ---- */
  290. /*YS 2000 made these two static and added prototypes*/
  291. static void Dispersion_Element_Hue(COLOUR Hue, int elem, int nelems);
  292. /*YS*/
  293.  
  294.  
  295. /*****************************************************************************
  296. *
  297. * FUNCTION
  298. *
  299. *   Initialize_Lighting_Code
  300. *
  301. * INPUT
  302. *
  303. * OUTPUT
  304. *   
  305. * RETURNS
  306. *   
  307. * AUTHOR
  308. *
  309. *   Dieter Bayer
  310. *   
  311. * DESCRIPTION
  312. *
  313. *   Allocate lists needed during lighting calculations.
  314. *
  315. * CHANGES
  316. *
  317. *   Sep 1994 : Creation.
  318. *
  319. *   Okt 1994 : Added initialization of Light_List and test if there are
  320. *              any light sources in the scene. [DB]
  321. *
  322. ******************************************************************************/
  323.  
  324. void Initialize_Lighting_Code()
  325. {
  326.   Light_List = NULL;
  327.   Texture_List = NULL;
  328.   Weight_List  = NULL;
  329.  
  330.   Number_Of_Textures_And_Weights = NUMBER_OF_ENTRIES;
  331.  
  332. #ifdef UseMediaAndLightCache
  333.  
  334.   InitMallocCaches();
  335.  
  336.   LightingCacheIndex++;
  337.   Light_List=LightListCache[LightingCacheIndex];
  338.   Texture_List = TextureListCache[LightingCacheIndex];
  339.   Weight_List = WeightListCache[LightingCacheIndex];
  340.  
  341. #else
  342.   /* Allocate memory for light list. */
  343.  
  344.   if (Frame.Number_Of_Light_Sources > 0)
  345.   {
  346.     Light_List = (LIGHT_TESTED *)POV_MALLOC(Frame.Number_Of_Light_Sources*sizeof(LIGHT_TESTED), "temporary light list");
  347.  
  348.     for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
  349.     {
  350.       Light_List[i].Tested = FALSE;
  351.  
  352.       Make_ColourA(Light_List[i].Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
  353.     }
  354.   }
  355.  
  356.   /* Allocate memory for texture and weight list. */
  357.  
  358.   Texture_List = (TEXTURE **)POV_MALLOC(Number_Of_Textures_And_Weights*sizeof(TEXTURE *), "texture list");
  359.  
  360.   Weight_List = (DBL *)POV_MALLOC(Number_Of_Textures_And_Weights*sizeof(DBL), "weight list");
  361. #endif  
  362.  
  363.   
  364. }
  365.  
  366.  
  367.  
  368. /*****************************************************************************
  369. *
  370. * FUNCTION
  371. *
  372. *   Reinitialize_Lighting_Code
  373. *
  374. * INPUT
  375. *
  376. *   Number_Of_Entries - New number of entries in the texture/weight lists
  377. *   
  378. * OUTPUT
  379. *
  380. * RETURNS
  381. *   
  382. * AUTHOR
  383. *
  384. *   Dieter Bayer
  385. *   
  386. * DESCRIPTION
  387. *
  388. *   Resize variable lists needed during lighting calculation.
  389. *
  390. * CHANGES
  391. *
  392. *   Jul 1995 : Creation.
  393. *
  394. *   Mar 1996 : We have to pass pointers to the lists to resize because during
  395. *              resizing the pointers to the lists change and thus the calling
  396. *              functions does not longer know where the lists are if the
  397. *              pointers to the lists where passed to it using arguments. [DB]
  398. *
  399. ******************************************************************************/
  400.  
  401. void Reinitialize_Lighting_Code(int Number_Of_Entries, TEXTURE ***Textures, DBL **Weights)
  402. {
  403.   if (Number_Of_Entries > Number_Of_Textures_And_Weights)
  404.   {
  405.     if (Number_Of_Entries >= INT_MAX / 2)
  406.     {
  407.       Error("Too many entries in texture and weight lists.\n");
  408.     }
  409.  
  410.     Number_Of_Textures_And_Weights = Number_Of_Entries;
  411.  
  412. #ifdef UseMediaAndLightCache
  413.     ReInitMallocCaches();
  414.     *Textures = Texture_List = TextureListCache[LightingCacheIndex];
  415.     *Weights = Weight_List = WeightListCache[LightingCacheIndex];
  416. #else
  417.     Texture_List = (TEXTURE **)POV_REALLOC(Texture_List, Number_Of_Textures_And_Weights*sizeof(TEXTURE *), "texture list");
  418.  
  419.     Weight_List = (DBL *)POV_REALLOC(Weight_List, Number_Of_Textures_And_Weights*sizeof(DBL), "weight list");
  420.  
  421.     *Textures = Texture_List;
  422.     *Weights  = Weight_List;
  423. #endif
  424.   }
  425. }
  426.  
  427.  
  428.  
  429. /*****************************************************************************
  430. *
  431. * FUNCTION
  432. *
  433. *   Deinitialize_Lighting_Code
  434. *
  435. * INPUT
  436. *   
  437. * OUTPUT
  438. *   
  439. * RETURNS
  440. *   
  441. * AUTHOR
  442. *
  443. *   Dieter Bayer
  444. *   
  445. * DESCRIPTION
  446. *
  447. *   Destroy all lists needed during lighting calculation.
  448. *
  449. * CHANGES
  450. *
  451. *   Sep 1994 : Creation.
  452. *
  453. *   Jul 1995 : Added code to free local texture and weight lists. [DB]
  454. *
  455. ******************************************************************************/
  456.  
  457. void Deinitialize_Lighting_Code()
  458. {
  459. #ifdef UseMediaAndLightCache
  460.   DeInitMallocCaches();
  461. #else
  462.   if (Light_List != NULL)
  463.   {
  464.     POV_FREE(Light_List);
  465.   }
  466.  
  467.   if (Texture_List != NULL)
  468.   {
  469.     POV_FREE(Texture_List);
  470.   }
  471.  
  472.   if (Weight_List != NULL)
  473.   {
  474.     POV_FREE(Weight_List);
  475.   }
  476. #endif
  477.   /*MH If a render is interrupted, this is set greater than one 
  478.   and dispersion would stop working if not given a value of 0*/
  479.  
  480.   if (disp_elem != 0) 
  481.   {
  482.    disp_elem = 0;
  483.   }
  484.  
  485.   Light_List   = NULL;
  486.   Texture_List = NULL;
  487.   Weight_List  = NULL;
  488. }
  489.  
  490.  
  491.  
  492. /*****************************************************************************
  493. *
  494. * FUNCTION
  495. *
  496. *   Determine_Apparent_Colour
  497. *
  498. * INPUT
  499. *
  500. *   Ray_Intersection - info on where ray hit & object it hit
  501. *   Ray              - the ray from which object is seen
  502. *   Weight           - Automatic depth control value
  503. *
  504. * OUTPUT
  505. *
  506. *   Colour           - resulting color is added to given color. The RGB
  507. *                      components are significant. The transmittance channel
  508. *                      is used as an alpha channel.
  509. *
  510. * RETURNS
  511. *
  512. * AUTHOR
  513. *
  514. *   POV-Ray Team
  515. *
  516. * DESCRIPTION
  517. *
  518. *   Given an intersection point, a ray, add that point's visible color
  519. *   to the given colour and return it.  This routine just does preliminary
  520. *   initializations and calls to set up the multi-texture blob list if any.
  521. *   Then it calls do_texture_map which in turn calls compute_lighted_texture
  522. *   to do the actual lighting calculations.  These functions were seperated
  523. *   from this function because do_texture_map may need to call itself
  524. *   recursively.
  525. *
  526. * CHANGES
  527. *
  528. *   Sep 1994 : Code for multi-textured blobs added. [DB]
  529. *
  530. *   Nov 1994 : Moved calls to Fog and Rainbow into tracing functions. [DB]
  531. *
  532. *   Jan 1995 : Moved much of code to do_texture_map and
  533. *              compute_lighted_texture [CEY]
  534. *
  535. *   Jul 1995 : Added code to support alpha channel. [DB]
  536. *
  537. *   Mar 1996 : Fixed severe bug (weight and texture lists were not saved) [DB]
  538. *
  539. ******************************************************************************/
  540.  
  541. void Determine_Apparent_Colour(INTERSECTION *Ray_Intersection, COLOUR Colour, RAY *Ray, DBL Weight)
  542. {
  543.   int i, Texture_Count;
  544. #ifndef UseMediaAndLightCache
  545.   size_t savelights_size, save_tw_size;
  546. #endif
  547.   DBL *save_Weights = NULL;
  548.   COLOUR C1;
  549.   VECTOR Raw_Normal;
  550.   VECTOR IPoint;
  551.   
  552.   /* NK 1998 */
  553.   UV_VECT UV_Coords;
  554.   /* NK ---- */
  555.   TEXTURE *Texture, **save_Textures = NULL;
  556.   LIGHT_TESTED *savelights = NULL;
  557.   DBL Normal_Direction;
  558.  
  559.  
  560.   /* NK phmap - set static variable to zero so we will gather */
  561.   /* non-zero will mean reuse already-gathered photons in the rest
  562.      of the layers */
  563.   photonsAlreadyGathered = 0;
  564.   /* NK --- */
  565.  
  566. #ifdef MotionBlurPatch
  567.   if (!backtraceFlag)
  568.   {
  569.     if (!TimeStamp && Ray_Intersection->Object->TimeStamp)
  570.       TimeStamp = Ray_Intersection->Object->TimeStamp;
  571.   }
  572. #endif
  573.  
  574.   /* NK depth */
  575.   Total_Depth += Ray_Intersection->Depth;
  576.   /* NK ---- */
  577.  
  578.   Assign_Vector(IPoint,Ray_Intersection->IPoint);
  579.  
  580.   /*
  581.    * Save existing light list if any. If we are not top level in recursion
  582.    * depth, this information may be reused by upper level of trace.
  583.    */
  584.  
  585. #ifdef UseMediaAndLightCache
  586.   LightingCacheIndex++; 
  587.   if ( LightingCacheIndex >= MaxLightCacheDepth) 
  588.   {
  589.     ResizeLightMallocCaches(MaxLightCacheDepth*2);
  590.   }
  591.  
  592. #ifdef AccumulateCacheStatistics
  593.   MaxAppColourRecCntr=max(MaxAppColourRecCntr,LightingCacheIndex);
  594. #endif
  595.  
  596.   Light_List=LightListCache[LightingCacheIndex];
  597. #else
  598.   savelights_size = (size_t)(Frame.Number_Of_Light_Sources*sizeof(LIGHT_TESTED));
  599.  
  600.   if (savelights_size > 0)
  601.   {
  602.     savelights = (LIGHT_TESTED *)POV_MALLOC(savelights_size, "Light list stack");
  603.     memcpy(savelights, Light_List, savelights_size);
  604.   }
  605. #endif
  606.   /* Init light list. */
  607.  
  608.   for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
  609.   {
  610.     Light_List[i].Tested = FALSE;
  611.   }
  612.  
  613.   /* Get the normal to the surface */
  614.  
  615.   Normal(Raw_Normal, Ray_Intersection->Object, Ray_Intersection);
  616.  
  617.   /* If the surface normal points away, flip its direction. */
  618.   VDot(Normal_Direction, Raw_Normal, Ray->Direction);
  619.   if (Normal_Direction > 0.0)
  620.   {
  621.     VScaleEq(Raw_Normal, -1.0);
  622.   }
  623.  
  624.   Assign_Vector(Ray_Intersection->INormal, Raw_Normal);
  625.   /* and save to intersection -hdf- */
  626.   Assign_Vector(Ray_Intersection->PNormal, Raw_Normal);
  627.  
  628.   if (Test_Flag(Ray_Intersection->Object, UV_FLAG) ||
  629.       (opts.postProcessFlags & PP_FLAG_IUV))
  630.   {
  631.     /* get the UV vect of the intersection */
  632.     UVCoord(UV_Coords, Ray_Intersection->Object, Ray_Intersection);
  633.     /* save the normal and UV coords into Intersection */
  634.     Assign_UV_Vect(Ray_Intersection->Iuv, UV_Coords);
  635.   }
  636.  
  637.   /* now switch to UV mapping if we need to */
  638.   if (Test_Flag(Ray_Intersection->Object, UV_FLAG))
  639.   {
  640.     IPoint[X] = UV_Coords[U];
  641.     IPoint[Y] = UV_Coords[V];
  642.     IPoint[Z] = 0;
  643.   }
  644.  
  645.   /*
  646.    * Save texture and weight lists.
  647.    */
  648.  
  649. #ifdef UseMediaAndLightCache
  650.   /* this has already been resized when LightingCacheIndex was incremented */
  651.   Weight_List=WeightListCache[LightingCacheIndex];
  652.   Texture_List=TextureListCache[LightingCacheIndex];
  653. #else
  654.   save_tw_size = (size_t)Number_Of_Textures_And_Weights;
  655.  
  656.   if (save_tw_size > 0)
  657.   {
  658.     save_Weights = (DBL *)POV_MALLOC(save_tw_size * sizeof(DBL), "Weight list stack");
  659.     memcpy(save_Weights, Weight_List, save_tw_size * sizeof(DBL));
  660.     save_Textures = (TEXTURE **)POV_MALLOC(save_tw_size * sizeof(TEXTURE *), "Weight list stack");
  661.     memcpy(save_Textures, Texture_List, save_tw_size * sizeof(TEXTURE *));
  662.   }
  663. #endif  
  664.  
  665.   /* Get texture list and weights. */
  666.  
  667. #ifdef InteriorTexturePatch
  668.   Texture_Count = create_texture_list (Ray_Intersection, Normal_Direction);
  669. #else
  670.   Texture_Count = create_texture_list (Ray_Intersection);
  671. #endif
  672.   /*
  673.    * Now, we perform the lighting calculations by stepping through
  674.    * the list of textures and summing the weighted color.
  675.    */
  676.  
  677.   for (i = 0; i < Texture_Count; i++)
  678.   {
  679.     /* If contribution of this texture is neglectable skip ahead. */
  680.  
  681.     if (Weight_List[i] < BLACK_LEVEL)
  682.     {
  683.       continue;
  684.     }
  685.  
  686.     Texture = Texture_List[i];
  687.  
  688.     /* NK phmap */
  689.     if(backtraceFlag)
  690.     {
  691.       C1[0] = Colour[0]*Weight_List[i];
  692.       C1[1] = Colour[1]*Weight_List[i];
  693.       C1[2] = Colour[2]*Weight_List[i];
  694.       do_texture_map(C1, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection, FALSE);
  695.     }
  696.     else
  697.     {
  698.     /* NK ---- */
  699.       do_texture_map(C1, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection, FALSE);
  700.  
  701.       Colour[RED]   += Weight_List[i] * C1[RED];
  702.       Colour[GREEN] += Weight_List[i] * C1[GREEN];
  703.       Colour[BLUE]  += Weight_List[i] * C1[BLUE];
  704.     /* NK phmap */
  705.     }
  706.     /* NK ---- */
  707.  
  708.     /* Use transmittance value for alpha channel support. [DB] */
  709.  
  710. /*
  711.     Colour[TRANSM]  += Weight_List[i] * C1[TRANSM];
  712. */
  713.     Colour[TRANSM] *= C1[TRANSM];
  714.   }
  715.  
  716.   /* Restore the light list to its original form */
  717.  
  718. #ifdef UseMediaAndLightCache
  719.   LightingCacheIndex--;
  720.  
  721.   Light_List=LightListCache[LightingCacheIndex];
  722. #else
  723.   if (savelights_size > 0)
  724.   {
  725.     memcpy(Light_List, savelights, savelights_size);
  726.     POV_FREE(savelights);
  727.   }
  728. #endif
  729.  
  730.   /* Restore the weight and texture list. */
  731.  
  732. #ifdef UseMediaAndLightCache
  733.   Weight_List=WeightListCache[LightingCacheIndex];
  734.   Texture_List=TextureListCache[LightingCacheIndex];
  735. #else
  736.   if (save_tw_size > 0)
  737.   {
  738.     memcpy(Weight_List, save_Weights, save_tw_size * sizeof(DBL));
  739.     memcpy(Texture_List, save_Textures, save_tw_size * sizeof(TEXTURE *));
  740.     POV_FREE(save_Weights);
  741.     POV_FREE(save_Textures);
  742.   }
  743. #endif
  744.  
  745.  
  746.   /* NK depth */
  747.   Total_Depth -= Ray_Intersection->Depth;
  748.   /* NK ---- */
  749. }
  750.  
  751.  
  752.  
  753. /*****************************************************************************
  754. *
  755. * FUNCTION
  756. *
  757. *   Test_Shadow
  758. *
  759. * INPUT
  760. *
  761. *   Light            - Light source
  762. *   P                - Point to test
  763. *
  764. * OUTPUT
  765. *
  766. *   Depth            - Distance to light source
  767. *   Light_Source_Ray - Light ray pointing towards the light source
  768. *   Eye_Ray          - Current viewing ray
  769. *   Colour           - Light color reaching point P
  770. *
  771. * RETURNS
  772. *
  773. *   int - TRUE if point lies in shadow
  774. *
  775. * AUTHOR
  776. *
  777. *   Dieter Bayer
  778. *
  779. * DESCRIPTION
  780. *
  781. *   Test if a given point is in shadow in respect to the given light source.
  782. *
  783. *   The viewing ray is used to initialize the ray containers of the
  784. *   light source ray.
  785. *
  786. * CHANGES
  787. *
  788. *   Nov 1994 : Creation.
  789. *
  790. ******************************************************************************/
  791.  
  792. int Test_Shadow(LIGHT_SOURCE *Light, DBL *Depth, RAY *Light_Source_Ray, RAY  *Eye_Ray, VECTOR P, COLOUR Colour)
  793. {
  794.   do_light(Light, Depth, Light_Source_Ray, Eye_Ray, P, Colour);
  795.  
  796.   /*
  797.    * There's no need to test for shadows if no light
  798.    * is coming from the light source.
  799.    */
  800.  
  801.   if ((Colour[X] < BLACK_LEVEL) && (Colour[Y] < BLACK_LEVEL) && (Colour[Z] < BLACK_LEVEL))
  802.   {
  803.     return(TRUE);
  804.   }
  805.   else
  806.   {
  807.     /* Test for shadows. */
  808.  
  809.     if ((opts.Quality_Flags & Q_SHADOW) && 
  810.       ((Light->Projected_Through_Object != NULL) || ((Light->Projected_Through_Object != NULL) || (Light->Light_Type != FILL_LIGHT_SOURCE))))
  811.     {
  812.       block_light_source(Light, *Depth, Light_Source_Ray, Eye_Ray, P, Colour);
  813.  
  814.       if ((Colour[X] < BLACK_LEVEL) && (Colour[Y] < BLACK_LEVEL) && (Colour[Z] < BLACK_LEVEL))
  815.       {
  816.         return(TRUE);
  817.       }
  818.     }
  819.   }
  820.  
  821.   return(FALSE);
  822. }
  823.  
  824.  
  825.  
  826. /*****************************************************************************
  827. *
  828. * FUNCTION
  829. *
  830. *   block_point_light_LBuffer
  831. *
  832. * INPUT
  833. *
  834. *   Light_Source       - Light source to test
  835. *
  836. * OUTPUT
  837. *
  838. *   Light_Source_Depth - (Remaining) distance to the light source
  839. *   Light_Source_Ray   - (Remaining) ray to the light source
  840. *   Colour             - Color reaching initial point from light source
  841. *
  842. * RETURNS
  843. *
  844. * AUTHOR
  845. *
  846. *   Dieter Bayer
  847. *
  848. * DESCRIPTION
  849. *
  850. *   Determine how much light from the given light source arrives at the
  851. *   given point (starting point of the light source ray). The light
  852. *   is blocked by solid objects and/or attenuated by translucent objects.
  853. *
  854. *   Note that both the distance to the light source and the light source
  855. *   ray are modified. Thus after a call to this function one knows
  856. *   how much distance remains to the light source and where the last
  857. *   intersection point with a translucent object was (starting point
  858. *   of light source ray after the call).
  859. *
  860. *   This function uses the light buffer to speed up shadow calculation.
  861. *
  862. * CHANGES
  863. *
  864. *   Jul 1994 : Creation.
  865. *
  866. ******************************************************************************/
  867.  
  868. #ifdef MotionBlurPatch
  869. static void block_point_light_LBuffer_with_blur (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
  870. {
  871.   COLOUR Colour2,ColourSum;
  872.   DBL Light_Source_Depth2, DepthSum;
  873.   RAY Light_Source_Ray2;
  874.  
  875.   if(TimeStamp || opts.motionBlurCount<=1)
  876.   {
  877.     block_point_light_LBuffer(Light_Source,Light_Source_Depth,Light_Source_Ray,Light_Colour);
  878.   }
  879.   else
  880.   {
  881.     Assign_Colour(Colour2,Light_Colour);
  882.     Light_Source_Depth2 = *Light_Source_Depth;
  883.     Light_Source_Ray2 = *Light_Source_Ray;
  884.     block_point_light_LBuffer(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
  885.  
  886.  
  887.     if(TimeStamp)
  888.     {
  889.       int tracedTimeStamp = TimeStamp;
  890.  
  891.       Assign_Colour(ColourSum,Colour2);
  892.       DepthSum=Light_Source_Depth2;
  893.  
  894.       for (TimeStamp=1; TimeStamp<=opts.motionBlurCount; TimeStamp++)
  895.       {
  896.         if(TimeStamp!=tracedTimeStamp)
  897.         {
  898.           Assign_Colour(Colour2,Light_Colour);
  899.           Light_Source_Depth2 = *Light_Source_Depth;
  900.           Light_Source_Ray2 = *Light_Source_Ray;
  901.           block_point_light_LBuffer(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
  902.  
  903.           DepthSum+=Light_Source_Depth2;
  904.           Add_Colour(ColourSum,ColourSum,Colour2);
  905.         }
  906.       }
  907.       Scale_Colour(Light_Colour,ColourSum,1.0/opts.motionBlurCount);
  908.       *Light_Source_Depth=DepthSum/opts.motionBlurCount;
  909.     }
  910.     else
  911.     {
  912.       Assign_Colour(Light_Colour,Colour2);
  913.       *Light_Source_Depth=Light_Source_Depth2;
  914.     }
  915.     TimeStamp = 0;
  916.   }
  917. }
  918. #endif
  919.  
  920. static void block_point_light_LBuffer(LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
  921. {
  922.   int Quit_Looking, Not_Found_Shadow, Cache_Me;
  923.   int u, v, axis;
  924.   DBL ax, ay, az;
  925.   VECTOR V1;
  926.   OBJECT *Blocking_Object;
  927.   ISTACK *Local_Stack;
  928.   INTERSECTION *Local_Intersection, Bounded_Intersection, Temp_Intersection;
  929.  
  930.   /* Projected through main tests */
  931.  
  932.   DBL Projected_Depth=0.0;
  933.  
  934.   if (Light_Source->Projected_Through_Object != NULL){
  935.     if (Intersection(&Temp_Intersection,
  936.     Light_Source->Projected_Through_Object,Light_Source_Ray)){
  937.       if ( (Temp_Intersection.Depth - *Light_Source_Depth) < 0.0 ){
  938.         Projected_Depth = 
  939.           *Light_Source_Depth - fabs(Temp_Intersection.Depth) + Small_Tolerance;
  940.       }else {
  941.          Light_Colour[0] =
  942.          Light_Colour[1] =
  943.          Light_Colour[2] = 0.0;
  944.          return;
  945.       }
  946.     }else {
  947.        Light_Colour[0] =
  948.        Light_Colour[1] =
  949.        Light_Colour[2] = 0.0;
  950.        return;    
  951.     }
  952.     if(Light_Source->Light_Type == FILL_LIGHT_SOURCE) return;
  953.   }
  954.  
  955.   Local_Stack = open_istack();
  956.  
  957.   Quit_Looking = FALSE;
  958.  
  959.   /* First test the cached object (don't cache semi-transparent objects). */
  960.  
  961.   if (Light_Source->Shadow_Cached_Object != NULL)
  962.   {
  963.     Increase_Counter(stats[Shadow_Ray_Tests]);
  964.  
  965.     if (Ray_In_Bound(Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
  966.     {
  967. #ifdef MotionBlurPatch
  968.       if (!TimeStamp || 
  969.           !Light_Source->Shadow_Cached_Object->TimeStamp ||
  970.           Light_Source->Shadow_Cached_Object->TimeStamp==TimeStamp)
  971. #endif
  972.       if (All_Intersections(Light_Source->Shadow_Cached_Object, Light_Source_Ray, Local_Stack))
  973.       {
  974.         while ((Local_Intersection=pop_entry(Local_Stack)) != NULL)
  975.         {
  976.           if ((!Check_No_Shadow_Group(Local_Intersection->Object, Light_Source)) &&
  977.               (Check_Light_Group(Local_Intersection->Object, Light_Source)) &&
  978.               (Local_Intersection->Depth < *Light_Source_Depth-SHADOW_TOLERANCE) &&
  979.               ((*Light_Source_Depth - Local_Intersection->Depth) > Projected_Depth) &&
  980.               (Local_Intersection->Depth > SHADOW_TOLERANCE))
  981.           {
  982.           Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
  983.           if (do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack))
  984.             {
  985.               Quit_Looking = TRUE;
  986.  
  987.               Increase_Counter(stats[Shadow_Cache_Hits]);
  988.  
  989.               break;
  990.             }
  991.           }
  992.         }
  993.       }
  994.     }
  995.  
  996.     /* Exit if the cached object was hit. */
  997.  
  998.     if (Quit_Looking)
  999.     {
  1000.       close_istack(Local_Stack);
  1001.  
  1002.       return;
  1003.     }
  1004.   }
  1005.  
  1006.   /*
  1007.    * Determine the side and the coordinates at which the ray
  1008.    * pierces the cube enclosing the light source.
  1009.    */
  1010.  
  1011.   V1[X] = -Light_Source_Ray->Direction[X];
  1012.   V1[Y] = -Light_Source_Ray->Direction[Y];
  1013.   V1[Z] = -Light_Source_Ray->Direction[Z];
  1014.  
  1015.   ax = fabs(V1[X]);
  1016.   ay = fabs(V1[Y]);
  1017.   az = fabs(V1[Z]);
  1018.  
  1019.   if ((ax>ay) && (ax>az))
  1020.   {
  1021.     if (V1[X]>0.0)
  1022.     {
  1023.       axis = XaxisP;
  1024.     }
  1025.     else
  1026.     {
  1027.       axis = XaxisM;
  1028.     }
  1029.  
  1030.     u = (int)(MAX_BUFFER_ENTRY * V1[Y]/ax);
  1031.     v = (int)(MAX_BUFFER_ENTRY * V1[Z]/ax);
  1032.   }
  1033.   else
  1034.   {
  1035.     if (ay>az)
  1036.     {
  1037.       if (V1[Y]>0.0)
  1038.       {
  1039.         axis = YaxisP;
  1040.       }
  1041.       else
  1042.       {
  1043.         axis = YaxisM;
  1044.       }
  1045.  
  1046.       u = (int)(MAX_BUFFER_ENTRY * V1[X]/ay);
  1047.       v = (int)(MAX_BUFFER_ENTRY * V1[Z]/ay);
  1048.     }
  1049.     else
  1050.     {
  1051.       if (V1[Z]>0.0)
  1052.       {
  1053.         axis = ZaxisP;
  1054.       }
  1055.       else
  1056.       {
  1057.         axis = ZaxisM;
  1058.       }
  1059.  
  1060.       u = (int)(MAX_BUFFER_ENTRY * V1[X]/az);
  1061.       v = (int)(MAX_BUFFER_ENTRY * V1[Y]/az);
  1062.     }
  1063.   }
  1064.  
  1065.   /* If there are no objects in the direction of the ray we can exit. */
  1066.  
  1067.   if (Light_Source->Light_Buffer[axis] == NULL)
  1068.   {
  1069.     close_istack(Local_Stack);
  1070.  
  1071.     return;
  1072.   }
  1073.  
  1074.   /* Look for shadows. */
  1075.  
  1076.   Not_Found_Shadow = TRUE;
  1077.  
  1078.   Cache_Me = FALSE;
  1079.  
  1080.   while (!Quit_Looking)
  1081.   {
  1082.     Increase_Counter(stats[Shadow_Ray_Tests]);
  1083.  
  1084.     Bounded_Intersection.Depth = *Light_Source_Depth;
  1085.  
  1086.     if (Intersect_Light_Tree(Light_Source_Ray, Light_Source->Light_Buffer[axis], u, v, &Bounded_Intersection, &Blocking_Object, Light_Source))
  1087.     {
  1088.       if (Bounded_Intersection.Depth > (*Light_Source_Depth - Projected_Depth) )
  1089.       {
  1090.         /* Intersection was beyond the light. */
  1091.  
  1092.         break;
  1093.       }
  1094.  
  1095.       if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  1096.       {
  1097.         Increase_Counter(stats[Shadow_Rays_Succeeded]);
  1098.  
  1099.         Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
  1100.  
  1101.         filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
  1102.  
  1103.         if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  1104.             (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  1105.             (fabs(Light_Colour[BLUE])  < BLACK_LEVEL) &&
  1106.             (Test_Flag(Blocking_Object, OPAQUE_FLAG)))
  1107.         {
  1108.           Cache_Me = Not_Found_Shadow;
  1109.  
  1110.           break; /* from while */
  1111.         }
  1112.       }
  1113.  
  1114.       /* Move the ray to the point of intersection, plus some */
  1115.  
  1116.       *Light_Source_Depth -= Bounded_Intersection.Depth;
  1117.  
  1118.       Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
  1119.  
  1120.       Not_Found_Shadow = FALSE;
  1121.     }
  1122.     else
  1123.     {
  1124.       /* No intersections in the direction of the ray. */
  1125.  
  1126.       break;
  1127.     }
  1128.   }
  1129.  
  1130.   if (Cache_Me)
  1131.   {
  1132.     Light_Source->Shadow_Cached_Object = Blocking_Object;
  1133.   }
  1134.  
  1135.   close_istack(Local_Stack);
  1136. }
  1137.  
  1138.  
  1139.  
  1140. /*****************************************************************************
  1141. *
  1142. * FUNCTION
  1143. *
  1144. *   block_point_light
  1145. *
  1146. * INPUT
  1147. *
  1148. *   Light_Source       - Light source to test
  1149. *   Eye_Ray            - Current viewing ray
  1150. *
  1151. * OUTPUT
  1152. *
  1153. *   Light_Source_Depth - (Remaining) distance to the light source
  1154. *   Light_Source_Ray   - (Remaining) ray to the light source
  1155. *   Colour             - Color reaching initial point from light source
  1156. *
  1157. * RETURNS
  1158. *
  1159. * AUTHOR
  1160. *
  1161. *   POV-Ray Team
  1162. *
  1163. * DESCRIPTION
  1164. *
  1165. *   See block_point_light_LBuffer for a description.
  1166. *
  1167. *   This function uses the hierarchical bounding box volume to
  1168. *   speed up shadow testing.
  1169. *
  1170. * CHANGES
  1171. *
  1172. *   -
  1173. *
  1174. ******************************************************************************/
  1175. #ifdef MotionBlurPatch
  1176. static void block_point_light_with_blur (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
  1177. {
  1178.   COLOUR Colour2,ColourSum;
  1179.   DBL Light_Source_Depth2, DepthSum;
  1180.   RAY Light_Source_Ray2;
  1181.  
  1182.   if(TimeStamp)
  1183.   {
  1184.     block_point_light(Light_Source,Light_Source_Depth,Light_Source_Ray,Light_Colour);
  1185.   }
  1186.   else
  1187.   {
  1188.     Assign_Colour(Colour2,Light_Colour);
  1189.     Light_Source_Depth2 = *Light_Source_Depth;
  1190.     Light_Source_Ray2 = *Light_Source_Ray;
  1191.     block_point_light(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
  1192.  
  1193.  
  1194.     if(TimeStamp)
  1195.     {
  1196.       int tracedTimeStamp = TimeStamp;
  1197.  
  1198.       Assign_Colour(ColourSum,Colour2);
  1199.       DepthSum=Light_Source_Depth2;
  1200.  
  1201.       for (TimeStamp=1; TimeStamp<=opts.motionBlurCount; TimeStamp++)
  1202.       {
  1203.         if(TimeStamp!=tracedTimeStamp)
  1204.         {
  1205.           Assign_Colour(Colour2,Light_Colour);
  1206.           Light_Source_Depth2 = *Light_Source_Depth;
  1207.           Light_Source_Ray2 = *Light_Source_Ray;
  1208.           block_point_light(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
  1209.  
  1210.           DepthSum+=Light_Source_Depth2;
  1211.           Add_Colour(ColourSum,ColourSum,Colour2);
  1212.         }
  1213.       }
  1214.       Scale_Colour(Light_Colour,ColourSum,1.0/opts.motionBlurCount);
  1215.       *Light_Source_Depth=DepthSum/opts.motionBlurCount;
  1216.     }
  1217.     else
  1218.     {
  1219.       Assign_Colour(Light_Colour,Colour2);
  1220.       *Light_Source_Depth=Light_Source_Depth2;
  1221.     }
  1222.     TimeStamp = 0;
  1223.   }
  1224. }
  1225. #endif
  1226.  
  1227. static void block_point_light (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
  1228. {
  1229.   OBJECT *Blocking_Object;
  1230.   int Quit_Looking, Not_Found_Shadow, Cache_Me, Maybe_Found;
  1231.   INTERSECTION *Local_Intersection, Bounded_Intersection, Temp_Intersection;
  1232.   ISTACK *Local_Stack;
  1233.  
  1234.   /* Projected through main tests */
  1235.   
  1236.   DBL Projected_Depth=0.0;
  1237.  
  1238.   if (Light_Source->Projected_Through_Object != NULL){
  1239.     if (Intersection(&Temp_Intersection,
  1240.     Light_Source->Projected_Through_Object,Light_Source_Ray)){
  1241.       if ( (Temp_Intersection.Depth - *Light_Source_Depth) < 0.0 ){
  1242.         Projected_Depth = 
  1243.           *Light_Source_Depth - fabs(Temp_Intersection.Depth) + Small_Tolerance;
  1244.       }else {
  1245.          Light_Colour[0] =
  1246.          Light_Colour[1] =
  1247.          Light_Colour[2] = 0.0;
  1248.          return;
  1249.       }
  1250.     }else {
  1251.        Light_Colour[0] =
  1252.        Light_Colour[1] =
  1253.        Light_Colour[2] = 0.0;
  1254.        return;    
  1255.     }
  1256.     if(Light_Source->Light_Type == FILL_LIGHT_SOURCE) return;
  1257.   }
  1258.  
  1259.  Local_Stack = open_istack ();
  1260.  
  1261.   Quit_Looking = FALSE;
  1262.  
  1263.   /* First test the cached object (don't cache semi-transparent objects). */
  1264.  
  1265.   if (Light_Source->Shadow_Cached_Object != NULL)
  1266.   {
  1267.     Increase_Counter(stats[Shadow_Ray_Tests]);
  1268.  
  1269.     if (Ray_In_Bound(Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
  1270.     {
  1271. #ifdef MotionBlurPatch
  1272.       if (!TimeStamp || 
  1273.           !Light_Source->Shadow_Cached_Object->TimeStamp ||
  1274.           Light_Source->Shadow_Cached_Object->TimeStamp==TimeStamp)
  1275. #endif
  1276.       if (All_Intersections(Light_Source->Shadow_Cached_Object, Light_Source_Ray, Local_Stack))
  1277.       {
  1278.         while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
  1279.         {
  1280.           if ((!Check_No_Shadow_Group(Local_Intersection->Object, Light_Source)) &&
  1281.               (Check_Light_Group(Local_Intersection->Object, Light_Source)) &&
  1282.               (Local_Intersection->Depth < *Light_Source_Depth-SHADOW_TOLERANCE) &&
  1283.               ((*Light_Source_Depth - Local_Intersection->Depth) > Projected_Depth) &&
  1284.               (Local_Intersection->Depth > SHADOW_TOLERANCE))
  1285.           {
  1286.             Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
  1287.             if (do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack))
  1288.             {
  1289.               Quit_Looking = TRUE;
  1290.  
  1291.               Increase_Counter(stats[Shadow_Cache_Hits]);
  1292.  
  1293.               break;
  1294.             }
  1295.           }
  1296.         }
  1297.       }
  1298.     }
  1299.  
  1300.     if (Quit_Looking)
  1301.     {
  1302.       close_istack (Local_Stack);
  1303.  
  1304.       return;
  1305.     }
  1306.   }
  1307.  
  1308.   /* Look for shadows. */
  1309.  
  1310.   Not_Found_Shadow = TRUE;
  1311.  
  1312.   Cache_Me = FALSE;
  1313.  
  1314.   if (!opts.Use_Slabs)
  1315.   {
  1316.     while (!Quit_Looking)
  1317.     {
  1318.       /* Use brute force method to get shadows. */
  1319.  
  1320.       Maybe_Found = FALSE;
  1321.  
  1322.       Bounded_Intersection.Depth = *Light_Source_Depth - Projected_Depth;
  1323.  
  1324.       for (Blocking_Object = Frame.Objects; Blocking_Object != NULL; Blocking_Object = Blocking_Object->Sibling)
  1325.       {
  1326.         if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  1327.         {
  1328.           if (!Check_No_Shadow_Group(Blocking_Object, Light_Source) &&
  1329.               (Check_Light_Group(Blocking_Object, Light_Source)))
  1330.           {
  1331.             Increase_Counter(stats[Shadow_Ray_Tests]);
  1332.  
  1333.             if (Intersection(&Temp_Intersection, Blocking_Object, Light_Source_Ray))
  1334.             {
  1335.               if (Temp_Intersection.Depth < Bounded_Intersection.Depth)
  1336.               {
  1337.                 Maybe_Found = TRUE;
  1338.  
  1339.                 Bounded_Intersection = Temp_Intersection;
  1340.               }
  1341.             }
  1342.           }
  1343.         }
  1344.       }
  1345.  
  1346.       if (Maybe_Found)
  1347.       {
  1348.         Increase_Counter(stats[Shadow_Rays_Succeeded]);
  1349.  
  1350.         Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
  1351.  
  1352.         filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
  1353.  
  1354.         if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  1355.             (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  1356.             (fabs(Light_Colour[BLUE])  < BLACK_LEVEL) &&
  1357.             (Test_Flag(Bounded_Intersection.Object, OPAQUE_FLAG)))
  1358.         {
  1359.           Cache_Me = Not_Found_Shadow;
  1360.  
  1361.           break;
  1362.         }
  1363.  
  1364.         /* Move the ray to the point of intersection, plus some */
  1365.  
  1366.         *Light_Source_Depth -= Bounded_Intersection.Depth;
  1367.  
  1368.         Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
  1369.  
  1370.         Not_Found_Shadow = FALSE;
  1371.       }
  1372.       else
  1373.       {
  1374.         /* No intersections in the direction of the ray. */
  1375.  
  1376.         break;
  1377.       }
  1378.     }
  1379.   }
  1380.   else
  1381.   {
  1382.     /* Use bounding slabs to look for shadows. */
  1383. #ifdef NoImageNoReflectionPatch
  1384.     /* JG start */
  1385.     In_Shadow_Ray = TRUE;
  1386.     /* JG end */
  1387. #endif
  1388.     while (!Quit_Looking)
  1389.     {
  1390.       Increase_Counter(stats[Shadow_Ray_Tests]);
  1391.  
  1392.       Bounded_Intersection.Depth = *Light_Source_Depth;
  1393.  
  1394.       if (Intersect_BBox_Tree(Root_Object, Light_Source_Ray, &Bounded_Intersection, &Blocking_Object))
  1395.       {
  1396.         if (Bounded_Intersection.Depth > (*Light_Source_Depth - Projected_Depth))
  1397.         {
  1398.           /* Intersection was beyond the light. */
  1399.  
  1400.           break;
  1401.         }
  1402.  
  1403.         if (!Check_No_Shadow_Group(Bounded_Intersection.Object, Light_Source) &&
  1404.              (Check_Light_Group(Bounded_Intersection.Object, Light_Source)) )
  1405.         {
  1406.           if (Blocking_Object != Light_Source->Shadow_Cached_Object)
  1407.           {
  1408.             Increase_Counter(stats[Shadow_Rays_Succeeded]);
  1409.  
  1410.             Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
  1411.  
  1412.             filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
  1413.  
  1414.             if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  1415.                 (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  1416.                 (fabs(Light_Colour[BLUE])  < BLACK_LEVEL) &&
  1417.                 (Test_Flag(Blocking_Object, OPAQUE_FLAG)))
  1418.             {
  1419.               Cache_Me = Not_Found_Shadow;
  1420.  
  1421.               break; /* from while */
  1422.             }
  1423.           }
  1424.         }
  1425.  
  1426.         /* Move the ray to the point of intersection, plus some */
  1427.  
  1428.         *Light_Source_Depth -= Bounded_Intersection.Depth;
  1429.  
  1430.         Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
  1431.  
  1432.         Not_Found_Shadow = FALSE;
  1433.       }
  1434.       else
  1435.       {
  1436.         /* No intersections in the direction of the ray */
  1437.  
  1438.         break;
  1439.       }
  1440.     }
  1441. #ifdef NoImageNoReflectionPatch
  1442.         /* JG start */
  1443.     In_Shadow_Ray = FALSE;
  1444.     /* JG end */
  1445. #endif
  1446.   }
  1447.  
  1448.   if (Cache_Me)
  1449.   {
  1450.     Light_Source->Shadow_Cached_Object = Blocking_Object;
  1451.   }
  1452.  
  1453.   close_istack (Local_Stack);
  1454. }
  1455.  
  1456.  
  1457.  
  1458. /*****************************************************************************
  1459. *
  1460. * FUNCTION
  1461. *
  1462. *   block_area_light
  1463. *
  1464. * INPUT
  1465. *
  1466. *   Light_Source       - Light source to test
  1467. *   IPoint             -
  1468. *   u1, v1, u2, v2     -
  1469. *   Level              -
  1470. *
  1471. * OUTPUT
  1472. *
  1473. *   Light_Source_Depth - (Remaining) distance to the light source
  1474. *   Light_Source_Ray   - (Remaining) ray to the light source
  1475. *   Light_Colour       - Color reaching initial point from light source
  1476. *
  1477. * RETURNS
  1478. *
  1479. * AUTHOR
  1480. *
  1481. *   POV-Ray Team
  1482. *
  1483. * DESCRIPTION
  1484. *
  1485. *   Get shadow for given area light source by recursively sampling
  1486. *   on the light source area.
  1487. *
  1488. *   The viewing ray is used to initialize the ray containers of the
  1489. *   light source ray.
  1490. *
  1491. * CHANGES
  1492. *
  1493. *   -
  1494. *
  1495. ******************************************************************************/
  1496. #ifdef FastArealight
  1497. static void do_light_area_light(LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY  *Eye_Ray, VECTOR IPoint);
  1498. static void do_light_area_light(LIGHT_SOURCE* Light_Source, DBL* Light_Source_Depth, RAY* Light_Source_Ray, RAY* Eye_Ray, VECTOR IPoint)
  1499. {
  1500.   DBL  a;
  1501.   VECTOR v1;
  1502.   /*
  1503.    * Get the light ray starting at the intersection point and pointing
  1504.    * towards the light source.
  1505.    */
  1506.  
  1507.   Assign_Vector(Light_Source_Ray->Initial, IPoint);
  1508.  
  1509.   /* NK 1998 parallel beams for cylinder source - added 'if' */
  1510.   if (Light_Source->Light_Type == CYLINDER_SOURCE)
  1511.   {
  1512.     DBL distToPointsAt;
  1513.     VECTOR toLightCtr;
  1514.  
  1515.     /* use new code to get ray direction - use center - points_at for direction */
  1516.     VSub(Light_Source_Ray->Direction, Light_Source->Center, Light_Source->Points_At);
  1517.  
  1518.     /* get vector pointing to center of light */
  1519.     VSub(toLightCtr, Light_Source->Center, IPoint);
  1520.  
  1521.     /* project light_ctr-intersect_point onto light_ctr-point_at*/
  1522.     VLength(distToPointsAt, Light_Source_Ray->Direction);
  1523.     VDot(*Light_Source_Depth, toLightCtr, Light_Source_Ray->Direction);
  1524.  
  1525.     /* lenght of shadow ray is the length of the projection */
  1526.     *Light_Source_Depth /= distToPointsAt;
  1527.  
  1528.     VNormalizeEq(Light_Source_Ray->Direction);
  1529.   }
  1530.   else
  1531.   {
  1532.     /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
  1533.       block used to be all that there was... the first half of the if
  1534.       statement (before the 'else') is new
  1535.     */
  1536.     VSub(Light_Source_Ray->Direction, Light_Source->Center, IPoint);
  1537.     VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
  1538.     VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
  1539.   }
  1540.  
  1541.   /* Attenuate light source color. */
  1542.  
  1543. /*  Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);*/
  1544.  
  1545.   /* Recalculate for Parallel light sources */
  1546.   if (Light_Source->Parallel)
  1547.   {
  1548.     if (Light_Source->Area_Light)
  1549.     {
  1550.       VSub(v1, Light_Source->Center, Light_Source->Points_At);
  1551.       VNormalizeEq(v1);
  1552.       VDot(a, v1, Light_Source_Ray->Direction);
  1553.       *Light_Source_Depth *= a;
  1554.       Assign_Vector(Light_Source_Ray->Direction, v1);
  1555.     }
  1556.     else
  1557.     {
  1558.       VDot(a, Light_Source->Direction, Light_Source_Ray->Direction);
  1559.       *Light_Source_Depth *= (-a);
  1560.       Assign_Vector(Light_Source_Ray->Direction, Light_Source->Direction);
  1561.       VScaleEq(Light_Source_Ray->Direction, -1.0);
  1562.     }
  1563.   }
  1564.   Light_Source_Ray->Index = - 1;
  1565.   {
  1566.     register int i;
  1567.     if ((Light_Source_Ray->Index = Eye_Ray->Index) >= MAX_CONTAINING_OBJECTS)
  1568.       Error("ERROR - Containing Index too high.\n");
  1569.     for (i = 0 ; i <= Eye_Ray->Index; i++)
  1570.       Light_Source_Ray->Interiors[i] = Eye_Ray->Interiors[i];
  1571.   }
  1572. }
  1573.  
  1574. #endif
  1575. /*YS april 2000
  1576.    In the function block_area_light() the function do_light() is called a few times. 
  1577.    Do_light() uses a parameter 'COLOUR Light_Colour', that is the last one. 
  1578.    Now, block_area_light() is sending dummy_colour simply because block_area_light() 
  1579.    doesn't need that one.
  1580.   All very well but do_light() is initialising that parameter.
  1581.   That's not the end of the story: do_light() calls Attenuate_light() and the result of that 
  1582.   function is only used to mess with light_colour again. And we do not need that one! Just think 
  1583.   of the code we throw away now. 
  1584.   To make it even better, the stripped down version of do_light can be merged directly in 
  1585.   block_area_light because the parameters are all variables themselves. Not much waste 
  1586.   of registers (at assembly level) but eliminating lots of subroutine calls.  */
  1587.   
  1588. static void block_area_light (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth,
  1589.   RAY *Light_Source_Ray, RAY  *Eye_Ray, VECTOR IPoint, COLOUR Light_Colour, int u1, int  v1, int  u2, int  v2, int  Level)
  1590. {
  1591.   COLOUR Sample_Colour[4];
  1592. #ifndef FastArealight
  1593.   COLOUR  Dummy_Colour;
  1594. #endif
  1595. #ifdef CircularOrientAreaLightPatch 
  1596.   VECTOR  Axis1_Save, Axis2_Save, Temp;
  1597. #endif
  1598.   VECTOR Center_Save, NewAxis1, NewAxis2;
  1599.   int i, j, u, v, New_u1, New_v1, New_u2, New_v2;
  1600. #ifdef CircularOrientAreaLightPatch 
  1601.   DBL Axis1_Length, Axis2_Length;
  1602.   unsigned char First_Call=FALSE;
  1603. #endif
  1604.  
  1605.   DBL Jitter_u, Jitter_v, ScaleFactor;
  1606.  
  1607.   /* First call, initialize */
  1608.  
  1609.   if ((u1 == 0) && (v1 == 0) && (u2 == 0) && (v2 == 0))
  1610.   {
  1611.  #ifdef CircularOrientAreaLightPatch 
  1612.    First_Call = TRUE;
  1613. #endif
  1614.     /* Flag uncalculated points with a negative value for Red */
  1615.  
  1616.     for (i = 0; i < Light_Source->Area_Size1; i++)
  1617.     {
  1618.       for (j = 0; j < Light_Source->Area_Size2; j++)
  1619.       {
  1620.         Light_Source->Light_Grid[i][j][RED] = -1.0;
  1621.       }
  1622.     }
  1623.  
  1624.     u1 = 0;
  1625.     v1 = 0;
  1626.     u2 = Light_Source->Area_Size1 - 1;
  1627.     v2 = Light_Source->Area_Size2 - 1;
  1628. #ifdef CircularOrientAreaLightPatch 
  1629.  
  1630.     /* Save the axis vectors since we may be changing them */
  1631.   if ( Light_Source->CircularOrient)
  1632.   {
  1633.       Assign_Vector(Axis1_Save,Light_Source->Axis1);
  1634.       Assign_Vector(Axis2_Save,Light_Source->Axis2);
  1635.   }  
  1636.     /* Orient the area light to face the intersection point [ENB 9/97] */
  1637.     if (Light_Source->Orient == TRUE)
  1638.     {
  1639.       /* Do Light source to get the correct Light_Source_Ray */
  1640.   #ifndef FastArealight
  1641.       do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
  1642.   #else
  1643.     do_light_area_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint);
  1644.   #endif
  1645.       VScaleEq(Light_Source_Ray->Direction,-1);
  1646.  
  1647.       /* Save the lengths of the axises */
  1648.       VLength(Axis1_Length, Light_Source->Axis1);
  1649.       VLength(Axis2_Length, Light_Source->Axis2);
  1650.  
  1651.   /* Make axis 1 be perpendicular with the light-ray 
  1652.          Done by setting temp to the normal of the axis-ray plane
  1653.          and then setting axis to the normal of the ray-temp plane.
  1654.          This makes the axis perpendicular with the light-ray
  1655.       */
  1656.       VScaleEq(Light_Source->Axis1,1/Axis1_Length);
  1657.       VCross(Temp,Light_Source->Axis1,Light_Source_Ray->Direction);
  1658.       VCross(Light_Source->Axis1,Light_Source_Ray->Direction,Temp);
  1659.       VNormalizeEq(Light_Source->Axis1);
  1660.       VScaleEq(Light_Source->Axis1,Axis1_Length);
  1661.  
  1662.   /* Make axis 2 be perpendicular with the light-ray */
  1663.       VScaleEq(Light_Source->Axis2,1/Axis2_Length);
  1664.       VCross(Temp,Light_Source->Axis2,Light_Source_Ray->Direction);
  1665.       VCross(Light_Source->Axis2,Light_Source_Ray->Direction,Temp);
  1666.       VNormalizeEq(Light_Source->Axis2);
  1667.       VScaleEq(Light_Source->Axis2,Axis1_Length);
  1668.  
  1669.       VScaleEq(Light_Source_Ray->Direction,-1);
  1670.     }
  1671.  
  1672.     /* Make sure that circular light sources are larger than 1 by x [ENB 9/97] */
  1673.     if (Light_Source->Orient == TRUE)
  1674.       if ((Light_Source->Area_Size1 <= 1) || (Light_Source->Area_Size2 <= 1))
  1675.         Light_Source->Orient = FALSE;
  1676. #endif
  1677.   }
  1678.  
  1679.   /* Save the light source center since we'll be fiddling with it */
  1680.  
  1681.   Assign_Vector(Center_Save,Light_Source->Center);
  1682.  
  1683.   /* Sample the four corners of the region */
  1684.  
  1685.   for (i = 0; i < 4; i++)
  1686.   {
  1687.     switch (i)
  1688.     {
  1689.       case 0: u = u1; v = v1; break;
  1690.       case 1: u = u2; v = v1; break;
  1691.       case 2: u = u1; v = v2; break;
  1692.       case 3: u = u2; v = v2; break;
  1693.       default: u = v = 0;  /* Should never happen! */
  1694.     }
  1695.  
  1696.     if (Light_Source->Light_Grid[u][v][RED] >= 0.0)
  1697.     {
  1698.       /* We've already calculated this point, reuse it */
  1699.  
  1700.       Assign_Colour(Sample_Colour[i],Light_Source->Light_Grid[u][v]);
  1701.     }
  1702.     else
  1703.     {
  1704.       Jitter_u = (DBL)u;
  1705.       Jitter_v = (DBL)v;
  1706.  
  1707.       if (Light_Source->Jitter)
  1708.       {
  1709.         Jitter_u += FRAND() - 0.5;
  1710.         Jitter_v += FRAND() - 0.5;
  1711.       }
  1712.  
  1713. #ifdef CircularOrientAreaLightPatch 
  1714.       /* Create circular are lights [ENB 9/97]
  1715.          First, make Jitter_u and Jitter_v be numbers from -1 to 1
  1716.          Second, set ScaleFactor to the abs max (Jitter_u,Jitter_v) (for shells)
  1717.          Third, divide ScaleFactor by the length of <Jitter_u,Jitter_v>
  1718.          Fourth, scale Jitter_u & Jitter_v by ScaleFactor
  1719.          Finally scale Axis1 by Jitter_u & Axis2 by Jitter_v
  1720.       */
  1721.       if (Light_Source->Circular == TRUE)
  1722.       {
  1723.         Jitter_u = Jitter_u / (Light_Source->Area_Size1 - 1) - 0.5 + 0.001;
  1724.         Jitter_v = Jitter_v / (Light_Source->Area_Size2 - 1) - 0.5 + 0.001;
  1725.         ScaleFactor = ((fabs(Jitter_u) > fabs(Jitter_v)) ? fabs(Jitter_u) : fabs(Jitter_v));
  1726.         ScaleFactor /= sqrt(Jitter_u * Jitter_u + Jitter_v * Jitter_v);
  1727.         Jitter_u *= ScaleFactor;
  1728.         Jitter_v *= ScaleFactor;
  1729.         VScale (NewAxis1, Light_Source->Axis1, Jitter_u);
  1730.         VScale (NewAxis2, Light_Source->Axis2, Jitter_v);
  1731.       }
  1732.       else
  1733.       {
  1734. #endif
  1735.       if (Light_Source->Area_Size1 > 1)
  1736.       {
  1737.         ScaleFactor = Jitter_u/(DBL)(Light_Source->Area_Size1 - 1) - 0.5;
  1738.  
  1739.         VScale (NewAxis1, Light_Source->Axis1, ScaleFactor)
  1740.       }
  1741.       else
  1742.       {
  1743.         Make_Vector(NewAxis1, 0.0, 0.0, 0.0);
  1744.       }
  1745.  
  1746.       if (Light_Source->Area_Size2 > 1)
  1747.       {
  1748.         ScaleFactor = Jitter_v/(DBL)(Light_Source->Area_Size2 - 1) - 0.5;
  1749.  
  1750.         VScale (NewAxis2, Light_Source->Axis2, ScaleFactor)
  1751.       }
  1752.       else
  1753.       {
  1754.         Make_Vector(NewAxis2, 0.0, 0.0, 0.0);
  1755.       }
  1756. #ifdef CircularOrientAreaLightPatch 
  1757.       }
  1758.  
  1759.       /* Find the center of the light to test */
  1760. #endif
  1761.       Assign_Vector(Light_Source->Center, Center_Save);
  1762.  
  1763.       VAddEq(Light_Source->Center, NewAxis1);
  1764.       VAddEq(Light_Source->Center, NewAxis2);
  1765.  
  1766.       /* Recalculate the light source ray but not the colour */
  1767.  
  1768.   #ifndef FastArealight
  1769.         do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
  1770.   #else
  1771.     {
  1772.       DBL  a;
  1773.       VECTOR v1;
  1774.        /* Get the light ray starting at the intersection point and pointing
  1775.        * towards the light source.   */
  1776.       Assign_Vector(Light_Source_Ray->Initial, IPoint);
  1777.       /* NK 1998 parallel beams for cylinder source - added 'if' */
  1778.       if (Light_Source->Light_Type == CYLINDER_SOURCE)
  1779.       {
  1780.         DBL distToPointsAt;
  1781.         VECTOR toLightCtr;
  1782.         /* use new code to get ray direction - use center - points_at for direction */
  1783.         VSub(Light_Source_Ray->Direction, Light_Source->Center, Light_Source->Points_At);
  1784.         /* get vector pointing to center of light */
  1785.         VSub(toLightCtr, Light_Source->Center, IPoint);
  1786.         /* project light_ctr-intersect_point onto light_ctr-point_at*/
  1787.         VLength(distToPointsAt, Light_Source_Ray->Direction);
  1788.         VDot(*Light_Source_Depth, toLightCtr, Light_Source_Ray->Direction);
  1789.         /* lenght of shadow ray is the length of the projection */
  1790.         *Light_Source_Depth /= distToPointsAt;
  1791.         VNormalizeEq(Light_Source_Ray->Direction);
  1792.       }
  1793.       else
  1794.       {
  1795.         /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
  1796.           block used to be all that there was... the first half of the if
  1797.           statement (before the 'else') is new  */
  1798.         VSub(Light_Source_Ray->Direction, Light_Source->Center, IPoint);
  1799.         VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
  1800.         VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
  1801.       }
  1802.       /* Attenuate light source color. */
  1803.     /*  Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);*/
  1804.       /* Recalculate for Parallel light sources */
  1805.       if (Light_Source->Parallel)
  1806.       {
  1807.         if (Light_Source->Area_Light)
  1808.         {
  1809.           VSub(v1, Light_Source->Center, Light_Source->Points_At);
  1810.           VNormalizeEq(v1);
  1811.           VDot(a, v1, Light_Source_Ray->Direction);
  1812.           *Light_Source_Depth *= a;
  1813.           Assign_Vector(Light_Source_Ray->Direction, v1);
  1814.         }
  1815.         else
  1816.         {
  1817.           VDot(a, Light_Source->Direction, Light_Source_Ray->Direction);
  1818.           *Light_Source_Depth *= (-a);
  1819.           Assign_Vector(Light_Source_Ray->Direction, Light_Source->Direction);
  1820.           VScaleEq(Light_Source_Ray->Direction, -1.0);
  1821.         }
  1822.       }
  1823.       Light_Source_Ray->Index = - 1;
  1824.       {
  1825.         register int i;
  1826.         if ((Light_Source_Ray->Index = Eye_Ray->Index) >= MAX_CONTAINING_OBJECTS)
  1827.           Error("ERROR - Containing Index too high.\n");
  1828.         for (i = 0 ; i <= Eye_Ray->Index; i++)
  1829.           Light_Source_Ray->Interiors[i] = Eye_Ray->Interiors[i];
  1830.       }
  1831.     }
  1832.     #endif
  1833.  
  1834.       Assign_Colour(Sample_Colour[i], Light_Colour);
  1835.  
  1836. #ifdef CircularOrientAreaLightPatch 
  1837.      /* Calculate the color coming from the corners */
  1838. #endif
  1839. #ifdef MotionBlurPatch
  1840.       block_point_light_with_blur(Light_Source, Light_Source_Depth, Light_Source_Ray, Sample_Colour[i]);
  1841. #else
  1842.       block_point_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Sample_Colour[i]);
  1843. #endif
  1844.  
  1845.       Assign_Colour(Light_Source->Light_Grid[u][v], Sample_Colour[i]);
  1846.     }
  1847.   }
  1848.  
  1849.   Assign_Vector(Light_Source->Center,Center_Save);
  1850.  
  1851. #ifdef CircularOrientAreaLightPatch 
  1852.   /* Get colors for lights between the corners */
  1853. #endif
  1854.   if ((u2 - u1 > 1) || (v2 - v1 > 1))
  1855.   {
  1856.     if ((Level < Light_Source->Adaptive_Level) ||
  1857.         (Colour_Distance(Sample_Colour[0], Sample_Colour[1]) > 0.1) ||
  1858.         (Colour_Distance(Sample_Colour[1], Sample_Colour[3]) > 0.1) ||
  1859.         (Colour_Distance(Sample_Colour[3], Sample_Colour[2]) > 0.1) ||
  1860.         (Colour_Distance(Sample_Colour[2], Sample_Colour[0]) > 0.1))
  1861.     {
  1862.       for (i = 0; i < 4; i++)
  1863.       {
  1864.         switch (i)
  1865.         {
  1866.           case 0:
  1867.  
  1868.             New_u1 = u1;
  1869.             New_v1 = v1;
  1870.             New_u2 = (int)floor ((u1 + u2)/2.0);
  1871.             New_v2 = (int)floor ((v1 + v2)/2.0);
  1872.  
  1873.             break;
  1874.  
  1875.           case 1:
  1876.  
  1877.             New_u1 = (int)ceil  ((u1 + u2)/2.0);
  1878.             New_v1 = v1;
  1879.             New_u2 = u2;
  1880.             New_v2 = (int)floor ((v1 + v2)/2.0);
  1881.  
  1882.             break;
  1883.  
  1884.           case 2:
  1885.  
  1886.             New_u1 = u1;
  1887.             New_v1 = (int)ceil  ((v1 + v2)/2.0);
  1888.             New_u2 = (int)floor ((u1 + u2)/2.0);
  1889.             New_v2 = v2;
  1890.  
  1891.             break;
  1892.  
  1893.           case 3:
  1894.  
  1895.             New_u1 = (int)ceil ((u1 + u2)/2.0);
  1896.             New_v1 = (int)ceil ((v1 + v2)/2.0);
  1897.             New_u2 = u2;
  1898.             New_v2 = v2;
  1899.  
  1900.             break;
  1901.  
  1902.           default:  /* Should never happen! */
  1903.  
  1904.             New_u1 = New_u2 = New_v1 = New_v2 = 0;
  1905.         }
  1906.  
  1907.         /* Recalculate the light source ray but not the colour */
  1908.  
  1909.   #ifndef FastArealight
  1910.         do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
  1911.   #else
  1912.         {
  1913.           DBL  a;
  1914.           VECTOR v1;
  1915.            /* Get the light ray starting at the intersection point and pointing
  1916.            * towards the light source.   */
  1917.           Assign_Vector(Light_Source_Ray->Initial, IPoint);
  1918.           /* NK 1998 parallel beams for cylinder source - added 'if' */
  1919.           if (Light_Source->Light_Type == CYLINDER_SOURCE)
  1920.           {
  1921.             DBL distToPointsAt;
  1922.             VECTOR toLightCtr;
  1923.             /* use new code to get ray direction - use center - points_at for direction */
  1924.             VSub(Light_Source_Ray->Direction, Light_Source->Center, Light_Source->Points_At);
  1925.             /* get vector pointing to center of light */
  1926.             VSub(toLightCtr, Light_Source->Center, IPoint);
  1927.             /* project light_ctr-intersect_point onto light_ctr-point_at*/
  1928.             VLength(distToPointsAt, Light_Source_Ray->Direction);
  1929.             VDot(*Light_Source_Depth, toLightCtr, Light_Source_Ray->Direction);
  1930.             /* lenght of shadow ray is the length of the projection */
  1931.             *Light_Source_Depth /= distToPointsAt;
  1932.             VNormalizeEq(Light_Source_Ray->Direction);
  1933.           }
  1934.           else
  1935.           {
  1936.             /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
  1937.               block used to be all that there was... the first half of the if
  1938.               statement (before the 'else') is new  */
  1939.             VSub(Light_Source_Ray->Direction, Light_Source->Center, IPoint);
  1940.             VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
  1941.             VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
  1942.           }
  1943.           /* Attenuate light source color. */
  1944.         /*  Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);*/
  1945.           /* Recalculate for Parallel light sources */
  1946.           if (Light_Source->Parallel)
  1947.           {
  1948.             if (Light_Source->Area_Light)
  1949.             {
  1950.               VSub(v1, Light_Source->Center, Light_Source->Points_At);
  1951.               VNormalizeEq(v1);
  1952.               VDot(a, v1, Light_Source_Ray->Direction);
  1953.               *Light_Source_Depth *= a;
  1954.               Assign_Vector(Light_Source_Ray->Direction, v1);
  1955.             }
  1956.             else
  1957.             {
  1958.               VDot(a, Light_Source->Direction, Light_Source_Ray->Direction);
  1959.               *Light_Source_Depth *= (-a);
  1960.               Assign_Vector(Light_Source_Ray->Direction, Light_Source->Direction);
  1961.               VScaleEq(Light_Source_Ray->Direction, -1.0);
  1962.             }
  1963.           }
  1964.           Light_Source_Ray->Index = - 1;
  1965.           {
  1966.             register int i;
  1967.             if ((Light_Source_Ray->Index = Eye_Ray->Index) >= MAX_CONTAINING_OBJECTS)
  1968.               Error("ERROR - Containing Index too high.\n");
  1969.             for (i = 0 ; i <= Eye_Ray->Index; i++)
  1970.               Light_Source_Ray->Interiors[i] = Eye_Ray->Interiors[i];
  1971.           }
  1972.         }
  1973.         #endif
  1974.  
  1975.         Assign_Colour(Sample_Colour[i],Light_Colour);
  1976.  
  1977.   #ifdef CircularOrientAreaLightPatch 
  1978.       /* Calculate the color of the area section (recursive part) */
  1979. #endif
  1980.         block_area_light (Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray,
  1981.           IPoint, Sample_Colour[i], New_u1, New_v1, New_u2, New_v2, Level+1);
  1982.       }
  1983.     }
  1984.   }
  1985.  
  1986.   /* Add up the light contributions */
  1987.   #ifndef FastArealight
  1988.     Make_Colour (Light_Colour, 0.0, 0.0, 0.0);
  1989.     for (i = 0; i < 4; i++)
  1990.    {
  1991.      Scale_Colour (Sample_Colour[i], Sample_Colour[i], 0.25);
  1992.     Add_Colour (Light_Colour, Light_Colour, Sample_Colour[i]);
  1993.    }
  1994.   #else
  1995.   Light_Colour[RED] = Sample_Colour[0][RED] * 0.25;
  1996.   Light_Colour[GREEN] = Sample_Colour[0][GREEN] * 0.25;
  1997.   Light_Colour[BLUE] = Sample_Colour[0][BLUE] * 0.25;
  1998.   Light_Colour[FILTER] += Sample_Colour[0][FILTER] * 0.25;
  1999.   Light_Colour[TRANSM] += Sample_Colour[0][TRANSM] * 0.25;
  2000.   for (i = 1; i < 4; i++)
  2001.   {
  2002.     Light_Colour[RED] += Sample_Colour[i][RED] * 0.25;
  2003.     Light_Colour[GREEN] += Sample_Colour[i][GREEN] * 0.25;
  2004.     Light_Colour[BLUE] += Sample_Colour[i][BLUE] * 0.25;
  2005.     Light_Colour[FILTER] += Sample_Colour[i][FILTER] * 0.25;
  2006.     Light_Colour[TRANSM] += Sample_Colour[i][TRANSM] * 0.25;
  2007.   }
  2008.  
  2009.   #endif
  2010. #ifdef CircularOrientAreaLightPatch 
  2011.    if (First_Call == TRUE)   
  2012.   {
  2013.     /* Reset the axises to what they were before */
  2014.    if ( Light_Source->CircularOrient)
  2015.     {
  2016.       Assign_Vector(Light_Source->Axis1,Axis1_Save);
  2017.       Assign_Vector(Light_Source->Axis2,Axis2_Save);
  2018.     }
  2019.    }
  2020. #endif
  2021. }
  2022.  
  2023.  
  2024. /*****************************************************************************
  2025. *
  2026. * FUNCTION
  2027. *
  2028. *   do_light
  2029. *
  2030. * INPUT
  2031. *
  2032. *   Light_Source       - Light source
  2033. *   Light_Source_Depth - Distance from surface to light source
  2034. *   Light_Source_Ray   - Ray from surface to light source
  2035. *   Eye_Ray            - Current viewing ray
  2036. *   IPoint             - Intersection point in surface
  2037. *   Colour             - Light's colour
  2038. *
  2039. * OUTPUT
  2040. *
  2041. *   Light_Source_Depth, Light_Source_Ray, Colour
  2042. *
  2043. * RETURNS
  2044. *
  2045. * AUTHOR
  2046. *
  2047. *   POV-Ray Team
  2048. *
  2049. * DESCRIPTION
  2050. *
  2051. *   The viewing ray is used to initialize the ray containers of the
  2052. *   light source ray.
  2053. *
  2054. * CHANGES
  2055. *
  2056. *   -
  2057. *
  2058. ******************************************************************************/
  2059.  
  2060. static void do_light(LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY  *Eye_Ray, VECTOR IPoint, COLOUR Light_Colour)
  2061. {
  2062.   DBL Attenuation,a;
  2063.   VECTOR v1;
  2064.  
  2065.   /* Get the light source colour. */
  2066.  
  2067.   Assign_Colour(Light_Colour, Light_Source->Colour);
  2068.  
  2069.   /*
  2070.    * Get the light ray starting at the intersection point and pointing
  2071.    * towards the light source.
  2072.    */
  2073.  
  2074.   Assign_Vector(Light_Source_Ray->Initial, IPoint);
  2075.  
  2076.   /* NK 1998 parallel beams for cylinder source - added 'if' */
  2077.   if (Light_Source->Light_Type == CYLINDER_SOURCE)
  2078.   {
  2079.     DBL distToPointsAt;
  2080.     VECTOR toLightCtr;
  2081.  
  2082.     /* use new code to get ray direction - use center - points_at for direction */
  2083.     VSub(Light_Source_Ray->Direction,Light_Source->Center, Light_Source->Points_At);
  2084.  
  2085.     /* get vector pointing to center of light */
  2086.     VSub(toLightCtr,Light_Source->Center, IPoint);
  2087.  
  2088.     /* project light_ctr-intersect_point onto light_ctr-point_at*/
  2089.     VLength(distToPointsAt, Light_Source_Ray->Direction);
  2090.     VDot(*Light_Source_Depth,toLightCtr, Light_Source_Ray->Direction);
  2091.  
  2092.     /* lenght of shadow ray is the length of the projection */
  2093.     *Light_Source_Depth /= distToPointsAt;
  2094.  
  2095.     VNormalizeEq(Light_Source_Ray->Direction);
  2096.   }
  2097.   else
  2098.   {
  2099.     /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
  2100.          block used to be all that there was... the first half of the if
  2101.          statement (before the 'else') is new
  2102.     */
  2103.     VSub(Light_Source_Ray->Direction,Light_Source->Center, IPoint);
  2104.  
  2105.     VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
  2106.  
  2107.     VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
  2108.   }
  2109.  
  2110.   /* Attenuate light source color. */
  2111.  
  2112.   Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);
  2113.  
  2114.   /* Recalculate for Parallel light sources */
  2115.   if (Light_Source->Parallel) {
  2116.     if (Light_Source->Area_Light) {
  2117.       VSub(v1,Light_Source->Center,Light_Source->Points_At);
  2118.       VNormalizeEq( v1 );
  2119.         VDot(a,v1,Light_Source_Ray->Direction);
  2120.       *Light_Source_Depth *= a;
  2121.         Assign_Vector(Light_Source_Ray->Direction,v1);
  2122.     } else {
  2123.       VDot(a,Light_Source->Direction,Light_Source_Ray->Direction);
  2124.       *Light_Source_Depth *= (-a);
  2125.       Assign_Vector(Light_Source_Ray->Direction,Light_Source->Direction);
  2126.       VScaleEq(Light_Source_Ray->Direction,-1.0);
  2127.     }
  2128.   }
  2129.  
  2130.   /* Now scale the color by the attenuation */
  2131.  
  2132.   VScaleEq(Light_Colour, Attenuation);
  2133.  
  2134.   /* Init ray containers. */
  2135.  
  2136.   Initialize_Ray_Containers(Light_Source_Ray);
  2137.  
  2138.   Copy_Ray_Containers(Light_Source_Ray, Eye_Ray);
  2139. }
  2140.  
  2141.  
  2142.  
  2143. /*****************************************************************************
  2144. *
  2145. * FUNCTION
  2146. *
  2147. *   do_diffuse
  2148. *
  2149. * INPUT
  2150. *
  2151. * OUTPUT
  2152. *
  2153. * RETURNS
  2154. *
  2155. * AUTHOR
  2156. *
  2157. *   POV-Ray Team
  2158. *
  2159. * DESCRIPTION
  2160. *
  2161. *   Calculate the diffuse color component I_d given by:
  2162. *
  2163. *     I_d = a * d * I * C * (N . L) ^ b
  2164. *
  2165. *   where d : surface's diffuse reflection coefficient
  2166. *         b : surface's brilliance
  2167. *         C : surface's color
  2168. *         N : surface's normal vector
  2169. *         L : light vector (pointing at the light)
  2170. *         I : intensity of the incoming light
  2171. *         a : attenuation factor
  2172. *
  2173. * CHANGES
  2174. *
  2175. *   -
  2176. *
  2177. ******************************************************************************/
  2178.  
  2179. static void do_diffuse(FINISH *Finish, RAY *Light_Source_Ray, VECTOR Layer_Normal, COLOUR Colour, COLOUR  Light_Colour, COLOUR  Layer_Pigment_Colour, DBL Attenuation)
  2180. {
  2181.   DBL Cos_Angle_Of_Incidence, Intensity;
  2182.  
  2183.   VDot(Cos_Angle_Of_Incidence, Layer_Normal, Light_Source_Ray->Direction);
  2184.  
  2185.   /* Brilliance is likely to be 1.0 (default value) */
  2186.  
  2187.   if (Finish->Brilliance != 1.0)
  2188.   {
  2189.     Intensity = pow(fabs(Cos_Angle_Of_Incidence), Finish->Brilliance);
  2190.   }
  2191.   else
  2192.   {
  2193.     Intensity = fabs(Cos_Angle_Of_Incidence);
  2194.   }
  2195.  
  2196.   Intensity *= Finish->Diffuse * Attenuation;
  2197.  
  2198.   if (Finish->Crand > 0.0)
  2199.   {
  2200.     Intensity -= FRAND() * Finish->Crand;
  2201.   }
  2202.  
  2203.   Colour[RED]   += Intensity * Layer_Pigment_Colour[RED]   * Light_Colour[RED];
  2204.   Colour[GREEN] += Intensity * Layer_Pigment_Colour[GREEN] * Light_Colour[GREEN];
  2205.   Colour[BLUE]  += Intensity * Layer_Pigment_Colour[BLUE]  * Light_Colour[BLUE];
  2206. }
  2207.  
  2208.  
  2209.  
  2210. /*****************************************************************************
  2211. *
  2212. * FUNCTION
  2213. *
  2214. *   do_irid
  2215. *
  2216. * INPUT
  2217. *
  2218. * OUTPUT
  2219. *
  2220. * RETURNS
  2221. *
  2222. * AUTHOR
  2223. *
  2224. *   Dan Farmer
  2225. *
  2226. * DESCRIPTION
  2227. *
  2228. *   IRIDESCENCE:
  2229. *   -----------
  2230. *   Programmed by Dan Farmer.
  2231. *
  2232. *   Based on Chapter 10.2.4 of Three-Dimensional Computer Graphics
  2233. *   by Alan Watt.
  2234. *
  2235. *   Modulates the diffuse coefficients as a function of wavelength, the angle
  2236. *   between the light direction vector, and the surface normal.  It models
  2237. *   thin-film interference, as in a soap bubble or oilslick.
  2238. *
  2239. *   Wavelength at which cancellation offurs is a function of the refractive
  2240. *   index of the film, its thickness, and the angle of incidence of the
  2241. *   incoming light.  In this implementation, IOR is kept constant, while the
  2242. *   thickness of the film is specified, as well as being modulated with a
  2243. *   turbulence function.
  2244. *
  2245. * CHANGES
  2246. *
  2247. *   -
  2248. *
  2249. ******************************************************************************/
  2250.  
  2251. static void do_irid(FINISH *Finish, RAY *Light_Source_Ray, VECTOR Layer_Normal, VECTOR  IPoint, COLOUR Colour)
  2252. {
  2253.   DBL rwl, gwl, bwl;
  2254.   DBL Cos_Angle_Of_Incidence, interference;
  2255.   DBL film_thickness;
  2256.   DBL noise, intensity;
  2257.   TURB Turb;
  2258.  
  2259.   film_thickness = Finish->Irid_Film_Thickness;
  2260.  
  2261.   if (Finish->Irid_Turb != 0)
  2262.   {
  2263.     /* Uses hardcoded octaves, lambda, omega */
  2264.     Turb.Omega=0.5;
  2265.     Turb.Lambda=2.0;
  2266.     Turb.Octaves=5;
  2267.  
  2268.     noise = Turbulence(IPoint, &Turb) * Finish->Irid_Turb;
  2269.  
  2270.     film_thickness *= noise;
  2271.   }
  2272.  
  2273.   /*
  2274.    * Approximate dominant wavelengths of primary hues.
  2275.    * Source: 3D Computer Graphics by John Vince (Addison Wesely)
  2276.    * These are initialized in parse.c (Parse_Frame)
  2277.    * and are user-adjustable with the irid_wavelength keyword.
  2278.    * Red = 700 nm  Grn = 520 nm Blu = 480 nm
  2279.    * Divided by 100 gives: rwl = 0.70;  gwl = 0.52;  bwl = 0.48;
  2280.    *
  2281.    * However... I originally "guessed" at the values and came up with
  2282.    * the following, which I'm using as the defaults, since it seems
  2283.    * to work better:  rwl = 0.25;  gwl = 0.18;  bwl = 0.14;
  2284.    */
  2285.  
  2286.   /* Could avoid these assignments if we want to */
  2287.  
  2288.   rwl = Frame.Irid_Wavelengths[RED];
  2289.   gwl = Frame.Irid_Wavelengths[GREEN];
  2290.   bwl = Frame.Irid_Wavelengths[BLUE];
  2291.  
  2292.   /* NOTE: Shouldn't we compute Cos_Angle_Of_Incidence just once? */
  2293.  
  2294.   VDot(Cos_Angle_Of_Incidence, Layer_Normal, Light_Source_Ray->Direction);
  2295.  
  2296.   /* Calculate phase offset. */
  2297.  
  2298.   interference = 4.0 * M_PI * film_thickness * Cos_Angle_Of_Incidence;
  2299.  
  2300.   intensity = Cos_Angle_Of_Incidence * Finish->Irid;
  2301.  
  2302.   /* Modify color by phase offset for each wavelength. */
  2303.  
  2304.   Colour[RED]  += Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/rwl)));
  2305.   Colour[GREEN]+= Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/gwl)));
  2306.   Colour[BLUE] += Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/bwl)));
  2307. }
  2308.  
  2309.  
  2310.  
  2311. /*****************************************************************************
  2312. *
  2313. * FUNCTION
  2314. *
  2315. *   do_phong
  2316. *
  2317. * INPUT
  2318. *
  2319. * OUTPUT
  2320. *
  2321. * RETURNS
  2322. *
  2323. * AUTHOR
  2324. *
  2325. *   POV-Ray Team
  2326. *
  2327. * DESCRIPTION
  2328. *
  2329. *   Calculate the phong reflected color component I_p given by:
  2330. *
  2331. *     I_p = p * C * (R . L) ^ s
  2332. *
  2333. *   where p : surface's phong reflection coefficient
  2334. *         s : surface's phong size
  2335. *         C : surface's color/light color depending on the metallic flag
  2336. *         R : reflection vector
  2337. *         L : light vector (pointing at the light)
  2338. *
  2339. *   The reflection vector is calculated from the surface normal and
  2340. *   the viewing vector (looking at the surface point):
  2341. *
  2342. *     R = -2 * (V . N) * N + V, with R . R = 1
  2343. *
  2344. * CHANGES
  2345. *
  2346. *   Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
  2347. *
  2348. ******************************************************************************/
  2349.  
  2350. static void do_phong(FINISH *Finish, RAY *Light_Source_Ray, VECTOR  Eye, VECTOR Layer_Normal, COLOUR Colour, COLOUR  Light_Colour, COLOUR  Layer_Pigment_Colour)
  2351. {
  2352.   DBL Cos_Angle_Of_Incidence, Intensity;
  2353.   VECTOR Reflect_Direction;
  2354.   DBL NdotL, x, F;
  2355.   COLOUR Cs;
  2356.  
  2357.   VDot(Cos_Angle_Of_Incidence, Eye, Layer_Normal);
  2358.  
  2359.   Cos_Angle_Of_Incidence *= -2.0;
  2360.  
  2361.   VLinComb2(Reflect_Direction, 1.0, Eye, Cos_Angle_Of_Incidence, Layer_Normal);
  2362.  
  2363.   VDot(Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
  2364.  
  2365.   if (Cos_Angle_Of_Incidence > 0.0)
  2366.   {
  2367.     if ((Finish->Phong_Size < 60) || (Cos_Angle_Of_Incidence > .0008)) /* rgs */
  2368.       Intensity = Finish->Phong * pow(Cos_Angle_Of_Incidence, Finish->Phong_Size);
  2369.     else
  2370.       Intensity = 0.0; /* ad */
  2371.  
  2372.     if (Finish->Metallic > 0.0)
  2373.     {
  2374.       /*
  2375.        * Calculate the reflected color by interpolating between
  2376.        * the light source color and the surface color according
  2377.        * to the (empirical) Fresnel reflectivity function. [DB 9/94]
  2378.        */
  2379.  
  2380.       VDot(NdotL, Layer_Normal, Light_Source_Ray->Direction);
  2381.  
  2382.       x = fabs(acos(NdotL)) / M_PI_2;
  2383.  
  2384.       F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  2385.  
  2386.       F=min(1.0,max(0.0,F));
  2387.       Cs[RED]   = Light_Colour[RED]   * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED]   - 1.0));
  2388.       Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
  2389.       Cs[BLUE]  = Light_Colour[BLUE]  * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE]  - 1.0));
  2390.  
  2391.       VAddScaledEq(Colour, Intensity, Cs);
  2392.     }
  2393.     else
  2394.     {
  2395.       Colour[RED]   += Intensity * Light_Colour[RED];
  2396.       Colour[GREEN] += Intensity * Light_Colour[GREEN];
  2397.       Colour[BLUE]  += Intensity * Light_Colour[BLUE];
  2398.     }
  2399.   }
  2400. }
  2401.  
  2402.  
  2403.  
  2404. /*****************************************************************************
  2405. *
  2406. * FUNCTION
  2407. *
  2408. *   do_specular
  2409. *
  2410. * INPUT
  2411. *
  2412. * OUTPUT
  2413. *
  2414. * INPUT
  2415. *
  2416. * OUTPUT
  2417. *
  2418. * RETURNS
  2419. *
  2420. * AUTHOR
  2421. *
  2422. *   POV-Ray Team
  2423. *
  2424. * DESCRIPTION
  2425. *
  2426. *   Calculate the specular reflected color component I_s given by:
  2427. *
  2428. *     I_s = s * C * (H . N) ^ (1 / r)
  2429. *
  2430. *   where s : surface's specular reflection coefficient
  2431. *         r : surface's roughness
  2432. *         C : surface's color/light color depending on the metallic flag
  2433. *         N : surface's normal
  2434. *         H : bisection vector between V and L
  2435. *
  2436. *   The bisecting vector H is calculated by
  2437. *
  2438. *     H = (L - V) / sqrt((L - V).(L - V))
  2439. *
  2440. * CHANGES
  2441. *
  2442. *   Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
  2443. *
  2444. ******************************************************************************/
  2445.  
  2446. static void do_specular(FINISH *Finish, RAY *Light_Source_Ray, VECTOR  REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR  Light_Colour, COLOUR  Layer_Pigment_Colour)
  2447. {
  2448.   DBL Cos_Angle_Of_Incidence, Intensity, Halfway_Length;
  2449.   VECTOR Halfway;
  2450.   DBL NdotL, x, F;
  2451.   COLOUR Cs;
  2452.  
  2453.   VHalf(Halfway, REye, Light_Source_Ray->Direction);
  2454.  
  2455.   VLength(Halfway_Length, Halfway);
  2456.  
  2457.   if (Halfway_Length > 0.0)
  2458.   {
  2459.     VDot(Cos_Angle_Of_Incidence, Halfway, Layer_Normal);
  2460.  
  2461.     Cos_Angle_Of_Incidence /= Halfway_Length;
  2462.  
  2463.     if (Cos_Angle_Of_Incidence > 0.0)
  2464.     {
  2465.       Intensity = Finish->Specular * pow(Cos_Angle_Of_Incidence, Finish->Roughness);
  2466.  
  2467.       if (Finish->Metallic > 0.0)
  2468.       {
  2469.         /*
  2470.          * Calculate the reflected color by interpolating between
  2471.          * the light source color and the surface color according
  2472.          * to the (empirical) Fresnel reflectivity function. [DB 9/94]
  2473.          */
  2474.  
  2475.         VDot(NdotL, Layer_Normal, Light_Source_Ray->Direction);
  2476.  
  2477.         x = fabs(acos(NdotL)) / M_PI_2;
  2478.  
  2479.         F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  2480.  
  2481.         F=min(1.0,max(0.0,F));
  2482.         Cs[RED]   = Light_Colour[RED]   * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED]   - 1.0));
  2483.         Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
  2484.         Cs[BLUE]  = Light_Colour[BLUE]  * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE]  - 1.0));
  2485.  
  2486.         VAddScaledEq(Colour, Intensity, Cs);
  2487.       }
  2488.       else
  2489.       {
  2490.         Colour[RED]   += Intensity * Light_Colour[RED];
  2491.         Colour[GREEN] += Intensity * Light_Colour[GREEN];
  2492.         Colour[BLUE]  += Intensity * Light_Colour[BLUE];
  2493.       }
  2494.     }
  2495.   }
  2496. }
  2497.  
  2498. /*****************************************************************************
  2499. *
  2500. * FUNCTION
  2501. *
  2502. *   do_blinn
  2503. *
  2504. * INPUT
  2505. *
  2506. * OUTPUT
  2507. *
  2508. * INPUT
  2509. *
  2510. * OUTPUT
  2511. *
  2512. * RETURNS
  2513. *
  2514. * AUTHOR
  2515. *
  2516. *   Nathan Kopp
  2517. *
  2518. * DESCRIPTION
  2519. *
  2520. *   Calculate the specular reflected color component I_s given by:
  2521. *
  2522. *     I_s = s * C * (H . N) ^ (1 / r)
  2523. *
  2524. *   where s : surface's specular reflection coefficient
  2525. *         r : surface's roughness
  2526. *         C : surface's color/light color depending on the metallic flag
  2527. *         N : surface's normal
  2528. *         H : bisection vector between V and L
  2529. *
  2530. *   The bisecting vector H is calculated by
  2531. *
  2532. *     H = (L - V) / sqrt((L - V).(L - V))
  2533. *
  2534. * CHANGES
  2535. *
  2536. *   Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
  2537. *
  2538. ******************************************************************************/
  2539.  
  2540. #ifdef BlinnPatch
  2541. static void do_blinn(FINISH *Finish, RAY *Light_Source_Ray, VECTOR  REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR  Light_Colour, COLOUR  Layer_Pigment_Colour,
  2542.                      INTERIOR *Interior)
  2543. {
  2544.   DBL Intensity, Halfway_Length;
  2545.   VECTOR Halfway;
  2546.   DBL x, F;
  2547.   COLOUR Cs;
  2548.   DBL beta, cosBeta, tanBeta, D;
  2549.   DBL VdotH, LdotH, NdotL, NdotH, NdotV;
  2550.   DBL G, cos_angle;
  2551.   DBL ior, /*ior2,*/ disp;
  2552.   DBL m,g;
  2553.   VECTOR Lv,Nv,Vv;
  2554.  
  2555.   /* Get ratio of iors depending on the interiors the ray is traversing. */
  2556.   if (Light_Source_Ray->Index == -1)
  2557.   {
  2558.     /* The ray is entering from the atmosphere. */
  2559.     ior = Frame.Atmosphere_IOR / Interior->IOR;
  2560.     disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
  2561.   }
  2562.   else
  2563.   {
  2564.     /* The ray is currently inside an object. */
  2565.     if ((Interior_In_Ray_Container(Light_Source_Ray, Interior)) >= 0)
  2566.     {
  2567.       if (Light_Source_Ray->Index == 0)
  2568.       {
  2569.         /* The ray is leaving into the atmosphere. */
  2570.         ior = Interior->IOR / Frame.Atmosphere_IOR;
  2571.         disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
  2572.       }
  2573.       else
  2574.       {
  2575.         /* The ray is leaving into another object. */
  2576.         ior = Interior->IOR / Light_Source_Ray->Interiors[Light_Source_Ray->Index]->IOR;
  2577.         disp = Interior->Dispersion / Light_Source_Ray->Interiors[Light_Source_Ray->Index]->Dispersion;
  2578.       }
  2579.     }
  2580.     else
  2581.     {
  2582.       /* The ray is entering a new object. */
  2583.       ior = Light_Source_Ray->Interiors[Light_Source_Ray->Index]->IOR / Interior->IOR;
  2584.       disp = Light_Source_Ray->Interiors[Light_Source_Ray->Index]->Dispersion / Interior->Dispersion;
  2585.     }
  2586.   }
  2587.  
  2588.   ior = 1.0/ior;
  2589.   disp = 1.0/disp;
  2590.  
  2591.   VHalf(Halfway, REye, Light_Source_Ray->Direction);
  2592.  
  2593.   VLength(Halfway_Length, Halfway);
  2594.  
  2595.   if (Halfway_Length > 0.0)
  2596.   {
  2597.     VScaleEq(Halfway, 1.0/Halfway_Length);
  2598.     VNormalize(Vv, REye);
  2599.     VNormalize(Lv, Light_Source_Ray->Direction);
  2600.     VNormalize(Nv, Layer_Normal);
  2601.     VDot(NdotL, Nv, Lv);
  2602.     VDot(NdotH, Nv, Halfway);
  2603.     VDot(NdotV, Nv, Vv);
  2604.     VDot(LdotH, Lv, Halfway);
  2605.     VdotH = LdotH;
  2606.  
  2607.     beta = acos(NdotH);
  2608.     cosBeta = cos(beta);
  2609.     tanBeta = tan(beta);
  2610.  
  2611.     m = Finish->Facets;
  2612.  
  2613.     D = 1.0 / (4.0 * m * cosBeta*cosBeta*cosBeta*cosBeta) * exp(-Sqr(tanBeta)/Sqr(m));
  2614.  
  2615.     G = min(1, min(2*NdotH*NdotV/VdotH, 2*NdotH*NdotL/VdotH));
  2616.     cos_angle = LdotH;
  2617.  
  2618.     if (cos_angle > 0.0)
  2619.     {
  2620.       g = sqrt(Sqr(ior) + Sqr(cos_angle) - 1);
  2621.       F = 0.5 * (Sqr(g - cos_angle) / Sqr(g + cos_angle));
  2622.       F = F * (1 + Sqr(cos_angle * (g + cos_angle) - 1) / Sqr(cos_angle * (g - cos_angle) + 1));
  2623.  
  2624.       F=min(1.0,max(0.0,F));
  2625.  
  2626.       Intensity = Finish->Blinn*D*G*F/(NdotL*NdotV*M_PI);
  2627.  
  2628.       if (Finish->Metallic > 0.0)
  2629.       {
  2630.         /*
  2631.          * Calculate the reflected color by interpolating between
  2632.          * the light source color and the surface color according
  2633.          * to the (empirical) Fresnel reflectivity function. [DB 9/94]
  2634.          */
  2635.         x = fabs(acos(NdotL)) / M_PI_2;
  2636.  
  2637.         F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  2638.  
  2639.         F=min(1.0,max(0.0,F));
  2640.         Cs[RED]   = Light_Colour[RED]   * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED]   - 1.0));
  2641.         Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
  2642.         Cs[BLUE]  = Light_Colour[BLUE]  * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE]  - 1.0));
  2643.  
  2644.         VAddScaledEq(Colour, Intensity, Cs);
  2645.       }
  2646.       else
  2647.       {
  2648.         Colour[RED]   += Intensity * Light_Colour[RED];
  2649.         Colour[GREEN] += Intensity * Light_Colour[GREEN];
  2650.         Colour[BLUE]  += Intensity * Light_Colour[BLUE];
  2651.       }
  2652.     }
  2653.   }
  2654. }
  2655.  
  2656. #endif
  2657.  
  2658.  
  2659. /*****************************************************************************
  2660. *
  2661. * FUNCTION
  2662. *
  2663. *   Diffuse
  2664. *
  2665. * INPUT
  2666. *
  2667. * OUTPUT
  2668. *
  2669. * RETURNS
  2670. *
  2671. * AUTHOR
  2672. *
  2673. *   POV-Ray Team
  2674. *
  2675. * DESCRIPTION
  2676. *
  2677. *   -
  2678. *
  2679. * CHANGES
  2680. *
  2681. *   -
  2682. *
  2683. ******************************************************************************/
  2684.  
  2685. static void Diffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR  Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object)
  2686. {
  2687.   int i;
  2688.   DBL Light_Source_Depth, Cos_Shadow_Angle;
  2689.   RAY Light_Source_Ray;
  2690.   LIGHT_SOURCE *Light_Source;
  2691.   VECTOR REye;
  2692.   COLOUR Light_Colour;
  2693.  
  2694. #ifdef BlinnPatch
  2695.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0) && (Finish->Blinn == 0.0))
  2696. #else
  2697.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
  2698. #endif
  2699.   {
  2700.     return;
  2701.   }
  2702.  
  2703. #ifdef BlinnPatch
  2704.   if (Finish->Specular != 0.0 || Finish->Blinn != 0.0)
  2705. #else
  2706.   if (Finish->Specular != 0.0)
  2707. #endif
  2708.   {
  2709.     REye[X] = -Eye->Direction[X];
  2710.     REye[Y] = -Eye->Direction[Y];
  2711.     REye[Z] = -Eye->Direction[Z];
  2712.   }
  2713.  
  2714.   for (i = 0, Light_Source = Frame.Light_Sources;
  2715.        Light_Source != NULL;
  2716.        Light_Source = Light_Source->Next_Light_Source, i++)
  2717.   {
  2718.     /* if Light is not in Object Light_Group Skip */
  2719.     if (!Check_Light_Group(Object,Light_Source))
  2720.       continue;
  2721.  
  2722.     /* Get a colour and a ray. */
  2723.  
  2724.     do_light(Light_Source, &Light_Source_Depth, &Light_Source_Ray, Eye, IPoint, Light_Colour);
  2725.  
  2726.     /* Don't calculate spotlights when outside of the light's cone. */
  2727.  
  2728.     if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  2729.         (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  2730.         (fabs(Light_Colour[BLUE])  < BLACK_LEVEL))
  2731.     {
  2732.       continue;
  2733.     }
  2734.  
  2735.     /* See if light on far side of surface from camera. */
  2736.  
  2737.     /* NK 1998 double_illuminate - changed to Test_Flag */
  2738.     if (!(Test_Flag(Object, DOUBLE_ILLUMINATE_FLAG)))
  2739.     {
  2740.       VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
  2741.  
  2742.       if (Cos_Shadow_Angle < EPSILON)
  2743.       {
  2744.         continue;
  2745.       }
  2746.     }
  2747.  
  2748.     /*
  2749.      * If light source was not blocked by any intervening object, then
  2750.      * calculate it's contribution to the object's overall illumination.
  2751.      */
  2752. /** poviso: July 14 '96 R.S. **/
  2753. #ifdef POVISO
  2754.     Shadow_Test_Flag = TRUE;
  2755. #endif
  2756. /** --- **/
  2757.  
  2758.     if ((opts.Quality_Flags & Q_SHADOW) && ((Light_Source->Projected_Through_Object != NULL) || (Light_Source->Light_Type != FILL_LIGHT_SOURCE)))
  2759.     {
  2760.       /* If this surface point has already been tested use previous result. */
  2761.  
  2762.       if (Light_List[i].Tested)
  2763.       {
  2764.         Assign_Colour(Light_Colour, Light_List[i].Colour);
  2765.       }
  2766.       else
  2767.       {
  2768.         block_light_source(Light_Source, Light_Source_Depth, &Light_Source_Ray, Eye, IPoint, Light_Colour);
  2769.  
  2770.         /* Store light colour. */
  2771.  
  2772.         Light_List[i].Tested = TRUE;
  2773.  
  2774.         Assign_Colour(Light_List[i].Colour, Light_Colour);
  2775.       }
  2776.     }
  2777. /** poviso: July 14 '96 R.S. **/
  2778. #ifdef POVISO
  2779.     Shadow_Test_Flag = FALSE;
  2780. #endif
  2781. /** --- **/
  2782.  
  2783.     if ((fabs(Light_Colour[RED])   > BLACK_LEVEL) ||
  2784.         (fabs(Light_Colour[GREEN]) > BLACK_LEVEL) ||
  2785.         (fabs(Light_Colour[BLUE])  > BLACK_LEVEL))
  2786.     {
  2787.       if (Finish->Diffuse > 0.0)
  2788.       {
  2789.         do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,Colour,Light_Colour,Layer_Pigment_Colour, Attenuation);
  2790.       }
  2791.  
  2792.       if ((Light_Source->Light_Type != FILL_LIGHT_SOURCE)
  2793.         /* NK rad 
  2794.           don't compute highlights for radiosity gather rays, since this causes
  2795.           problems with colors being far too bright
  2796.           */
  2797.        && (Radiosity_Trace_Level<=1))
  2798.         /* NK ---- */
  2799.       {
  2800.         if (Finish->Phong > 0.0)
  2801.         {
  2802.           do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
  2803.         }
  2804. #ifdef BlinnPatch
  2805.         if (Finish->Blinn > 0.0)
  2806.         {
  2807.           do_blinn(Finish,&Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour, Object->Interior);
  2808.         }
  2809. #endif
  2810.  
  2811.         if (Finish->Specular > 0.0)
  2812.         {
  2813.           do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
  2814.         }
  2815.       }
  2816.  
  2817.       if (Finish->Irid > 0.0)
  2818.       {
  2819.         do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,Colour);
  2820.       }
  2821.  
  2822.     }
  2823.   }
  2824. }
  2825.  
  2826.  
  2827.  
  2828. /* NK phmap */
  2829. /*****************************************************************************
  2830. *
  2831. * FUNCTION
  2832. *
  2833. *   PhotonDiffuse (based on Diffuse)
  2834. *
  2835. *   Preconditions:
  2836. *     same as Diffuse() with this addition:
  2837. *
  2838. *     If photonOptions.photonsEnabled is true now, then
  2839. *     InitBacktraceEverything must have been called with
  2840. *     photonOptions.photonsEnabled true.
  2841. *
  2842. *
  2843. * AUTHOR
  2844. *
  2845. *   Nathan Kopp (this is based on Diffuse)
  2846. *
  2847. * DESCRIPTION
  2848. *
  2849. *   Computes diffuse, phong, specular, etc. based on the incoming photons
  2850. *   stored in the various photon maps.
  2851. *
  2852. * CHANGES
  2853. *
  2854. *   -
  2855. *
  2856. ******************************************************************************/
  2857.  
  2858.  
  2859. static void PhotonDiffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR  Layer_Normal, VECTOR Raw_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object)
  2860. {
  2861.   DBL Cos_Shadow_Angle;
  2862.   RAY Light_Source_Ray;
  2863.   VECTOR REye;
  2864.   COLOUR Light_Colour, TempCol, Colour2;
  2865.   DBL Size, r, tempr;
  2866.   int n, tempn;
  2867.   int j;
  2868.   int step;
  2869.   DBL thisDensity=0;
  2870.   DBL prevDensity=0.0000000000000001; /* avoid div-by-zero error */
  2871.   int expanded = FALSE;
  2872.   DBL att;  /* attenuation for lambertian compensation & filters */
  2873.  
  2874.   if (!photonOptions.photonsEnabled || photonOptions.photonMap.numPhotons<1)
  2875.   {
  2876.     Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
  2877.     return;
  2878.   }
  2879.  
  2880.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
  2881.   {
  2882.     Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
  2883.     return;
  2884.   }
  2885.  
  2886.   /* statistics */
  2887.   Increase_Counter(stats[Gather_Performed_Count]);
  2888.  
  2889.   if (Finish->Specular != 0.0)
  2890.   {
  2891.     REye[X] = -Eye->Direction[X];
  2892.     REye[Y] = -Eye->Direction[Y];
  2893.     REye[Z] = -Eye->Direction[Z];
  2894.   }
  2895.  
  2896.   Make_Colour(Colour,0,0,0);
  2897.  
  2898.   Size = photonOptions.photonMap.minGatherRad;
  2899.  
  2900.   Make_Colour(Colour2,0,0,0);
  2901.  
  2902.   n=-1;
  2903.   step=0;
  2904.   while(n<photonOptions.minGatherCount && step<photonOptions.photonMap.gatherNumSteps)
  2905.   {
  2906.     Make_Colour(TempCol,0,0,0);
  2907.     tempr = 0;
  2908.  
  2909.     /* gather the photons */
  2910.     if (photonsAlreadyGathered<=0)
  2911.     {
  2912.       tempn=gatherPhotons(IPoint, Size, &tempr,Layer_Normal,TRUE,&photonOptions.photonMap);
  2913.     }
  2914.     else
  2915.     {
  2916.       tempn = photonsAlreadyGathered;
  2917.       tempr = previousRad;
  2918.     }
  2919.  
  2920.     /* now go through these photons and add up their contribution */
  2921.     for(j=0; j<tempn; j++)
  2922.     {
  2923.       SMALL_COLOUR col;
  2924.       /*DBL theta,phi;*/
  2925.       int theta,phi;
  2926.  
  2927.       /* convert small color to normal color */
  2928.       col = photonOptions.photonGatherList[j]->Colour;
  2929.       UNPACK_COLOUR(Light_Colour, col, photonOptions.photonMap);
  2930.  
  2931.       /* convert theta/phi to vector direction 
  2932.          Use a pre-computed array of sin/cos to avoid many calls to the
  2933.          sin() and cos() functions.  These arrays were initialized in
  2934.          InitBacktraceEverything.
  2935.       */
  2936.       theta = photonOptions.photonGatherList[j]->theta+127;
  2937.       phi = photonOptions.photonGatherList[j]->phi+127;
  2938.       
  2939.       Light_Source_Ray.Direction[Y] = photonOptions.sinTheta[theta];
  2940.       Light_Source_Ray.Direction[X] = photonOptions.cosTheta[theta];
  2941.  
  2942.       Light_Source_Ray.Direction[Z] = Light_Source_Ray.Direction[X]*photonOptions.sinTheta[phi];
  2943.       Light_Source_Ray.Direction[X] = Light_Source_Ray.Direction[X]*photonOptions.cosTheta[phi];
  2944.  
  2945.       VSub(Light_Source_Ray.Initial, photonOptions.photonGatherList[j]->Loc, Light_Source_Ray.Direction);
  2946.  
  2947.       /* this compensates for real lambertian (diffuse) lighting (see paper) */
  2948.       /* use raw normal, not layer normal */
  2949.       /* VDot(att, Layer_Normal, Light_Source_Ray.Direction); */
  2950.       VDot(att, Raw_Normal, Light_Source_Ray.Direction);
  2951.       if (att>1) att=1.0;
  2952.       if (att<.1) att = 0.1; /* limit to 10x - otherwise we get bright dots */
  2953.       att = 1.0 / fabs(att);
  2954.  
  2955.       /* do gaussian filter */
  2956.       /*att *= 0.918*(1.0-(1.0-exp((-1.953) * photonOptions.photonDistances[j])) / (1.0-exp(-1.953)) );*/
  2957.       /* do cone filter */
  2958.       /*att *= 1.0-(sqrt(photonOptions.photonDistances[j])/(4.0 * tempr)) / (1.0-2.0/(3.0*4.0));*/
  2959.  
  2960.       VScaleEq(Light_Colour,att);
  2961.  
  2962.       /* See if light on far side of surface from camera. */
  2963.       if (!(Test_Flag(Object, DOUBLE_ILLUMINATE_FLAG)))
  2964.       {
  2965.         VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
  2966.         if (Cos_Shadow_Angle < EPSILON)
  2967.           continue;
  2968.       }
  2969.  
  2970.       /* now add diffuse, phong, specular, irid contribution */
  2971.       if (Finish->Diffuse > 0.0)
  2972.       {
  2973.         do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,TempCol,Light_Colour,Layer_Pigment_Colour, Attenuation);
  2974.       }
  2975.  
  2976.       /* NK rad 
  2977.         don't compute highlights for radiosity gather rays, since this causes
  2978.         problems with colors being far too bright
  2979.         */
  2980.       if(Radiosity_Trace_Level<=1)
  2981.       /* NK ---- */
  2982.       {
  2983.         if (Finish->Phong > 0.0)
  2984.         {
  2985.           do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
  2986.         }
  2987.         if (Finish->Specular > 0.0)
  2988.         {
  2989.           do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
  2990.         }
  2991.       }
  2992.  
  2993.       if (Finish->Irid > 0.0)
  2994.       {
  2995.         do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,TempCol);
  2996.       }
  2997.  
  2998.     }
  2999.  
  3000.     /* density of this search */
  3001.     thisDensity = tempn / (tempr*tempr);
  3002.  
  3003.     /*
  3004.       this next line handles the adaptive search
  3005.       if
  3006.         the density change ((thisDensity-prevDensity)/prevDensity) is small enough
  3007.           or
  3008.         this is the first time through (step==0)
  3009.           or
  3010.         the number gathered is less than photonOptions.minExpandCount and greater than zero
  3011.  
  3012.       then
  3013.         use the color from this new gathering step and discard any previous
  3014.         color
  3015.  
  3016.       This adaptive search is explained my paper "Simulating Reflective and Refractive
  3017.       Caustics in POV-Ray Using a Photon Map" - May, 1999
  3018.     */
  3019.     if(((thisDensity-prevDensity)/prevDensity < photonOptions.expandTolerance) 
  3020.        || (step==0) 
  3021.        || (tempn<photonOptions.minExpandCount && tempn>0))
  3022.     {
  3023.       /* it passes the tests, so use the new color */
  3024.       
  3025.       if (step>0)
  3026.         expanded = TRUE;
  3027.  
  3028.       prevDensity = thisDensity;
  3029.       if (prevDensity==0)
  3030.         prevDensity = 0.0000000000000001;  /* avoid div-by-zero error */
  3031.  
  3032.       Assign_Colour(Colour2, TempCol);
  3033.  
  3034.       r = tempr;
  3035.       n = tempn;
  3036.     }
  3037.  
  3038.     if(photonsAlreadyGathered)
  3039.     {
  3040.       step = photonOptions.photonMap.gatherNumSteps; /* so we don't gather again */
  3041.     }
  3042.     else
  3043.     {
  3044.       Size+=photonOptions.photonMap.gatherRadStep;
  3045.       step++;
  3046.     }
  3047.  
  3048.   }
  3049.   
  3050.   /* stats */
  3051.   if (expanded)
  3052.     Increase_Counter(stats[Gather_Expanded_Count]);
  3053.  
  3054.   /* finish the photons equation */
  3055.   VScaleEq(Colour2, (DBL)(1.0)/(M_PI*r*r));
  3056.  
  3057.   /* add photon contribution to total lighting */
  3058.   VAddEq(Colour, Colour2);
  3059.  
  3060.   /* save results for subsequent layers */
  3061.   /* even if an expanded search was thrown away, the closest photons n will
  3062.   still be the closest n photons */
  3063.   previousRad = r;
  3064.   photonsAlreadyGathered = n;
  3065. }
  3066. /* NK ---- */
  3067.  
  3068. /*****************************************************************************
  3069. *
  3070. * FUNCTION
  3071. *
  3072. *   Reflect
  3073. *
  3074. * INPUT
  3075. *   
  3076. * OUTPUT
  3077. *   
  3078. * RETURNS
  3079. *
  3080. * AUTHOR
  3081. *
  3082. *   POV-Ray Team
  3083. *
  3084. * DESCRIPTION
  3085. *
  3086. *   Trace a ray along the direction of the reflected light and
  3087. *   return light internsity coming from that direction.
  3088. *
  3089. * CHANGES
  3090. *
  3091. *   JUN 1997 : Changed to return color coming along the reflected ray. [DB]
  3092. *
  3093. ******************************************************************************/
  3094.  
  3095. static void Reflect(VECTOR IPoint, RAY *Ray, VECTOR Normal, VECTOR Raw_Normal, COLOUR Colour, DBL Weight, DBL Blur, int Samples)
  3096. {
  3097.   RAY New_Ray;
  3098.   /* This function heavily edited by MBP to implement reflection-blur. */
  3099.   COLOUR Temp_Colour2;
  3100. /*  register DBL Normal_Component;*/
  3101.   VECTOR Jitter_Normal, Jitter_Offset;
  3102.   VECTOR Jitter_Raw_Normal;
  3103.   int blur_count, samples = Samples;
  3104.   DBL x, y, z, t, r, n, n2;
  3105.   int doBlur, startBlur;
  3106. #ifdef NoImageNoReflectionPatch
  3107.   /* Object-Ray Options [ENB 9/97] */
  3108.   In_Reflection_Ray = TRUE;
  3109. #endif
  3110.  
  3111.   Trace_Level++;
  3112.  
  3113.   startBlur = FALSE;
  3114.  
  3115.   if(fabs(Blur)<EPSILON)
  3116.   {
  3117.      /* ComeBack put if blur=0 then samples=1 into post of finish!!!!!! */
  3118.     doBlur = FALSE;
  3119.   }
  3120.   else
  3121.   {
  3122.     doBlur = TRUE;
  3123.   }
  3124.  
  3125.   /* Sometimes we don't want to do any blurring... */
  3126.   if(alreadyBlurred ||
  3127.      Trace_Level > opts.Reflection_Blur_Max || 
  3128.      Weight < opts.Reflection_Blur_Max_ADC ||
  3129.      firstRadiosityPass
  3130.     )
  3131.   {
  3132.     samples = 1;
  3133.   }
  3134.  
  3135.   if (doBlur && !alreadyBlurred) 
  3136.   {
  3137.     startBlur = TRUE;
  3138.     alreadyBlurred = TRUE;
  3139.   }
  3140.  
  3141.   /* NK phmap - added checking for backtraceFlag */
  3142.   if(!backtraceFlag)
  3143.   {
  3144.     Make_ColourA (Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
  3145.   }
  3146.   else if (samples > 1)
  3147.   {
  3148.     Colour[0]/=samples;
  3149.     Colour[1]/=samples;
  3150.     Colour[2]/=samples;
  3151.   }
  3152.  
  3153.   for (blur_count = 0; blur_count < samples; blur_count++) {
  3154.     /* We work with a copy of the normal so the original isn't affected. */
  3155.     Assign_Vector(Jitter_Normal, Normal);
  3156.     Assign_Vector(Jitter_Raw_Normal, Raw_Normal);
  3157.  
  3158.     if(doBlur)
  3159.     {
  3160.       /* only do this if we are using blur */
  3161.  
  3162.       /* Pick a random point on the surface of a unit sphere.
  3163.          Uses a method called the "trig method" explained in the
  3164.          comp.graphics.algorithms FAQ. */
  3165.       z = (FRAND() * 2) - 1;
  3166.       t = FRAND() * M_PI * 2;
  3167.       r = sqrt(1 - z*z);
  3168.       x = r * cos(t);
  3169.       y = r * sin(t);
  3170.       Make_Vector(Jitter_Offset, x, y, z);
  3171.  
  3172.       /* Add the jittering to the normal */
  3173.       VAddScaledEq(Jitter_Normal, Blur, Jitter_Offset);
  3174.       VAddScaledEq(Jitter_Raw_Normal, Blur, Jitter_Offset );
  3175.     }
  3176.  
  3177.     /* Normals must always have length 1 or weird things happen in color calculations. */
  3178.     VNormalizeEq(Jitter_Normal);
  3179.     VNormalizeEq(Jitter_Raw_Normal);
  3180.  
  3181.     /* The rest of this is essentally what was originally here, with small changes. */
  3182.     VDot(n,Ray->Direction, Jitter_Normal);
  3183.     n *= -2.0;
  3184.     VAddScaled(New_Ray.Direction, Ray->Direction, n, Jitter_Normal);
  3185.  
  3186.     /* Nathan Kopp & CEY 1998 - Reflection bugfix
  3187.     if the new ray is going the opposet direction as raw normal, we
  3188.     need to fix it.
  3189.     */
  3190.  
  3191.     VDot(n, New_Ray.Direction, Jitter_Raw_Normal);
  3192.  
  3193.     if (n < 0.0)
  3194.     {
  3195.       /* It needs fixing.  Which kind? */
  3196.  
  3197.       VDot(n2,New_Ray.Direction,Jitter_Normal);
  3198.  
  3199.       if (n2 < 0.0)
  3200.       {
  3201.         /* reflected inside rear virtual surface. Reflect Ray using Raw_Normal */
  3202.         VDot(n,Ray->Direction,Jitter_Raw_Normal);
  3203.         n *= -2.0;
  3204.         VAddScaled(New_Ray.Direction, Ray->Direction, n,Jitter_Raw_Normal);
  3205.       }
  3206.       else
  3207.       {
  3208.         /* Double reflect NRay using Raw_Normal */
  3209.         /*VDot(n,New_Ray.Direction,Jitter_Raw_Normal); - kept the old n around */
  3210.         n *= -2.0;
  3211.         VAddScaledEq(New_Ray.Direction, n, Jitter_Raw_Normal);
  3212.       }
  3213.     }
  3214.     VNormalizeEq(New_Ray.Direction);
  3215.     /* NK & CEY ---- */
  3216.  
  3217.     Assign_Vector(New_Ray.Initial, IPoint);
  3218.  
  3219.     Copy_Ray_Containers(&New_Ray, Ray);
  3220.  
  3221.     Increase_Counter(stats[Reflected_Rays_Traced]);
  3222.  
  3223.     /* Trace reflected ray. */
  3224.     /* NK phmap - added checking for backtraceFlag */
  3225.     if(!backtraceFlag)
  3226.     {
  3227.       Trace (&New_Ray, Temp_Colour2, Weight, NULL);
  3228.       VAddEq(Colour, Temp_Colour2);
  3229.     }
  3230.     else
  3231.     {
  3232. #ifdef MotionBlurPatch
  3233.       Trace_With_Blur(&New_Ray, Colour, Weight, NULL);
  3234. #else
  3235.       Trace(&New_Ray, Colour, Weight, NULL);
  3236. #endif
  3237.     }
  3238.   }
  3239.   Trace_Level--;
  3240.  
  3241.   /* if we started the blur, then let's un-start it */
  3242.   if (startBlur) 
  3243.   {
  3244.     alreadyBlurred = FALSE;
  3245.   }
  3246.  
  3247.   /* NK phmap - added checking for backtraceFlag */
  3248.   if(!backtraceFlag)
  3249.   {
  3250.     VInverseScaleEq(Colour, samples);
  3251.   }
  3252. }
  3253.  
  3254. /*****************************************************************************
  3255. *
  3256. * FUNCTION
  3257. *
  3258. *   Refract
  3259. *
  3260. * INPUT
  3261. *
  3262. *   Interior - interior of the current object containing the ior to use
  3263. *   IPoint   - current intersection point (here the new ray starts)
  3264. *   Ray      - current incoming ray that will be refracted, transmitted
  3265. *              or reflected (due to total internal reflection)
  3266. *   Normal   - surface normal at the current intersection point
  3267. *   Colour   - current color emitted back along the ray
  3268. *   Weight   - current weight used by the adaptive tree depth control
  3269. *
  3270. * OUTPUT
  3271. *
  3272. *   Colour   - current color including the light due to refraction,
  3273. *              transmission or total internal reflection
  3274. *
  3275. * RETURNS
  3276. *
  3277. *   int - TRUE, if total internal reflection occured
  3278. *
  3279. * AUTHOR
  3280. *
  3281. *   POV-Ray Team
  3282. *
  3283. * DESCRIPTION
  3284. *
  3285. *   Trace a transmitted ray (either refracted or reflected due to total
  3286. *   internal reflection) and return the light intesity coming from the
  3287. *   direction of the transmitted ray.
  3288. *
  3289. * CHANGES
  3290. *
  3291. *   Aug 1995 : Modified to correctly handle the contained texture
  3292. *              list in the transmit only case. [DB]
  3293. *
  3294. *   Jun 1997 : Rewritten to use interior structure. [DB]
  3295. *
  3296. *   Spring 1998 : Rewritten to incorporate Daren Wilson's dispersion AND photon
  3297. *                 mapping.
  3298. *
  3299. ******************************************************************************/
  3300. /* NK phmap ------------
  3301.   the Refract function here is highly modified and probably quite
  3302.   messy right now.  The primary reason is the inclusion of Daren
  3303.   Wilson's dispersion code.
  3304.   
  3305.   This needs MUCH better comments for the whole thing.
  3306.   Mr. Wilson & Mr. Parker: if you want to help clean this up and add
  3307.   comments, you're very much welcome to.  ;-)
  3308. */
  3309. /* NK phmap */
  3310. static COLOUR GFilCol; /* not thread safe */
  3311. /* NK ---- */
  3312.  
  3313.  
  3314. /*__inline  double sqr(double x)  { return x*x; }*/
  3315. #define sqr(x) ((x)*(x))
  3316.  
  3317. static void Dispersion_Element_Hue(COLOUR Hue, int elem, int nelems)
  3318. {
  3319.   /* 
  3320.     Gives color to a dispersion element.
  3321.  
  3322.     Requirements:
  3323.       * Sum of all hues must add to white (or white*constand)
  3324.       (white tiles seen through glass should still be white)
  3325.       
  3326.     * Each hue must be maximally saturated, bright
  3327.       (The code shown here cheats a little)
  3328.       
  3329.     * colors must range from red at h=0 to violet at h=1
  3330.  
  3331.     This code is not necessarily the best, just proof-of-concept      
  3332.     EXPERIMENTAL AND DELICATE
  3333.     Better code could be written with look-up tables of the 
  3334.     famous CIE colour matching functions.
  3335.   */
  3336.   
  3337.   float h, coh;
  3338.   float ybulge;
  3339.   
  3340.   /* h goes from 0 at red end to 1.0 at blue end */
  3341.   h = (elem-1)*1.0/(nelems-1);
  3342.  
  3343.   /* co-h goes from 1.0 at red end to 0.0 at blue end */
  3344.   coh = 1.0 - h; 
  3345.   
  3346.   Hue[RED] = 0.9 - (h/0.5);
  3347.   Hue[BLUE] = 1.0 - (coh/0.6);
  3348.  
  3349.   if (Hue[RED] < 0.0)  Hue[RED] = 0.0;
  3350.   if (Hue[BLUE] < 0.0)  Hue[BLUE] = 0.0;
  3351.  
  3352.  
  3353.   Hue[RED]=1.0 - sqr(1.0-Hue[RED]);  
  3354.   Hue[BLUE]=1.0-sqr(1.0-Hue[BLUE]); 
  3355.   
  3356.   
  3357.   Hue[GREEN] = 1.0 - Hue[RED] - Hue[BLUE];
  3358.  
  3359.   if (h>0.85)
  3360.     Hue[RED] = 8*(h-0.85);  /* was 4 */
  3361.  
  3362.   ybulge =  -4.0*(h-0.1)*(h-0.6);
  3363.   if (ybulge<0) ybulge=0;
  3364.   Hue[RED] += ybulge * 0.5; /* added * 0.5  */
  3365.   Hue[GREEN] += ybulge;
  3366. }
  3367.  
  3368. static double Element_IOR(double ior, double disp,  int e, int nelems)
  3369. {
  3370.   return ior * pow(disp, (e-1)*1.0/(nelems-1)-0.5);
  3371. }
  3372.  
  3373.  
  3374. static int Refract_Guts(COLOUR Colour,  
  3375.     DBL ior,
  3376.     VECTOR IPoint,
  3377.     VECTOR Normal, VECTOR Local_Normal,
  3378.     DBL n,
  3379.     RAY *Ray, RAY *NRay,
  3380.     DBL Weight,
  3381.     VECTOR Raw_Normal
  3382.     )
  3383. {
  3384.   /* Adds result of refracted ray to Colour            */
  3385.   /* All other args are input args - don't change them */
  3386.   /* Pass by value the RAYs and maybe make local copy of normals? */
  3387.   DBL t;
  3388.   
  3389.   /* Compute refrated ray direction using Heckbert's method. */
  3390.   t = 1.0 + Sqr(ior) * (Sqr(n) - 1.0);
  3391.  
  3392.   if (t < 0.0)
  3393.   {
  3394.     /* Total internal reflection occures. */
  3395.     Increase_Counter(stats[Internal_Reflected_Rays_Traced]);
  3396.     Reflect(IPoint, /*N?*/ Ray, /*L?*/ Normal, Raw_Normal, Colour, Weight, 0, 1); /* ???? */
  3397.     return 1;
  3398.   }
  3399.  
  3400.   t = ior * n - sqrt(t);
  3401.   VLinComb2(NRay->Direction, ior, /*N?*/Ray->Direction, t, Local_Normal);
  3402.  
  3403.   /* Trace a refracted ray. */
  3404.   Increase_Counter(stats[Refracted_Rays_Traced]);
  3405.     
  3406.   Trace_Level++;
  3407. #ifdef MotionBlurPatch
  3408.   Trace_With_Blur(NRay, Colour, Weight, NULL);
  3409. #else
  3410.   Trace(NRay, Colour, Weight, NULL);
  3411. #endif
  3412.   Trace_Level--;
  3413.  
  3414.   return 0;
  3415. }
  3416.  
  3417.  
  3418. static int BacktraceRefract(INTERIOR *Interior, VECTOR IPoint, RAY *Ray, VECTOR Normal, VECTOR Raw_Normal, COLOUR Colour, DBL Weight)
  3419. {
  3420.   int nr;
  3421.   DBL n, ior, disp;
  3422.   VECTOR Local_Normal;
  3423.   RAY NRay;
  3424.   COLOUR Hue, Elem;
  3425.   int i;
  3426.  
  3427.   /* Set up new ray. */
  3428.   Copy_Ray_Containers(&NRay, Ray);
  3429.   Assign_Vector(NRay.Initial, IPoint);
  3430.  
  3431.   /* get the dispersion elements from the light's blend map */
  3432.   if ((disp_elem == 0) && (photonOptions.Light->blend_map))
  3433.       disp_nelems = photonOptions.Light->blend_map->Number_Of_Entries;
  3434.   
  3435.   /* Get ratio of iors depending on the interiors the ray is traversing. */
  3436.   if (Ray->Index == -1)
  3437.   {
  3438.     /* The ray is entering from the atmosphere. */
  3439.     Ray_Enter(&NRay, Interior);
  3440.     ior = Frame.Atmosphere_IOR / Interior->IOR;
  3441.     disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
  3442.   }
  3443.   else
  3444.   {
  3445.     /* The ray is currently inside an object. */
  3446.     if ((nr = Interior_In_Ray_Container(&NRay, Interior)) >= 0)
  3447.     {
  3448.       /* The ray is leaving the current object. */
  3449.       Ray_Exit(&NRay, nr);
  3450.  
  3451.       if (NRay.Index == -1)
  3452.       {
  3453.         /* The ray is leaving into the atmosphere. */
  3454.         ior = Interior->IOR / Frame.Atmosphere_IOR;
  3455.         disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
  3456.       }
  3457.       else
  3458.       {
  3459.         /* The ray is leaving into another object. */
  3460.         ior = Interior->IOR / NRay.Interiors[NRay.Index]->IOR;
  3461.         disp = Interior->Dispersion / NRay.Interiors[NRay.Index]->Dispersion;
  3462.     
  3463.         /* Use the largest disp_nelems of the two interiors */
  3464.         if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
  3465.           disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
  3466.       }
  3467.     }
  3468.     else
  3469.     {
  3470.       /* The ray is entering a new object. */
  3471.       ior = NRay.Interiors[NRay.Index]->IOR / Interior->IOR;
  3472.       disp = NRay.Interiors[NRay.Index]->Dispersion / Interior->Dispersion;
  3473.  
  3474.       /* Use the largest disp_nelems of the two interiors */
  3475.       if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
  3476.         disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
  3477.  
  3478.       Ray_Enter(&NRay, Interior);
  3479.  
  3480.     }
  3481.   }
  3482.  
  3483.   /* Do the two mediums traversed have the sampe indices of refraction? */
  3484.   /* DSW: they must also match in dispersion ratios                     */
  3485.   if (fabs(ior - 1.0) < EPSILON
  3486.    && fabs(disp - 1.0) < EPSILON)
  3487.   {
  3488.     COLOUR lc;
  3489.  
  3490.     /* Only transmit the ray. */
  3491.     Assign_Vector(NRay.Direction, Ray->Direction);
  3492.  
  3493.     /* Trace a transmitted ray. */
  3494.     Increase_Counter(stats[Transmitted_Rays_Traced]);
  3495.     
  3496.     lc[0] = Colour[0]*(GFilCol[0] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3497.     lc[1] = Colour[1]*(GFilCol[1] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3498.     lc[2] = Colour[2]*(GFilCol[2] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3499.  
  3500.     Trace_Level++;
  3501. #ifdef MotionBlurPatch
  3502.     Trace_With_Blur(&NRay, lc, Weight, NULL);
  3503. #else
  3504.     Trace(&NRay, lc, Weight, NULL);
  3505. #endif
  3506.     Trace_Level--;
  3507.   }
  3508.   else    /* different media */
  3509.   {
  3510.     /* Refract the ray. */
  3511.     VDot(n, Ray->Direction, Normal);
  3512.  
  3513.     if (n <= 0.0)
  3514.     {
  3515.       Assign_Vector(Local_Normal, Normal);
  3516.       n = -n;
  3517.     }
  3518.     else
  3519.     {
  3520.       Local_Normal[X] = -Normal[X];
  3521.       Local_Normal[Y] = -Normal[Y];
  3522.       Local_Normal[Z] = -Normal[Z];
  3523.     }
  3524.  
  3525.     /* DSW: If this is the first time this ray is encountering          */
  3526.     /* a dispersive medium, we need to loop over the color components.  */
  3527.     /* If the ray has already been dispersed, use trace a monochromatic */
  3528.     /* ray, with no further looping.                                    */
  3529.  
  3530.     if (disp_elem>0 || disp_nelems <= 1 || fabs(disp-1.0)<EPSILON || firstRadiosityPass)
  3531.     {
  3532.       DBL ior2;
  3533.       /* We're already tracing an element */
  3534.       /* NK phmap */
  3535.       COLOUR lc;
  3536.       lc[0] = Colour[0]*(GFilCol[0] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3537.       lc[1] = Colour[1]*(GFilCol[1] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3538.       lc[2] = Colour[2]*(GFilCol[2] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3539.       ior2 = ior /sqrt(disp) * pow(disp, RGBtoHue(lc));
  3540.       return Refract_Guts(lc, ior2, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
  3541.     }
  3542.  
  3543.     else
  3544.     {
  3545.       /* An undispersed ray needs to be broken into elements */
  3546.       
  3547.       /* Trace each element */
  3548.       COLOUR lc;
  3549.       DBL ior2;
  3550.       BLEND_MAP *Map = photonOptions.Light->blend_map;
  3551.       SNGL Value;
  3552.  
  3553.       /* NK phmap */
  3554.       lc[0] = Colour[0]*(GFilCol[0] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3555.       lc[1] = Colour[1]*(GFilCol[1] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3556.       lc[2] = Colour[2]*(GFilCol[2] * GFilCol[FILTER] + GFilCol[TRANSM]);
  3557.  
  3558. #define MONTE_CARLO_DISP_PHOT_SPLIT 0
  3559. #if MONTE_CARLO_DISP_PHOT_SPLIT
  3560.       i = rand()%Map->Number_Of_Entries;
  3561. #else
  3562.       for (i = 0; i < Map->Number_Of_Entries; i++)
  3563. #endif
  3564.       {
  3565.         disp_elem = i+1;
  3566.  
  3567. #define USE_BLEND_MAP 1
  3568. #if USE_BLEND_MAP
  3569.        /* get the dispersion elements from the light's blend map */
  3570.         Value = Map->Blend_Map_Entries[i].value;
  3571. #if MONTE_CARLO_DISP_PHOT_SPLIT
  3572.         Value *= Map->Number_Of_Entries;
  3573. #endif
  3574.         VScale(Hue,Map->Blend_Map_Entries[i].Vals.Colour,Value);
  3575.  
  3576.         /* we really want to use just the hue that we got from the
  3577.            color_map, but we still want it to be filtered by previous
  3578.            surfaces */
  3579.         if(photonOptions.Light->Colour[0])
  3580.           Elem[0] = Hue[0] * lc[0] / photonOptions.Light->Colour[0];
  3581.         else
  3582.           Elem[0] = 0;
  3583.         if(photonOptions.Light->Colour[1])
  3584.           Elem[1] = Hue[1] * lc[1] / photonOptions.Light->Colour[1];
  3585.         else
  3586.           Elem[1] = 0;
  3587.         if(photonOptions.Light->Colour[2])
  3588.           Elem[2] = Hue[2] * lc[2] / photonOptions.Light->Colour[2];
  3589.         else
  3590.           Elem[2] = 0;
  3591. #else
  3592.         Dispersion_Element_Hue(Hue, disp_elem, disp_nelems+1);
  3593.         /*Dispersion_Element_Hue(Hue, rand()%1000, 1000);*/
  3594.         Elem[RED]   = lc[RED]   * Hue[RED];
  3595.         Elem[GREEN] = lc[GREEN] * Hue[GREEN];
  3596.         Elem[BLUE]  = lc[BLUE]  * Hue[BLUE];
  3597. #endif
  3598.  
  3599.  
  3600.         ior2 = ior /sqrt(disp) * pow(disp, RGBtoHue(Elem));
  3601.  
  3602.         if (RGBtoHue(Elem)<0)
  3603.         {
  3604.           Make_Colour(Elem, 0,1,0);
  3605.         }
  3606.         else if (RGBtoHue(Elem)>1)
  3607.         {
  3608.           Make_Colour(Elem, 0,0,1);
  3609.         }
  3610.  
  3611.         Refract_Guts(Elem, ior2, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
  3612.  
  3613.           /*ior *= ior_mult;*/
  3614.         }
  3615.         /* NK ---- */
  3616.       disp_elem = 0;   /* reset this for next pixel's tracing */
  3617.       disp_nelems = 0;   /* reset this for next pixel's tracing */
  3618.     }
  3619.   
  3620.   
  3621.   }    /* end of different media */
  3622.  
  3623.   return(0);
  3624. }
  3625.  
  3626. static int Refract(INTERIOR *Interior, VECTOR IPoint, RAY *Ray, VECTOR Normal, VECTOR Raw_Normal, COLOUR Colour, DBL Weight)
  3627. {
  3628.   int nr;
  3629.   DBL n, ior, disp, ior_mult;
  3630.   VECTOR Local_Normal;
  3631.   RAY NRay;
  3632.   COLOUR Hue, Sum, Elem;
  3633. #ifdef PostProcessPatch2
  3634.   DBL depth;
  3635. #endif
  3636.  
  3637.   /* Set up new ray. */
  3638.   Copy_Ray_Containers(&NRay, Ray);
  3639.   Assign_Vector(NRay.Initial, IPoint);
  3640.  
  3641.   if (disp_elem == 0)
  3642.     disp_nelems = Interior->Disp_NElems;
  3643.   
  3644.   disp = 1.0;
  3645.  
  3646.   /* Get ratio of iors depending on the interiors the ray is traversing. */
  3647.   if (Ray->Index == -1)
  3648.   {
  3649.     /* The ray is entering from the atmosphere. */
  3650.     Ray_Enter(&NRay, Interior);
  3651.     ior = Frame.Atmosphere_IOR / Interior->IOR;
  3652.     if (disp_nelems>1)
  3653.       disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
  3654.   }
  3655.   else
  3656.   {
  3657.     /* The ray is currently inside an object. */
  3658.     if ((nr = Interior_In_Ray_Container(&NRay, Interior)) >= 0)
  3659.     {
  3660.       /* The ray is leaving the current object. */
  3661.       Ray_Exit(&NRay, nr);
  3662.  
  3663.       if (NRay.Index == -1)
  3664.       {
  3665.         /* The ray is leaving into the atmosphere. */
  3666.         ior = Interior->IOR / Frame.Atmosphere_IOR;
  3667.         if (disp_nelems>1)
  3668.           disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
  3669.       }
  3670.       else
  3671.       {
  3672.         /* The ray is leaving into another object. */
  3673.         ior = Interior->IOR / NRay.Interiors[NRay.Index]->IOR;
  3674.  
  3675.         /* Use the largest disp_nelems of the two interiors */
  3676.         if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
  3677.           disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
  3678.  
  3679.         if (disp_nelems>1)
  3680.           disp = Interior->Dispersion / NRay.Interiors[NRay.Index]->Dispersion;
  3681.       }
  3682.     }
  3683.     else
  3684.     {
  3685.       /* The ray is entering a new object. */
  3686.       ior = NRay.Interiors[NRay.Index]->IOR / Interior->IOR;
  3687.       
  3688.       /* Use the largest disp_nelems of the two interiors */
  3689.       if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
  3690.         disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
  3691.  
  3692.       if (disp_nelems>1)
  3693.         disp = NRay.Interiors[NRay.Index]->Dispersion / Interior->Dispersion;
  3694.  
  3695.       Ray_Enter(&NRay, Interior);
  3696.  
  3697.     }
  3698.   }
  3699.  
  3700.   /* Do the two mediums traversed have the sampe indices of refraction? */
  3701.   /* DSW: they must also match in dispersion ratios                     */
  3702.   if (fabs(ior - 1.0) < EPSILON
  3703.    && fabs(disp - 1.0) < EPSILON)
  3704.   {
  3705.     /* Only transmit the ray. */
  3706.     Assign_Vector(NRay.Direction, Ray->Direction);
  3707.  
  3708.     /* Trace a transmitted ray. */
  3709.     Increase_Counter(stats[Transmitted_Rays_Traced]);
  3710.     
  3711.     Trace_Level++;
  3712. #ifdef PostProcessPatch2
  3713.   depth = 
  3714. #endif
  3715. #ifdef MotionBlurPatch
  3716.     Trace_With_Blur(&NRay, Colour, Weight, NULL);
  3717. #else
  3718.     Trace(&NRay, Colour, Weight, NULL);
  3719. #endif
  3720. #ifdef PostProcessPatch2
  3721.   if (fabs(Weight-1.0)<EPSILON)
  3722.     savedRefractDepth = depth;
  3723. #endif
  3724.     Trace_Level--;
  3725.   }
  3726.   else    /* different media */
  3727.   {
  3728.     /* Refract the ray. */
  3729.     VDot(n, Ray->Direction, Normal);
  3730.  
  3731.     if (n <= 0.0)
  3732.     {
  3733.       Assign_Vector(Local_Normal, Normal);
  3734.       n = -n;
  3735.     }
  3736.     else
  3737.     {
  3738.       Local_Normal[X] = -Normal[X];
  3739.       Local_Normal[Y] = -Normal[Y];
  3740.       Local_Normal[Z] = -Normal[Z];
  3741.     }
  3742.  
  3743.     /* DSW: If this is the first time this ray is encountering          */
  3744.     /* a dispersive medium, we need to loop over the color components.  */
  3745.     /* If the ray has already been dispersed, use trace a monochromatic */
  3746.     /* ray, with no further looping.                                    */
  3747.  
  3748.     if (disp_elem>0 || disp_nelems <= 1 || fabs(disp-1.0)<EPSILON || firstRadiosityPass)
  3749.     {
  3750.       /* We're already tracing an element */
  3751.       if (disp_nelems>1 && disp_elem > 0)
  3752.         ior = Element_IOR(ior, disp, disp_elem, disp_nelems);
  3753.  
  3754.       return Refract_Guts(Colour, ior, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
  3755.     }
  3756.  
  3757.     else
  3758.     {
  3759.       /* An undispersed ray needs to be broken into elements */
  3760.       
  3761.       /*if (disp_nelems==0) disp_nelems = DEFAULT_DISP_NELEMS;*/
  3762.       /* or use an adaptive formula? */
  3763.       
  3764.       /* Trace each element */
  3765.       
  3766.       ior = ior /sqrt(disp);
  3767.       ior_mult = pow(disp, 1.0/(disp_nelems-1));
  3768.  
  3769.       Sum[RED]=0.0f;
  3770.       Sum[GREEN]=0.0f;
  3771.       Sum[BLUE]=0.0f;
  3772.  
  3773.       for (disp_elem = 1;  disp_elem < disp_nelems;  disp_elem++)
  3774.       {
  3775.         /* Call an arbitrary C lib function,  to avoid a GCC 2.8.1 optimizer bug */
  3776.         /*strchr("A", 'A');*/
  3777.         Refract_Guts(Elem, ior, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
  3778.         
  3779.         Dispersion_Element_Hue(Hue, disp_elem, disp_nelems);
  3780.         /* speed it up by building a lookup table at povray init */
  3781.         /* or no: need to recalc if disp_nelems is adaptive,     */
  3782.         /* then we'd need a bunch of tables or calc fresh        */
  3783.       
  3784.         Sum[RED]   += Elem[RED]   * Hue[RED];
  3785.         Sum[GREEN] += Elem[GREEN] * Hue[GREEN];
  3786.         Sum[BLUE]  += Elem[BLUE]  * Hue[BLUE];
  3787.  
  3788.         ior *= ior_mult;
  3789.       }
  3790.         
  3791.       /* compute final color, with fudge factor */
  3792.       Colour[RED]   = Sum[RED]   /disp_nelems *3.0;
  3793.       Colour[GREEN] = Sum[GREEN] /disp_nelems *3.0;
  3794.       Colour[BLUE]  = Sum[BLUE]  /disp_nelems *3.0;
  3795.  
  3796.       disp_elem = 0;   /* reset this for next pixel's tracing */
  3797.       disp_nelems = 0;   /* reset this for next pixel's tracing */
  3798.     }
  3799.   
  3800.   
  3801.   }    /* end of different media */
  3802.  
  3803.   return(0);
  3804. }
  3805.  
  3806. /* NK ---- */
  3807.  
  3808. /*****************************************************************************
  3809. *
  3810. * FUNCTION
  3811. *
  3812. *   create_texture_list
  3813. *
  3814. * INPUT
  3815. *
  3816. * OUTPUT
  3817. *
  3818. * RETURNS
  3819. *
  3820. * AUTHOR
  3821. *
  3822. *   Chris Young based on Dieter Bayer code
  3823. *
  3824. * DESCRIPTION
  3825. *
  3826. *   Get the list of textures used by current object and the list of
  3827. *   appropriate weights for each texture. Only multi-colored objects
  3828. *   will have more than one texture.
  3829. *
  3830. * CHANGES
  3831. *
  3832. *   Feb 1995 : Added code for triangle mesh texturing. [DB]
  3833. *
  3834. *   Jul 1995 : Modified code to use pre-allocated lists. [DB]
  3835. *
  3836. ******************************************************************************/
  3837.  
  3838. static int create_texture_list(INTERSECTION *Ray_Intersection
  3839. #ifdef InteriorTexturePatch
  3840. , DBL realNormDir
  3841. #endif
  3842.  )
  3843. {
  3844.   int Texture_Count;
  3845.   BLOB *Blob;
  3846. #ifdef IsoBlobPatch
  3847.     ISOBLOB *Isoblob; /* Lummox JR, July 1999 -- for the code below */
  3848. #endif
  3849.   MESH_TRIANGLE *Triangle;
  3850. #ifdef InteriorTexturePatch
  3851.   int useInteriorTexture = FALSE;/*Chris Huff: Interior Texture patch*/
  3852.   if((realNormDir > 0)&&(Ray_Intersection->Object->Interior_Texture != NULL))/*Chris Huff: Interior Texture patch*/
  3853.       useInteriorTexture = TRUE;
  3854. #endif
  3855.   /* Test, if object is multi-textured. */
  3856.  
  3857.   if (Test_Flag(Ray_Intersection->Object, MULTITEXTURE_FLAG))
  3858.   {
  3859.     /* Handle blobs. */
  3860.  
  3861.     if (Ray_Intersection->Object->Methods == &Blob_Methods)
  3862.     {
  3863.       Blob = (BLOB *)Ray_Intersection->Object;
  3864.  
  3865.       /* Get list of weighted textures. */
  3866.  
  3867.       Determine_Blob_Textures(Blob, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
  3868.     }
  3869. #ifdef IsoBlobPatch
  3870.     /* Handle isoblobs-- Lummox JR, July 1999. */
  3871.  
  3872.     if (Ray_Intersection->Object->Methods == &Isoblob_Methods)
  3873.     {
  3874.       Isoblob = (ISOBLOB *)Ray_Intersection->Object;
  3875.  
  3876.       /* Get list of weighted textures. */
  3877.  
  3878.       Determine_Isoblob_Textures(Isoblob, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
  3879.     }
  3880.     /* End Lummox JR's addition */
  3881. #endif
  3882.  
  3883.     /* Handle meshes. */
  3884.  
  3885.     if (Ray_Intersection->Object->Methods == &Mesh_Methods)
  3886.     {
  3887.       /* Set texture to triangle's or object's texture. */
  3888.  
  3889.       Triangle = (MESH_TRIANGLE *)Ray_Intersection->Pointer;
  3890.  
  3891. #ifdef ColorTrianglePatch
  3892.       /* NK */
  3893.       if (Triangle->ThreeTex)
  3894.       {
  3895.         VECTOR Weights;
  3896.         Mesh_Interpolate(Weights, Ray_Intersection->IPoint,
  3897.             (MESH *)Ray_Intersection->Object, Triangle);
  3898.  
  3899.         if (Triangle->Texture >= 0)
  3900.           Texture_List[0] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture];
  3901.         else
  3902.           Texture_List[0] = Ray_Intersection->Object->Texture;
  3903.  
  3904.         if (Triangle->Texture2 >= 0)
  3905.           Texture_List[1] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture2];
  3906.         else
  3907.           Texture_List[1] = Ray_Intersection->Object->Texture;
  3908.  
  3909.         if (Triangle->Texture3 >= 0)
  3910.           Texture_List[2] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture3];
  3911.         else
  3912.           Texture_List[2] = Ray_Intersection->Object->Texture;
  3913.  
  3914.         Weight_List[0] = Weights[0];
  3915.         Weight_List[1] = Weights[1];
  3916.         Weight_List[2] = Weights[2];
  3917.  
  3918.         Texture_Count = 3;
  3919.       }
  3920.       else
  3921.       {
  3922.       /* NK ---- */
  3923. #endif
  3924.         if (Triangle->Texture >= 0)
  3925.         {
  3926.           /* NK 1999 moved textures from Mesh_Data_Struct to Mesh_Struct */
  3927.           Texture_List[0] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture];
  3928.           /* NK ---- */
  3929.         }
  3930.         else
  3931.         {
  3932.           Texture_List[0] = Ray_Intersection->Object->Texture;
  3933.         }
  3934.  
  3935.         Weight_List[0] = 1.0;
  3936.  
  3937.         Texture_Count = 1;
  3938. #ifdef ColorTrianglePatch
  3939.       }
  3940. #endif
  3941.     }
  3942.  
  3943.   }
  3944. #ifdef MultiTextureCsgPatch
  3945.   else if(Ray_Intersection->Object->Texture == NULL)
  3946.   {
  3947.     CSG* Csg;
  3948.     /* this should only happen with a multi-tex CSG object */
  3949.     if (!Ray_Intersection->Pointer)
  3950.       Error("Object has no texture");
  3951.  
  3952.     Csg = (CSG*)Ray_Intersection->Pointer;
  3953.     Determine_CSG_Textures(Csg, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
  3954.   }
  3955. #endif
  3956.   else
  3957.   {
  3958.  
  3959.     /* Set texture to object's texture. */
  3960.  
  3961. #ifdef InteriorTexturePatch
  3962.     /* Set texture to object's texture. */
  3963.     if(useInteriorTexture == TRUE)/*Chris Huff: Interior Texture patch*/
  3964.     {
  3965.       Texture_List[0] = Ray_Intersection->Object->Interior_Texture;
  3966.     }
  3967.     else
  3968.     {
  3969.       Texture_List[0] = Ray_Intersection->Object->Texture;
  3970.     }
  3971. #else
  3972.     Texture_List[0] = Ray_Intersection->Object->Texture;
  3973. #endif
  3974.     Weight_List[0]  = 1.0;
  3975.  
  3976.     Texture_Count = 1;
  3977.   }
  3978.  
  3979.   return(Texture_Count);
  3980. }
  3981.  
  3982.  
  3983.  
  3984. /*****************************************************************************
  3985. *
  3986. * FUNCTION
  3987. *
  3988. *   do_texture_map
  3989. *
  3990. * INPUT
  3991. *
  3992. *   Texture          - possibly texture_mapped texture to be evaluated
  3993. *   IPoint           - point to be evaluated
  3994. *   Raw_Normal       - non-purturbed surface normal
  3995. *   Ray              - view ray needed for reflection and highlighs
  3996. *                      light source ray needed for caustics
  3997. *   Weight           - ADC control value
  3998. *   Ray_Intersection - only Ray_Int..->Object->Type actually
  3999. *                      needed.  Will clean-up later.
  4000. *   Shadow_Flag      - tells if computation should use
  4001. *                      compute_lighted_texture or compute_shadow_texture
  4002. *
  4003. * OUTPUT
  4004. *
  4005. *   Result_Colour    - If Shadow_Flag true then the illuminated
  4006. *                      color (RGB only) of IPoint is returned.
  4007. *                      If false, the amount by which a shadow ray is
  4008. *                      filtered and attenuated is returned.
  4009. *                      Includes RGB and T.
  4010. *
  4011. * RETURNS
  4012. *
  4013. * AUTHOR
  4014. *
  4015. *   POV-Ray Team
  4016. *
  4017. * DESCRIPTION
  4018. *
  4019. *   This routine recursively calls itself until it gets a
  4020. *   non-texture_mapped texture that is potentially layered.
  4021. *   It then calls compute_lighted_texture or compute_shadow_texture
  4022. *   to compute the color which is returned in the argument Result_Colour.
  4023. *
  4024. * CHANGES
  4025. *
  4026. ******************************************************************************/
  4027.  
  4028. static void do_texture_map(COLOUR Result_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal,
  4029.   RAY *Ray, DBL Weight, INTERSECTION *Ray_Intersection, int Shadow_Flag)
  4030. {
  4031.   BLEND_MAP *Blend_Map = Texture->Blend_Map;
  4032.   BLEND_MAP_ENTRY *Prev, *Cur;
  4033.   DBL value1, value2;
  4034.   COLOUR C2;
  4035.   VECTOR CPoint, TPoint;
  4036.   /* NK 1998 reset_children - added CPoint above
  4037.  
  4038.      ipoint - interseciton point (and evaluation point)
  4039.      epoint - evaluation point
  4040.      tpoint - turbulated/transformed point
  4041.      cpoint - epoint for children textures
  4042.   */
  4043.  
  4044.   if (Texture->Type <= LAST_SPECIAL_PATTERN)
  4045.   {
  4046.     switch (Texture->Type)
  4047.     {
  4048.       case NO_PATTERN:
  4049.  
  4050.         Make_ColourA(Result_Colour, 1.0, 1.0, 1.0, 1.0, 1.0);
  4051.  
  4052.         break;
  4053.  
  4054.       case AVERAGE_PATTERN:
  4055.  
  4056. #ifdef NormalBugFix
  4057. #ifdef UnofficialBlocking
  4058.         if(opts.unofficialVersion>=30)
  4059. #else
  4060.         if(opts.Language_Version>310)
  4061. #endif
  4062.         {
  4063.           if(warpNormalTextures>MAX_NESTED_TEXTURES)
  4064.             Error("Too many nested textures.");
  4065.           warpNormalTextureList[warpNormalTextures++] = Texture;
  4066.         }
  4067. #endif
  4068.         /* NK 1998 reset_children - added ", TRUE" & changed tpoint to cpoint */
  4069.         Warp_EPoint(CPoint, IPoint, (TPATTERN *)Texture, TRUE);
  4070.  
  4071.         /* NK phmap */
  4072.         if (backtraceFlag)
  4073.           backtrace_average_textures(Result_Colour, Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4074.         else
  4075.         /* NK ---- */
  4076.           average_textures(Result_Colour, Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4077. #ifdef NormalBugFix
  4078. #ifdef UnofficialBlocking
  4079.         if(opts.unofficialVersion>=30)
  4080. #else
  4081.         if(opts.Language_Version>310)
  4082. #endif
  4083.         {
  4084.           warpNormalTextures--;
  4085.         }
  4086. #endif
  4087.  
  4088.         break;
  4089.  
  4090.       case BITMAP_PATTERN:
  4091.  
  4092. #ifdef NormalBugFix
  4093. #ifdef UnofficialBlocking
  4094.         if(opts.unofficialVersion>=30)
  4095. #else
  4096.         if(opts.Language_Version>310)
  4097. #endif
  4098.         {
  4099.           if(warpNormalTextures>MAX_NESTED_TEXTURES)
  4100.             Error("Too many nested textures.");
  4101.           warpNormalTextureList[warpNormalTextures++] = Texture;
  4102.         }
  4103. #endif
  4104.         /* NK 1998 reset_children - added ", FALSE" and second call to warp_epoint */
  4105.         Warp_EPoint (TPoint, IPoint, (TPATTERN *)Texture, FALSE);
  4106.         Warp_EPoint (CPoint, IPoint, (TPATTERN *)Texture, TRUE);
  4107.         /* NK ---- */
  4108.  
  4109.         Texture = material_map(TPoint, Texture);
  4110.  
  4111.         /* NK 1998 reset_children - changed TPoint to CPoint */
  4112.         do_texture_map(Result_Colour, Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4113. #ifdef NormalBugFix
  4114. #ifdef UnofficialBlocking
  4115.         if(opts.unofficialVersion>=30)
  4116. #else
  4117.         if(opts.Language_Version>310)
  4118. #endif
  4119.         {
  4120.           warpNormalTextures--;
  4121.         }
  4122. #endif
  4123.  
  4124.         break;
  4125.  
  4126.       case PLAIN_PATTERN:
  4127.  
  4128.         /* nk phmap */
  4129.         if (backtraceFlag)
  4130.         {
  4131.           compute_backtrace_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection);
  4132.         }
  4133.         else 
  4134.         /* NK ---- */
  4135.  
  4136.         if (Shadow_Flag)
  4137.         {
  4138.           compute_shadow_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Ray_Intersection);
  4139.         }
  4140.         else
  4141.         {
  4142.           compute_lighted_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection);
  4143.         }
  4144.  
  4145.         break;
  4146.  
  4147.       default:
  4148.  
  4149.         Error("Bad texture type in do_texture_map()\n");
  4150.     }
  4151.   }
  4152.   else
  4153.   {
  4154.     /* call warp_epoint with "warping_children" set to
  4155.        FALSE, so any RESET_CHILDREN warps will not be applied */
  4156.     /* NK 19 Nov 1999 added Warp_EPoint */
  4157.     Warp_EPoint (TPoint, IPoint, (TPATTERN *)Texture, FALSE);
  4158.     value1 = Evaluate_TPat ((TPATTERN *)Texture,TPoint,Ray_Intersection);
  4159.  
  4160.     Search_Blend_Map (value1, Blend_Map, &Prev, &Cur);
  4161.  
  4162. #ifdef NormalBugFix
  4163. #ifdef UnofficialBlocking
  4164.     if(opts.unofficialVersion>=30)
  4165. #else
  4166.     if(opts.Language_Version>310)
  4167. #endif
  4168.     {
  4169.       if(warpNormalTextures>MAX_NESTED_TEXTURES)
  4170.         Error("Too many nested textures.");
  4171.       warpNormalTextureList[warpNormalTextures++] = Texture;
  4172.     }
  4173. #endif
  4174.     /* NK 1998 reset_children - changed TPoint to CPoint and added ", TRUE" */
  4175.     Warp_EPoint (CPoint, IPoint, (TPATTERN *)Texture, TRUE);
  4176.  
  4177.     /* NK phmap */
  4178.     if(backtraceFlag)
  4179.     {
  4180.       if (Prev == Cur)
  4181.       {
  4182.         do_texture_map(Result_Colour, Cur->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4183.       }
  4184.       else
  4185.       {
  4186.         value1 = (value1 - Prev->value) / (Cur->value - Prev->value);
  4187.         value2 = 1.0 - value1;
  4188.         VScale(C2, Result_Colour, value1);
  4189.         do_texture_map(C2, Cur->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4190.         VScale(C2, Result_Colour, value2);
  4191.         do_texture_map(C2, Prev->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4192.       }
  4193.     }
  4194.     else
  4195.     {
  4196.       /* NK ---- */
  4197.       do_texture_map(Result_Colour, Cur->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4198.  
  4199.       if (Prev != Cur)
  4200.       {
  4201.         do_texture_map(C2, Prev->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
  4202.  
  4203.         value1 = (value1 - Prev->value) / (Cur->value - Prev->value);
  4204.         value2 = 1.0 - value1;
  4205.  
  4206.         CLinComb2(Result_Colour,value1,Result_Colour,value2,C2);
  4207.       }
  4208.       /* NK phmap */
  4209.     }
  4210.     /* NK ---- */
  4211. #ifdef NormalBugFix
  4212. #ifdef UnofficialBlocking
  4213.         if(opts.unofficialVersion>=30)
  4214. #else
  4215.         if(opts.Language_Version>310)
  4216. #endif
  4217.         {
  4218.           warpNormalTextures--;
  4219.         }
  4220. #endif
  4221.   }
  4222. }
  4223.  
  4224.  
  4225.  
  4226.  
  4227. /*****************************************************************************
  4228. *
  4229. * FUNCTION
  4230. *
  4231. *   compute_lighted_texture
  4232. *
  4233. * INPUT
  4234. *
  4235. *   Texture          - a linked list of texture layers
  4236. *   IPoint           - point to be evaluated
  4237. *   Raw_Normal       - non-purturbed surface normal
  4238. *   Ray              - needed for reflection and highlighs
  4239. *   Weight           - ADC control value
  4240. *   Intersection - current intersection (need object type and depth)
  4241. *
  4242. * OUTPUT
  4243. *
  4244. *   ResCol    - illuminated color of IPoint
  4245. *
  4246. * RETURNS
  4247. *
  4248. * AUTHOR
  4249. *
  4250. *   POV-Ray Team
  4251. *
  4252. * DESCRIPTION
  4253. *
  4254. *   This routine loops through all layers of a texture and computes
  4255. *   the appearent color of the point with illumination, shadows,
  4256. *   reflection, refraction... everything.  This piece of code was broken out
  4257. *   of Determine_Appearent_Colour because texture_map needs to call it twice.
  4258. *
  4259. * CHANGES
  4260. *
  4261. *   Jul 1995 : Added code to support alpha channel. [DB]
  4262. *
  4263. *   Jul 1995 : Moved code for save list allocation. [DB]
  4264. *
  4265. *   Aug 1995 : Added code for distance based attenuation in translucent
  4266. *              objects and halos. [DB]
  4267. *
  4268. *   Oct 1996 : Replaced halo code by participating media code. [DB]
  4269. *
  4270. *   Sep 1999 : Expanded distance based attenuation to include colour.
  4271. *              Edward Coffey
  4272. *
  4273. ******************************************************************************/
  4274.  
  4275. static void compute_lighted_texture(COLOUR ResCol, TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal, RAY *Ray, DBL Weight, INTERSECTION *Intersection)
  4276. {
  4277.   int i, radiosity_done, radiosity_needed;
  4278.   int layer_number;
  4279.   int inside_hollow_object;
  4280.   int one_colour_found, colour_found;
  4281.   DBL w1;/*, w2;*/
  4282.   DBL /*Normal_Direction, */New_Weight;/*, TempWeight;*/
  4283.   DBL Att, Trans, Max_Radiosity_Contribution;
  4284.   VECTOR LayNormal, TopNormal;
  4285.   COLOUR AttCol, LayCol, RflCol, RfrCol, FilCol;
  4286.   COLOUR TmpCol, AmbCol, Tmp;
  4287.   INTERIOR *Interior;
  4288.   IMEDIA **TmpMedia, **MediaList;
  4289.   DBL Cos_Angle_Incidence;
  4290.   TEXTURE *Layer;
  4291.  
  4292. #define MAX_LAYERS 20
  4293.  
  4294.   int    TIR_occured;
  4295.  
  4296.   DBL    ListWeight[MAX_LAYERS];
  4297.   DBL    ListReflecBlur[MAX_LAYERS];
  4298.   int    ListReflecSamples[MAX_LAYERS];
  4299.   VECTOR ListNormal[MAX_LAYERS];
  4300.   COLOUR ListReflec[MAX_LAYERS];
  4301.   SNGL   ListReflEx[MAX_LAYERS];
  4302.  
  4303.   /*
  4304.    * ResCol builds up the apparent visible color of the point.
  4305.    * Only RGB components are significant.  You can't "see" transparency --
  4306.    * you see the color of whatever is behind the transparent surface.
  4307.    * This color includes the visible appearence of what is behind the
  4308.    * transparency so only RGB is needed.
  4309.    */
  4310.  
  4311.   Make_ColourA(ResCol, 0.0, 0.0, 0.0, 0.0, 0.0);
  4312.  
  4313.   /*
  4314.    * FilCol serves two purposes.  It accumulates the filter properties
  4315.    * of a multi-layer texture so that if a ray makes it all the way through
  4316.    * all layers, the color of object behind is filtered by this object.
  4317.    * It also is used to attenuate how much of an underlayer you
  4318.    * can see in a layered texture.  Note that when computing the reflective
  4319.    * properties of a layered texture, the upper layers don't filter the
  4320.    * light from the lower layers -- the layer colors add together (even
  4321.    * before we added additive transparency via the "transmit" 5th
  4322.    * color channel).  However when computing the transmitted rays, all layers
  4323.    * filter the light from any objects behind this object. [CY 1/95]
  4324.    */
  4325.  
  4326.   /* NK layers - switched transmit component to zero */
  4327.   Make_ColourA(FilCol, 1.0, 1.0, 1.0, 1.0, 0.0);
  4328.   /* NK ---- */
  4329.  
  4330.   Trans = 1.0;
  4331.  
  4332.   /* Add in radiosity (stochastic interreflection-based ambient light) if desired */
  4333.  
  4334.   radiosity_done = FALSE;
  4335.  
  4336.   /* Note that there is no gathering of filter or transparency */
  4337.  
  4338.   Make_ColourA(AmbCol, 1., 1., 1., 0., 0.);
  4339.  
  4340.   if ((opts.Options & RADIOSITY && opts.Radiosity_Enabled) &&
  4341.       /*(Trace_Level == Radiosity_Trace_Level) &&*/  /* NK rad - allow rad on reflection */
  4342.       (Radiosity_Trace_Level <= opts.Radiosity_Recursion_Limit))
  4343.   {
  4344.     /*
  4345.      * For "real" (physically-based) diffuse interreflections, the
  4346.      * ambient light level is independent of any surface properties, so
  4347.      * the light gathering is done only once.  This block just sets up
  4348.      * for the code inside the loop, which is first-time-through.
  4349.      */
  4350.  
  4351.     radiosity_needed = 1;
  4352.   }
  4353.   else
  4354.   {
  4355.     radiosity_needed = 0;
  4356.   }
  4357.  
  4358.   /*
  4359.    * Loop through the layers and compute the ambient, diffuse,
  4360.    * phong and specular for these textures.
  4361.    */
  4362.  
  4363.   one_colour_found = FALSE;
  4364.  
  4365.   for (layer_number = 0, Layer = Texture;
  4366.       (Layer != NULL) && (Trans > BLACK_LEVEL);
  4367.       layer_number++, Layer = (TEXTURE *)Layer->Next)
  4368.   {
  4369.     /* Get perturbed surface normal. */
  4370.  
  4371.     Assign_Vector(LayNormal, Raw_Normal);
  4372.  
  4373.     if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
  4374.     {
  4375. #ifdef NormalBugFix
  4376. #ifdef UnofficialBlocking
  4377.         if(opts.unofficialVersion>=30)
  4378. #else
  4379.         if(opts.Language_Version>310)
  4380. #endif
  4381.         {
  4382.           for(i=0; i<warpNormalTextures; i++)
  4383.           {
  4384.             Warp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
  4385.               TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
  4386.           }
  4387.         }
  4388. #endif
  4389.       Perturb_Normal(LayNormal, Layer->Tnormal, IPoint, Intersection);
  4390.       if((Test_Flag(Layer->Tnormal,DONT_SCALE_BUMPS_FLAG)))
  4391.         VNormalizeEq(LayNormal);
  4392. #ifdef NormalBugFix
  4393. #ifdef UnofficialBlocking
  4394.         if(opts.unofficialVersion>=30)
  4395. #else
  4396.         if(opts.Language_Version>310)
  4397. #endif
  4398.         {
  4399.           for(i=warpNormalTextures-1; i>=0; i--)
  4400.           {
  4401.             UnWarp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
  4402.               TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
  4403.           }
  4404.         }
  4405. #endif
  4406.     }
  4407.  
  4408.     /* NK 1998 Reflection Bugfix - removed normal flipping code.. it is
  4409.             done earlier in this function.  This change also fixes the
  4410.             infamous "normal average" bug */
  4411.  
  4412.     /* Store top layer normal.*/
  4413.  
  4414.     if (!layer_number)
  4415.     {
  4416.       Assign_Vector(TopNormal, LayNormal);
  4417.     }
  4418.  
  4419.     /* Get surface colour. */
  4420.  
  4421.     New_Weight = Weight * Trans;
  4422.  
  4423.     /* NK 1998 - added Intersection */
  4424.     colour_found = Compute_Pigment (LayCol, Layer->Pigment, IPoint, Intersection);
  4425.  
  4426.     /*
  4427.      * If a valid color was returned set one_colour_found to TRUE.
  4428.      * An invalid color is returned if a surface point is outside
  4429.      * an image map used just once.
  4430.      */
  4431.  
  4432.     if (colour_found)
  4433.     {
  4434.       one_colour_found = TRUE;
  4435.     }
  4436.  
  4437.     /*
  4438.      * This section of code used to be the routine Compute_Reflected_Colour.
  4439.      * I copied it in here to rearrange some of it more easily and to
  4440.      * see if we could eliminate passing a zillion parameters for no
  4441.      * good reason. [CY 1/95]
  4442.      */
  4443.  
  4444.     if (opts.Quality_Flags & Q_FULL_AMBIENT)
  4445.     {
  4446.       /* Only use top layer and kill transparency if low quality. */
  4447.  
  4448.       Assign_Colour(ResCol, LayCol);
  4449.  
  4450.       ResCol[FILTER] =
  4451.       ResCol[TRANSM] = 0.0;
  4452.     }
  4453.     else
  4454.     {
  4455.       /* --------------------------------------------- */
  4456.       /* Store vital information for later reflection. */
  4457.       if (layer_number == MAX_LAYERS)
  4458.       {
  4459.         Error("Too many texture layers.");
  4460.       }
  4461.  
  4462.       ListReflEx[layer_number] = Layer->Finish->Reflect_Exp;
  4463.       ListWeight[layer_number] = New_Weight;
  4464.       ListReflecBlur[layer_number] = Layer->Finish->Reflection_Blur;
  4465.       ListReflecSamples[layer_number]=Layer->Finish->Reflection_Samples;
  4466.  
  4467.       /* NK 1999 moved here */
  4468.       /* Added by MBP for angle-dependent reflectivity */
  4469.       VDot(Cos_Angle_Incidence, Ray->Direction, LayNormal);
  4470.       Cos_Angle_Incidence *= -1.0;
  4471.  
  4472.       if (Intersection->Object->Interior || 
  4473.         (Layer->Finish->Reflection_Type != 1)) 
  4474.       {
  4475.         determine_reflectivity (&ListWeight[layer_number], ListReflec[layer_number],
  4476.                   Layer->Finish->Reflection_Max, Layer->Finish->Reflection_Min, 
  4477.                   Layer->Finish->Reflection_Type, Layer->Finish->Reflection_Falloff, 
  4478.                   Cos_Angle_Incidence, Ray, Intersection->Object->Interior);
  4479.       }
  4480.       else
  4481.       {
  4482.         Error("Reflection_Type 1 used with no interior.\n");
  4483.       }
  4484.  
  4485.       /* Added by MBP for metallic reflection */
  4486.       if (Layer->Finish->Reflect_Metallic != 0.0)
  4487.       {
  4488.         DBL R_M=Layer->Finish->Reflect_Metallic;
  4489.  
  4490.         DBL x = fabs(acos(Cos_Angle_Incidence)) / M_PI_2;
  4491.         DBL F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  4492.         F=min(1.0,max(0.0,F));
  4493.  
  4494.         ListReflec[layer_number][0]*=
  4495.           (1.0 + R_M * (1.0 - F) * (LayCol[0] - 1.0));
  4496.         ListReflec[layer_number][1]*=
  4497.           (1.0 + R_M * (1.0 - F) * (LayCol[1] - 1.0));
  4498.         ListReflec[layer_number][2]*=
  4499.           (1.0 + R_M * (1.0 - F) * (LayCol[2] - 1.0));
  4500.         /*
  4501.         ListReflec[layer_number][0]*=
  4502.           (1.0 + R_M*LayCol[0] - R_M);
  4503.         ListReflec[layer_number][1]*=
  4504.           (1.0 + R_M*LayCol[1] - R_M);
  4505.         ListReflec[layer_number][2]*=
  4506.           (1.0 + R_M*LayCol[2] - R_M);
  4507.           */
  4508.       }
  4509.       /* NK ---- */
  4510.  
  4511.       /* NK - SHOULD do something like this:*/
  4512.       /*
  4513.       ListReflec[layer_number][0]*=FilCol[0];
  4514.       ListReflec[layer_number][1]*=FilCol[1];
  4515.       ListReflec[layer_number][2]*=FilCol[2];
  4516.       */
  4517.  
  4518.       /* --------------------------------------------- */
  4519.       /* now compute the BRDF contribution ----------- */
  4520.  
  4521.       Att = (1.0 - min(1.0, fabs(LayCol[FILTER]*max3(LayCol[0],LayCol[1],LayCol[2])) + LayCol[TRANSM]));
  4522.  
  4523.       Make_Colour (TmpCol, 0.0, 0.0, 0.0);
  4524.  
  4525.       /* if radiosity calculation needed, but not yet done, do it now */
  4526.       if (radiosity_needed && !radiosity_done)
  4527.       {
  4528.         /* This check eliminates radiosity calculations on "luminous" objects with ambient=1 */
  4529.  
  4530.         /*if ((Layer->Finish->Ambient[0] != 1.0) ||
  4531.             (Layer->Finish->Ambient[1] != 1.0) ||
  4532.             (Layer->Finish->Ambient[2] != 1.0))
  4533.         {*/
  4534.           /* calculate max possible contribution of radiosity, to see if calculating it is worthwhile */
  4535.  
  4536.           Tmp[0] = FilCol[0]*Att * LayCol[0] * Layer->Finish->Diffuse;
  4537.           Tmp[1] = FilCol[1]*Att * LayCol[1] * Layer->Finish->Diffuse;
  4538.           Tmp[2] = FilCol[2]*Att * LayCol[2] * Layer->Finish->Diffuse;
  4539.  
  4540.           Max_Radiosity_Contribution = Tmp[0] *.287 + Tmp[1] *.589 + Tmp[2] * .114;
  4541.  
  4542.           if (Max_Radiosity_Contribution > BLACK_LEVEL * 3.0)
  4543.           {
  4544.             /* NK rad 22 Nov 1999 - added LayNormal */
  4545.             if (opts.Radiosity_Use_Normal)
  4546.               (void)Compute_Ambient(Intersection->IPoint, Raw_Normal, LayNormal, AmbCol, Weight * Max_Radiosity_Contribution);
  4547.             else
  4548.               (void)Compute_Ambient(Intersection->IPoint, Raw_Normal, Raw_Normal, AmbCol, Weight * Max_Radiosity_Contribution);
  4549.  
  4550.             radiosity_done = TRUE;
  4551.           }
  4552.       }
  4553.  
  4554.       /* Add ambient contribution. */
  4555.  
  4556.       if(radiosity_needed)
  4557.       {
  4558.         TmpCol[0] += FilCol[0]*Att * LayCol[0] * AmbCol[0] * Layer->Finish->Diffuse;
  4559.         TmpCol[1] += FilCol[1]*Att * LayCol[1] * AmbCol[1] * Layer->Finish->Diffuse;
  4560.         TmpCol[2] += FilCol[2]*Att * LayCol[2] * AmbCol[2] * Layer->Finish->Diffuse;
  4561.       }
  4562.       TmpCol[0] += FilCol[0]*Att * LayCol[0] * Layer->Finish->Ambient[0] * Frame.Ambient_Light[0];
  4563.       TmpCol[1] += FilCol[1]*Att * LayCol[1] * Layer->Finish->Ambient[1] * Frame.Ambient_Light[1];
  4564.       TmpCol[2] += FilCol[2]*Att * LayCol[2] * Layer->Finish->Ambient[2] * Frame.Ambient_Light[2];
  4565.  
  4566.       /* 
  4567.       fix this bug so radiosity/ambient doesn't get multiplied by
  4568.       FilCol[] twice 
  4569.       */
  4570.       VAddEq(ResCol, TmpCol);
  4571.       Make_Colour(TmpCol,0.0,0.0,0.0);
  4572.  
  4573.       /* NK phmap */
  4574.       /* this is needed so blocking light sources know if I am ignoring
  4575.          photons (or other valuable information */
  4576.       photonOptions.objectFlags = Intersection->Object->Ph_Flags;
  4577.       /* NK ---- */
  4578.  
  4579.       /* Add diffuse, phong, specular, and iridescence contribution. */
  4580.       Diffuse(Layer->Finish, Intersection->IPoint, Ray, LayNormal, LayCol, TmpCol, Att, Intersection->Object);
  4581.       /* NK layers */
  4582.       TmpCol[0]*=FilCol[0];
  4583.       TmpCol[1]*=FilCol[1];
  4584.       TmpCol[2]*=FilCol[2];
  4585.       /* NK ---- */
  4586.       VAddEq(ResCol, TmpCol);
  4587.  
  4588.       /* NK phmap */
  4589.       /* now do the same for the photons in the area */
  4590.       if(!(Intersection->Object->Ph_Flags & PH_FLAG_IGNORE_PHOTONS))
  4591.       {
  4592.         PhotonDiffuse(Layer->Finish, Intersection->IPoint, Ray, LayNormal, Raw_Normal, LayCol, TmpCol, Att, Intersection->Object);
  4593.         /* NK layers */
  4594.         TmpCol[0]*=FilCol[0];
  4595.         TmpCol[1]*=FilCol[1];
  4596.         TmpCol[2]*=FilCol[2];
  4597.         /* NK ---- */
  4598.         VAddEq(ResCol, TmpCol);
  4599.       }
  4600.       /* NK ---- */
  4601.       /*GlobalPhotonDiffuse(Layer->Finish, Intersection->IPoint, Ray, LayNormal, LayCol, TmpCol, Att, Intersection->Object);*/
  4602.       /*TmpCol[0]*=FilCol[0];
  4603.       TmpCol[1]*=FilCol[1];
  4604.       TmpCol[2]*=FilCol[2];
  4605.       */
  4606.       /*VAddEq(ResCol, TmpCol);*/
  4607.  
  4608.     }
  4609.  
  4610.     /* Get new filter color. */
  4611.  
  4612.     if (colour_found)
  4613.     {
  4614.       FilCol[0] *= (LayCol[0]*LayCol[3]+LayCol[4]);
  4615.       FilCol[1] *= (LayCol[1]*LayCol[3]+LayCol[4]);
  4616.       FilCol[2] *= (LayCol[2]*LayCol[3]+LayCol[4]);
  4617.       /* note FilCol[3] stays at 1.0, [4] stays at 0.0 */
  4618.       
  4619.       if(Layer->Finish->Conserve_Energy)
  4620.       {
  4621.         /* adjust filcol based on reflection */
  4622.         /* this would work so much better with r,g,b,rt,gt,bt */
  4623.         FilCol[0]*=min(1.0,1.0-ListReflec[layer_number][0]);
  4624.         FilCol[1]*=min(1.0,1.0-ListReflec[layer_number][1]);
  4625.         FilCol[2]*=min(1.0,1.0-ListReflec[layer_number][2]);
  4626.       }
  4627.     }
  4628.  
  4629.     /* Get new remaining translucency. */
  4630.  
  4631.     /* NK layers - changed this */
  4632.     Trans = min(1.0, fabs(FilCol[FILTER]*GREY_SCALE(FilCol)) + fabs(FilCol[TRANSM]));
  4633.     /* NK ---- */
  4634.   }
  4635.  
  4636.   /*
  4637.    * Calculate transmitted component.
  4638.    *
  4639.    * If the surface is translucent a transmitted ray is traced
  4640.    * and its contribution is added to the total ResCol after
  4641.    * filtering it by FilCol.
  4642.    */
  4643.  
  4644.   TIR_occured = FALSE;
  4645.  
  4646.   if (((Interior = Intersection->Object->Interior) != NULL) && (Trans > BLACK_LEVEL) && (opts.Quality_Flags & Q_REFRACT))
  4647.   {
  4648.     w1 = fabs(FilCol[FILTER]) * max3(FilCol[0], FilCol[1], FilCol[2]);
  4649.     /* NK layers
  4650.     w2 = 0.0; fabs(FilCol[TRANSM]);
  4651.  
  4652.     New_Weight = Weight * max(w1, w2);
  4653.     */
  4654.     New_Weight = Weight * w1;
  4655.  
  4656.     /* Trace refracted ray. */
  4657.  
  4658.     TIR_occured = Refract(Interior, Intersection->IPoint, Ray, TopNormal, Raw_Normal, RfrCol, New_Weight);
  4659.  
  4660.     /* Get distance based attenuation. */
  4661.  
  4662.     AttCol[0] = AttCol[1] = AttCol[2] = Interior->Old_Refract;
  4663.  
  4664.     if ((Interior != NULL) && Interior_In_Ray_Container(Ray, Interior) >= 0)
  4665.     {
  4666.       if (fabs(Interior->Fade_Distance) > EPSILON)
  4667.       {
  4668.         /* NK attenuate */
  4669.         if (Interior->Fade_Power>=1000)
  4670.         {
  4671.           AttCol[0] *= exp(-(1.0-Interior->Fade_Colour[0])*Intersection->Depth/Interior->Fade_Distance);
  4672.           AttCol[1] *= exp(-(1.0-Interior->Fade_Colour[1])*Intersection->Depth/Interior->Fade_Distance);
  4673.           AttCol[2] *= exp(-(1.0-Interior->Fade_Colour[2])*Intersection->Depth/Interior->Fade_Distance);
  4674.         }
  4675.         else
  4676.         {
  4677.           Att = 1.0 + pow(Intersection->Depth / Interior->Fade_Distance, Interior->Fade_Power);
  4678.           AttCol[0] *= Interior->Fade_Colour[0] + (1.0 - Interior->Fade_Colour[0]) / Att;
  4679.           AttCol[1] *= Interior->Fade_Colour[1] + (1.0 - Interior->Fade_Colour[1]) / Att;
  4680.           AttCol[2] *= Interior->Fade_Colour[2] + (1.0 - Interior->Fade_Colour[2]) / Att;
  4681.         }
  4682.       }
  4683.     }
  4684.  
  4685.     /* If total internal reflection occured the transmitted light is not filtered. */
  4686.  
  4687.     if (TIR_occured)
  4688.     {
  4689.       ResCol[0] += AttCol[0] * RfrCol[0];
  4690.       ResCol[1] += AttCol[1] * RfrCol[1];
  4691.       ResCol[2] += AttCol[2] * RfrCol[2];
  4692.     }
  4693.     else
  4694.     {
  4695.       if (one_colour_found)
  4696.       {
  4697.         ResCol[0] += AttCol[0] * RfrCol[0] * (FilCol[0] * FilCol[FILTER] + FilCol[TRANSM]);
  4698.         ResCol[1] += AttCol[1] * RfrCol[1] * (FilCol[1] * FilCol[FILTER] + FilCol[TRANSM]);
  4699.         ResCol[2] += AttCol[2] * RfrCol[2] * (FilCol[2] * FilCol[FILTER] + FilCol[TRANSM]);
  4700.       }
  4701.       else
  4702.       {
  4703.         ResCol[0] += AttCol[0] * RfrCol[0];
  4704.         ResCol[1] += AttCol[1] * RfrCol[1];
  4705.         ResCol[2] += AttCol[2] * RfrCol[2];
  4706.       }
  4707.     }
  4708.  
  4709.     /* We need to know the transmittance value for the alpha channel. [DB] */
  4710.  
  4711.     ResCol[TRANSM] = (0.30*AttCol[0] + 0.59*AttCol[1] + 0.11*AttCol[2]) * FilCol[TRANSM];
  4712.   }
  4713.  
  4714.   /*
  4715.    * Calculate reflected component.
  4716.    *
  4717.    * If total internal reflection occured all reflections using
  4718.    * TopNormal are skipped.
  4719.    */
  4720.  
  4721.   if (opts.Quality_Flags & Q_REFLECT)
  4722.   {
  4723.     for (i = 0; i < layer_number; i++)
  4724.     {
  4725.       if ((!TIR_occured) ||
  4726.           (fabs(TopNormal[0]-ListNormal[i][0]) > EPSILON) ||
  4727.           (fabs(TopNormal[1]-ListNormal[i][1]) > EPSILON) ||
  4728.           (fabs(TopNormal[2]-ListNormal[i][2]) > EPSILON))
  4729.       {
  4730.         if ((ListReflec[i][0] != 0.0) ||
  4731.             (ListReflec[i][1] != 0.0) ||
  4732.             (ListReflec[i][2] != 0.0))
  4733.         {
  4734.           Reflect(Intersection->IPoint, Ray,
  4735.             LayNormal, Raw_Normal, RflCol, ListWeight[i],
  4736.             ListReflecBlur[i], ListReflecSamples[i]);
  4737.  
  4738.           if (ListReflEx[i] != 1.0)
  4739.           {
  4740.             ResCol[0] += ListReflec[i][0] * pow(RflCol[0],ListReflEx[i]);
  4741.             ResCol[1] += ListReflec[i][1] * pow(RflCol[1],ListReflEx[i]);
  4742.             ResCol[2] += ListReflec[i][2] * pow(RflCol[2],ListReflEx[i]);
  4743.           }
  4744.           else
  4745.           {
  4746.             ResCol[0] += ListReflec[i][0] * RflCol[0];
  4747.             ResCol[1] += ListReflec[i][1] * RflCol[1];
  4748.             ResCol[2] += ListReflec[i][2] * RflCol[2];
  4749.           }
  4750.         }
  4751.       }
  4752.     }
  4753.   }
  4754.  
  4755.   /*
  4756.    * Calculate participating media effects.
  4757.    */
  4758.  
  4759.   if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Index > -1))
  4760.   {
  4761.     inside_hollow_object = TRUE;
  4762.  
  4763.     /* Test for any solid object. */
  4764.  
  4765.     for (i = 0; i <= Ray->Index; i++)
  4766.     {
  4767.       if (!Ray->Interiors[i]->hollow)
  4768.       {
  4769.         inside_hollow_object = FALSE;
  4770.  
  4771.         break;
  4772.       }
  4773.     }
  4774.  
  4775.     /* Calculate effects of all media we're currently in. */
  4776.  
  4777.     if (inside_hollow_object)
  4778.     {
  4779. #ifdef UseMediaAndLightCache
  4780.       LightingMediaListIndex++; 
  4781. #ifdef AccumulateCacheStatistics
  4782.       MaxLightedTexture=max(MaxLightedTexture,LightingMediaListIndex);
  4783. #endif
  4784.  
  4785.       if ( LightingMediaListIndex >= MaxMediaCacheDepth)
  4786.       {
  4787.         ResizeMediaMallocCaches(MaxMediaCacheDepth*2);
  4788.       }
  4789.  
  4790.       if ( Ray->Index+2 >= LightingMediaListCacheSize[LightingMediaListIndex])
  4791.       {
  4792.         POV_FREE(LightingMediaListCache[LightingMediaListIndex]);
  4793.         LightingMediaListCache[LightingMediaListIndex] = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
  4794.         LightingMediaListCacheSize[LightingMediaListIndex] = Ray->Index+2;
  4795.       }
  4796.       
  4797.       MediaList=LightingMediaListCache[LightingMediaListIndex];
  4798. #else
  4799.       MediaList = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
  4800. #endif
  4801.  
  4802.       TmpMedia = MediaList;
  4803.  
  4804.       for (i = 0; i <= Ray->Index; i++)
  4805.       {
  4806.         if (Ray->Interiors[i]->hollow)
  4807.         {
  4808.           if (Ray->Interiors[i]->IMedia != NULL)
  4809.           {
  4810.             *TmpMedia = Ray->Interiors[i]->IMedia;
  4811.  
  4812.             TmpMedia++;
  4813.           }
  4814.         }
  4815.       }
  4816.  
  4817.       *TmpMedia = NULL;
  4818.  
  4819. #ifdef UseMediaAndLightCache
  4820.       if ( *MediaList != NULL)        
  4821.         Simulate_Media(MediaList, Ray, Intersection, ResCol, FALSE);
  4822.  
  4823.       LightingMediaListIndex--;
  4824. #else
  4825.       Simulate_Media(MediaList, Ray, Intersection, ResCol, FALSE);
  4826.       POV_FREE(MediaList);
  4827. #endif
  4828.     }
  4829.   }
  4830. }
  4831.  
  4832.  
  4833.  
  4834. /*****************************************************************************
  4835. *
  4836. * FUNCTION
  4837. *
  4838. *   compute_shadow_texture
  4839. *
  4840. * INPUT
  4841. *
  4842. *   Texture          - layered texture through which shadow ray passes
  4843. *   IPoint           - point through which shadow ray passes
  4844. *   Raw_Normal       - non-purturbed surface normal
  4845. *   Ray              - light source ray
  4846. *   Ray_Intersection - current intersection (need intersection depth)
  4847. *
  4848. * OUTPUT
  4849. *
  4850. *   Filter_Colour - returned filter for shadow ray
  4851. *
  4852. * RETURNS
  4853. *
  4854. * AUTHOR
  4855. *
  4856. *   POV-Ray Team
  4857. *
  4858. * DESCRIPTION
  4859. *
  4860. * CHANGES
  4861. *
  4862. *   Dec 1994 : Separated from filter_shadow_ray to do texture_map [CEY]
  4863. *
  4864. *   May 1995 : Added caustic code by Steve Anger. [DB]
  4865. *
  4866. *   Aug 1995 : Caustic code moved here from filter_shadow_ray. [CEY]
  4867. *
  4868. *   Oct 1996 : Replaced halo code by participating media code. [DB]
  4869. *
  4870. ******************************************************************************/
  4871. static void compute_shadow_texture (COLOUR Filter_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, INTERSECTION *Ray_Intersection)
  4872. {
  4873.   int i, inside_hollow_object, colour_found, one_colour_found;
  4874.   DBL Caustics, dot, k;
  4875.   VECTOR Layer_Normal;
  4876.   COLOUR Refraction, Layer_Pigment_Colour;
  4877.   IMEDIA **Media_List, **Tmp;
  4878.   TEXTURE *Layer;
  4879.   INTERIOR *Interior = Ray_Intersection->Object->Interior;
  4880.  
  4881.   /* NK layers - switched transmit component to zero */
  4882.   Make_ColourA(Filter_Colour, 1.0, 1.0, 1.0, 1.0, 0.0);
  4883.  
  4884.   one_colour_found = FALSE;
  4885.  
  4886.   for (Layer = Texture; (Layer != NULL) &&
  4887.        (fabs(Filter_Colour[FILTER]) + fabs(Filter_Colour[TRANSM]) > BLACK_LEVEL);
  4888.        Layer = (TEXTURE *)Layer->Next)
  4889.   {
  4890.     /* NK 1998 - added Intersection */
  4891.     colour_found = Compute_Pigment (Layer_Pigment_Colour, Layer->Pigment, IPoint, Ray_Intersection);
  4892.  
  4893.     if (colour_found)
  4894.     {
  4895.       one_colour_found = TRUE;
  4896.  
  4897.       /*
  4898.       Filter_Colour[RED]    *= Layer_Pigment_Colour[RED];
  4899.       Filter_Colour[GREEN]  *= Layer_Pigment_Colour[GREEN];
  4900.       Filter_Colour[BLUE]   *= Layer_Pigment_Colour[BLUE];
  4901.       Filter_Colour[FILTER] *= Layer_Pigment_Colour[FILTER];
  4902.       Filter_Colour[TRANSM] *= Layer_Pigment_Colour[TRANSM];
  4903.       */
  4904.       /* NK layers - changed this */
  4905.       Filter_Colour[RED]    *= Layer_Pigment_Colour[RED]*Layer_Pigment_Colour[FILTER]+Layer_Pigment_Colour[TRANSM];
  4906.       Filter_Colour[GREEN]  *= Layer_Pigment_Colour[GREEN]*Layer_Pigment_Colour[FILTER]+Layer_Pigment_Colour[TRANSM];
  4907.       Filter_Colour[BLUE]   *= Layer_Pigment_Colour[BLUE]*Layer_Pigment_Colour[FILTER]+Layer_Pigment_Colour[TRANSM];
  4908.       /*Filter_Colour[FILTER] *= Layer_Pigment_Colour[FILTER];*/
  4909.       /*Filter_Colour[TRANSM] *= Layer_Pigment_Colour[TRANSM];*/
  4910.       /* NK ---- */
  4911.     }
  4912.  
  4913.     /* Get normal for faked caustics. (Will rewrite later to cache) */
  4914.  
  4915.     if ((Interior != NULL) && ((Caustics = Interior->Caustics) != 0.0))
  4916.     {
  4917.       Assign_Vector(Layer_Normal, Raw_Normal);
  4918.  
  4919.       if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
  4920.       {
  4921. #ifdef NormalBugFix
  4922. #ifdef UnofficialBlocking
  4923.         if(opts.unofficialVersion>=30)
  4924. #else
  4925.         if(opts.Language_Version>310)
  4926. #endif
  4927.         {
  4928.           for(i=0; i<warpNormalTextures; i++)
  4929.           {
  4930.             Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)warpNormalTextureList[i],
  4931.               TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
  4932.           }
  4933.         }
  4934. #endif
  4935.         Perturb_Normal(Layer_Normal, Layer->Tnormal, IPoint, Ray_Intersection);
  4936.         if((Test_Flag(Layer->Tnormal,DONT_SCALE_BUMPS_FLAG)))
  4937.           VNormalizeEq(Layer_Normal);
  4938. #ifdef NormalBugFix
  4939. #ifdef UnofficialBlocking
  4940.         if(opts.unofficialVersion>=30)
  4941. #else
  4942.         if(opts.Language_Version>310)
  4943. #endif
  4944.         {
  4945.           for(i=warpNormalTextures-1; i>=0; i--)
  4946.           {
  4947.             UnWarp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)warpNormalTextureList[i],
  4948.               TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
  4949.           }
  4950.         }
  4951. #endif
  4952.       }
  4953.  
  4954.       /* Get new filter/transmit values. */
  4955.  
  4956.       VDot (dot, Layer_Normal, Ray->Direction);
  4957.  
  4958.       k = (1.0 + pow(fabs(dot), Caustics));
  4959.  
  4960.       /*Filter_Colour[FILTER] *= k;
  4961.       Filter_Colour[TRANSM] *= k;
  4962.       */
  4963.       Filter_Colour[RED] *= k;
  4964.       Filter_Colour[GREEN] *= k;
  4965.       Filter_Colour[BLUE] *= k;
  4966.     }
  4967.   }
  4968.  
  4969.   /* Get distance based attenuation. */
  4970.  
  4971.   if (Interior != NULL)
  4972.   {
  4973.     Make_Colour(Refraction, 1.0, 1.0, 1.0);
  4974.  
  4975.     if (Interior_In_Ray_Container(Ray, Interior) >= 0)
  4976.     {
  4977.       if ((Interior->Fade_Power > 0.0) && (fabs(Interior->Fade_Distance) > EPSILON))
  4978.       {
  4979.         /* NK - attenuation */
  4980.         if (Interior->Fade_Power>=1000)
  4981.         {
  4982.           Refraction[0] *= exp(-(1.0-Interior->Fade_Colour[0])*Ray_Intersection->Depth/Interior->Fade_Distance);
  4983.           Refraction[1] *= exp(-(1.0-Interior->Fade_Colour[1])*Ray_Intersection->Depth/Interior->Fade_Distance);
  4984.           Refraction[2] *= exp(-(1.0-Interior->Fade_Colour[2])*Ray_Intersection->Depth/Interior->Fade_Distance);
  4985.         }
  4986.         else
  4987.         {
  4988.           k = 1.0 + pow(Ray_Intersection->Depth / Interior->Fade_Distance, Interior->Fade_Power);
  4989.           Refraction[0] *= Interior->Fade_Colour[0] + (1 - Interior->Fade_Colour[0]) / k;
  4990.           Refraction[1] *= Interior->Fade_Colour[1] + (1 - Interior->Fade_Colour[1]) / k;
  4991.           Refraction[2] *= Interior->Fade_Colour[2] + (1 - Interior->Fade_Colour[2]) / k;
  4992.         }
  4993.       }
  4994.     }
  4995.   }
  4996.   else
  4997.   {
  4998.     Make_Colour(Refraction, 0.0, 0.0, 0.0);
  4999.   }
  5000.  
  5001.   /* Get distance based attenuation. */
  5002.  
  5003.   Filter_Colour[RED]    *= Refraction[0];
  5004.   Filter_Colour[GREEN]  *= Refraction[1];
  5005.   Filter_Colour[BLUE]   *= Refraction[2];
  5006.   /*Filter_Colour[FILTER] *= Refraction;*/ /* NK layers - commented this */
  5007.   /*Filter_Colour[TRANSM] *= Refraction;*/
  5008.  
  5009.   /*
  5010.    * If no valid color was found we set the filtering channel
  5011.    * to zero to make sure that no light amplification occures.
  5012.    * That would happen if both the filter and transmit channel
  5013.    * were used.
  5014.    */
  5015.  
  5016.   if (!one_colour_found)
  5017.   {
  5018.     Filter_Colour[FILTER] = 0.0;
  5019.   }
  5020.  
  5021.   /* Calculate participating media effects. */
  5022.  
  5023.   if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Index > -1))
  5024.   {
  5025.     inside_hollow_object = TRUE;
  5026.  
  5027.     /* Test for any solid object. */
  5028.  
  5029.     for (i = 0; i <= Ray->Index; i++)
  5030.     {
  5031.       if (!Ray->Interiors[i]->hollow)
  5032.       {
  5033.         inside_hollow_object = FALSE;
  5034.  
  5035.         break;
  5036.       }
  5037.     }
  5038.  
  5039.     /* Calculate effects of all participating media we're currently in. */
  5040.  
  5041.     if (inside_hollow_object)
  5042.     {
  5043. #ifdef UseMediaAndLightCache
  5044.       ShadowMediaListIndex++;  
  5045.  
  5046. #ifdef AccumulateCacheStatistics
  5047.       MaxShadowTextRecCntr=max(MaxShadowTextRecCntr,ShadowMediaListIndex);
  5048. #endif
  5049.       if ( ShadowMediaListIndex >= MaxMediaCacheDepth)
  5050.       {
  5051.         ResizeMediaMallocCaches(MaxMediaCacheDepth*2);
  5052.       }
  5053.  
  5054.       if ( Ray->Index+2 >= ShadowMediaListCacheSize[ShadowMediaListIndex])
  5055.       {
  5056.         POV_FREE(ShadowMediaListCache[ShadowMediaListIndex]);
  5057.         ShadowMediaListCache[ShadowMediaListIndex] = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
  5058.         ShadowMediaListCacheSize[ShadowMediaListIndex]=Ray->Index+2;
  5059.       }
  5060.  
  5061.       Media_List=ShadowMediaListCache[ShadowMediaListIndex];
  5062. #else
  5063.       Media_List = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
  5064. #endif
  5065.       Tmp = Media_List;
  5066.  
  5067.       for (i = 0; i <= Ray->Index; i++)
  5068.       {
  5069.         if (Ray->Interiors[i]->hollow)
  5070.         {
  5071.           if (Ray->Interiors[i]->IMedia != NULL)
  5072.           {
  5073.             *Tmp = Ray->Interiors[i]->IMedia;
  5074.  
  5075.             Tmp++;
  5076.           }
  5077.         }
  5078.       }
  5079.  
  5080.       *Tmp = NULL;
  5081. #ifdef UseMediaAndLightCache
  5082.       if ( *Media_List != NULL)
  5083.         Simulate_Media(Media_List, Ray, Ray_Intersection, Filter_Colour, TRUE);
  5084.  
  5085.       ShadowMediaListIndex--;
  5086. #else
  5087.       Simulate_Media(Media_List, Ray, Ray_Intersection, Filter_Colour, TRUE);
  5088.       POV_FREE(Media_List);
  5089. #endif
  5090.     }
  5091.   }
  5092. }
  5093.  
  5094. /* NK phmap */
  5095. /*****************************************************************************
  5096. *
  5097. * FUNCTION
  5098. *
  5099. *   BacktraceDiffuse - currently unused
  5100. *
  5101. *    This was intended for using photon mapping as an estimation of radiance
  5102. *    to replace or supplement the radiosity feature, but it hasn't been
  5103. *    implemented yet.
  5104. *
  5105. * INPUT
  5106. *
  5107. * OUTPUT
  5108. *
  5109. * RETURNS
  5110. *
  5111. * AUTHOR
  5112. *
  5113. *   -
  5114. *
  5115. * DESCRIPTION
  5116. *
  5117. *   -
  5118. *
  5119. * CHANGES
  5120. *
  5121. *   -
  5122. *
  5123. ******************************************************************************/
  5124.  
  5125. static void BacktraceDiffuse (FINISH *Finish, VECTOR IPoint, RAY *Out, VECTOR  Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object, RAY *Light_Source_Ray, COLOUR Light_Colour)
  5126. {
  5127.   VECTOR REye;
  5128.  
  5129.   Make_ColourA(Colour, 0,0,0,0,0);
  5130.  
  5131.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
  5132.   {
  5133.     return;
  5134.   }
  5135.  
  5136.   if (Finish->Specular != 0.0)
  5137.   {
  5138.     REye[X] = -Out->Direction[X];
  5139.     REye[Y] = -Out->Direction[Y];
  5140.     REye[Z] = -Out->Direction[Z];
  5141.   }
  5142.  
  5143.   if ((fabs(Light_Colour[RED])   > BLACK_LEVEL) ||
  5144.       (fabs(Light_Colour[GREEN]) > BLACK_LEVEL) ||
  5145.       (fabs(Light_Colour[BLUE])  > BLACK_LEVEL))
  5146.   {
  5147.     if (Finish->Diffuse > 0.0)
  5148.     {
  5149.       do_diffuse(Finish,Light_Source_Ray,Layer_Normal,Colour,Light_Colour,Layer_Pigment_Colour, Attenuation);
  5150.     }
  5151.  
  5152.     if (Finish->Phong > 0.0)
  5153.     {
  5154.       do_phong(Finish,Light_Source_Ray,Out->Direction,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
  5155.     }
  5156.  
  5157.     if (Finish->Specular > 0.0)
  5158.     {
  5159.       do_specular(Finish,Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
  5160.     }
  5161.  
  5162.     if (Finish->Irid > 0.0)
  5163.     {
  5164.       do_irid(Finish,Light_Source_Ray,Layer_Normal,IPoint,Colour);
  5165.     }
  5166.  
  5167.   }
  5168. }
  5169.  
  5170.  
  5171. /*****************************************************************************
  5172. *
  5173. * FUNCTION
  5174. *
  5175. *   compute_backtrace_texture
  5176. *
  5177. * INPUT
  5178. *
  5179. *   Texture          - a linked list of texture layers
  5180. *   IPoint           - point to be evaluated
  5181. *   Raw_Normal       - non-purturbed surface normal
  5182. *   Ray              - needed for reflection and highlighs
  5183. *   Weight           - ADC control value
  5184. *   Intersection - current intersection (need object type and depth)
  5185. *   ResCol    - color of light beam
  5186. *
  5187. * OUTPUT
  5188. *
  5189. * RETURNS
  5190. *
  5191. * AUTHOR
  5192. *
  5193. *   Nathan Kopp - adpated from compute_lighted_texture by POV-Ray Team
  5194. *
  5195. * DESCRIPTION
  5196. *
  5197. *   MUST CHANGE THIS DESCRIPTION
  5198. *   This routine loops through all layers of a texture and computes
  5199. *   the appearent color of the point with illumination, shadows,
  5200. *   reflection, refraction... everything.  This piece of code was broken out
  5201. *   of Determine_Appearent_Colour because texture_map needs to call it twice.
  5202. *
  5203. * CHANGES
  5204. *
  5205. *
  5206. ******************************************************************************/
  5207.  
  5208. static void compute_backtrace_texture(COLOUR LightCol, TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal, RAY *Ray, DBL Weight, INTERSECTION *Intersection)
  5209. {
  5210.   int i;
  5211.   int layer_number;
  5212.   int one_colour_found, colour_found;
  5213.   DBL w1, w2;
  5214.   DBL New_Weight, TempWeight;
  5215.   DBL Att, Trans;
  5216.   VECTOR LayNormal, TopNormal;
  5217.   COLOUR LayCol, FilCol;
  5218.   COLOUR AttCol, TmpCol, ResCol, CurLightCol;
  5219.   INTERIOR *Interior;
  5220.   /* IMEDIA **TmpMedia, **MediaList; */
  5221.   TEXTURE *Layer;
  5222.   RAY NewRay;
  5223.   int doReflection, doDiffuse, doRefraction;
  5224.   DBL reflectionWeight, refractionWeight, diffuseWeight, dieWeight, totalWeight;
  5225.   DBL choice;
  5226.   int inside_hollow_object;
  5227.   IMEDIA ** MediaList, **TmpMedia;
  5228.   DBL Cos_Angle_Incidence;
  5229.  
  5230. #define MAX_LAYERS 20
  5231.  
  5232.   int    TIR_occured;
  5233.  
  5234.   DBL    ListWeight[MAX_LAYERS];
  5235.   DBL    ListReflecBlur[MAX_LAYERS];
  5236.   int    ListReflecSamples[MAX_LAYERS];
  5237.   VECTOR ListNormal[MAX_LAYERS];
  5238.   COLOUR ListReflec[MAX_LAYERS];
  5239.   SNGL   ListReflEx[MAX_LAYERS];
  5240.  
  5241.   /*
  5242.    * LightCol is the color of the light beam.
  5243.    */
  5244.  
  5245.   /* result color for doing diffuse */
  5246.   Make_ColourA(ResCol, 0.0, 0.0, 0.0, 0.0, 0.0);
  5247.  
  5248.   /* NK 1998 - switched transmit component to zero */
  5249.   Make_ColourA(FilCol, 1.0, 1.0, 1.0, 1.0, 0.0);
  5250.  
  5251.   Trans = 1.0;
  5252.  
  5253.   /* initialize the new ray... we will probably end up using it */
  5254.   Assign_Vector(NewRay.Initial, Intersection->IPoint);
  5255.   Copy_Ray_Containers(&NewRay, Ray);
  5256.  
  5257.  
  5258. #define MEDIA_BACKTRACE
  5259. #ifdef MEDIA_BACKTRACE
  5260.   /*
  5261.    *  what I've got here for media might work, but maybe not... needs
  5262.    *   testing.  Plus, we really want to optionally store photons in
  5263.    *   the media... but how do we do that???
  5264.    */
  5265.  
  5266.   /*
  5267.    * Calculate participating media effects.
  5268.    */
  5269.   if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Index > -1))
  5270.   {
  5271. /*    DBL dist;*/
  5272. /*    VECTOR TempPoint;*/
  5273.  
  5274.     inside_hollow_object = TRUE;
  5275.  
  5276.     /* Test for any solid object. */
  5277.  
  5278.     for (i = 0; i <= Ray->Index; i++)
  5279.     {
  5280.       if (!Ray->Interiors[i]->hollow)
  5281.       {
  5282.         inside_hollow_object = FALSE;
  5283.  
  5284.         break;
  5285.       }
  5286.     }
  5287.  
  5288.     /* Calculate effects of all media we're currently in. */
  5289.  
  5290.     if (inside_hollow_object)
  5291.     {
  5292.       MediaList = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
  5293.  
  5294.       TmpMedia = MediaList;
  5295.  
  5296.       for (i = 0; i <= Ray->Index; i++)
  5297.       {
  5298.         if (Ray->Interiors[i]->hollow)
  5299.         {
  5300.           if (Ray->Interiors[i]->IMedia != NULL)
  5301.           {
  5302.             *TmpMedia = Ray->Interiors[i]->IMedia;
  5303.  
  5304.             TmpMedia++;
  5305.           }
  5306.         }
  5307.       }
  5308.  
  5309.       *TmpMedia = NULL;
  5310.  
  5311. #if MEDIA_INTERACTION
  5312. /*
  5313.       if ((Trace_Level > 1) && 
  5314.           !photonOptions.passThruPrev && photonOptions.maxMediaSteps>0 &&
  5315.           !(Intersection->Object->Ph_Flags & PH_FLAG_IGNORE_PHOTONS) &&
  5316.           Check_Light_Group(Intersection->Object,photonOptions.Light))
  5317. */
  5318.       if ((Trace_Level > 1) && 
  5319.           !photonOptions.passThruPrev && photonOptions.maxMediaSteps>0)
  5320.       {
  5321.         Backtrace_Simulate_Media(MediaList, Ray, Intersection, LightCol);
  5322.       }
  5323.       else
  5324.       {
  5325.         Simulate_Media(MediaList, Ray, Intersection, LightCol, TRUE);  /* light ray */
  5326.       }
  5327. #else
  5328.       Simulate_Media(MediaList, Ray, Intersection, LightCol, TRUE);  /* light ray */
  5329. #endif
  5330.  
  5331.       POV_FREE(MediaList);
  5332.     }
  5333.   }
  5334.  
  5335.   /* atmosphere attenuation */
  5336.   /* - this is already done in Trace?!???! (Do_Finite_Atmosphere)
  5337.   if ((photonOptions.Light->Media_Interaction) &&
  5338.       (photonOptions.Light->Media_Attenuation))
  5339.   {
  5340.     do_light_ray_atmosphere(Ray, Intersection, LightCol, TRUE);
  5341.   }
  5342.   */
  5343. #endif
  5344.  
  5345.   /* Get distance based attenuation. */
  5346.   Interior = Intersection->Object->Interior;
  5347.   AttCol[0] = AttCol[1] = AttCol[2] = Interior->Old_Refract;
  5348.  
  5349.   if (Interior != NULL)
  5350.   {
  5351.     if (Interior_In_Ray_Container(Ray, Interior) >= 0)
  5352.     {
  5353.       if ((Interior->Fade_Power > 0.0) && (fabs(Interior->Fade_Distance) > EPSILON))
  5354.       {
  5355.         /* NK attenuate */
  5356.         if (Interior->Fade_Power>=1000)
  5357.         {
  5358.           AttCol[0] *= exp(-(1.0-Interior->Fade_Colour[0])*Intersection->Depth/Interior->Fade_Distance);
  5359.           AttCol[1] *= exp(-(1.0-Interior->Fade_Colour[1])*Intersection->Depth/Interior->Fade_Distance);
  5360.           AttCol[2] *= exp(-(1.0-Interior->Fade_Colour[2])*Intersection->Depth/Interior->Fade_Distance);
  5361.         }
  5362.         else
  5363.         {
  5364.           Att = 1.0 + pow(Intersection->Depth / Interior->Fade_Distance, Interior->Fade_Power);
  5365.           AttCol[0] *= Interior->Fade_Colour[0] + (1.0 - Interior->Fade_Colour[0]) / Att;
  5366.           AttCol[1] *= Interior->Fade_Colour[1] + (1.0 - Interior->Fade_Colour[1]) / Att;
  5367.           AttCol[2] *= Interior->Fade_Colour[2] + (1.0 - Interior->Fade_Colour[2]) / Att;
  5368.         }
  5369.       }
  5370.     }
  5371.   }
  5372.   LightCol[0] *= AttCol[0];
  5373.   LightCol[1] *= AttCol[1];
  5374.   LightCol[2] *= AttCol[2];
  5375.  
  5376.   /* set size here */
  5377.   photonOptions.photonDepth += Intersection->Depth;
  5378.  
  5379.  
  5380.   /* First, we should save this photon! */
  5381.   if ((Trace_Level > 1) && !photonOptions.passThruPrev && 
  5382.        !(Intersection->Object->Ph_Flags & PH_FLAG_IGNORE_PHOTONS) &&
  5383.        Check_Light_Group(Intersection->Object,photonOptions.Light))
  5384.   {
  5385.     addSurfacePhoton(Intersection->IPoint, Ray->Initial, LightCol, Raw_Normal);
  5386.   }
  5387.  
  5388.   if (photonOptions.passThruThis)
  5389.   {
  5390.     RAY NRay;
  5391.  
  5392.     Copy_Ray_Containers(&NRay, Ray);
  5393.     Assign_Vector(NRay.Initial, IPoint);
  5394.     Assign_Vector(NRay.Direction, Ray->Direction);
  5395.  
  5396.     Trace_Level++;
  5397. #ifdef MotionBlurPatch
  5398.     Trace_With_Blur(&NRay, LightCol, Weight, NULL);
  5399. #else
  5400.     Trace(&NRay, LightCol, Weight, NULL);
  5401. #endif
  5402.     Trace_Level--;
  5403.   }
  5404.  
  5405.   /*
  5406.    * Loop through the layers and compute the ambient, diffuse,
  5407.    * phong and specular for these textures.
  5408.    */
  5409.   one_colour_found = FALSE;
  5410.   for (layer_number = 0, Layer = Texture;
  5411.       (Layer != NULL) && (Trans > BLACK_LEVEL);
  5412.       layer_number++, Layer = (TEXTURE *)Layer->Next)
  5413.   {
  5414.     /* Get perturbed surface normal. */
  5415.     Assign_Vector(LayNormal, Raw_Normal);
  5416.  
  5417.     if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
  5418.     {
  5419. #ifdef NormalBugFix
  5420. #ifdef UnofficialBlocking
  5421.         if(opts.unofficialVersion>=30)
  5422. #else
  5423.         if(opts.Language_Version>310)
  5424. #endif
  5425.         {
  5426.           for(i=0; i<warpNormalTextures; i++)
  5427.           {
  5428.             Warp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
  5429.               TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
  5430.           }
  5431.         }
  5432. #endif
  5433.       Perturb_Normal(LayNormal, Layer->Tnormal, IPoint, Intersection);
  5434.       if((Test_Flag(Layer->Tnormal,DONT_SCALE_BUMPS_FLAG)))
  5435.         VNormalizeEq(LayNormal);
  5436. #ifdef NormalBugFix
  5437. #ifdef UnofficialBlocking
  5438.         if(opts.unofficialVersion>=30)
  5439. #else
  5440.         if(opts.Language_Version>310)
  5441. #endif
  5442.         {
  5443.           for(i=warpNormalTextures-1; i>=0; i--)
  5444.           {
  5445.             UnWarp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
  5446.               TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
  5447.           }
  5448.         }
  5449. #endif
  5450.     }
  5451.  
  5452.     /* Store top layer normal.*/
  5453.     if (!layer_number)
  5454.     {
  5455.       Assign_Vector(TopNormal, LayNormal);
  5456.     }
  5457.  
  5458.     /* Get surface colour. */
  5459.     New_Weight = Weight * Trans;
  5460.     colour_found = Compute_Pigment (LayCol, Layer->Pigment, IPoint, Intersection);
  5461.     
  5462.     Att = Trans * (1.0 - min(1.0, LayCol[FILTER] + LayCol[TRANSM]));
  5463.  
  5464.     LayCol[0]*=FilCol[0];
  5465.     LayCol[1]*=FilCol[1];
  5466.     LayCol[2]*=FilCol[2];
  5467.     VAddScaledEq(ResCol, Att, LayCol);
  5468.  
  5469.     /*
  5470.      * If a valid color was returned set one_colour_found to TRUE.
  5471.      * An invalid color is returned if a surface point is outside
  5472.      * an image map used just once.
  5473.      */
  5474.     if (colour_found)
  5475.     {
  5476.       one_colour_found = TRUE;
  5477.     }
  5478.  
  5479.     /* Store vital information for later reflection. */
  5480.     if (layer_number == MAX_LAYERS)
  5481.     {
  5482.       Error("Too many texture layers.");
  5483.     }
  5484.  
  5485.     ListReflEx[layer_number] = Layer->Finish->Reflect_Exp;
  5486.     ListWeight[layer_number] = New_Weight;
  5487.     ListReflecBlur[layer_number] = Layer->Finish->Reflection_Blur;
  5488.     ListReflecSamples[layer_number]=Layer->Finish->Reflection_Samples;
  5489.  
  5490.     /* NK 1999 moved here */
  5491.     /* Added by MBP for angle-dependent reflectivity */
  5492.     VDot(Cos_Angle_Incidence, Ray->Direction, LayNormal);
  5493.     Cos_Angle_Incidence *= -1.0;
  5494.  
  5495.     if (Intersection->Object->Interior || 
  5496.       (Layer->Finish->Reflection_Type != 1)) 
  5497.     {
  5498.       determine_reflectivity (&ListWeight[layer_number], ListReflec[layer_number],
  5499.                 Layer->Finish->Reflection_Max, Layer->Finish->Reflection_Min, 
  5500.                 Layer->Finish->Reflection_Type, Layer->Finish->Reflection_Falloff, 
  5501.                 Cos_Angle_Incidence, Ray, Intersection->Object->Interior);
  5502.     }
  5503.     else
  5504.     {
  5505.       Error("Reflection_Type 1 used with no interior.\n");
  5506.     }
  5507.  
  5508.     /* Added by MBP for metallic reflection */
  5509.     if (Layer->Finish->Reflect_Metallic != 0.0)
  5510.     {
  5511.       DBL R_M=Layer->Finish->Reflect_Metallic;
  5512.  
  5513.       DBL x = fabs(acos(Cos_Angle_Incidence)) / M_PI_2;
  5514.       DBL F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
  5515.       F=min(1.0,max(0.0,F));
  5516.  
  5517.       ListReflec[layer_number][0]*=
  5518.         (1.0 + R_M * (1.0 - F) * (LayCol[0] - 1.0));
  5519.       ListReflec[layer_number][1]*=
  5520.         (1.0 + R_M * (1.0 - F) * (LayCol[1] - 1.0));
  5521.       ListReflec[layer_number][2]*=
  5522.         (1.0 + R_M * (1.0 - F) * (LayCol[2] - 1.0));
  5523.       /*
  5524.       ListReflec[layer_number][0]*=
  5525.         (1.0 + R_M*LayCol[0] - R_M);
  5526.       ListReflec[layer_number][1]*=
  5527.         (1.0 + R_M*LayCol[1] - R_M);
  5528.       ListReflec[layer_number][2]*=
  5529.         (1.0 + R_M*LayCol[2] - R_M);
  5530.       */
  5531.     }
  5532.     /* NK ---- */
  5533.  
  5534.     /* NK - SOULD do something like this:*/
  5535.     /*
  5536.     ListReflec[layer_number][0]*=FilCol[0];
  5537.     ListReflec[layer_number][1]*=FilCol[1];
  5538.     ListReflec[layer_number][2]*=FilCol[2];
  5539.     */
  5540.  
  5541.     /* Get new filter color. */
  5542.     if (colour_found)
  5543.     {
  5544.       FilCol[0] *= (LayCol[0]*LayCol[3]+LayCol[4]);
  5545.       FilCol[1] *= (LayCol[1]*LayCol[3]+LayCol[4]);
  5546.       FilCol[2] *= (LayCol[2]*LayCol[3]+LayCol[4]);
  5547.       /* note FilCol[3] stays at 1.0 , [4] stays at 0.0 */
  5548.       if(Layer->Finish->Conserve_Energy)
  5549.       {
  5550.         /* adjust filcol based on reflection */
  5551.         /* this would work so much better with r,g,b,rt,gt,bt */
  5552.         FilCol[0]*=min(1.0,1.0-ListReflec[layer_number][0]);
  5553.         FilCol[1]*=min(1.0,1.0-ListReflec[layer_number][1]);
  5554.         FilCol[2]*=min(1.0,1.0-ListReflec[layer_number][2]);
  5555.       }
  5556.     }
  5557.  
  5558.     /* Get new remaining translucency. */
  5559.     Trans = min(1.0, fabs(FilCol[FILTER]*GREY_SCALE(FilCol)));
  5560.   }
  5561.  
  5562.   /*******************
  5563.     now that we have color info, we can determine what we want to do next
  5564.   ********************/
  5565.  
  5566.   if (photonOptions.photonObject)
  5567.   {
  5568.     /* if photon is for caustic map, then do
  5569.          reflection/refraction always
  5570.          diffuse never
  5571.     */
  5572.     doReflection = 1;
  5573.     doRefraction = 1;
  5574.     doDiffuse = 0;
  5575.   }
  5576.   else
  5577.   {
  5578.     /* if photon is for global map, then decide which we want to do
  5579.     */
  5580.     diffuseWeight = max(0.0, fabs(GREY_SCALE(ResCol)));
  5581.     /* use top-layer finish only */
  5582.     if(Texture->Finish)
  5583.       diffuseWeight*=Texture->Finish->Diffuse;
  5584.     refractionWeight = Trans;
  5585.     /* reflection only for top layer!!!!!! */
  5586.     reflectionWeight = max(0.0, fabs(GREY_SCALE(ListReflec[0])));
  5587.     dieWeight = max(0.0,(1.0-diffuseWeight));
  5588.  
  5589.     /* normalize weights: make sum be 1.0 */
  5590.     totalWeight = reflectionWeight + refractionWeight + diffuseWeight + dieWeight;
  5591.     if (reflectionWeight + refractionWeight + diffuseWeight>BLACK_LEVEL)
  5592.     {
  5593.       diffuseWeight /= totalWeight;
  5594.       refractionWeight /= totalWeight;
  5595.       reflectionWeight /= totalWeight;
  5596.       dieWeight /= totalWeight;
  5597.  
  5598.       /* now, determine which we want to use */
  5599.       choice = FRAND();
  5600.       if (choice<diffuseWeight)
  5601.       {
  5602.         /* do diffuse */
  5603.         VScaleEq(ResCol,1.0/diffuseWeight);
  5604.         /*if (diffuseWeight<.999)
  5605.         {
  5606.           VScaleEq(ResCol,20.0);
  5607.         }
  5608.         else
  5609.         {
  5610.           VScaleEq(ResCol,2.0);
  5611.         }*/
  5612.         doReflection = 0;
  5613.         doRefraction = 0;
  5614.         doDiffuse = 1;
  5615.         photonOptions.passThruPrev = FALSE;
  5616.       }
  5617.       else if (choice<diffuseWeight+refractionWeight)
  5618.       {
  5619.         /* do refraction */
  5620.         VScaleEq(FilCol,1.0/refractionWeight);
  5621.         doReflection = 0;
  5622.         doRefraction = 1;
  5623.         doDiffuse = 0;
  5624.         photonOptions.passThruPrev = TRUE;
  5625.       }
  5626.       else if (choice<diffuseWeight+refractionWeight+reflectionWeight)
  5627.       {
  5628.         /* do reflection */
  5629.         VScaleEq(ListReflec[0],1.0/reflectionWeight);
  5630.         doReflection = 1;
  5631.         doRefraction = 0;
  5632.         doDiffuse = 0;
  5633.         photonOptions.passThruPrev = TRUE;
  5634.       }
  5635.       /* else die */
  5636.     }
  5637.     else
  5638.     {
  5639.       doReflection = 0;
  5640.       doRefraction = 0;
  5641.       doDiffuse = 0;
  5642.     }
  5643.  
  5644.   }
  5645.  
  5646.   if (doDiffuse)
  5647.   {
  5648.     ChooseRay(&NewRay, LayNormal, Ray, Raw_Normal, rand()%400);
  5649.  
  5650.     CurLightCol[0] = LightCol[0]*ResCol[0];
  5651.     CurLightCol[1] = LightCol[1]*ResCol[1];
  5652.     CurLightCol[2] = LightCol[2]*ResCol[2];
  5653.  
  5654.     /* don't trace if < BLACK_LEVEL */
  5655.  
  5656.     /* now trace it */
  5657.     Trace_Level++;
  5658.     Trace(&NewRay, CurLightCol, 1.0, NULL);
  5659.     Trace_Level--;
  5660.   }
  5661.  
  5662.   /*
  5663.    * Calculate transmitted component.
  5664.    *
  5665.    * If the surface is translucent a transmitted ray is traced
  5666.    * and its illunination is filtered by FilCol.
  5667.    */
  5668.   if (doRefraction)
  5669.   {
  5670.     TIR_occured = FALSE;
  5671.     if ( ((Intersection->Object->Ph_Flags & PH_FLAG_RFR_ON) &&
  5672.           !(photonOptions.lightFlags & PH_FLAG_RFR_OFF)) ||
  5673.          (!(Intersection->Object->Ph_Flags & PH_FLAG_RFR_OFF) &&
  5674.           (photonOptions.lightFlags & PH_FLAG_RFR_ON)) ||
  5675.           photonOptions.passThruThis)
  5676.     if (((Interior = Intersection->Object->Interior) != NULL) && (Trans > BLACK_LEVEL) && (opts.Quality_Flags & Q_REFRACT))
  5677.     {
  5678.       w1 = fabs(FilCol[FILTER]) * max3(FilCol[0], FilCol[1], FilCol[2]);
  5679.       w2 = fabs(FilCol[TRANSM]);
  5680.  
  5681.       New_Weight = Weight * max(w1, w2);
  5682.  
  5683.       /* Trace refracted ray. */
  5684.       Assign_Colour(GFilCol, FilCol);
  5685.       TIR_occured = BacktraceRefract(Interior, Intersection->IPoint, Ray, TopNormal, Raw_Normal, LightCol, New_Weight);
  5686.     }
  5687.   }
  5688.  
  5689.   /*
  5690.    * Calculate reflected component.
  5691.    *
  5692.    * If total internal reflection occured all reflections using
  5693.    * TopNormal are skipped.
  5694.    */
  5695.   if(doReflection)
  5696.   {
  5697.     if ( (((Intersection->Object->Ph_Flags & PH_FLAG_RFL_ON) &&
  5698.           !(photonOptions.lightFlags & PH_FLAG_RFL_OFF)) ||
  5699.          (!(Intersection->Object->Ph_Flags & PH_FLAG_RFL_OFF) &&
  5700.           (photonOptions.lightFlags & PH_FLAG_RFL_ON))) &&
  5701.             !photonOptions.passThruThis)
  5702.     if (opts.Quality_Flags & Q_REFLECT)
  5703.     {
  5704.       for (i = 0; i < layer_number; i++)
  5705.       {
  5706.         if ((!TIR_occured) ||
  5707.             (fabs(TopNormal[0]-ListNormal[i][0]) > EPSILON) ||
  5708.             (fabs(TopNormal[1]-ListNormal[i][1]) > EPSILON) ||
  5709.             (fabs(TopNormal[2]-ListNormal[i][2]) > EPSILON))
  5710.         {
  5711.           if ((ListReflec[i][0] != 0.0) ||
  5712.               (ListReflec[i][1] != 0.0) ||
  5713.               (ListReflec[i][2] != 0.0))
  5714.           {
  5715.             /* Added by MBP for metallic reflection */
  5716.             TmpCol[0]=LightCol[0];
  5717.             TmpCol[1]=LightCol[1];
  5718.             TmpCol[2]=LightCol[2];
  5719.  
  5720.             if (ListReflEx[i] != 1.0)
  5721.             {
  5722.               TmpCol[0] = ListReflec[i][0] * pow(TmpCol[0],ListReflEx[i]);
  5723.               TmpCol[1] = ListReflec[i][1] * pow(TmpCol[1],ListReflEx[i]);
  5724.               TmpCol[2] = ListReflec[i][2] * pow(TmpCol[2],ListReflEx[i]);
  5725.             }
  5726.             else
  5727.             {
  5728.               TmpCol[0] = ListReflec[i][0] * TmpCol[0];
  5729.               TmpCol[1] = ListReflec[i][1] * TmpCol[1];
  5730.               TmpCol[2] = ListReflec[i][2] * TmpCol[2];
  5731.             }
  5732.  
  5733.             TempWeight = ListWeight[i] * max3(ListReflec[i][0], ListReflec[i][1], ListReflec[i][2]);
  5734.  
  5735.             if (photonOptions.photonReflectionBlur)
  5736.             {
  5737.               Reflect(Intersection->IPoint, Ray,
  5738.                 LayNormal, Raw_Normal, TmpCol, TempWeight,
  5739.                 ListReflecBlur[i], ListReflecSamples[i]);
  5740.             }
  5741.             else
  5742.             {
  5743.               Reflect(Intersection->IPoint, Ray,
  5744.                 LayNormal, Raw_Normal, TmpCol, TempWeight,
  5745.                 0.0,1);
  5746.             }
  5747.  
  5748.           }
  5749.         }
  5750.  
  5751.         /* if global photons, the stop after first layer */
  5752.         if (photonOptions.photonObject==NULL)
  5753.           i=layer_number;
  5754.       }
  5755.     }
  5756.   }
  5757.  
  5758.   /* now reset the depth! */
  5759.   photonOptions.photonDepth -= Intersection->Depth;
  5760. }
  5761.  
  5762. /* NK ---- */
  5763.  
  5764.  
  5765. /*****************************************************************************
  5766. *
  5767. * FUNCTION
  5768. *
  5769. *   filter_shadow_ray
  5770. *
  5771. * INPUT
  5772. *
  5773. * OUTPUT
  5774. *
  5775. * RETURNS
  5776. *
  5777. * AUTHOR
  5778. *
  5779. *   POV-Ray Team
  5780. *
  5781. * DESCRIPTION
  5782. *
  5783. *   -
  5784. *
  5785. * CHANGES
  5786. *
  5787. *   Aug 1994 : Code for early exit due to opaque object added. [DB]
  5788. *
  5789. *   Sep 1994 : Code for multi-textured blobs added. [DB]
  5790. *
  5791. *   May 1995 : Added caustic code by Steve Anger. [DB]
  5792. *
  5793. *   Aug 1995 : Added code to attenuate light source color
  5794. *              due to atmospheric effects. [DB]
  5795. *
  5796. ******************************************************************************/
  5797. static void filter_shadow_ray(INTERSECTION *Ray_Intersection, RAY *Light_Source_Ray, COLOUR Colour)
  5798. {
  5799.   int i, Texture_Count;
  5800.   VECTOR IPoint;
  5801.   VECTOR Raw_Normal;
  5802.   COLOUR FC1, Temp_Colour;
  5803.   TEXTURE *Texture = NULL;  /* To remove uninitialized use warning [AED] */
  5804.   size_t save_tw_size;
  5805.   DBL *save_Weights = NULL;
  5806.   TEXTURE **save_Textures = NULL;
  5807.   /* NK 1998 */
  5808.   UV_VECT UV_Coords;
  5809.   /* NK ---- */
  5810.   DBL Normal_Direction;
  5811.  
  5812. #ifdef MotionBlurPatch
  5813.   if (!backtraceFlag)
  5814.   {
  5815.     if (!TimeStamp && Ray_Intersection->Object->TimeStamp)
  5816.       TimeStamp = Ray_Intersection->Object->TimeStamp;
  5817.   }
  5818. #endif
  5819.  
  5820.   /* NK phmap */
  5821.   if ((photonOptions.photonsEnabled) && 
  5822.       (Ray_Intersection->Object->Ph_Flags & PH_FLAG_TARGET) && 
  5823.       !(photonOptions.objectFlags & PH_FLAG_IGNORE_PHOTONS))
  5824.   {
  5825.     if( ((Ray_Intersection->Object->Ph_Flags & PH_FLAG_RFR_ON) &&
  5826.          !(photonOptions.lightFlags & PH_FLAG_RFR_OFF)) ||
  5827.          (!(Ray_Intersection->Object->Ph_Flags & PH_FLAG_RFR_OFF) &&
  5828.          (photonOptions.lightFlags & PH_FLAG_RFR_ON)) )
  5829.     {
  5830.       Make_Colour(Colour, 0.0, 0.0, 0.0);
  5831.       return;
  5832.     }
  5833.   }
  5834.   /* NK ---- */
  5835.  
  5836.   Assign_Vector(IPoint, Ray_Intersection->IPoint);
  5837.  
  5838.   if (!(opts.Quality_Flags & Q_SHADOW))
  5839.   {
  5840.     return;
  5841.   }
  5842.  
  5843.   /* If the object is opaque there's no need to go any further. [DB 8/94] */
  5844.  
  5845.   if (Test_Flag(Ray_Intersection->Object, OPAQUE_FLAG))
  5846.   {
  5847.     Make_Colour(Colour, 0.0, 0.0, 0.0);
  5848.     return;
  5849.   }
  5850.  
  5851.   /* Get the normal to the surface */
  5852.  
  5853.   Normal(Raw_Normal, Ray_Intersection->Object, Ray_Intersection);
  5854.   /* If the surface normal points away, flip its direction. */
  5855.   VDot(Normal_Direction, Raw_Normal, Light_Source_Ray->Direction);
  5856.   if (Normal_Direction > 0.0)
  5857.   {
  5858.     VScaleEq(Raw_Normal, -1.0);
  5859.   }
  5860.  
  5861.   Assign_Vector(Ray_Intersection->INormal, Raw_Normal);
  5862.   /* and save to intersection -hdf- */
  5863.   Assign_Vector(Ray_Intersection->PNormal, Raw_Normal);
  5864.  
  5865.   if (Test_Flag(Ray_Intersection->Object, UV_FLAG) ||
  5866.       (opts.postProcessFlags & PP_FLAG_IUV))
  5867.   {
  5868.     /* get the UV vect of the intersection */
  5869.     UVCoord(UV_Coords, Ray_Intersection->Object, Ray_Intersection);
  5870.     /* save the normal and UV coords into Intersection */
  5871.     Assign_UV_Vect(Ray_Intersection->Iuv, UV_Coords);
  5872.   }
  5873.  
  5874.   /* now switch to UV mapping if we need to */
  5875.   if (Test_Flag(Ray_Intersection->Object, UV_FLAG))
  5876.   {
  5877.     IPoint[X] = UV_Coords[U];
  5878.     IPoint[Y] = UV_Coords[V];
  5879.     IPoint[Z] = 0;
  5880.   }
  5881.  
  5882.   /*
  5883.    * Save texture and weight lists.
  5884.    */
  5885.  
  5886.   save_tw_size = (size_t)Number_Of_Textures_And_Weights;
  5887. #ifdef UseMediaAndLightCache
  5888.   LightingCacheIndex++; 
  5889.   if ( LightingCacheIndex >= MaxLightCacheDepth) 
  5890.   {
  5891.     ResizeLightMallocCaches(MaxLightCacheDepth*2);
  5892.   }
  5893.  
  5894. #ifdef AccumulateCacheStatistics
  5895.   MaxAppColourRecCntr=max(MaxAppColourRecCntr,LightingCacheIndex);
  5896. #endif
  5897.  
  5898.   Weight_List=WeightListCache[LightingCacheIndex];
  5899.   Light_List=LightListCache[LightingCacheIndex];
  5900.   Texture_List=TextureListCache[LightingCacheIndex];
  5901.  
  5902. #else
  5903.   if (save_tw_size > 0)
  5904.   {
  5905.     save_Weights = (DBL *)POV_MALLOC(save_tw_size * sizeof(DBL), "Weight list stack");
  5906.     memcpy(save_Weights, Weight_List, save_tw_size * sizeof(DBL));
  5907.     save_Textures = (TEXTURE **)POV_MALLOC(save_tw_size * sizeof(TEXTURE *), "Weight list stack");
  5908.     memcpy(save_Textures, Texture_List, save_tw_size * sizeof(TEXTURE *));
  5909.   }
  5910. #endif  
  5911.   /* Get texture list and weights. */
  5912.  
  5913. #ifdef InteriorTexturePatch
  5914.   Texture_Count = create_texture_list(Ray_Intersection, Normal_Direction);
  5915. #else
  5916.   Texture_Count = create_texture_list(Ray_Intersection);
  5917. #endif
  5918.   Make_ColourA(Temp_Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
  5919.  
  5920.   for (i = 0; i < Texture_Count; i++)
  5921.   {
  5922.     /* If contribution of this texture is neglectable skip ahead. */
  5923.  
  5924.     if (Weight_List[i] < BLACK_LEVEL)
  5925.     {
  5926.       continue;
  5927.     }
  5928.  
  5929.     Texture = Texture_List[i];
  5930.  
  5931.     do_texture_map(FC1, Texture, IPoint, Raw_Normal, Light_Source_Ray, 0.0, Ray_Intersection, TRUE);
  5932.  
  5933.     Temp_Colour[RED]     += Weight_List[i] * FC1[RED];
  5934.     Temp_Colour[GREEN]   += Weight_List[i] * FC1[GREEN];
  5935.     Temp_Colour[BLUE]    += Weight_List[i] * FC1[BLUE];
  5936.     Temp_Colour[FILTER]  += Weight_List[i] * FC1[FILTER];
  5937.     Temp_Colour[TRANSM]  += Weight_List[i] * FC1[TRANSM];
  5938.   }
  5939.  
  5940.   /* Restore the weight and texture list. */
  5941.  
  5942. #ifdef UseMediaAndLightCache
  5943.   LightingCacheIndex--;
  5944.   Weight_List=WeightListCache[LightingCacheIndex];
  5945.   Light_List=LightListCache[LightingCacheIndex];
  5946.   Texture_List=TextureListCache[LightingCacheIndex];
  5947. #else
  5948.   if (save_tw_size > 0)
  5949.   {
  5950.     memcpy(Weight_List, save_Weights, save_tw_size * sizeof(DBL));
  5951.     memcpy(Texture_List, save_Textures, save_tw_size * sizeof(TEXTURE *));
  5952.     POV_FREE(save_Weights);
  5953.     POV_FREE(save_Textures);
  5954.   }
  5955. #endif  
  5956.   if (fabs(Temp_Colour[FILTER]) + fabs(Temp_Colour[TRANSM]) < BLACK_LEVEL)
  5957.   {
  5958.     Make_Colour(Colour, 0.0, 0.0, 0.0);
  5959.   }
  5960.   else
  5961.   {
  5962.     Colour[RED]   *= Temp_Colour[FILTER] * Temp_Colour[RED]  + Temp_Colour[TRANSM];
  5963.     Colour[GREEN] *= Temp_Colour[FILTER] * Temp_Colour[GREEN]+ Temp_Colour[TRANSM];
  5964.     Colour[BLUE]  *= Temp_Colour[FILTER] * Temp_Colour[BLUE] + Temp_Colour[TRANSM];
  5965.   }
  5966.  
  5967.   /* Get atmospheric attenuation. */
  5968.  
  5969.   do_light_ray_atmosphere(Light_Source_Ray, Ray_Intersection, Colour, TRUE);
  5970.  
  5971. }
  5972.  
  5973.  
  5974. /*****************************************************************************
  5975. *
  5976. * FUNCTION
  5977. *
  5978. *   do_blocking
  5979. *
  5980. * INPUT
  5981. *
  5982. * OUTPUT
  5983. *
  5984. * RETURNS
  5985. *
  5986. * AUTHOR
  5987. *
  5988. *   POV-Ray Team
  5989. *
  5990. * DESCRIPTION
  5991. *
  5992. *   -
  5993. *
  5994. * CHANGES
  5995. *
  5996. *   -
  5997. *
  5998. ******************************************************************************/
  5999.  
  6000. static int do_blocking(INTERSECTION *Local_Intersection, RAY *Light_Source_Ray, COLOUR Light_Colour, ISTACK *Local_Stack)
  6001. {
  6002.   Increase_Counter(stats[Shadow_Rays_Succeeded]);
  6003.  
  6004.   filter_shadow_ray(Local_Intersection, Light_Source_Ray, Light_Colour);
  6005.  
  6006.   if ((fabs(Light_Colour[RED])   < BLACK_LEVEL) &&
  6007.       (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
  6008.       (fabs(Light_Colour[BLUE])  < BLACK_LEVEL))
  6009.   {
  6010.     while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
  6011.     {
  6012.     }
  6013.  
  6014.     return(TRUE);
  6015.   }
  6016.  
  6017.   return(FALSE);
  6018. }
  6019.  
  6020.  
  6021.  
  6022. /*****************************************************************************
  6023. *
  6024. * FUNCTION
  6025. *
  6026. *   block_light_source
  6027. *
  6028. * INPUT
  6029. *
  6030. *   Light            - Light source
  6031. *   Depth            - Distance to light source
  6032. *   Light_Source_Ray - Light ray
  6033. *   Eye_Ray          - Ray from eye to current intersection point
  6034. *   P                - Surface point to shade
  6035. *
  6036. * OUTPUT
  6037. *
  6038. *   Colour           - Light color reaching point P
  6039. *
  6040. * RETURNS
  6041. *
  6042. * AUTHOR
  6043. *
  6044. *   Dieter Bayer
  6045. *
  6046. * DESCRIPTION
  6047. *
  6048. *   Determine how much light from the given light source reaches
  6049. *   the given point. This includes attenuation due to blocking
  6050. *   and translucent objects and atmospheric effects.
  6051. *
  6052. * CHANGES
  6053. *
  6054. *   Jan 1995 : Creation (Extracted from common code).
  6055. *
  6056. *   Aug 1995 : Added code to support atmospheric effects. [DB]
  6057. *
  6058. ******************************************************************************/
  6059.  
  6060. static void block_light_source(LIGHT_SOURCE *Light, DBL Depth, RAY *Light_Source_Ray, RAY  *Eye_Ray, VECTOR P, COLOUR Colour)
  6061. {
  6062.   DBL New_Depth;
  6063.   INTERSECTION Intersection;
  6064.   RAY New_Ray;
  6065.  
  6066.   /* NK phmap */
  6067.   /* save the light's flags so we know if we used real caustics */
  6068.   photonOptions.lightFlags = Light->Ph_Flags;
  6069.   /* NK ---- */
  6070.  
  6071. #ifdef MotionBlurPatch
  6072.   /* NK Apr 2000 - allow light sources inside motion blur */
  6073.   if (TimeStamp)
  6074.   {
  6075.     if (Light->TimeStamp && TimeStamp != Light->TimeStamp) 
  6076.     {
  6077.       Make_Colour(Colour,0.0,0.0,0.0);
  6078.       return;
  6079.     }
  6080.   }
  6081.   else
  6082.   {
  6083.     if (Light->TimeStamp) TimeStamp = Light->TimeStamp;
  6084.   }
  6085. #endif
  6086.  
  6087.   /* Store current depth and ray because they will be modified. */
  6088.  
  6089.   New_Depth = Depth;
  6090.  
  6091.   New_Ray = *Light_Source_Ray;
  6092.  
  6093.   /* Get shadows from current light source. */
  6094.  
  6095.   if ((Light->Area_Light) && (opts.Quality_Flags & Q_AREA_LIGHT))
  6096.   {
  6097.     block_area_light(Light, &New_Depth, &New_Ray, Eye_Ray, P, Colour, 0, 0, 0, 0, 0);
  6098.   }
  6099.   else
  6100.   {
  6101.     /* NK parallel - can't use light buffer with parallel lights */
  6102.     if ((opts.Options & USE_LIGHT_BUFFER) && (Light->Light_Type!=CYLINDER_SOURCE) &&
  6103.         !(Light->Parallel))
  6104.     /* NK ---- */
  6105.     {
  6106. #ifdef MotionBlurPatch
  6107.       block_point_light_LBuffer_with_blur(Light, &New_Depth, &New_Ray, Colour);
  6108. #else
  6109.       block_point_light_LBuffer(Light, &New_Depth, &New_Ray, Colour);
  6110. #endif
  6111.     }
  6112.     else
  6113.     {
  6114. #ifdef MotionBlurPatch
  6115.       block_point_light_with_blur(Light, &New_Depth, &New_Ray, Colour);
  6116. #else
  6117.       block_point_light(Light, &New_Depth, &New_Ray, Colour);
  6118. #endif
  6119.     }
  6120.   }
  6121.  
  6122.   /*
  6123.    * If there's some distance left for the ray to reach the light source
  6124.    * we have to apply atmospheric stuff to this part of the ray.
  6125.    */
  6126.  
  6127.   if ((New_Depth > SHADOW_TOLERANCE) &&
  6128.       (Light->Media_Interaction) &&
  6129.       (Light->Media_Attenuation))
  6130.   {
  6131.     Intersection.Depth = New_Depth;
  6132.     Set_Media_Light(Light); /* Needed to test Light group against medias */
  6133.  
  6134.     do_light_ray_atmosphere(&New_Ray, &Intersection, Colour, FALSE);
  6135.   }
  6136. }
  6137.  
  6138.  
  6139.  
  6140. /*****************************************************************************
  6141. *
  6142. * FUNCTION
  6143. *
  6144. *   average_textures
  6145. *
  6146. * INPUT
  6147. *
  6148. * OUTPUT
  6149. *
  6150. * RETURNS
  6151. *
  6152. * AUTHOR
  6153. *
  6154. *   POV-Ray Team
  6155. *
  6156. * DESCRIPTION
  6157. *
  6158. *   -
  6159. *
  6160. * CHANGES
  6161. *
  6162. *   -
  6163. *
  6164. ******************************************************************************/
  6165.  
  6166. static void average_textures (COLOUR Result_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal,
  6167.   RAY *Ray, DBL Weight, INTERSECTION *Ray_Intersection, int Shadow_Flag)
  6168. {
  6169.    int i;
  6170.    COLOUR LC;
  6171.    BLEND_MAP *Map = Texture->Blend_Map;
  6172.    SNGL Value;
  6173.    SNGL Total = 0.0;
  6174.  
  6175.    Make_Colour (Result_Colour, 0.0, 0.0, 0.0);
  6176.  
  6177.    for (i = 0; i < Map->Number_Of_Entries; i++)
  6178.    {
  6179.      Value = Map->Blend_Map_Entries[i].value;
  6180.  
  6181.      do_texture_map (LC,Map->Blend_Map_Entries[i].Vals.Texture, IPoint,Raw_Normal,Ray,Weight,Ray_Intersection,Shadow_Flag);
  6182.  
  6183.      Result_Colour[RED]   += LC[RED]   *Value;
  6184.      Result_Colour[GREEN] += LC[GREEN] *Value;
  6185.      Result_Colour[BLUE]  += LC[BLUE]  *Value;
  6186.      Result_Colour[FILTER]+= LC[FILTER]*Value;
  6187.      Result_Colour[TRANSM]+= LC[TRANSM]*Value;
  6188.  
  6189.      Total += Value;
  6190.    }
  6191.  
  6192.    Result_Colour[RED]   /= Total;
  6193.    Result_Colour[GREEN] /= Total;
  6194.    Result_Colour[BLUE]  /= Total;
  6195.    Result_Colour[FILTER]/= Total;
  6196.    Result_Colour[TRANSM]/= Total;
  6197. }
  6198.  
  6199. /* NK phmap */
  6200. /*****************************************************************************
  6201. *
  6202. * FUNCTION
  6203. *
  6204. *   backtrace_average_textures
  6205. *
  6206. * INPUT
  6207. *
  6208. * OUTPUT
  6209. *
  6210. * RETURNS
  6211. *
  6212. * AUTHOR
  6213. *
  6214. *   Nathan Kopp
  6215. *   based on average_textures by the POV-Ray Team
  6216. *
  6217. * DESCRIPTION
  6218. *
  6219. *   -
  6220. *
  6221. * CHANGES
  6222. *
  6223. *   -
  6224. *
  6225. ******************************************************************************/
  6226.  
  6227. static void backtrace_average_textures (COLOUR Result_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR  Raw_Normal,
  6228.   RAY *Ray, DBL Weight, INTERSECTION *Ray_Intersection, int Shadow_Flag)
  6229. {
  6230.    int i;
  6231.    COLOUR LC;
  6232.    BLEND_MAP *Map = Texture->Blend_Map;
  6233.    SNGL Value;
  6234.    SNGL Total = 0.0;
  6235.  
  6236.    /*Make_Colour (Result_Colour, 0.0, 0.0, 0.0);*/
  6237.  
  6238.    for (i = 0; i < Map->Number_Of_Entries; i++)
  6239.    {
  6240.      Value = Map->Blend_Map_Entries[i].value;
  6241.      Total += Value;
  6242.    }
  6243.  
  6244.    for (i = 0; i < Map->Number_Of_Entries; i++)
  6245.    {
  6246.      Value = Map->Blend_Map_Entries[i].value / Total;
  6247.      VScale(LC, Result_Colour, Value);
  6248.  
  6249.      do_texture_map (LC,Map->Blend_Map_Entries[i].Vals.Texture, IPoint,Raw_Normal,Ray,Weight,Ray_Intersection,Shadow_Flag);
  6250.    }
  6251. }
  6252. /* NK ---- */
  6253.  
  6254. /*****************************************************************************
  6255. *
  6256. * FUNCTION
  6257. *
  6258. *   do_light_ray_atmosphere
  6259. *
  6260. * INPUT
  6261. *
  6262. *   Light_Source_Ray - Current ray towards light source
  6263. *   Ray_Intersection - Current intersection with a blocking object
  6264. *   Texture          - Current PNFH texture
  6265. *   Valid_Object     - Flag: 1=a valid object is in the intersection struct
  6266. *
  6267. * OUTPUT
  6268. *
  6269. *   Colour           - Attenuated light source color
  6270. *
  6271. * RETURNS
  6272. *
  6273. * AUTHOR
  6274. *
  6275. *   Dieter Bayer
  6276. *
  6277. * DESCRIPTION
  6278. *
  6279. *   Determine the influence of atmospheric effects on a light source ray.
  6280. *
  6281. * CHANGES
  6282. *
  6283. *   Aug 1995 : Creation.
  6284. *
  6285. ******************************************************************************/
  6286.  
  6287. static void do_light_ray_atmosphere(RAY *Light_Source_Ray, INTERSECTION *Ray_Intersection, COLOUR Colour, int Valid_Object)
  6288. {
  6289.   int interior_nr;
  6290.   int i, all_hollow;
  6291.  
  6292.   /* Why are we here? */
  6293.  
  6294.   if ((Colour[RED] < BLACK_LEVEL) && (Colour[GREEN] < BLACK_LEVEL) && (Colour[BLUE] < BLACK_LEVEL))
  6295.   {
  6296.     return;
  6297.   }
  6298.  
  6299.   all_hollow = TRUE;
  6300.  
  6301.   for (i = 0; i <= Light_Source_Ray->Index; i++)
  6302.   {
  6303.     if (!Light_Source_Ray->Interiors[i]->hollow)
  6304.     {
  6305.       all_hollow = FALSE;
  6306.  
  6307.       break;
  6308.     }
  6309.   }
  6310.  
  6311.   /* Apply atmospheric effects inside and/or outside any object. */
  6312.  
  6313.   if ((opts.Quality_Flags & Q_VOLUME) && (all_hollow || (Valid_Object && Ray_Intersection->Object->Interior != NULL)))
  6314.   {
  6315.     Do_Finite_Atmosphere(Light_Source_Ray, Ray_Intersection, Colour, TRUE);
  6316.   }
  6317.  
  6318.   /* Handle contained textures. */
  6319.  
  6320.   if (Valid_Object)
  6321.   {
  6322.     if (Light_Source_Ray->Index == -1)
  6323.     {
  6324.       /* The ray is entering from the atmosphere */
  6325.  
  6326.       Ray_Enter(Light_Source_Ray, Ray_Intersection->Object->Interior);
  6327.     }
  6328.     else
  6329.     {
  6330.       /* The ray is currently inside an object */
  6331.  
  6332.       if ((interior_nr = Interior_In_Ray_Container(Light_Source_Ray, Ray_Intersection->Object->Interior)) >= 0)
  6333.       {
  6334.         /* The ray is leaving the current object */
  6335.  
  6336.         Ray_Exit(Light_Source_Ray, interior_nr);
  6337.       }
  6338.       else
  6339.       {
  6340.         /* The ray is entering a new object */
  6341.  
  6342.         Ray_Enter(Light_Source_Ray, Ray_Intersection->Object->Interior);
  6343.       }
  6344.     }
  6345.   }
  6346. }
  6347.  
  6348. /*****************************************************************************
  6349. *
  6350. * FUNCTION
  6351. *
  6352. *   determine_reflectivity
  6353. *
  6354. * INPUT
  6355. *
  6356. * OUTPUT
  6357. *
  6358. *   weight           - ADC weight of reflected ray
  6359. *   reflection       - Reflectivity value to be passed to Reflect()
  6360. *
  6361. * RETURNS
  6362. *
  6363. * AUTHOR
  6364. *
  6365. *   Michael Paul  <mbp@locke.ccil.org>
  6366. *
  6367. * DESCRIPTION
  6368. *
  6369. *   Determine the reflecivity of a surface at a point, taking into account the
  6370. *   surface's reflectivity and the viewing angle
  6371. *
  6372. * CHANGES
  6373. *
  6374. *   Sep 1998 : Creation
  6375. *
  6376. ******************************************************************************/
  6377.  
  6378. void determine_reflectivity(DBL *weight, RGB reflectivity, COLOUR Reflection_Max,
  6379.         COLOUR Reflection_Min, int Reflection_Type, DBL Reflection_Falloff, 
  6380.     DBL cos_angle, RAY *Ray, INTERIOR *Interior)
  6381. {
  6382.   DBL Temp_Weight_Min, Temp_Weight_Max;
  6383.   DBL Reflection_Frac;
  6384.   DBL g, F;
  6385.   int i;
  6386.  
  6387.   DBL ior, ior2, disp;
  6388.  
  6389.   if (Reflection_Type==1)
  6390.   {
  6391.     /* Get ratio of iors depending on the interiors the ray is traversing. */
  6392.     if (Ray->Index == -1)
  6393.     {
  6394.       /* The ray is entering from the atmosphere. */
  6395.       ior = Frame.Atmosphere_IOR / Interior->IOR;
  6396.       disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
  6397.     }
  6398.     else
  6399.     {
  6400.       /* The ray is currently inside an object. */
  6401.       if ((Interior_In_Ray_Container(Ray, Interior)) >= 0)
  6402.       {
  6403.         if (Ray->Index == 0)
  6404.         {
  6405.           /* The ray is leaving into the atmosphere. */
  6406.           ior = Interior->IOR / Frame.Atmosphere_IOR;
  6407.           disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
  6408.         }
  6409.         else
  6410.         {
  6411.           /* The ray is leaving into another object. */
  6412.           ior = Interior->IOR / Ray->Interiors[Ray->Index]->IOR;
  6413.           disp = Interior->Dispersion / Ray->Interiors[Ray->Index]->Dispersion;
  6414.         }
  6415.       }
  6416.       else
  6417.       {
  6418.         /* The ray is entering a new object. */
  6419.         ior = Ray->Interiors[Ray->Index]->IOR / Interior->IOR;
  6420.         disp = Ray->Interiors[Ray->Index]->Dispersion / Interior->Dispersion;
  6421.       }
  6422.     }
  6423.  
  6424.     ior = 1.0/ior;
  6425.     disp = 1.0/disp;
  6426.   }
  6427.  
  6428.  
  6429.   switch (Reflection_Type)
  6430.   {
  6431.     case 0:  /* Standard reflection */
  6432.       Temp_Weight_Max = max3(Reflection_Max[RED], Reflection_Max[GREEN], Reflection_Max[BLUE]);
  6433.       Temp_Weight_Min = max3(Reflection_Min[RED], Reflection_Min[GREEN], Reflection_Min[BLUE]);
  6434.       *weight = *weight * max(Temp_Weight_Max, Temp_Weight_Min);
  6435.  
  6436.       if(fabs(Reflection_Falloff-1.0)>EPSILON)
  6437.       {
  6438.         Reflection_Frac = pow(1.0 - cos_angle, Reflection_Falloff);
  6439.       }
  6440.       else
  6441.       {
  6442.         Reflection_Frac = 1.0 - cos_angle;
  6443.       }
  6444.       if(fabs(Reflection_Frac)<EPSILON)
  6445.       {
  6446.         Assign_Vector(reflectivity, Reflection_Min);
  6447.       }
  6448.       else if (fabs(Reflection_Frac-1.0)<EPSILON)
  6449.       {
  6450.         Assign_Vector(reflectivity, Reflection_Max);
  6451.       }
  6452.       else
  6453.       {
  6454.         VLinComb2(reflectivity, Reflection_Frac, Reflection_Max, (1 - Reflection_Frac), Reflection_Min);
  6455.       }
  6456.       break;
  6457.  
  6458.     case 1:  /* Fresnel */
  6459.       if(fabs(disp - 1.0) < EPSILON)
  6460.       {
  6461.         g = sqrt(Sqr(ior) + Sqr(cos_angle) - 1);
  6462.         F = 0.5 * (Sqr(g - cos_angle) / Sqr(g + cos_angle));
  6463.         F = F * (1 + Sqr(cos_angle * (g + cos_angle) - 1) / Sqr(cos_angle * (g - cos_angle) + 1));
  6464.  
  6465.         F=min(1.0,max(0.0,F));
  6466.         /* NK - changed - not always monochromatic anymore */
  6467.         if(Reflection_Max[0]==0.0 && Reflection_Max[1]==0.0 && Reflection_Max[2]==0.0)
  6468.         {
  6469.           Make_RGB(reflectivity,F,F,F);
  6470.         }
  6471.         else
  6472.         {
  6473.           VLinComb2(reflectivity,F,Reflection_Max,(1.0-F),Reflection_Min);
  6474.         }
  6475.       }
  6476.       for (i=0;i<3; i++)
  6477.       {
  6478.         ior2 = ior /sqrt(disp) * pow(disp,(DBL)i/2.5);
  6479.         g = sqrt(Sqr(ior2) + Sqr(cos_angle) - 1.0);
  6480.         F = 0.5 * (Sqr(g - cos_angle) / Sqr(g + cos_angle));
  6481.         F = F * (1.0 + Sqr(cos_angle * (g + cos_angle) - 1.0) / Sqr(cos_angle * (g - cos_angle) + 1.0));
  6482.  
  6483.         F=min(1.0,max(0.0,F));
  6484.         /* NK - changed - not always monochromatic anymore */
  6485.         if(Reflection_Max[0]==0.0 && Reflection_Max[1]==0.0 && Reflection_Max[2]==0.0)
  6486.         {
  6487.           reflectivity[i]=F;
  6488.         }
  6489.         else
  6490.         {
  6491.           reflectivity[i] = F*Reflection_Max[i] + (1.0-F)*Reflection_Min[i];
  6492.         }
  6493.       }
  6494.  
  6495.       *weight = *weight * max3(reflectivity[0],reflectivity[1],reflectivity[2]);
  6496.       break;
  6497.  
  6498.     default:
  6499.       Error("Illegal reflection_type.\n");
  6500.   }
  6501. }
  6502.  
  6503. /* NK phmap */
  6504. /*****************************************************************************
  6505. *
  6506. * FUNCTION
  6507. *
  6508. *   GlobalPhotonDiffuse (based on Diffuse)
  6509. *
  6510. *   Preconditions:
  6511. *     same as Diffuse() with this addition:
  6512. *
  6513. *     If photonOptions.photonsEnabled is true now, then
  6514. *     InitBacktraceEverything must have been called with
  6515. *     photonOptions.photonsEnabled true.
  6516. *
  6517. *
  6518. * AUTHOR
  6519. *
  6520. *   Nathan Kopp (this is based on Diffuse)
  6521. *
  6522. * DESCRIPTION
  6523. *
  6524. *   Computes diffuse, phong, specular, etc. based on the incoming photons
  6525. *   stored in the various photon maps.
  6526. *
  6527. * CHANGES
  6528. *
  6529. *   -
  6530. *
  6531. ******************************************************************************/
  6532.  
  6533. static void GlobalPhotonDiffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR  Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object)
  6534. {
  6535.   DBL Cos_Shadow_Angle;
  6536.   RAY Light_Source_Ray;
  6537.   VECTOR REye;
  6538.   COLOUR Light_Colour, TempCol, Colour2;
  6539.   DBL Size, r, tempr;
  6540.   int n, tempn;
  6541.   int j;
  6542.   /*int step;*/
  6543.   DBL thisDensity=0;
  6544.   DBL prevDensity=0.0000000000000001; /* avoid div-by-zero error */
  6545.   int expanded = FALSE;
  6546.   DBL att;  /* attenuation for lambertian compensation & filters */
  6547.  
  6548.   if (!photonOptions.globalPhotonMap.numPhotons)
  6549.   {
  6550.     Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
  6551.     return;
  6552.   }
  6553.  
  6554.   if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
  6555.   {
  6556.     Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
  6557.     return;
  6558.   }
  6559.  
  6560.   /* statistics */
  6561.   Increase_Counter(stats[Gather_Performed_Count]);
  6562.  
  6563.   if (Finish->Specular != 0.0)
  6564.   {
  6565.     REye[X] = -Eye->Direction[X];
  6566.     REye[Y] = -Eye->Direction[Y];
  6567.     REye[Z] = -Eye->Direction[Z];
  6568.   }
  6569.  
  6570.   Make_Colour(Colour,0,0,0);
  6571.   Make_Colour(Colour2,0,0,0);
  6572.     Make_Colour(TempCol,0,0,0);
  6573.  
  6574.   /*Size = photonOptions.globalGatherRad;*/
  6575.   Size = 2.0;
  6576.  
  6577.     tempr = 0;
  6578.  
  6579.     /* gather the photons */
  6580.     tempn=gatherPhotons(IPoint, Size, &tempr,Layer_Normal,TRUE,&photonOptions.globalPhotonMap);
  6581.  
  6582.     /* now go through these photons and add up their contribution */
  6583.     for(j=0; j<tempn; j++)
  6584.     {
  6585.       SMALL_COLOUR col;
  6586.       /*DBL theta,phi;*/
  6587.       int theta,phi;
  6588.  
  6589.       /* convert small color to normal color */
  6590.       col = photonOptions.photonGatherList[j]->Colour;
  6591.       UNPACK_COLOUR(Light_Colour, col, photonOptions.globalPhotonMap);
  6592.  
  6593.       /* convert theta/phi to vector direction 
  6594.          Use a pre-computed array of sin/cos to avoid many calls to the
  6595.          sin() and cos() functions.  These arrays were initialized in
  6596.          InitBacktraceEverything.
  6597.       */
  6598.       theta = photonOptions.photonGatherList[j]->theta+127;
  6599.       phi = photonOptions.photonGatherList[j]->phi+127;
  6600.       
  6601.       Light_Source_Ray.Direction[Y] = photonOptions.sinTheta[theta];
  6602.       Light_Source_Ray.Direction[X] = photonOptions.cosTheta[theta];
  6603.  
  6604.       Light_Source_Ray.Direction[Z] = Light_Source_Ray.Direction[X]*photonOptions.sinTheta[phi];
  6605.       Light_Source_Ray.Direction[X] = Light_Source_Ray.Direction[X]*photonOptions.cosTheta[phi];
  6606.  
  6607.       VSub(Light_Source_Ray.Initial, photonOptions.photonGatherList[j]->Loc, Light_Source_Ray.Direction);
  6608.  
  6609.       /* this compensates for real lambertian (diffuse) lighting (see paper) */
  6610.       VDot(att, Layer_Normal, Light_Source_Ray.Direction);
  6611.       if (att>1) att=1.0;
  6612.       if (att<.1) att = 0.1; /* limit to 10x - otherwise we get bright dots */
  6613.       att = 1.0 / fabs(att);
  6614.  
  6615.       /* do gaussian filter */
  6616.       /*att *= 0.918*(1.0-(1.0-exp((-1.953) * photonOptions.photonDistances[j])) / (1.0-exp(-1.953)) );*/
  6617.       /* do cone filter */
  6618.       /*att *= 1.0-(sqrt(photonOptions.photonDistances[j])/(4.0 * tempr)) / (1.0-2.0/(3.0*4.0));*/
  6619.  
  6620.       VScaleEq(Light_Colour,att);
  6621.  
  6622.       /* See if light on far side of surface from camera. */
  6623.       if (!(Test_Flag(Object, DOUBLE_ILLUMINATE_FLAG)))
  6624.       {
  6625.         VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
  6626.         if (Cos_Shadow_Angle < EPSILON)
  6627.           continue;
  6628.       }
  6629.  
  6630.       /* now add diffuse, phong, specular, irid contribution */
  6631.       if (Finish->Diffuse > 0.0)
  6632.       {
  6633.         do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,TempCol,Light_Colour,Layer_Pigment_Colour, Attenuation);
  6634.       }
  6635.       if (Finish->Phong > 0.0)
  6636.       {
  6637.         do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
  6638.       }
  6639.       if (Finish->Specular > 0.0)
  6640.       {
  6641.         do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
  6642.       }
  6643.       if (Finish->Irid > 0.0)
  6644.       {
  6645.         do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,TempCol);
  6646.       }
  6647.  
  6648.     }
  6649.  
  6650.     /* density of this search */
  6651.     thisDensity = tempn / (tempr*tempr);
  6652.  
  6653.       r = tempr;
  6654.       n = tempn;
  6655.       Assign_Colour(Colour2, TempCol);
  6656.  
  6657.   /* finish the photons equation */
  6658.   VScaleEq(Colour2, (DBL)(1.0)/(M_PI*r*r));
  6659.  
  6660.   /* add photon contribution to total lighting */
  6661.   VAddEq(Colour, Colour2);
  6662. }
  6663. /* NK ---- */
  6664.  
  6665.  
  6666.  
  6667.  
  6668.  
  6669.  
  6670.  
  6671.  
  6672. #ifdef UseMediaAndLightCache
  6673.  
  6674. static void InitMallocCaches(void)
  6675.   int i;
  6676.   long DBLSize = Number_Of_Textures_And_Weights * sizeof(DBL);
  6677.   long TEXTURESize = Number_Of_Textures_And_Weights * sizeof(TEXTURE *);
  6678.   int NumberOfLightSources = Frame.Number_Of_Light_Sources;
  6679.  
  6680.   MaxMediaCacheDepth = DEFAULT_MEDIA_BUF_DEPTH;
  6681.   MaxLightCacheDepth = DEFAULT_LIGHT_BUF_DEPTH;
  6682.  
  6683.   MediaMallocCacheSize=0;
  6684.   TotalMallocCacheSize=0;
  6685.  
  6686. #ifdef AccumulateCacheStatistics
  6687.   MaxShadowTextRecCntr=-1;
  6688.   MaxLightedTexture=-1;
  6689.   MaxAppColourRecCntr=-1;
  6690.   MaxSimMediatRecCntr=-1;
  6691. #endif
  6692.  
  6693.   ShadowMediaListIndex=-1;
  6694.   LightingMediaListIndex=-1;
  6695.   MediaCacheIndex=-1;
  6696.   LightingCacheIndex=-1;
  6697.  
  6698.   if ( NumberOfLightSources==0 )
  6699.     NumberOfLightSources = 2;
  6700.  
  6701.   s0 = (DBL *)POV_MALLOC(NumberOfLightSources*sizeof(DBL), "temp data");
  6702.   s1 = (DBL *)POV_MALLOC(NumberOfLightSources*sizeof(DBL), "temp data");
  6703.  
  6704.   ShadowMediaListCacheSize = (long *)POV_MALLOC(MaxMediaCacheDepth*sizeof(long *), "temp media list");
  6705.   LightingMediaListCacheSize = (long *)POV_MALLOC(MaxMediaCacheDepth*sizeof(long *), "temp media list");
  6706.   MediaIntervalCacheSize = (long *)POV_MALLOC(MaxMediaCacheDepth*sizeof(long *), "temp media list");
  6707.   ShadowMediaListCache = (IMEDIA ***)POV_MALLOC(MaxMediaCacheDepth*sizeof(IMEDIA **), "temp media list");
  6708.   LightingMediaListCache = (IMEDIA ***)POV_MALLOC(MaxMediaCacheDepth*sizeof(IMEDIA **), "temp media list");
  6709.   MediaLightListCache = (LIGHT_LIST **)POV_MALLOC(MaxMediaCacheDepth*sizeof(LIGHT_LIST *), "light list");
  6710.   MediaLitIntervalCache = (LIT_INTERVAL **)POV_MALLOC(MaxMediaCacheDepth*sizeof(LIT_INTERVAL *), "lit interval");
  6711.   MediaIntervalCache = (MEDIA_INTERVAL **)POV_MALLOC(MaxMediaCacheDepth*sizeof(MEDIA_INTERVAL *), "media intervals");
  6712.  
  6713.   for ( i=0; i<MaxMediaCacheDepth; i++) 
  6714.   {
  6715.     ShadowMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
  6716.     ShadowMediaListCacheSize[i]=10;
  6717.     LightingMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
  6718.     LightingMediaListCacheSize[i]=10;
  6719.     MediaLightListCache[i] = (LIGHT_LIST *)POV_MALLOC(NumberOfLightSources*sizeof(LIGHT_LIST), "light list");
  6720.     MediaLitIntervalCache[i] = (LIT_INTERVAL *)POV_MALLOC((2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL), "lit interval");
  6721.     MediaIntervalCache[i]= (MEDIA_INTERVAL *)POV_MALLOC(10*sizeof(MEDIA_INTERVAL), "media intervals");
  6722.     MediaIntervalCacheSize[i]=10;
  6723.     
  6724.     MediaMallocCacheSize+=10*sizeof(IMEDIA *)+10*sizeof(IMEDIA *)+NumberOfLightSources*sizeof(LIGHT_LIST)+
  6725.       (2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL)+10*sizeof(MEDIA_INTERVAL);
  6726.   }
  6727.  
  6728.   TotalMallocCacheSize += MediaMallocCacheSize;
  6729.  
  6730.   WeightListCache = (DBL **)POV_MALLOC(MaxLightCacheDepth*sizeof(DBL *), "Weight list stack");
  6731.   TextureListCache = (TEXTURE ***)POV_MALLOC(MaxLightCacheDepth*sizeof(TEXTURE **), "Weight list stack");
  6732.   LightListCache = (LIGHT_TESTED **)POV_MALLOC(MaxLightCacheDepth*sizeof(LIGHT_TESTED *), "Weight list stack");
  6733.  
  6734.   for ( i=0; i<MaxLightCacheDepth; i++) 
  6735.   {
  6736.     WeightListCache[i]= (DBL *)POV_MALLOC(DBLSize, "Weight list stack");
  6737.     TextureListCache[i]= (TEXTURE **)POV_MALLOC(TEXTURESize, "Weight list stack");
  6738.     LightListCache[i] = (LIGHT_TESTED *)POV_MALLOC(max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED), "Weight list stack");
  6739.     TotalMallocCacheSize += DBLSize+ TEXTURESize+ DBLSize+ TEXTURESize+
  6740.             max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED);
  6741.   }
  6742. }
  6743.  
  6744.  
  6745. static void DeInitMallocCaches(void)
  6746.   int i;
  6747.  
  6748.   if ( s0 != NULL)  POV_FREE(s0); s0=NULL;
  6749.   if ( s1 != NULL) POV_FREE(s1); s1=NULL;
  6750.  
  6751.   if (ShadowMediaListCache)
  6752.   {
  6753.     for (i=0; i<MaxMediaCacheDepth; i++) 
  6754.     {
  6755.       if ( ShadowMediaListCache[i] != NULL) POV_FREE(ShadowMediaListCache[i]);
  6756.       ShadowMediaListCache[i]=NULL;
  6757.  
  6758.       if ( LightingMediaListCache[i] != NULL) POV_FREE(LightingMediaListCache[i]);
  6759.       LightingMediaListCache[i]=NULL;
  6760.  
  6761.       if ( MediaLightListCache[i] != NULL) POV_FREE(MediaLightListCache[i]);
  6762.       MediaLightListCache[i]=NULL;
  6763.  
  6764.       if ( MediaLitIntervalCache[i] != NULL) POV_FREE(MediaLitIntervalCache[i]);
  6765.       MediaLitIntervalCache[i]=NULL;
  6766.  
  6767.       if ( MediaIntervalCache[i] != NULL) POV_FREE(MediaIntervalCache[i]);
  6768.       MediaIntervalCache[i]=NULL;
  6769.     }
  6770.   }
  6771.  
  6772.   if (ShadowMediaListCache != NULL) POV_FREE(ShadowMediaListCache);
  6773.   ShadowMediaListCache=NULL;
  6774.  
  6775.   if ( LightingMediaListCache != NULL) POV_FREE(LightingMediaListCache);
  6776.   LightingMediaListCache=NULL;
  6777.  
  6778.   if ( MediaLightListCache != NULL) POV_FREE(MediaLightListCache);
  6779.   MediaLightListCache=NULL;
  6780.  
  6781.   if ( MediaLitIntervalCache != NULL) POV_FREE(MediaLitIntervalCache);
  6782.   MediaLitIntervalCache=NULL;
  6783.  
  6784.   if ( MediaIntervalCache != NULL) POV_FREE(MediaIntervalCache);
  6785.   MediaIntervalCache=NULL;
  6786.  
  6787.  
  6788.   if (LightListCache)
  6789.   {
  6790.     for (i=0; i<MaxLightCacheDepth; i++) 
  6791.     {
  6792.       if ( LightListCache[i] != NULL) POV_FREE(LightListCache[i]);   
  6793.       LightListCache[i]=NULL;
  6794.  
  6795.       if ( WeightListCache[i] != NULL) POV_FREE(WeightListCache[i]); 
  6796.       WeightListCache[i]=NULL;
  6797.  
  6798.       if ( TextureListCache[i] != NULL) POV_FREE(TextureListCache[i]);  
  6799.       TextureListCache[i]=NULL;
  6800.     }
  6801.   }
  6802.   /*YS sept 17 2000 memory leak fix */
  6803.   if ( ShadowMediaListCacheSize != NULL) POV_FREE(ShadowMediaListCacheSize);  
  6804.       ShadowMediaListCacheSize=NULL; 
  6805.   if ( LightingMediaListCacheSize != NULL) POV_FREE(LightingMediaListCacheSize);  
  6806.       LightingMediaListCacheSize=NULL; 
  6807.   if ( MediaIntervalCacheSize != NULL) POV_FREE(MediaIntervalCacheSize);  
  6808.       MediaIntervalCacheSize=NULL; 
  6809.     /*YS*/
  6810.  
  6811.   if ( LightListCache != NULL) POV_FREE(LightListCache);   
  6812.   LightListCache=NULL;
  6813.  
  6814.   if ( WeightListCache != NULL) POV_FREE(WeightListCache); 
  6815.   WeightListCache=NULL;
  6816.  
  6817.   if ( TextureListCache != NULL) POV_FREE(TextureListCache);  
  6818.   TextureListCache=NULL;
  6819. }
  6820.     
  6821. static void ReInitMallocCaches(void)
  6822.   int i;
  6823.   long DBLSize=Number_Of_Textures_And_Weights * sizeof(DBL);
  6824.   long TEXTURESize=Number_Of_Textures_And_Weights * sizeof(TEXTURE *);
  6825.   
  6826.   TotalMallocCacheSize=MediaMallocCacheSize;
  6827.  
  6828.   for ( i=0; i<MaxLightCacheDepth; i++)
  6829.   {
  6830.     WeightListCache[i]= (DBL *)POV_REALLOC(WeightListCache[i],DBLSize, "Weight list stack");
  6831.     TextureListCache[i]= (TEXTURE **)POV_REALLOC(TextureListCache[i],TEXTURESize, "Weight list stack");
  6832.     LightListCache[i] = (LIGHT_TESTED *)POV_REALLOC(LightListCache[i],max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED), "Weight list stack");
  6833.     TotalMallocCacheSize+=DBLSize+ TEXTURESize+  DBLSize+TEXTURESize+
  6834.       max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED);
  6835.   }
  6836. }
  6837.  
  6838.  
  6839. void ResizeMediaMallocCaches(long newSize)
  6840.   int i;
  6841.   int NumberOfLightSources = Frame.Number_Of_Light_Sources;
  6842.   if ( NumberOfLightSources==0 ) NumberOfLightSources = 2;
  6843.   /* subtract this... we'll add it back later */
  6844.   TotalMallocCacheSize -= MediaMallocCacheSize;
  6845.   ShadowMediaListCacheSize = (long *)POV_REALLOC(ShadowMediaListCacheSize, newSize*sizeof(long *), "temp media list");
  6846.   LightingMediaListCacheSize = (long *)POV_REALLOC(LightingMediaListCacheSize, newSize*sizeof(long *), "temp media list");
  6847.   MediaIntervalCacheSize = (long *)POV_REALLOC(MediaIntervalCacheSize, newSize*sizeof(long *), "temp media list");
  6848.   ShadowMediaListCache = (IMEDIA ***)POV_REALLOC(ShadowMediaListCache, newSize*sizeof(IMEDIA **), "temp media list");
  6849.   LightingMediaListCache = (IMEDIA ***)POV_REALLOC(LightingMediaListCache, newSize*sizeof(IMEDIA **), "temp media list");
  6850.   MediaLightListCache = (LIGHT_LIST **)POV_REALLOC(MediaLightListCache, newSize*sizeof(LIGHT_LIST *), "light list");
  6851.   MediaLitIntervalCache = (LIT_INTERVAL **)POV_REALLOC(MediaLitIntervalCache, newSize*sizeof(LIT_INTERVAL *), "lit interval");
  6852.   MediaIntervalCache = (MEDIA_INTERVAL **)POV_REALLOC(MediaIntervalCache, newSize*sizeof(MEDIA_INTERVAL *), "media intervals");
  6853.  
  6854.  
  6855.   for ( i=MaxMediaCacheDepth; i<newSize; i++) 
  6856.   {
  6857.     ShadowMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
  6858.     ShadowMediaListCacheSize[i]=10;
  6859.     LightingMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
  6860.     LightingMediaListCacheSize[i]=10;
  6861.     MediaLightListCache[i] = (LIGHT_LIST *)POV_MALLOC(NumberOfLightSources*sizeof(LIGHT_LIST), "light list");
  6862.     MediaLitIntervalCache[i] = (LIT_INTERVAL *)POV_MALLOC((2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL), "lit interval");
  6863.     MediaIntervalCache[i]= (MEDIA_INTERVAL *)POV_MALLOC(10*sizeof(MEDIA_INTERVAL), "media intervals");
  6864.     MediaIntervalCacheSize[i]=10;
  6865.     
  6866.     MediaMallocCacheSize+=10*sizeof(IMEDIA *)+10*sizeof(IMEDIA *)+NumberOfLightSources*sizeof(LIGHT_LIST)+
  6867.       (2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL)+10*sizeof(MEDIA_INTERVAL);
  6868.   }
  6869.   MaxMediaCacheDepth=newSize;
  6870.  
  6871.   /* add media stuff back on now */
  6872.   TotalMallocCacheSize += MediaMallocCacheSize;
  6873. }
  6874.  
  6875. void ResizeLightMallocCaches(long newSize)
  6876. {
  6877.   int i;
  6878.   long DBLSize = Number_Of_Textures_And_Weights * sizeof(DBL);
  6879.   long TEXTURESize = Number_Of_Textures_And_Weights * sizeof(TEXTURE *);
  6880.   int NumberOfLightSources = Frame.Number_Of_Light_Sources;
  6881.   if ( NumberOfLightSources==0 ) NumberOfLightSources = 2;
  6882.  
  6883.   WeightListCache = (DBL **)POV_REALLOC(WeightListCache, newSize*sizeof(DBL *), "Weight list stack");
  6884.   TextureListCache = (TEXTURE ***)POV_REALLOC(TextureListCache, newSize*sizeof(TEXTURE **), "Weight list stack");
  6885.   LightListCache = (LIGHT_TESTED **)POV_REALLOC(LightListCache, newSize*sizeof(LIGHT_TESTED *), "Weight list stack");
  6886.  
  6887.   for ( i=MaxLightCacheDepth; i<newSize; i++) 
  6888.   {
  6889.     WeightListCache[i]= (DBL *)POV_MALLOC(DBLSize, "Weight list stack");
  6890.     TextureListCache[i]= (TEXTURE **)POV_MALLOC(TEXTURESize, "Weight list stack");
  6891.     LightListCache[i] = (LIGHT_TESTED *)POV_MALLOC(max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED), "Weight list stack");
  6892.     TotalMallocCacheSize += DBLSize+ TEXTURESize+ DBLSize+ TEXTURESize+
  6893.             max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED);
  6894.   }
  6895.     MaxLightCacheDepth=newSize;
  6896.  
  6897. }
  6898.  
  6899. #pragma peephole off 
  6900.  
  6901. #endif
  6902.  
  6903.