home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * lighting.c
- *
- * -------------------------------------------------------
- * ATTENTION:
- * This is an unofficial version of lighting.c modified by
- * Ryoichi Suzuki, rsuzuki@etl.go.jp for use with
- * "isosurface" shape type.
- * -------------------------------------------------------
- * This module calculates lighting properties like ambient, diffuse, specular,
- * reflection, refraction, etc.
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996,1999 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file.
- * If POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by email to team-coord@povray.org or visit us on the web at
- * http://www.povray.org. The latest version of POV-Ray may be found at this site.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- * Modifications by Robert G. Smith & Andreas Dilger, March 1999, used with
- * permission
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
- #include "blob.h"
- #include "bbox.h"
- #include "colour.h"
- #include "image.h"
- #include "interior.h"
- #ifdef IsoBlobPatch
- #include "isoblob.h" /* Lummox JR, July 1999 */
- #endif
- #include "lbuffer.h"
- #include "lighting.h"
- #include "media.h"
- #include "mesh.h"
- #include "normal.h"
- #include "objects.h"
- #include "octree.h"
- #include "pattern.h" /* [CEY 10/94] */
- #include "pigment.h"
- #include "povray.h"
- #include "radiosit.h"
- #include "ray.h"
- #include "render.h"
- #include "texture.h"
- #include "lightgrp.h"
-
- /*YS april 2000 cache */
- #ifdef UseMediaAndLightCache
-
- /* ------- cache init / reinit / deinit -------- */
- static void InitMallocCaches(void);
- static void DeInitMallocCaches(void);
- static void ReInitMallocCaches(void);
-
- /* ------- cache sizes for statistics gathering ------- */
- long TotalMallocCacheSize=0;
- long MediaMallocCacheSize=0;
-
- /* ------- Caches for DetermineApparantColour ------- */
- long MaxLightCacheDepth = 0;
- long LightingCacheIndex = -1;
-
- DBL **WeightListCache = NULL; /* cache weight list - each is fixed size */
- TEXTURE ***TextureListCache = NULL; /* cache texture list - each is fixed size */
- LIGHT_TESTED **LightListCache = NULL; /* cache for light_list - each is fixed size */
-
-
- /* ------- Caches for media calculations ------- */
- long MaxMediaCacheDepth = 0;
-
- /* caches for all & lit intervals */
- long MediaCacheIndex=-1;
- LIGHT_LIST **MediaLightListCache = NULL; /* cache for light_list - each is fixed size */
- LIT_INTERVAL **MediaLitIntervalCache = NULL; /* cache for lit_interval - each is fixed size */
- MEDIA_INTERVAL **MediaIntervalCache = NULL; /* cache for media_interval */
- long *MediaIntervalCacheSize = NULL; /* interval array sizes vary */
-
- /* cache for media list in shadow calculations */
- long ShadowMediaListIndex=-1;
- IMEDIA ***ShadowMediaListCache = NULL;
- long *ShadowMediaListCacheSize = NULL;
-
- /* cache for media list in lighting calculations */
- long LightingMediaListIndex=-1;
- IMEDIA ***LightingMediaListCache = NULL;
- long *LightingMediaListCacheSize = NULL;
-
- /* s0 and s1 - always the same size - just malloc once and keep the arrays */
- DBL *s0 = NULL;
- DBL *s1 = NULL;
-
- #ifdef AccumulateCacheStatistics
- long MaxAppColourRecCntr=-1;
- long MaxSimMediatRecCntr=-1;
- long MaxShadowTextRecCntr=-1;
- long MaxLightedTexture=-1;
- #endif
-
- #endif
- /*YS*/
-
- /* NK phmap */
- #include "photons.h"
- /* NK ---- */
- #include "matrices.h"
- #ifdef PostProcessPatch
- #include "postproc.h"
- #endif
- #ifdef MultiTextureCsgPatch
- #include "csg.h"
- #endif
-
- #ifdef MotionBlurPatch
- extern int TimeStamp;
- #endif
-
- #ifdef PostProcessPatch
- extern DBL savedRefractDepth;
- #endif
-
- /* Global vars to remember which colour component is being traced */
- int disp_elem; /* not thread safe */ /* 0=normal, 1..nelems=we're tracing elements */
- int disp_nelems; /* not thread safe */
-
- int alreadyBlurred;
-
- /* NK rad */
- extern int firstRadiosityPass;
- /* NK ---- */
-
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
-
- #define BLACK_LEVEL 0.003
-
- /*
- * "Small_Tolerance" is just too tight for higher order polynomial equations.
- * this value should probably be a variable of some sort, but for now just
- * use a reasonably small value. If people render real small objects real
- * close to each other then there may be some shading problems. Otherwise
- * having SHADOW_TOLERANCE as large as this won't affect images.
- */
-
- #define SHADOW_TOLERANCE 1.0e-3
-
- /* Number of inital entries in the texture and weight list. */
-
- #define NUMBER_OF_ENTRIES 16
-
-
-
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
-
-
-
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
-
- /* static variables for multi-layer speedups */
- /* this is a hack and should be done in a cleaner way in the future */
- /* NOT THREAD SAFE */
- static int photonsAlreadyGathered;
- static DBL previousRad;
-
- static LIGHT_TESTED *Light_List; /* not thread safe */
- static TEXTURE **Texture_List; /* not thread safe */
- static DBL *Weight_List; /* not thread safe */
-
- static int Number_Of_Textures_And_Weights; /* not thread safe */
-
-
- /** poviso:. July 14 '96 R.S. **/
- #ifdef POVISO
- int Shadow_Test_Flag = FALSE;
- #endif
- /** --- **/
-
- #ifdef NormalBugFix
- #define MAX_NESTED_TEXTURES 100
- static TEXTURE *warpNormalTextureList[MAX_NESTED_TEXTURES];
- int warpNormalTextures;
- #endif
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
-
- static void block_area_light (LIGHT_SOURCE *Light_Source,
- DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray,
- VECTOR IPoint, COLOUR Light_Colour, int u1, int v1, int u2, int v2, int Level);
-
- static void block_point_light (LIGHT_SOURCE *Light_Source,
- DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour);
-
- static void block_point_light_LBuffer (LIGHT_SOURCE *Light_Source,
- DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour);
-
- static void do_light (LIGHT_SOURCE *Light_Source,
- DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR IPoint,
- COLOUR Light_Colour);
-
- static int do_blocking (INTERSECTION *Local_Intersection,
- RAY *Light_Source_Ray, COLOUR Light_Colour, ISTACK *Local_Stack);
-
- static void do_phong (FINISH *Finish, RAY *Light_Source_Ray,
- VECTOR Eye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
- COLOUR Layer_Texture_Colour);
-
- static void do_specular (FINISH *Finish, RAY *Light_Source_Ray,
- VECTOR REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
- COLOUR Layer_Pigment_Colour);
-
- static void do_diffuse (FINISH *Finish, RAY *Light_Source_Ray,
- VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour,
- COLOUR Layer_Pigment_Colour, DBL Attenuation);
-
- static void do_irid (FINISH *Finish, RAY *Light_Source_Ray,
- VECTOR Layer_Normal, VECTOR IPoint, COLOUR Colour);
-
- static void Diffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR Layer_Normal,
- COLOUR Layer_Pigment_Colour, COLOUR Colour,DBL Attenuation, OBJECT *Object);
-
- static void Reflect (VECTOR, RAY*, VECTOR, VECTOR, COLOUR, DBL, DBL, int);
-
- static int Refract (INTERIOR*, VECTOR, RAY*, VECTOR, VECTOR, COLOUR, DBL);
-
- static void filter_shadow_ray (INTERSECTION *Ray_Intersection,
- RAY *Light_Source_Ray, COLOUR Colour);
-
- #ifdef InteriorTexturePatch
- static int create_texture_list (INTERSECTION *Ray_Intersection, DBL realNormDir);
- #else
- static int create_texture_list (INTERSECTION *Ray_Intersection);
- #endif
- static void do_texture_map (COLOUR Result_Colour,
- TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
- INTERSECTION *Ray_Intersection, int Shadow_Flag);
-
- static void average_textures (COLOUR Result_Colour,
- TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
- INTERSECTION *Ray_Intersection, int Shadow_Flag);
-
- static void compute_lighted_texture (COLOUR Result_Colour,
- TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
- INTERSECTION *Ray_Intersection);
-
- static void compute_shadow_texture (COLOUR Filter_Colour,
- TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray,
- INTERSECTION *Ray_Intersection);
-
- static void block_light_source (LIGHT_SOURCE *Light,
- DBL Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR P, COLOUR Colour);
-
- static void do_light_ray_atmosphere (RAY *Light_Source_Ray,
- INTERSECTION *Ray_Intersection, COLOUR Colour, int Valid_Object);
-
- static void determine_reflectivity (DBL *weight,
- RGB reflectivity, COLOUR Reflection_Max, COLOUR Reflection_Min,
- int Reflection_Type, DBL Reflection_Falloff, DBL cos_angle, RAY *Ray, INTERIOR *Interior);
-
- /* NK phmap */
- static void compute_backtrace_texture(COLOUR LightCol,
- TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
- INTERSECTION *Intersection);
-
- static void backtrace_average_textures (COLOUR Result_Colour,
- TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight,
- INTERSECTION *Ray_Intersection, int Shadow_Flag);
-
- static void GlobalPhotonDiffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object);
- /* NK ---- */
- /*YS 2000 made these two static and added prototypes*/
- static void Dispersion_Element_Hue(COLOUR Hue, int elem, int nelems);
- /*YS*/
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Initialize_Lighting_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Allocate lists needed during lighting calculations.
- *
- * CHANGES
- *
- * Sep 1994 : Creation.
- *
- * Okt 1994 : Added initialization of Light_List and test if there are
- * any light sources in the scene. [DB]
- *
- ******************************************************************************/
-
- void Initialize_Lighting_Code()
- {
- Light_List = NULL;
- Texture_List = NULL;
- Weight_List = NULL;
-
- Number_Of_Textures_And_Weights = NUMBER_OF_ENTRIES;
-
- #ifdef UseMediaAndLightCache
-
- InitMallocCaches();
-
- LightingCacheIndex++;
- Light_List=LightListCache[LightingCacheIndex];
- Texture_List = TextureListCache[LightingCacheIndex];
- Weight_List = WeightListCache[LightingCacheIndex];
-
- #else
- /* Allocate memory for light list. */
-
- if (Frame.Number_Of_Light_Sources > 0)
- {
- Light_List = (LIGHT_TESTED *)POV_MALLOC(Frame.Number_Of_Light_Sources*sizeof(LIGHT_TESTED), "temporary light list");
-
- for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
- {
- Light_List[i].Tested = FALSE;
-
- Make_ColourA(Light_List[i].Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
- }
- }
-
- /* Allocate memory for texture and weight list. */
-
- Texture_List = (TEXTURE **)POV_MALLOC(Number_Of_Textures_And_Weights*sizeof(TEXTURE *), "texture list");
-
- Weight_List = (DBL *)POV_MALLOC(Number_Of_Textures_And_Weights*sizeof(DBL), "weight list");
- #endif
-
-
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Reinitialize_Lighting_Code
- *
- * INPUT
- *
- * Number_Of_Entries - New number of entries in the texture/weight lists
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Resize variable lists needed during lighting calculation.
- *
- * CHANGES
- *
- * Jul 1995 : Creation.
- *
- * Mar 1996 : We have to pass pointers to the lists to resize because during
- * resizing the pointers to the lists change and thus the calling
- * functions does not longer know where the lists are if the
- * pointers to the lists where passed to it using arguments. [DB]
- *
- ******************************************************************************/
-
- void Reinitialize_Lighting_Code(int Number_Of_Entries, TEXTURE ***Textures, DBL **Weights)
- {
- if (Number_Of_Entries > Number_Of_Textures_And_Weights)
- {
- if (Number_Of_Entries >= INT_MAX / 2)
- {
- Error("Too many entries in texture and weight lists.\n");
- }
-
- Number_Of_Textures_And_Weights = Number_Of_Entries;
-
- #ifdef UseMediaAndLightCache
- ReInitMallocCaches();
- *Textures = Texture_List = TextureListCache[LightingCacheIndex];
- *Weights = Weight_List = WeightListCache[LightingCacheIndex];
- #else
- Texture_List = (TEXTURE **)POV_REALLOC(Texture_List, Number_Of_Textures_And_Weights*sizeof(TEXTURE *), "texture list");
-
- Weight_List = (DBL *)POV_REALLOC(Weight_List, Number_Of_Textures_And_Weights*sizeof(DBL), "weight list");
-
- *Textures = Texture_List;
- *Weights = Weight_List;
- #endif
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Deinitialize_Lighting_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy all lists needed during lighting calculation.
- *
- * CHANGES
- *
- * Sep 1994 : Creation.
- *
- * Jul 1995 : Added code to free local texture and weight lists. [DB]
- *
- ******************************************************************************/
-
- void Deinitialize_Lighting_Code()
- {
- #ifdef UseMediaAndLightCache
- DeInitMallocCaches();
- #else
- if (Light_List != NULL)
- {
- POV_FREE(Light_List);
- }
-
- if (Texture_List != NULL)
- {
- POV_FREE(Texture_List);
- }
-
- if (Weight_List != NULL)
- {
- POV_FREE(Weight_List);
- }
- #endif
- /*MH If a render is interrupted, this is set greater than one
- and dispersion would stop working if not given a value of 0*/
-
- if (disp_elem != 0)
- {
- disp_elem = 0;
- }
-
- Light_List = NULL;
- Texture_List = NULL;
- Weight_List = NULL;
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Determine_Apparent_Colour
- *
- * INPUT
- *
- * Ray_Intersection - info on where ray hit & object it hit
- * Ray - the ray from which object is seen
- * Weight - Automatic depth control value
- *
- * OUTPUT
- *
- * Colour - resulting color is added to given color. The RGB
- * components are significant. The transmittance channel
- * is used as an alpha channel.
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Given an intersection point, a ray, add that point's visible color
- * to the given colour and return it. This routine just does preliminary
- * initializations and calls to set up the multi-texture blob list if any.
- * Then it calls do_texture_map which in turn calls compute_lighted_texture
- * to do the actual lighting calculations. These functions were seperated
- * from this function because do_texture_map may need to call itself
- * recursively.
- *
- * CHANGES
- *
- * Sep 1994 : Code for multi-textured blobs added. [DB]
- *
- * Nov 1994 : Moved calls to Fog and Rainbow into tracing functions. [DB]
- *
- * Jan 1995 : Moved much of code to do_texture_map and
- * compute_lighted_texture [CEY]
- *
- * Jul 1995 : Added code to support alpha channel. [DB]
- *
- * Mar 1996 : Fixed severe bug (weight and texture lists were not saved) [DB]
- *
- ******************************************************************************/
-
- void Determine_Apparent_Colour(INTERSECTION *Ray_Intersection, COLOUR Colour, RAY *Ray, DBL Weight)
- {
- int i, Texture_Count;
- #ifndef UseMediaAndLightCache
- size_t savelights_size, save_tw_size;
- #endif
- DBL *save_Weights = NULL;
- COLOUR C1;
- VECTOR Raw_Normal;
- VECTOR IPoint;
-
- /* NK 1998 */
- UV_VECT UV_Coords;
- /* NK ---- */
- TEXTURE *Texture, **save_Textures = NULL;
- LIGHT_TESTED *savelights = NULL;
- DBL Normal_Direction;
-
-
- /* NK phmap - set static variable to zero so we will gather */
- /* non-zero will mean reuse already-gathered photons in the rest
- of the layers */
- photonsAlreadyGathered = 0;
- /* NK --- */
-
- #ifdef MotionBlurPatch
- if (!backtraceFlag)
- {
- if (!TimeStamp && Ray_Intersection->Object->TimeStamp)
- TimeStamp = Ray_Intersection->Object->TimeStamp;
- }
- #endif
-
- /* NK depth */
- Total_Depth += Ray_Intersection->Depth;
- /* NK ---- */
-
- Assign_Vector(IPoint,Ray_Intersection->IPoint);
-
- /*
- * Save existing light list if any. If we are not top level in recursion
- * depth, this information may be reused by upper level of trace.
- */
-
- #ifdef UseMediaAndLightCache
- LightingCacheIndex++;
- if ( LightingCacheIndex >= MaxLightCacheDepth)
- {
- ResizeLightMallocCaches(MaxLightCacheDepth*2);
- }
-
- #ifdef AccumulateCacheStatistics
- MaxAppColourRecCntr=max(MaxAppColourRecCntr,LightingCacheIndex);
- #endif
-
- Light_List=LightListCache[LightingCacheIndex];
- #else
- savelights_size = (size_t)(Frame.Number_Of_Light_Sources*sizeof(LIGHT_TESTED));
-
- if (savelights_size > 0)
- {
- savelights = (LIGHT_TESTED *)POV_MALLOC(savelights_size, "Light list stack");
- memcpy(savelights, Light_List, savelights_size);
- }
- #endif
- /* Init light list. */
-
- for (i = 0; i < Frame.Number_Of_Light_Sources; i++)
- {
- Light_List[i].Tested = FALSE;
- }
-
- /* Get the normal to the surface */
-
- Normal(Raw_Normal, Ray_Intersection->Object, Ray_Intersection);
-
- /* If the surface normal points away, flip its direction. */
- VDot(Normal_Direction, Raw_Normal, Ray->Direction);
- if (Normal_Direction > 0.0)
- {
- VScaleEq(Raw_Normal, -1.0);
- }
-
- Assign_Vector(Ray_Intersection->INormal, Raw_Normal);
- /* and save to intersection -hdf- */
- Assign_Vector(Ray_Intersection->PNormal, Raw_Normal);
-
- if (Test_Flag(Ray_Intersection->Object, UV_FLAG) ||
- (opts.postProcessFlags & PP_FLAG_IUV))
- {
- /* get the UV vect of the intersection */
- UVCoord(UV_Coords, Ray_Intersection->Object, Ray_Intersection);
- /* save the normal and UV coords into Intersection */
- Assign_UV_Vect(Ray_Intersection->Iuv, UV_Coords);
- }
-
- /* now switch to UV mapping if we need to */
- if (Test_Flag(Ray_Intersection->Object, UV_FLAG))
- {
- IPoint[X] = UV_Coords[U];
- IPoint[Y] = UV_Coords[V];
- IPoint[Z] = 0;
- }
-
- /*
- * Save texture and weight lists.
- */
-
- #ifdef UseMediaAndLightCache
- /* this has already been resized when LightingCacheIndex was incremented */
- Weight_List=WeightListCache[LightingCacheIndex];
- Texture_List=TextureListCache[LightingCacheIndex];
- #else
- save_tw_size = (size_t)Number_Of_Textures_And_Weights;
-
- if (save_tw_size > 0)
- {
- save_Weights = (DBL *)POV_MALLOC(save_tw_size * sizeof(DBL), "Weight list stack");
- memcpy(save_Weights, Weight_List, save_tw_size * sizeof(DBL));
- save_Textures = (TEXTURE **)POV_MALLOC(save_tw_size * sizeof(TEXTURE *), "Weight list stack");
- memcpy(save_Textures, Texture_List, save_tw_size * sizeof(TEXTURE *));
- }
- #endif
-
- /* Get texture list and weights. */
-
- #ifdef InteriorTexturePatch
- Texture_Count = create_texture_list (Ray_Intersection, Normal_Direction);
- #else
- Texture_Count = create_texture_list (Ray_Intersection);
- #endif
- /*
- * Now, we perform the lighting calculations by stepping through
- * the list of textures and summing the weighted color.
- */
-
- for (i = 0; i < Texture_Count; i++)
- {
- /* If contribution of this texture is neglectable skip ahead. */
-
- if (Weight_List[i] < BLACK_LEVEL)
- {
- continue;
- }
-
- Texture = Texture_List[i];
-
- /* NK phmap */
- if(backtraceFlag)
- {
- C1[0] = Colour[0]*Weight_List[i];
- C1[1] = Colour[1]*Weight_List[i];
- C1[2] = Colour[2]*Weight_List[i];
- do_texture_map(C1, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection, FALSE);
- }
- else
- {
- /* NK ---- */
- do_texture_map(C1, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection, FALSE);
-
- Colour[RED] += Weight_List[i] * C1[RED];
- Colour[GREEN] += Weight_List[i] * C1[GREEN];
- Colour[BLUE] += Weight_List[i] * C1[BLUE];
- /* NK phmap */
- }
- /* NK ---- */
-
- /* Use transmittance value for alpha channel support. [DB] */
-
- /*
- Colour[TRANSM] += Weight_List[i] * C1[TRANSM];
- */
- Colour[TRANSM] *= C1[TRANSM];
- }
-
- /* Restore the light list to its original form */
-
- #ifdef UseMediaAndLightCache
- LightingCacheIndex--;
-
- Light_List=LightListCache[LightingCacheIndex];
- #else
- if (savelights_size > 0)
- {
- memcpy(Light_List, savelights, savelights_size);
- POV_FREE(savelights);
- }
- #endif
-
- /* Restore the weight and texture list. */
-
- #ifdef UseMediaAndLightCache
- Weight_List=WeightListCache[LightingCacheIndex];
- Texture_List=TextureListCache[LightingCacheIndex];
- #else
- if (save_tw_size > 0)
- {
- memcpy(Weight_List, save_Weights, save_tw_size * sizeof(DBL));
- memcpy(Texture_List, save_Textures, save_tw_size * sizeof(TEXTURE *));
- POV_FREE(save_Weights);
- POV_FREE(save_Textures);
- }
- #endif
-
-
- /* NK depth */
- Total_Depth -= Ray_Intersection->Depth;
- /* NK ---- */
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Test_Shadow
- *
- * INPUT
- *
- * Light - Light source
- * P - Point to test
- *
- * OUTPUT
- *
- * Depth - Distance to light source
- * Light_Source_Ray - Light ray pointing towards the light source
- * Eye_Ray - Current viewing ray
- * Colour - Light color reaching point P
- *
- * RETURNS
- *
- * int - TRUE if point lies in shadow
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Test if a given point is in shadow in respect to the given light source.
- *
- * The viewing ray is used to initialize the ray containers of the
- * light source ray.
- *
- * CHANGES
- *
- * Nov 1994 : Creation.
- *
- ******************************************************************************/
-
- int Test_Shadow(LIGHT_SOURCE *Light, DBL *Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR P, COLOUR Colour)
- {
- do_light(Light, Depth, Light_Source_Ray, Eye_Ray, P, Colour);
-
- /*
- * There's no need to test for shadows if no light
- * is coming from the light source.
- */
-
- if ((Colour[X] < BLACK_LEVEL) && (Colour[Y] < BLACK_LEVEL) && (Colour[Z] < BLACK_LEVEL))
- {
- return(TRUE);
- }
- else
- {
- /* Test for shadows. */
-
- if ((opts.Quality_Flags & Q_SHADOW) &&
- ((Light->Projected_Through_Object != NULL) || ((Light->Projected_Through_Object != NULL) || (Light->Light_Type != FILL_LIGHT_SOURCE))))
- {
- block_light_source(Light, *Depth, Light_Source_Ray, Eye_Ray, P, Colour);
-
- if ((Colour[X] < BLACK_LEVEL) && (Colour[Y] < BLACK_LEVEL) && (Colour[Z] < BLACK_LEVEL))
- {
- return(TRUE);
- }
- }
- }
-
- return(FALSE);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * block_point_light_LBuffer
- *
- * INPUT
- *
- * Light_Source - Light source to test
- *
- * OUTPUT
- *
- * Light_Source_Depth - (Remaining) distance to the light source
- * Light_Source_Ray - (Remaining) ray to the light source
- * Colour - Color reaching initial point from light source
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Determine how much light from the given light source arrives at the
- * given point (starting point of the light source ray). The light
- * is blocked by solid objects and/or attenuated by translucent objects.
- *
- * Note that both the distance to the light source and the light source
- * ray are modified. Thus after a call to this function one knows
- * how much distance remains to the light source and where the last
- * intersection point with a translucent object was (starting point
- * of light source ray after the call).
- *
- * This function uses the light buffer to speed up shadow calculation.
- *
- * CHANGES
- *
- * Jul 1994 : Creation.
- *
- ******************************************************************************/
-
- #ifdef MotionBlurPatch
- static void block_point_light_LBuffer_with_blur (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
- {
- COLOUR Colour2,ColourSum;
- DBL Light_Source_Depth2, DepthSum;
- RAY Light_Source_Ray2;
-
- if(TimeStamp || opts.motionBlurCount<=1)
- {
- block_point_light_LBuffer(Light_Source,Light_Source_Depth,Light_Source_Ray,Light_Colour);
- }
- else
- {
- Assign_Colour(Colour2,Light_Colour);
- Light_Source_Depth2 = *Light_Source_Depth;
- Light_Source_Ray2 = *Light_Source_Ray;
- block_point_light_LBuffer(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
-
-
- if(TimeStamp)
- {
- int tracedTimeStamp = TimeStamp;
-
- Assign_Colour(ColourSum,Colour2);
- DepthSum=Light_Source_Depth2;
-
- for (TimeStamp=1; TimeStamp<=opts.motionBlurCount; TimeStamp++)
- {
- if(TimeStamp!=tracedTimeStamp)
- {
- Assign_Colour(Colour2,Light_Colour);
- Light_Source_Depth2 = *Light_Source_Depth;
- Light_Source_Ray2 = *Light_Source_Ray;
- block_point_light_LBuffer(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
-
- DepthSum+=Light_Source_Depth2;
- Add_Colour(ColourSum,ColourSum,Colour2);
- }
- }
- Scale_Colour(Light_Colour,ColourSum,1.0/opts.motionBlurCount);
- *Light_Source_Depth=DepthSum/opts.motionBlurCount;
- }
- else
- {
- Assign_Colour(Light_Colour,Colour2);
- *Light_Source_Depth=Light_Source_Depth2;
- }
- TimeStamp = 0;
- }
- }
- #endif
-
- static void block_point_light_LBuffer(LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
- {
- int Quit_Looking, Not_Found_Shadow, Cache_Me;
- int u, v, axis;
- DBL ax, ay, az;
- VECTOR V1;
- OBJECT *Blocking_Object;
- ISTACK *Local_Stack;
- INTERSECTION *Local_Intersection, Bounded_Intersection, Temp_Intersection;
-
- /* Projected through main tests */
-
- DBL Projected_Depth=0.0;
-
- if (Light_Source->Projected_Through_Object != NULL){
- if (Intersection(&Temp_Intersection,
- Light_Source->Projected_Through_Object,Light_Source_Ray)){
- if ( (Temp_Intersection.Depth - *Light_Source_Depth) < 0.0 ){
- Projected_Depth =
- *Light_Source_Depth - fabs(Temp_Intersection.Depth) + Small_Tolerance;
- }else {
- Light_Colour[0] =
- Light_Colour[1] =
- Light_Colour[2] = 0.0;
- return;
- }
- }else {
- Light_Colour[0] =
- Light_Colour[1] =
- Light_Colour[2] = 0.0;
- return;
- }
- if(Light_Source->Light_Type == FILL_LIGHT_SOURCE) return;
- }
-
- Local_Stack = open_istack();
-
- Quit_Looking = FALSE;
-
- /* First test the cached object (don't cache semi-transparent objects). */
-
- if (Light_Source->Shadow_Cached_Object != NULL)
- {
- Increase_Counter(stats[Shadow_Ray_Tests]);
-
- if (Ray_In_Bound(Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
- {
- #ifdef MotionBlurPatch
- if (!TimeStamp ||
- !Light_Source->Shadow_Cached_Object->TimeStamp ||
- Light_Source->Shadow_Cached_Object->TimeStamp==TimeStamp)
- #endif
- if (All_Intersections(Light_Source->Shadow_Cached_Object, Light_Source_Ray, Local_Stack))
- {
- while ((Local_Intersection=pop_entry(Local_Stack)) != NULL)
- {
- if ((!Check_No_Shadow_Group(Local_Intersection->Object, Light_Source)) &&
- (Check_Light_Group(Local_Intersection->Object, Light_Source)) &&
- (Local_Intersection->Depth < *Light_Source_Depth-SHADOW_TOLERANCE) &&
- ((*Light_Source_Depth - Local_Intersection->Depth) > Projected_Depth) &&
- (Local_Intersection->Depth > SHADOW_TOLERANCE))
- {
- Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
- if (do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack))
- {
- Quit_Looking = TRUE;
-
- Increase_Counter(stats[Shadow_Cache_Hits]);
-
- break;
- }
- }
- }
- }
- }
-
- /* Exit if the cached object was hit. */
-
- if (Quit_Looking)
- {
- close_istack(Local_Stack);
-
- return;
- }
- }
-
- /*
- * Determine the side and the coordinates at which the ray
- * pierces the cube enclosing the light source.
- */
-
- V1[X] = -Light_Source_Ray->Direction[X];
- V1[Y] = -Light_Source_Ray->Direction[Y];
- V1[Z] = -Light_Source_Ray->Direction[Z];
-
- ax = fabs(V1[X]);
- ay = fabs(V1[Y]);
- az = fabs(V1[Z]);
-
- if ((ax>ay) && (ax>az))
- {
- if (V1[X]>0.0)
- {
- axis = XaxisP;
- }
- else
- {
- axis = XaxisM;
- }
-
- u = (int)(MAX_BUFFER_ENTRY * V1[Y]/ax);
- v = (int)(MAX_BUFFER_ENTRY * V1[Z]/ax);
- }
- else
- {
- if (ay>az)
- {
- if (V1[Y]>0.0)
- {
- axis = YaxisP;
- }
- else
- {
- axis = YaxisM;
- }
-
- u = (int)(MAX_BUFFER_ENTRY * V1[X]/ay);
- v = (int)(MAX_BUFFER_ENTRY * V1[Z]/ay);
- }
- else
- {
- if (V1[Z]>0.0)
- {
- axis = ZaxisP;
- }
- else
- {
- axis = ZaxisM;
- }
-
- u = (int)(MAX_BUFFER_ENTRY * V1[X]/az);
- v = (int)(MAX_BUFFER_ENTRY * V1[Y]/az);
- }
- }
-
- /* If there are no objects in the direction of the ray we can exit. */
-
- if (Light_Source->Light_Buffer[axis] == NULL)
- {
- close_istack(Local_Stack);
-
- return;
- }
-
- /* Look for shadows. */
-
- Not_Found_Shadow = TRUE;
-
- Cache_Me = FALSE;
-
- while (!Quit_Looking)
- {
- Increase_Counter(stats[Shadow_Ray_Tests]);
-
- Bounded_Intersection.Depth = *Light_Source_Depth;
-
- if (Intersect_Light_Tree(Light_Source_Ray, Light_Source->Light_Buffer[axis], u, v, &Bounded_Intersection, &Blocking_Object, Light_Source))
- {
- if (Bounded_Intersection.Depth > (*Light_Source_Depth - Projected_Depth) )
- {
- /* Intersection was beyond the light. */
-
- break;
- }
-
- if (Blocking_Object != Light_Source->Shadow_Cached_Object)
- {
- Increase_Counter(stats[Shadow_Rays_Succeeded]);
-
- Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
-
- filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
-
- if ((fabs(Light_Colour[RED]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[BLUE]) < BLACK_LEVEL) &&
- (Test_Flag(Blocking_Object, OPAQUE_FLAG)))
- {
- Cache_Me = Not_Found_Shadow;
-
- break; /* from while */
- }
- }
-
- /* Move the ray to the point of intersection, plus some */
-
- *Light_Source_Depth -= Bounded_Intersection.Depth;
-
- Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
-
- Not_Found_Shadow = FALSE;
- }
- else
- {
- /* No intersections in the direction of the ray. */
-
- break;
- }
- }
-
- if (Cache_Me)
- {
- Light_Source->Shadow_Cached_Object = Blocking_Object;
- }
-
- close_istack(Local_Stack);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * block_point_light
- *
- * INPUT
- *
- * Light_Source - Light source to test
- * Eye_Ray - Current viewing ray
- *
- * OUTPUT
- *
- * Light_Source_Depth - (Remaining) distance to the light source
- * Light_Source_Ray - (Remaining) ray to the light source
- * Colour - Color reaching initial point from light source
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * See block_point_light_LBuffer for a description.
- *
- * This function uses the hierarchical bounding box volume to
- * speed up shadow testing.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- #ifdef MotionBlurPatch
- static void block_point_light_with_blur (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
- {
- COLOUR Colour2,ColourSum;
- DBL Light_Source_Depth2, DepthSum;
- RAY Light_Source_Ray2;
-
- if(TimeStamp)
- {
- block_point_light(Light_Source,Light_Source_Depth,Light_Source_Ray,Light_Colour);
- }
- else
- {
- Assign_Colour(Colour2,Light_Colour);
- Light_Source_Depth2 = *Light_Source_Depth;
- Light_Source_Ray2 = *Light_Source_Ray;
- block_point_light(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
-
-
- if(TimeStamp)
- {
- int tracedTimeStamp = TimeStamp;
-
- Assign_Colour(ColourSum,Colour2);
- DepthSum=Light_Source_Depth2;
-
- for (TimeStamp=1; TimeStamp<=opts.motionBlurCount; TimeStamp++)
- {
- if(TimeStamp!=tracedTimeStamp)
- {
- Assign_Colour(Colour2,Light_Colour);
- Light_Source_Depth2 = *Light_Source_Depth;
- Light_Source_Ray2 = *Light_Source_Ray;
- block_point_light(Light_Source,&Light_Source_Depth2,&Light_Source_Ray2,Colour2);
-
- DepthSum+=Light_Source_Depth2;
- Add_Colour(ColourSum,ColourSum,Colour2);
- }
- }
- Scale_Colour(Light_Colour,ColourSum,1.0/opts.motionBlurCount);
- *Light_Source_Depth=DepthSum/opts.motionBlurCount;
- }
- else
- {
- Assign_Colour(Light_Colour,Colour2);
- *Light_Source_Depth=Light_Source_Depth2;
- }
- TimeStamp = 0;
- }
- }
- #endif
-
- static void block_point_light (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, COLOUR Light_Colour)
- {
- OBJECT *Blocking_Object;
- int Quit_Looking, Not_Found_Shadow, Cache_Me, Maybe_Found;
- INTERSECTION *Local_Intersection, Bounded_Intersection, Temp_Intersection;
- ISTACK *Local_Stack;
-
- /* Projected through main tests */
-
- DBL Projected_Depth=0.0;
-
- if (Light_Source->Projected_Through_Object != NULL){
- if (Intersection(&Temp_Intersection,
- Light_Source->Projected_Through_Object,Light_Source_Ray)){
- if ( (Temp_Intersection.Depth - *Light_Source_Depth) < 0.0 ){
- Projected_Depth =
- *Light_Source_Depth - fabs(Temp_Intersection.Depth) + Small_Tolerance;
- }else {
- Light_Colour[0] =
- Light_Colour[1] =
- Light_Colour[2] = 0.0;
- return;
- }
- }else {
- Light_Colour[0] =
- Light_Colour[1] =
- Light_Colour[2] = 0.0;
- return;
- }
- if(Light_Source->Light_Type == FILL_LIGHT_SOURCE) return;
- }
-
- Local_Stack = open_istack ();
-
- Quit_Looking = FALSE;
-
- /* First test the cached object (don't cache semi-transparent objects). */
-
- if (Light_Source->Shadow_Cached_Object != NULL)
- {
- Increase_Counter(stats[Shadow_Ray_Tests]);
-
- if (Ray_In_Bound(Light_Source_Ray, Light_Source->Shadow_Cached_Object->Bound))
- {
- #ifdef MotionBlurPatch
- if (!TimeStamp ||
- !Light_Source->Shadow_Cached_Object->TimeStamp ||
- Light_Source->Shadow_Cached_Object->TimeStamp==TimeStamp)
- #endif
- if (All_Intersections(Light_Source->Shadow_Cached_Object, Light_Source_Ray, Local_Stack))
- {
- while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
- {
- if ((!Check_No_Shadow_Group(Local_Intersection->Object, Light_Source)) &&
- (Check_Light_Group(Local_Intersection->Object, Light_Source)) &&
- (Local_Intersection->Depth < *Light_Source_Depth-SHADOW_TOLERANCE) &&
- ((*Light_Source_Depth - Local_Intersection->Depth) > Projected_Depth) &&
- (Local_Intersection->Depth > SHADOW_TOLERANCE))
- {
- Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
- if (do_blocking(Local_Intersection, Light_Source_Ray, Light_Colour, Local_Stack))
- {
- Quit_Looking = TRUE;
-
- Increase_Counter(stats[Shadow_Cache_Hits]);
-
- break;
- }
- }
- }
- }
- }
-
- if (Quit_Looking)
- {
- close_istack (Local_Stack);
-
- return;
- }
- }
-
- /* Look for shadows. */
-
- Not_Found_Shadow = TRUE;
-
- Cache_Me = FALSE;
-
- if (!opts.Use_Slabs)
- {
- while (!Quit_Looking)
- {
- /* Use brute force method to get shadows. */
-
- Maybe_Found = FALSE;
-
- Bounded_Intersection.Depth = *Light_Source_Depth - Projected_Depth;
-
- for (Blocking_Object = Frame.Objects; Blocking_Object != NULL; Blocking_Object = Blocking_Object->Sibling)
- {
- if (Blocking_Object != Light_Source->Shadow_Cached_Object)
- {
- if (!Check_No_Shadow_Group(Blocking_Object, Light_Source) &&
- (Check_Light_Group(Blocking_Object, Light_Source)))
- {
- Increase_Counter(stats[Shadow_Ray_Tests]);
-
- if (Intersection(&Temp_Intersection, Blocking_Object, Light_Source_Ray))
- {
- if (Temp_Intersection.Depth < Bounded_Intersection.Depth)
- {
- Maybe_Found = TRUE;
-
- Bounded_Intersection = Temp_Intersection;
- }
- }
- }
- }
- }
-
- if (Maybe_Found)
- {
- Increase_Counter(stats[Shadow_Rays_Succeeded]);
-
- Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
-
- filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
-
- if ((fabs(Light_Colour[RED]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[BLUE]) < BLACK_LEVEL) &&
- (Test_Flag(Bounded_Intersection.Object, OPAQUE_FLAG)))
- {
- Cache_Me = Not_Found_Shadow;
-
- break;
- }
-
- /* Move the ray to the point of intersection, plus some */
-
- *Light_Source_Depth -= Bounded_Intersection.Depth;
-
- Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
-
- Not_Found_Shadow = FALSE;
- }
- else
- {
- /* No intersections in the direction of the ray. */
-
- break;
- }
- }
- }
- else
- {
- /* Use bounding slabs to look for shadows. */
- #ifdef NoImageNoReflectionPatch
- /* JG start */
- In_Shadow_Ray = TRUE;
- /* JG end */
- #endif
- while (!Quit_Looking)
- {
- Increase_Counter(stats[Shadow_Ray_Tests]);
-
- Bounded_Intersection.Depth = *Light_Source_Depth;
-
- if (Intersect_BBox_Tree(Root_Object, Light_Source_Ray, &Bounded_Intersection, &Blocking_Object))
- {
- if (Bounded_Intersection.Depth > (*Light_Source_Depth - Projected_Depth))
- {
- /* Intersection was beyond the light. */
-
- break;
- }
-
- if (!Check_No_Shadow_Group(Bounded_Intersection.Object, Light_Source) &&
- (Check_Light_Group(Bounded_Intersection.Object, Light_Source)) )
- {
- if (Blocking_Object != Light_Source->Shadow_Cached_Object)
- {
- Increase_Counter(stats[Shadow_Rays_Succeeded]);
-
- Set_Media_Light(Light_Source); /* Needed to test Light group against medias */
-
- filter_shadow_ray(&Bounded_Intersection, Light_Source_Ray, Light_Colour);
-
- if ((fabs(Light_Colour[RED]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[BLUE]) < BLACK_LEVEL) &&
- (Test_Flag(Blocking_Object, OPAQUE_FLAG)))
- {
- Cache_Me = Not_Found_Shadow;
-
- break; /* from while */
- }
- }
- }
-
- /* Move the ray to the point of intersection, plus some */
-
- *Light_Source_Depth -= Bounded_Intersection.Depth;
-
- Assign_Vector(Light_Source_Ray->Initial, Bounded_Intersection.IPoint);
-
- Not_Found_Shadow = FALSE;
- }
- else
- {
- /* No intersections in the direction of the ray */
-
- break;
- }
- }
- #ifdef NoImageNoReflectionPatch
- /* JG start */
- In_Shadow_Ray = FALSE;
- /* JG end */
- #endif
- }
-
- if (Cache_Me)
- {
- Light_Source->Shadow_Cached_Object = Blocking_Object;
- }
-
- close_istack (Local_Stack);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * block_area_light
- *
- * INPUT
- *
- * Light_Source - Light source to test
- * IPoint -
- * u1, v1, u2, v2 -
- * Level -
- *
- * OUTPUT
- *
- * Light_Source_Depth - (Remaining) distance to the light source
- * Light_Source_Ray - (Remaining) ray to the light source
- * Light_Colour - Color reaching initial point from light source
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Get shadow for given area light source by recursively sampling
- * on the light source area.
- *
- * The viewing ray is used to initialize the ray containers of the
- * light source ray.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
- #ifdef FastArealight
- static void do_light_area_light(LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR IPoint);
- static void do_light_area_light(LIGHT_SOURCE* Light_Source, DBL* Light_Source_Depth, RAY* Light_Source_Ray, RAY* Eye_Ray, VECTOR IPoint)
- {
- DBL a;
- VECTOR v1;
- /*
- * Get the light ray starting at the intersection point and pointing
- * towards the light source.
- */
-
- Assign_Vector(Light_Source_Ray->Initial, IPoint);
-
- /* NK 1998 parallel beams for cylinder source - added 'if' */
- if (Light_Source->Light_Type == CYLINDER_SOURCE)
- {
- DBL distToPointsAt;
- VECTOR toLightCtr;
-
- /* use new code to get ray direction - use center - points_at for direction */
- VSub(Light_Source_Ray->Direction, Light_Source->Center, Light_Source->Points_At);
-
- /* get vector pointing to center of light */
- VSub(toLightCtr, Light_Source->Center, IPoint);
-
- /* project light_ctr-intersect_point onto light_ctr-point_at*/
- VLength(distToPointsAt, Light_Source_Ray->Direction);
- VDot(*Light_Source_Depth, toLightCtr, Light_Source_Ray->Direction);
-
- /* lenght of shadow ray is the length of the projection */
- *Light_Source_Depth /= distToPointsAt;
-
- VNormalizeEq(Light_Source_Ray->Direction);
- }
- else
- {
- /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
- block used to be all that there was... the first half of the if
- statement (before the 'else') is new
- */
- VSub(Light_Source_Ray->Direction, Light_Source->Center, IPoint);
- VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
- VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
- }
-
- /* Attenuate light source color. */
-
- /* Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);*/
-
- /* Recalculate for Parallel light sources */
- if (Light_Source->Parallel)
- {
- if (Light_Source->Area_Light)
- {
- VSub(v1, Light_Source->Center, Light_Source->Points_At);
- VNormalizeEq(v1);
- VDot(a, v1, Light_Source_Ray->Direction);
- *Light_Source_Depth *= a;
- Assign_Vector(Light_Source_Ray->Direction, v1);
- }
- else
- {
- VDot(a, Light_Source->Direction, Light_Source_Ray->Direction);
- *Light_Source_Depth *= (-a);
- Assign_Vector(Light_Source_Ray->Direction, Light_Source->Direction);
- VScaleEq(Light_Source_Ray->Direction, -1.0);
- }
- }
- Light_Source_Ray->Index = - 1;
- {
- register int i;
- if ((Light_Source_Ray->Index = Eye_Ray->Index) >= MAX_CONTAINING_OBJECTS)
- Error("ERROR - Containing Index too high.\n");
- for (i = 0 ; i <= Eye_Ray->Index; i++)
- Light_Source_Ray->Interiors[i] = Eye_Ray->Interiors[i];
- }
- }
-
- #endif
- /*YS april 2000
- In the function block_area_light() the function do_light() is called a few times.
- Do_light() uses a parameter 'COLOUR Light_Colour', that is the last one.
- Now, block_area_light() is sending dummy_colour simply because block_area_light()
- doesn't need that one.
- All very well but do_light() is initialising that parameter.
- That's not the end of the story: do_light() calls Attenuate_light() and the result of that
- function is only used to mess with light_colour again. And we do not need that one! Just think
- of the code we throw away now.
- To make it even better, the stripped down version of do_light can be merged directly in
- block_area_light because the parameters are all variables themselves. Not much waste
- of registers (at assembly level) but eliminating lots of subroutine calls. */
-
- static void block_area_light (LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth,
- RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR IPoint, COLOUR Light_Colour, int u1, int v1, int u2, int v2, int Level)
- {
- COLOUR Sample_Colour[4];
- #ifndef FastArealight
- COLOUR Dummy_Colour;
- #endif
- #ifdef CircularOrientAreaLightPatch
- VECTOR Axis1_Save, Axis2_Save, Temp;
- #endif
- VECTOR Center_Save, NewAxis1, NewAxis2;
- int i, j, u, v, New_u1, New_v1, New_u2, New_v2;
- #ifdef CircularOrientAreaLightPatch
- DBL Axis1_Length, Axis2_Length;
- unsigned char First_Call=FALSE;
- #endif
-
- DBL Jitter_u, Jitter_v, ScaleFactor;
-
- /* First call, initialize */
-
- if ((u1 == 0) && (v1 == 0) && (u2 == 0) && (v2 == 0))
- {
- #ifdef CircularOrientAreaLightPatch
- First_Call = TRUE;
- #endif
- /* Flag uncalculated points with a negative value for Red */
-
- for (i = 0; i < Light_Source->Area_Size1; i++)
- {
- for (j = 0; j < Light_Source->Area_Size2; j++)
- {
- Light_Source->Light_Grid[i][j][RED] = -1.0;
- }
- }
-
- u1 = 0;
- v1 = 0;
- u2 = Light_Source->Area_Size1 - 1;
- v2 = Light_Source->Area_Size2 - 1;
- #ifdef CircularOrientAreaLightPatch
-
- /* Save the axis vectors since we may be changing them */
- if ( Light_Source->CircularOrient)
- {
- Assign_Vector(Axis1_Save,Light_Source->Axis1);
- Assign_Vector(Axis2_Save,Light_Source->Axis2);
- }
- /* Orient the area light to face the intersection point [ENB 9/97] */
- if (Light_Source->Orient == TRUE)
- {
- /* Do Light source to get the correct Light_Source_Ray */
- #ifndef FastArealight
- do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
- #else
- do_light_area_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint);
- #endif
- VScaleEq(Light_Source_Ray->Direction,-1);
-
- /* Save the lengths of the axises */
- VLength(Axis1_Length, Light_Source->Axis1);
- VLength(Axis2_Length, Light_Source->Axis2);
-
- /* Make axis 1 be perpendicular with the light-ray
- Done by setting temp to the normal of the axis-ray plane
- and then setting axis to the normal of the ray-temp plane.
- This makes the axis perpendicular with the light-ray
- */
- VScaleEq(Light_Source->Axis1,1/Axis1_Length);
- VCross(Temp,Light_Source->Axis1,Light_Source_Ray->Direction);
- VCross(Light_Source->Axis1,Light_Source_Ray->Direction,Temp);
- VNormalizeEq(Light_Source->Axis1);
- VScaleEq(Light_Source->Axis1,Axis1_Length);
-
- /* Make axis 2 be perpendicular with the light-ray */
- VScaleEq(Light_Source->Axis2,1/Axis2_Length);
- VCross(Temp,Light_Source->Axis2,Light_Source_Ray->Direction);
- VCross(Light_Source->Axis2,Light_Source_Ray->Direction,Temp);
- VNormalizeEq(Light_Source->Axis2);
- VScaleEq(Light_Source->Axis2,Axis1_Length);
-
- VScaleEq(Light_Source_Ray->Direction,-1);
- }
-
- /* Make sure that circular light sources are larger than 1 by x [ENB 9/97] */
- if (Light_Source->Orient == TRUE)
- if ((Light_Source->Area_Size1 <= 1) || (Light_Source->Area_Size2 <= 1))
- Light_Source->Orient = FALSE;
- #endif
- }
-
- /* Save the light source center since we'll be fiddling with it */
-
- Assign_Vector(Center_Save,Light_Source->Center);
-
- /* Sample the four corners of the region */
-
- for (i = 0; i < 4; i++)
- {
- switch (i)
- {
- case 0: u = u1; v = v1; break;
- case 1: u = u2; v = v1; break;
- case 2: u = u1; v = v2; break;
- case 3: u = u2; v = v2; break;
- default: u = v = 0; /* Should never happen! */
- }
-
- if (Light_Source->Light_Grid[u][v][RED] >= 0.0)
- {
- /* We've already calculated this point, reuse it */
-
- Assign_Colour(Sample_Colour[i],Light_Source->Light_Grid[u][v]);
- }
- else
- {
- Jitter_u = (DBL)u;
- Jitter_v = (DBL)v;
-
- if (Light_Source->Jitter)
- {
- Jitter_u += FRAND() - 0.5;
- Jitter_v += FRAND() - 0.5;
- }
-
- #ifdef CircularOrientAreaLightPatch
- /* Create circular are lights [ENB 9/97]
- First, make Jitter_u and Jitter_v be numbers from -1 to 1
- Second, set ScaleFactor to the abs max (Jitter_u,Jitter_v) (for shells)
- Third, divide ScaleFactor by the length of <Jitter_u,Jitter_v>
- Fourth, scale Jitter_u & Jitter_v by ScaleFactor
- Finally scale Axis1 by Jitter_u & Axis2 by Jitter_v
- */
- if (Light_Source->Circular == TRUE)
- {
- Jitter_u = Jitter_u / (Light_Source->Area_Size1 - 1) - 0.5 + 0.001;
- Jitter_v = Jitter_v / (Light_Source->Area_Size2 - 1) - 0.5 + 0.001;
- ScaleFactor = ((fabs(Jitter_u) > fabs(Jitter_v)) ? fabs(Jitter_u) : fabs(Jitter_v));
- ScaleFactor /= sqrt(Jitter_u * Jitter_u + Jitter_v * Jitter_v);
- Jitter_u *= ScaleFactor;
- Jitter_v *= ScaleFactor;
- VScale (NewAxis1, Light_Source->Axis1, Jitter_u);
- VScale (NewAxis2, Light_Source->Axis2, Jitter_v);
- }
- else
- {
- #endif
- if (Light_Source->Area_Size1 > 1)
- {
- ScaleFactor = Jitter_u/(DBL)(Light_Source->Area_Size1 - 1) - 0.5;
-
- VScale (NewAxis1, Light_Source->Axis1, ScaleFactor)
- }
- else
- {
- Make_Vector(NewAxis1, 0.0, 0.0, 0.0);
- }
-
- if (Light_Source->Area_Size2 > 1)
- {
- ScaleFactor = Jitter_v/(DBL)(Light_Source->Area_Size2 - 1) - 0.5;
-
- VScale (NewAxis2, Light_Source->Axis2, ScaleFactor)
- }
- else
- {
- Make_Vector(NewAxis2, 0.0, 0.0, 0.0);
- }
- #ifdef CircularOrientAreaLightPatch
- }
-
- /* Find the center of the light to test */
- #endif
- Assign_Vector(Light_Source->Center, Center_Save);
-
- VAddEq(Light_Source->Center, NewAxis1);
- VAddEq(Light_Source->Center, NewAxis2);
-
- /* Recalculate the light source ray but not the colour */
-
- #ifndef FastArealight
- do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
- #else
- {
- DBL a;
- VECTOR v1;
- /* Get the light ray starting at the intersection point and pointing
- * towards the light source. */
- Assign_Vector(Light_Source_Ray->Initial, IPoint);
- /* NK 1998 parallel beams for cylinder source - added 'if' */
- if (Light_Source->Light_Type == CYLINDER_SOURCE)
- {
- DBL distToPointsAt;
- VECTOR toLightCtr;
- /* use new code to get ray direction - use center - points_at for direction */
- VSub(Light_Source_Ray->Direction, Light_Source->Center, Light_Source->Points_At);
- /* get vector pointing to center of light */
- VSub(toLightCtr, Light_Source->Center, IPoint);
- /* project light_ctr-intersect_point onto light_ctr-point_at*/
- VLength(distToPointsAt, Light_Source_Ray->Direction);
- VDot(*Light_Source_Depth, toLightCtr, Light_Source_Ray->Direction);
- /* lenght of shadow ray is the length of the projection */
- *Light_Source_Depth /= distToPointsAt;
- VNormalizeEq(Light_Source_Ray->Direction);
- }
- else
- {
- /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
- block used to be all that there was... the first half of the if
- statement (before the 'else') is new */
- VSub(Light_Source_Ray->Direction, Light_Source->Center, IPoint);
- VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
- VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
- }
- /* Attenuate light source color. */
- /* Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);*/
- /* Recalculate for Parallel light sources */
- if (Light_Source->Parallel)
- {
- if (Light_Source->Area_Light)
- {
- VSub(v1, Light_Source->Center, Light_Source->Points_At);
- VNormalizeEq(v1);
- VDot(a, v1, Light_Source_Ray->Direction);
- *Light_Source_Depth *= a;
- Assign_Vector(Light_Source_Ray->Direction, v1);
- }
- else
- {
- VDot(a, Light_Source->Direction, Light_Source_Ray->Direction);
- *Light_Source_Depth *= (-a);
- Assign_Vector(Light_Source_Ray->Direction, Light_Source->Direction);
- VScaleEq(Light_Source_Ray->Direction, -1.0);
- }
- }
- Light_Source_Ray->Index = - 1;
- {
- register int i;
- if ((Light_Source_Ray->Index = Eye_Ray->Index) >= MAX_CONTAINING_OBJECTS)
- Error("ERROR - Containing Index too high.\n");
- for (i = 0 ; i <= Eye_Ray->Index; i++)
- Light_Source_Ray->Interiors[i] = Eye_Ray->Interiors[i];
- }
- }
- #endif
-
- Assign_Colour(Sample_Colour[i], Light_Colour);
-
- #ifdef CircularOrientAreaLightPatch
- /* Calculate the color coming from the corners */
- #endif
- #ifdef MotionBlurPatch
- block_point_light_with_blur(Light_Source, Light_Source_Depth, Light_Source_Ray, Sample_Colour[i]);
- #else
- block_point_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Sample_Colour[i]);
- #endif
-
- Assign_Colour(Light_Source->Light_Grid[u][v], Sample_Colour[i]);
- }
- }
-
- Assign_Vector(Light_Source->Center,Center_Save);
-
- #ifdef CircularOrientAreaLightPatch
- /* Get colors for lights between the corners */
- #endif
- if ((u2 - u1 > 1) || (v2 - v1 > 1))
- {
- if ((Level < Light_Source->Adaptive_Level) ||
- (Colour_Distance(Sample_Colour[0], Sample_Colour[1]) > 0.1) ||
- (Colour_Distance(Sample_Colour[1], Sample_Colour[3]) > 0.1) ||
- (Colour_Distance(Sample_Colour[3], Sample_Colour[2]) > 0.1) ||
- (Colour_Distance(Sample_Colour[2], Sample_Colour[0]) > 0.1))
- {
- for (i = 0; i < 4; i++)
- {
- switch (i)
- {
- case 0:
-
- New_u1 = u1;
- New_v1 = v1;
- New_u2 = (int)floor ((u1 + u2)/2.0);
- New_v2 = (int)floor ((v1 + v2)/2.0);
-
- break;
-
- case 1:
-
- New_u1 = (int)ceil ((u1 + u2)/2.0);
- New_v1 = v1;
- New_u2 = u2;
- New_v2 = (int)floor ((v1 + v2)/2.0);
-
- break;
-
- case 2:
-
- New_u1 = u1;
- New_v1 = (int)ceil ((v1 + v2)/2.0);
- New_u2 = (int)floor ((u1 + u2)/2.0);
- New_v2 = v2;
-
- break;
-
- case 3:
-
- New_u1 = (int)ceil ((u1 + u2)/2.0);
- New_v1 = (int)ceil ((v1 + v2)/2.0);
- New_u2 = u2;
- New_v2 = v2;
-
- break;
-
- default: /* Should never happen! */
-
- New_u1 = New_u2 = New_v1 = New_v2 = 0;
- }
-
- /* Recalculate the light source ray but not the colour */
-
- #ifndef FastArealight
- do_light(Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray, IPoint, Dummy_Colour);
- #else
- {
- DBL a;
- VECTOR v1;
- /* Get the light ray starting at the intersection point and pointing
- * towards the light source. */
- Assign_Vector(Light_Source_Ray->Initial, IPoint);
- /* NK 1998 parallel beams for cylinder source - added 'if' */
- if (Light_Source->Light_Type == CYLINDER_SOURCE)
- {
- DBL distToPointsAt;
- VECTOR toLightCtr;
- /* use new code to get ray direction - use center - points_at for direction */
- VSub(Light_Source_Ray->Direction, Light_Source->Center, Light_Source->Points_At);
- /* get vector pointing to center of light */
- VSub(toLightCtr, Light_Source->Center, IPoint);
- /* project light_ctr-intersect_point onto light_ctr-point_at*/
- VLength(distToPointsAt, Light_Source_Ray->Direction);
- VDot(*Light_Source_Depth, toLightCtr, Light_Source_Ray->Direction);
- /* lenght of shadow ray is the length of the projection */
- *Light_Source_Depth /= distToPointsAt;
- VNormalizeEq(Light_Source_Ray->Direction);
- }
- else
- {
- /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
- block used to be all that there was... the first half of the if
- statement (before the 'else') is new */
- VSub(Light_Source_Ray->Direction, Light_Source->Center, IPoint);
- VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
- VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
- }
- /* Attenuate light source color. */
- /* Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);*/
- /* Recalculate for Parallel light sources */
- if (Light_Source->Parallel)
- {
- if (Light_Source->Area_Light)
- {
- VSub(v1, Light_Source->Center, Light_Source->Points_At);
- VNormalizeEq(v1);
- VDot(a, v1, Light_Source_Ray->Direction);
- *Light_Source_Depth *= a;
- Assign_Vector(Light_Source_Ray->Direction, v1);
- }
- else
- {
- VDot(a, Light_Source->Direction, Light_Source_Ray->Direction);
- *Light_Source_Depth *= (-a);
- Assign_Vector(Light_Source_Ray->Direction, Light_Source->Direction);
- VScaleEq(Light_Source_Ray->Direction, -1.0);
- }
- }
- Light_Source_Ray->Index = - 1;
- {
- register int i;
- if ((Light_Source_Ray->Index = Eye_Ray->Index) >= MAX_CONTAINING_OBJECTS)
- Error("ERROR - Containing Index too high.\n");
- for (i = 0 ; i <= Eye_Ray->Index; i++)
- Light_Source_Ray->Interiors[i] = Eye_Ray->Interiors[i];
- }
- }
- #endif
-
- Assign_Colour(Sample_Colour[i],Light_Colour);
-
- #ifdef CircularOrientAreaLightPatch
- /* Calculate the color of the area section (recursive part) */
- #endif
- block_area_light (Light_Source, Light_Source_Depth, Light_Source_Ray, Eye_Ray,
- IPoint, Sample_Colour[i], New_u1, New_v1, New_u2, New_v2, Level+1);
- }
- }
- }
-
- /* Add up the light contributions */
- #ifndef FastArealight
- Make_Colour (Light_Colour, 0.0, 0.0, 0.0);
- for (i = 0; i < 4; i++)
- {
- Scale_Colour (Sample_Colour[i], Sample_Colour[i], 0.25);
- Add_Colour (Light_Colour, Light_Colour, Sample_Colour[i]);
- }
- #else
- Light_Colour[RED] = Sample_Colour[0][RED] * 0.25;
- Light_Colour[GREEN] = Sample_Colour[0][GREEN] * 0.25;
- Light_Colour[BLUE] = Sample_Colour[0][BLUE] * 0.25;
- Light_Colour[FILTER] += Sample_Colour[0][FILTER] * 0.25;
- Light_Colour[TRANSM] += Sample_Colour[0][TRANSM] * 0.25;
- for (i = 1; i < 4; i++)
- {
- Light_Colour[RED] += Sample_Colour[i][RED] * 0.25;
- Light_Colour[GREEN] += Sample_Colour[i][GREEN] * 0.25;
- Light_Colour[BLUE] += Sample_Colour[i][BLUE] * 0.25;
- Light_Colour[FILTER] += Sample_Colour[i][FILTER] * 0.25;
- Light_Colour[TRANSM] += Sample_Colour[i][TRANSM] * 0.25;
- }
-
- #endif
- #ifdef CircularOrientAreaLightPatch
- if (First_Call == TRUE)
- {
- /* Reset the axises to what they were before */
- if ( Light_Source->CircularOrient)
- {
- Assign_Vector(Light_Source->Axis1,Axis1_Save);
- Assign_Vector(Light_Source->Axis2,Axis2_Save);
- }
- }
- #endif
- }
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_light
- *
- * INPUT
- *
- * Light_Source - Light source
- * Light_Source_Depth - Distance from surface to light source
- * Light_Source_Ray - Ray from surface to light source
- * Eye_Ray - Current viewing ray
- * IPoint - Intersection point in surface
- * Colour - Light's colour
- *
- * OUTPUT
- *
- * Light_Source_Depth, Light_Source_Ray, Colour
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * The viewing ray is used to initialize the ray containers of the
- * light source ray.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void do_light(LIGHT_SOURCE *Light_Source, DBL *Light_Source_Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR IPoint, COLOUR Light_Colour)
- {
- DBL Attenuation,a;
- VECTOR v1;
-
- /* Get the light source colour. */
-
- Assign_Colour(Light_Colour, Light_Source->Colour);
-
- /*
- * Get the light ray starting at the intersection point and pointing
- * towards the light source.
- */
-
- Assign_Vector(Light_Source_Ray->Initial, IPoint);
-
- /* NK 1998 parallel beams for cylinder source - added 'if' */
- if (Light_Source->Light_Type == CYLINDER_SOURCE)
- {
- DBL distToPointsAt;
- VECTOR toLightCtr;
-
- /* use new code to get ray direction - use center - points_at for direction */
- VSub(Light_Source_Ray->Direction,Light_Source->Center, Light_Source->Points_At);
-
- /* get vector pointing to center of light */
- VSub(toLightCtr,Light_Source->Center, IPoint);
-
- /* project light_ctr-intersect_point onto light_ctr-point_at*/
- VLength(distToPointsAt, Light_Source_Ray->Direction);
- VDot(*Light_Source_Depth,toLightCtr, Light_Source_Ray->Direction);
-
- /* lenght of shadow ray is the length of the projection */
- *Light_Source_Depth /= distToPointsAt;
-
- VNormalizeEq(Light_Source_Ray->Direction);
- }
- else
- {
- /* NK 1998 parallel beams for cylinder source - the stuff in this 'else'
- block used to be all that there was... the first half of the if
- statement (before the 'else') is new
- */
- VSub(Light_Source_Ray->Direction,Light_Source->Center, IPoint);
-
- VLength(*Light_Source_Depth, Light_Source_Ray->Direction);
-
- VInverseScaleEq(Light_Source_Ray->Direction, *Light_Source_Depth);
- }
-
- /* Attenuate light source color. */
-
- Attenuation = Attenuate_Light(Light_Source, Light_Source_Ray, *Light_Source_Depth);
-
- /* Recalculate for Parallel light sources */
- if (Light_Source->Parallel) {
- if (Light_Source->Area_Light) {
- VSub(v1,Light_Source->Center,Light_Source->Points_At);
- VNormalizeEq( v1 );
- VDot(a,v1,Light_Source_Ray->Direction);
- *Light_Source_Depth *= a;
- Assign_Vector(Light_Source_Ray->Direction,v1);
- } else {
- VDot(a,Light_Source->Direction,Light_Source_Ray->Direction);
- *Light_Source_Depth *= (-a);
- Assign_Vector(Light_Source_Ray->Direction,Light_Source->Direction);
- VScaleEq(Light_Source_Ray->Direction,-1.0);
- }
- }
-
- /* Now scale the color by the attenuation */
-
- VScaleEq(Light_Colour, Attenuation);
-
- /* Init ray containers. */
-
- Initialize_Ray_Containers(Light_Source_Ray);
-
- Copy_Ray_Containers(Light_Source_Ray, Eye_Ray);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_diffuse
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Calculate the diffuse color component I_d given by:
- *
- * I_d = a * d * I * C * (N . L) ^ b
- *
- * where d : surface's diffuse reflection coefficient
- * b : surface's brilliance
- * C : surface's color
- * N : surface's normal vector
- * L : light vector (pointing at the light)
- * I : intensity of the incoming light
- * a : attenuation factor
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void do_diffuse(FINISH *Finish, RAY *Light_Source_Ray, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour, COLOUR Layer_Pigment_Colour, DBL Attenuation)
- {
- DBL Cos_Angle_Of_Incidence, Intensity;
-
- VDot(Cos_Angle_Of_Incidence, Layer_Normal, Light_Source_Ray->Direction);
-
- /* Brilliance is likely to be 1.0 (default value) */
-
- if (Finish->Brilliance != 1.0)
- {
- Intensity = pow(fabs(Cos_Angle_Of_Incidence), Finish->Brilliance);
- }
- else
- {
- Intensity = fabs(Cos_Angle_Of_Incidence);
- }
-
- Intensity *= Finish->Diffuse * Attenuation;
-
- if (Finish->Crand > 0.0)
- {
- Intensity -= FRAND() * Finish->Crand;
- }
-
- Colour[RED] += Intensity * Layer_Pigment_Colour[RED] * Light_Colour[RED];
- Colour[GREEN] += Intensity * Layer_Pigment_Colour[GREEN] * Light_Colour[GREEN];
- Colour[BLUE] += Intensity * Layer_Pigment_Colour[BLUE] * Light_Colour[BLUE];
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_irid
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dan Farmer
- *
- * DESCRIPTION
- *
- * IRIDESCENCE:
- * -----------
- * Programmed by Dan Farmer.
- *
- * Based on Chapter 10.2.4 of Three-Dimensional Computer Graphics
- * by Alan Watt.
- *
- * Modulates the diffuse coefficients as a function of wavelength, the angle
- * between the light direction vector, and the surface normal. It models
- * thin-film interference, as in a soap bubble or oilslick.
- *
- * Wavelength at which cancellation offurs is a function of the refractive
- * index of the film, its thickness, and the angle of incidence of the
- * incoming light. In this implementation, IOR is kept constant, while the
- * thickness of the film is specified, as well as being modulated with a
- * turbulence function.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void do_irid(FINISH *Finish, RAY *Light_Source_Ray, VECTOR Layer_Normal, VECTOR IPoint, COLOUR Colour)
- {
- DBL rwl, gwl, bwl;
- DBL Cos_Angle_Of_Incidence, interference;
- DBL film_thickness;
- DBL noise, intensity;
- TURB Turb;
-
- film_thickness = Finish->Irid_Film_Thickness;
-
- if (Finish->Irid_Turb != 0)
- {
- /* Uses hardcoded octaves, lambda, omega */
- Turb.Omega=0.5;
- Turb.Lambda=2.0;
- Turb.Octaves=5;
-
- noise = Turbulence(IPoint, &Turb) * Finish->Irid_Turb;
-
- film_thickness *= noise;
- }
-
- /*
- * Approximate dominant wavelengths of primary hues.
- * Source: 3D Computer Graphics by John Vince (Addison Wesely)
- * These are initialized in parse.c (Parse_Frame)
- * and are user-adjustable with the irid_wavelength keyword.
- * Red = 700 nm Grn = 520 nm Blu = 480 nm
- * Divided by 100 gives: rwl = 0.70; gwl = 0.52; bwl = 0.48;
- *
- * However... I originally "guessed" at the values and came up with
- * the following, which I'm using as the defaults, since it seems
- * to work better: rwl = 0.25; gwl = 0.18; bwl = 0.14;
- */
-
- /* Could avoid these assignments if we want to */
-
- rwl = Frame.Irid_Wavelengths[RED];
- gwl = Frame.Irid_Wavelengths[GREEN];
- bwl = Frame.Irid_Wavelengths[BLUE];
-
- /* NOTE: Shouldn't we compute Cos_Angle_Of_Incidence just once? */
-
- VDot(Cos_Angle_Of_Incidence, Layer_Normal, Light_Source_Ray->Direction);
-
- /* Calculate phase offset. */
-
- interference = 4.0 * M_PI * film_thickness * Cos_Angle_Of_Incidence;
-
- intensity = Cos_Angle_Of_Incidence * Finish->Irid;
-
- /* Modify color by phase offset for each wavelength. */
-
- Colour[RED] += Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/rwl)));
- Colour[GREEN]+= Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/gwl)));
- Colour[BLUE] += Finish->Irid * (intensity * (1.0 - 0.5 * cos(interference/bwl)));
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_phong
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Calculate the phong reflected color component I_p given by:
- *
- * I_p = p * C * (R . L) ^ s
- *
- * where p : surface's phong reflection coefficient
- * s : surface's phong size
- * C : surface's color/light color depending on the metallic flag
- * R : reflection vector
- * L : light vector (pointing at the light)
- *
- * The reflection vector is calculated from the surface normal and
- * the viewing vector (looking at the surface point):
- *
- * R = -2 * (V . N) * N + V, with R . R = 1
- *
- * CHANGES
- *
- * Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
- *
- ******************************************************************************/
-
- static void do_phong(FINISH *Finish, RAY *Light_Source_Ray, VECTOR Eye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour, COLOUR Layer_Pigment_Colour)
- {
- DBL Cos_Angle_Of_Incidence, Intensity;
- VECTOR Reflect_Direction;
- DBL NdotL, x, F;
- COLOUR Cs;
-
- VDot(Cos_Angle_Of_Incidence, Eye, Layer_Normal);
-
- Cos_Angle_Of_Incidence *= -2.0;
-
- VLinComb2(Reflect_Direction, 1.0, Eye, Cos_Angle_Of_Incidence, Layer_Normal);
-
- VDot(Cos_Angle_Of_Incidence, Reflect_Direction, Light_Source_Ray->Direction);
-
- if (Cos_Angle_Of_Incidence > 0.0)
- {
- if ((Finish->Phong_Size < 60) || (Cos_Angle_Of_Incidence > .0008)) /* rgs */
- Intensity = Finish->Phong * pow(Cos_Angle_Of_Incidence, Finish->Phong_Size);
- else
- Intensity = 0.0; /* ad */
-
- if (Finish->Metallic > 0.0)
- {
- /*
- * Calculate the reflected color by interpolating between
- * the light source color and the surface color according
- * to the (empirical) Fresnel reflectivity function. [DB 9/94]
- */
-
- VDot(NdotL, Layer_Normal, Light_Source_Ray->Direction);
-
- x = fabs(acos(NdotL)) / M_PI_2;
-
- F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
-
- F=min(1.0,max(0.0,F));
- Cs[RED] = Light_Colour[RED] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED] - 1.0));
- Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
- Cs[BLUE] = Light_Colour[BLUE] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE] - 1.0));
-
- VAddScaledEq(Colour, Intensity, Cs);
- }
- else
- {
- Colour[RED] += Intensity * Light_Colour[RED];
- Colour[GREEN] += Intensity * Light_Colour[GREEN];
- Colour[BLUE] += Intensity * Light_Colour[BLUE];
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_specular
- *
- * INPUT
- *
- * OUTPUT
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Calculate the specular reflected color component I_s given by:
- *
- * I_s = s * C * (H . N) ^ (1 / r)
- *
- * where s : surface's specular reflection coefficient
- * r : surface's roughness
- * C : surface's color/light color depending on the metallic flag
- * N : surface's normal
- * H : bisection vector between V and L
- *
- * The bisecting vector H is calculated by
- *
- * H = (L - V) / sqrt((L - V).(L - V))
- *
- * CHANGES
- *
- * Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
- *
- ******************************************************************************/
-
- static void do_specular(FINISH *Finish, RAY *Light_Source_Ray, VECTOR REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour, COLOUR Layer_Pigment_Colour)
- {
- DBL Cos_Angle_Of_Incidence, Intensity, Halfway_Length;
- VECTOR Halfway;
- DBL NdotL, x, F;
- COLOUR Cs;
-
- VHalf(Halfway, REye, Light_Source_Ray->Direction);
-
- VLength(Halfway_Length, Halfway);
-
- if (Halfway_Length > 0.0)
- {
- VDot(Cos_Angle_Of_Incidence, Halfway, Layer_Normal);
-
- Cos_Angle_Of_Incidence /= Halfway_Length;
-
- if (Cos_Angle_Of_Incidence > 0.0)
- {
- Intensity = Finish->Specular * pow(Cos_Angle_Of_Incidence, Finish->Roughness);
-
- if (Finish->Metallic > 0.0)
- {
- /*
- * Calculate the reflected color by interpolating between
- * the light source color and the surface color according
- * to the (empirical) Fresnel reflectivity function. [DB 9/94]
- */
-
- VDot(NdotL, Layer_Normal, Light_Source_Ray->Direction);
-
- x = fabs(acos(NdotL)) / M_PI_2;
-
- F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
-
- F=min(1.0,max(0.0,F));
- Cs[RED] = Light_Colour[RED] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED] - 1.0));
- Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
- Cs[BLUE] = Light_Colour[BLUE] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE] - 1.0));
-
- VAddScaledEq(Colour, Intensity, Cs);
- }
- else
- {
- Colour[RED] += Intensity * Light_Colour[RED];
- Colour[GREEN] += Intensity * Light_Colour[GREEN];
- Colour[BLUE] += Intensity * Light_Colour[BLUE];
- }
- }
- }
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_blinn
- *
- * INPUT
- *
- * OUTPUT
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Nathan Kopp
- *
- * DESCRIPTION
- *
- * Calculate the specular reflected color component I_s given by:
- *
- * I_s = s * C * (H . N) ^ (1 / r)
- *
- * where s : surface's specular reflection coefficient
- * r : surface's roughness
- * C : surface's color/light color depending on the metallic flag
- * N : surface's normal
- * H : bisection vector between V and L
- *
- * The bisecting vector H is calculated by
- *
- * H = (L - V) / sqrt((L - V).(L - V))
- *
- * CHANGES
- *
- * Sep 1994 : Added improved color calculation for metallic surfaces. [DB]
- *
- ******************************************************************************/
-
- #ifdef BlinnPatch
- static void do_blinn(FINISH *Finish, RAY *Light_Source_Ray, VECTOR REye, VECTOR Layer_Normal, COLOUR Colour, COLOUR Light_Colour, COLOUR Layer_Pigment_Colour,
- INTERIOR *Interior)
- {
- DBL Intensity, Halfway_Length;
- VECTOR Halfway;
- DBL x, F;
- COLOUR Cs;
- DBL beta, cosBeta, tanBeta, D;
- DBL VdotH, LdotH, NdotL, NdotH, NdotV;
- DBL G, cos_angle;
- DBL ior, /*ior2,*/ disp;
- DBL m,g;
- VECTOR Lv,Nv,Vv;
-
- /* Get ratio of iors depending on the interiors the ray is traversing. */
- if (Light_Source_Ray->Index == -1)
- {
- /* The ray is entering from the atmosphere. */
- ior = Frame.Atmosphere_IOR / Interior->IOR;
- disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
- }
- else
- {
- /* The ray is currently inside an object. */
- if ((Interior_In_Ray_Container(Light_Source_Ray, Interior)) >= 0)
- {
- if (Light_Source_Ray->Index == 0)
- {
- /* The ray is leaving into the atmosphere. */
- ior = Interior->IOR / Frame.Atmosphere_IOR;
- disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
- }
- else
- {
- /* The ray is leaving into another object. */
- ior = Interior->IOR / Light_Source_Ray->Interiors[Light_Source_Ray->Index]->IOR;
- disp = Interior->Dispersion / Light_Source_Ray->Interiors[Light_Source_Ray->Index]->Dispersion;
- }
- }
- else
- {
- /* The ray is entering a new object. */
- ior = Light_Source_Ray->Interiors[Light_Source_Ray->Index]->IOR / Interior->IOR;
- disp = Light_Source_Ray->Interiors[Light_Source_Ray->Index]->Dispersion / Interior->Dispersion;
- }
- }
-
- ior = 1.0/ior;
- disp = 1.0/disp;
-
- VHalf(Halfway, REye, Light_Source_Ray->Direction);
-
- VLength(Halfway_Length, Halfway);
-
- if (Halfway_Length > 0.0)
- {
- VScaleEq(Halfway, 1.0/Halfway_Length);
- VNormalize(Vv, REye);
- VNormalize(Lv, Light_Source_Ray->Direction);
- VNormalize(Nv, Layer_Normal);
- VDot(NdotL, Nv, Lv);
- VDot(NdotH, Nv, Halfway);
- VDot(NdotV, Nv, Vv);
- VDot(LdotH, Lv, Halfway);
- VdotH = LdotH;
-
- beta = acos(NdotH);
- cosBeta = cos(beta);
- tanBeta = tan(beta);
-
- m = Finish->Facets;
-
- D = 1.0 / (4.0 * m * cosBeta*cosBeta*cosBeta*cosBeta) * exp(-Sqr(tanBeta)/Sqr(m));
-
- G = min(1, min(2*NdotH*NdotV/VdotH, 2*NdotH*NdotL/VdotH));
- cos_angle = LdotH;
-
- if (cos_angle > 0.0)
- {
- g = sqrt(Sqr(ior) + Sqr(cos_angle) - 1);
- F = 0.5 * (Sqr(g - cos_angle) / Sqr(g + cos_angle));
- F = F * (1 + Sqr(cos_angle * (g + cos_angle) - 1) / Sqr(cos_angle * (g - cos_angle) + 1));
-
- F=min(1.0,max(0.0,F));
-
- Intensity = Finish->Blinn*D*G*F/(NdotL*NdotV*M_PI);
-
- if (Finish->Metallic > 0.0)
- {
- /*
- * Calculate the reflected color by interpolating between
- * the light source color and the surface color according
- * to the (empirical) Fresnel reflectivity function. [DB 9/94]
- */
- x = fabs(acos(NdotL)) / M_PI_2;
-
- F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
-
- F=min(1.0,max(0.0,F));
- Cs[RED] = Light_Colour[RED] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[RED] - 1.0));
- Cs[GREEN] = Light_Colour[GREEN] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[GREEN] - 1.0));
- Cs[BLUE] = Light_Colour[BLUE] * (1.0 + Finish->Metallic * (1.0 - F) * (Layer_Pigment_Colour[BLUE] - 1.0));
-
- VAddScaledEq(Colour, Intensity, Cs);
- }
- else
- {
- Colour[RED] += Intensity * Light_Colour[RED];
- Colour[GREEN] += Intensity * Light_Colour[GREEN];
- Colour[BLUE] += Intensity * Light_Colour[BLUE];
- }
- }
- }
- }
-
- #endif
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Diffuse
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void Diffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object)
- {
- int i;
- DBL Light_Source_Depth, Cos_Shadow_Angle;
- RAY Light_Source_Ray;
- LIGHT_SOURCE *Light_Source;
- VECTOR REye;
- COLOUR Light_Colour;
-
- #ifdef BlinnPatch
- if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0) && (Finish->Blinn == 0.0))
- #else
- if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
- #endif
- {
- return;
- }
-
- #ifdef BlinnPatch
- if (Finish->Specular != 0.0 || Finish->Blinn != 0.0)
- #else
- if (Finish->Specular != 0.0)
- #endif
- {
- REye[X] = -Eye->Direction[X];
- REye[Y] = -Eye->Direction[Y];
- REye[Z] = -Eye->Direction[Z];
- }
-
- for (i = 0, Light_Source = Frame.Light_Sources;
- Light_Source != NULL;
- Light_Source = Light_Source->Next_Light_Source, i++)
- {
- /* if Light is not in Object Light_Group Skip */
- if (!Check_Light_Group(Object,Light_Source))
- continue;
-
- /* Get a colour and a ray. */
-
- do_light(Light_Source, &Light_Source_Depth, &Light_Source_Ray, Eye, IPoint, Light_Colour);
-
- /* Don't calculate spotlights when outside of the light's cone. */
-
- if ((fabs(Light_Colour[RED]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[BLUE]) < BLACK_LEVEL))
- {
- continue;
- }
-
- /* See if light on far side of surface from camera. */
-
- /* NK 1998 double_illuminate - changed to Test_Flag */
- if (!(Test_Flag(Object, DOUBLE_ILLUMINATE_FLAG)))
- {
- VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
-
- if (Cos_Shadow_Angle < EPSILON)
- {
- continue;
- }
- }
-
- /*
- * If light source was not blocked by any intervening object, then
- * calculate it's contribution to the object's overall illumination.
- */
- /** poviso: July 14 '96 R.S. **/
- #ifdef POVISO
- Shadow_Test_Flag = TRUE;
- #endif
- /** --- **/
-
- if ((opts.Quality_Flags & Q_SHADOW) && ((Light_Source->Projected_Through_Object != NULL) || (Light_Source->Light_Type != FILL_LIGHT_SOURCE)))
- {
- /* If this surface point has already been tested use previous result. */
-
- if (Light_List[i].Tested)
- {
- Assign_Colour(Light_Colour, Light_List[i].Colour);
- }
- else
- {
- block_light_source(Light_Source, Light_Source_Depth, &Light_Source_Ray, Eye, IPoint, Light_Colour);
-
- /* Store light colour. */
-
- Light_List[i].Tested = TRUE;
-
- Assign_Colour(Light_List[i].Colour, Light_Colour);
- }
- }
- /** poviso: July 14 '96 R.S. **/
- #ifdef POVISO
- Shadow_Test_Flag = FALSE;
- #endif
- /** --- **/
-
- if ((fabs(Light_Colour[RED]) > BLACK_LEVEL) ||
- (fabs(Light_Colour[GREEN]) > BLACK_LEVEL) ||
- (fabs(Light_Colour[BLUE]) > BLACK_LEVEL))
- {
- if (Finish->Diffuse > 0.0)
- {
- do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,Colour,Light_Colour,Layer_Pigment_Colour, Attenuation);
- }
-
- if ((Light_Source->Light_Type != FILL_LIGHT_SOURCE)
- /* NK rad
- don't compute highlights for radiosity gather rays, since this causes
- problems with colors being far too bright
- */
- && (Radiosity_Trace_Level<=1))
- /* NK ---- */
- {
- if (Finish->Phong > 0.0)
- {
- do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
- }
- #ifdef BlinnPatch
- if (Finish->Blinn > 0.0)
- {
- do_blinn(Finish,&Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour, Object->Interior);
- }
- #endif
-
- if (Finish->Specular > 0.0)
- {
- do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
- }
- }
-
- if (Finish->Irid > 0.0)
- {
- do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,Colour);
- }
-
- }
- }
- }
-
-
-
- /* NK phmap */
- /*****************************************************************************
- *
- * FUNCTION
- *
- * PhotonDiffuse (based on Diffuse)
- *
- * Preconditions:
- * same as Diffuse() with this addition:
- *
- * If photonOptions.photonsEnabled is true now, then
- * InitBacktraceEverything must have been called with
- * photonOptions.photonsEnabled true.
- *
- *
- * AUTHOR
- *
- * Nathan Kopp (this is based on Diffuse)
- *
- * DESCRIPTION
- *
- * Computes diffuse, phong, specular, etc. based on the incoming photons
- * stored in the various photon maps.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
-
- 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)
- {
- DBL Cos_Shadow_Angle;
- RAY Light_Source_Ray;
- VECTOR REye;
- COLOUR Light_Colour, TempCol, Colour2;
- DBL Size, r, tempr;
- int n, tempn;
- int j;
- int step;
- DBL thisDensity=0;
- DBL prevDensity=0.0000000000000001; /* avoid div-by-zero error */
- int expanded = FALSE;
- DBL att; /* attenuation for lambertian compensation & filters */
-
- if (!photonOptions.photonsEnabled || photonOptions.photonMap.numPhotons<1)
- {
- Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
- return;
- }
-
- if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
- {
- Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
- return;
- }
-
- /* statistics */
- Increase_Counter(stats[Gather_Performed_Count]);
-
- if (Finish->Specular != 0.0)
- {
- REye[X] = -Eye->Direction[X];
- REye[Y] = -Eye->Direction[Y];
- REye[Z] = -Eye->Direction[Z];
- }
-
- Make_Colour(Colour,0,0,0);
-
- Size = photonOptions.photonMap.minGatherRad;
-
- Make_Colour(Colour2,0,0,0);
-
- n=-1;
- step=0;
- while(n<photonOptions.minGatherCount && step<photonOptions.photonMap.gatherNumSteps)
- {
- Make_Colour(TempCol,0,0,0);
- tempr = 0;
-
- /* gather the photons */
- if (photonsAlreadyGathered<=0)
- {
- tempn=gatherPhotons(IPoint, Size, &tempr,Layer_Normal,TRUE,&photonOptions.photonMap);
- }
- else
- {
- tempn = photonsAlreadyGathered;
- tempr = previousRad;
- }
-
- /* now go through these photons and add up their contribution */
- for(j=0; j<tempn; j++)
- {
- SMALL_COLOUR col;
- /*DBL theta,phi;*/
- int theta,phi;
-
- /* convert small color to normal color */
- col = photonOptions.photonGatherList[j]->Colour;
- UNPACK_COLOUR(Light_Colour, col, photonOptions.photonMap);
-
- /* convert theta/phi to vector direction
- Use a pre-computed array of sin/cos to avoid many calls to the
- sin() and cos() functions. These arrays were initialized in
- InitBacktraceEverything.
- */
- theta = photonOptions.photonGatherList[j]->theta+127;
- phi = photonOptions.photonGatherList[j]->phi+127;
-
- Light_Source_Ray.Direction[Y] = photonOptions.sinTheta[theta];
- Light_Source_Ray.Direction[X] = photonOptions.cosTheta[theta];
-
- Light_Source_Ray.Direction[Z] = Light_Source_Ray.Direction[X]*photonOptions.sinTheta[phi];
- Light_Source_Ray.Direction[X] = Light_Source_Ray.Direction[X]*photonOptions.cosTheta[phi];
-
- VSub(Light_Source_Ray.Initial, photonOptions.photonGatherList[j]->Loc, Light_Source_Ray.Direction);
-
- /* this compensates for real lambertian (diffuse) lighting (see paper) */
- /* use raw normal, not layer normal */
- /* VDot(att, Layer_Normal, Light_Source_Ray.Direction); */
- VDot(att, Raw_Normal, Light_Source_Ray.Direction);
- if (att>1) att=1.0;
- if (att<.1) att = 0.1; /* limit to 10x - otherwise we get bright dots */
- att = 1.0 / fabs(att);
-
- /* do gaussian filter */
- /*att *= 0.918*(1.0-(1.0-exp((-1.953) * photonOptions.photonDistances[j])) / (1.0-exp(-1.953)) );*/
- /* do cone filter */
- /*att *= 1.0-(sqrt(photonOptions.photonDistances[j])/(4.0 * tempr)) / (1.0-2.0/(3.0*4.0));*/
-
- VScaleEq(Light_Colour,att);
-
- /* See if light on far side of surface from camera. */
- if (!(Test_Flag(Object, DOUBLE_ILLUMINATE_FLAG)))
- {
- VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
- if (Cos_Shadow_Angle < EPSILON)
- continue;
- }
-
- /* now add diffuse, phong, specular, irid contribution */
- if (Finish->Diffuse > 0.0)
- {
- do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,TempCol,Light_Colour,Layer_Pigment_Colour, Attenuation);
- }
-
- /* NK rad
- don't compute highlights for radiosity gather rays, since this causes
- problems with colors being far too bright
- */
- if(Radiosity_Trace_Level<=1)
- /* NK ---- */
- {
- if (Finish->Phong > 0.0)
- {
- do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
- }
- if (Finish->Specular > 0.0)
- {
- do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
- }
- }
-
- if (Finish->Irid > 0.0)
- {
- do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,TempCol);
- }
-
- }
-
- /* density of this search */
- thisDensity = tempn / (tempr*tempr);
-
- /*
- this next line handles the adaptive search
- if
- the density change ((thisDensity-prevDensity)/prevDensity) is small enough
- or
- this is the first time through (step==0)
- or
- the number gathered is less than photonOptions.minExpandCount and greater than zero
-
- then
- use the color from this new gathering step and discard any previous
- color
-
- This adaptive search is explained my paper "Simulating Reflective and Refractive
- Caustics in POV-Ray Using a Photon Map" - May, 1999
- */
- if(((thisDensity-prevDensity)/prevDensity < photonOptions.expandTolerance)
- || (step==0)
- || (tempn<photonOptions.minExpandCount && tempn>0))
- {
- /* it passes the tests, so use the new color */
-
- if (step>0)
- expanded = TRUE;
-
- prevDensity = thisDensity;
- if (prevDensity==0)
- prevDensity = 0.0000000000000001; /* avoid div-by-zero error */
-
- Assign_Colour(Colour2, TempCol);
-
- r = tempr;
- n = tempn;
- }
-
- if(photonsAlreadyGathered)
- {
- step = photonOptions.photonMap.gatherNumSteps; /* so we don't gather again */
- }
- else
- {
- Size+=photonOptions.photonMap.gatherRadStep;
- step++;
- }
-
- }
-
- /* stats */
- if (expanded)
- Increase_Counter(stats[Gather_Expanded_Count]);
-
- /* finish the photons equation */
- VScaleEq(Colour2, (DBL)(1.0)/(M_PI*r*r));
-
- /* add photon contribution to total lighting */
- VAddEq(Colour, Colour2);
-
- /* save results for subsequent layers */
- /* even if an expanded search was thrown away, the closest photons n will
- still be the closest n photons */
- previousRad = r;
- photonsAlreadyGathered = n;
- }
- /* NK ---- */
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Reflect
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Trace a ray along the direction of the reflected light and
- * return light internsity coming from that direction.
- *
- * CHANGES
- *
- * JUN 1997 : Changed to return color coming along the reflected ray. [DB]
- *
- ******************************************************************************/
-
- static void Reflect(VECTOR IPoint, RAY *Ray, VECTOR Normal, VECTOR Raw_Normal, COLOUR Colour, DBL Weight, DBL Blur, int Samples)
- {
- RAY New_Ray;
- /* This function heavily edited by MBP to implement reflection-blur. */
- COLOUR Temp_Colour2;
- /* register DBL Normal_Component;*/
- VECTOR Jitter_Normal, Jitter_Offset;
- VECTOR Jitter_Raw_Normal;
- int blur_count, samples = Samples;
- DBL x, y, z, t, r, n, n2;
- int doBlur, startBlur;
- #ifdef NoImageNoReflectionPatch
- /* Object-Ray Options [ENB 9/97] */
- In_Reflection_Ray = TRUE;
- #endif
-
- Trace_Level++;
-
- startBlur = FALSE;
-
- if(fabs(Blur)<EPSILON)
- {
- /* ComeBack put if blur=0 then samples=1 into post of finish!!!!!! */
- doBlur = FALSE;
- }
- else
- {
- doBlur = TRUE;
- }
-
- /* Sometimes we don't want to do any blurring... */
- if(alreadyBlurred ||
- Trace_Level > opts.Reflection_Blur_Max ||
- Weight < opts.Reflection_Blur_Max_ADC ||
- firstRadiosityPass
- )
- {
- samples = 1;
- }
-
- if (doBlur && !alreadyBlurred)
- {
- startBlur = TRUE;
- alreadyBlurred = TRUE;
- }
-
- /* NK phmap - added checking for backtraceFlag */
- if(!backtraceFlag)
- {
- Make_ColourA (Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
- }
- else if (samples > 1)
- {
- Colour[0]/=samples;
- Colour[1]/=samples;
- Colour[2]/=samples;
- }
-
- for (blur_count = 0; blur_count < samples; blur_count++) {
- /* We work with a copy of the normal so the original isn't affected. */
- Assign_Vector(Jitter_Normal, Normal);
- Assign_Vector(Jitter_Raw_Normal, Raw_Normal);
-
- if(doBlur)
- {
- /* only do this if we are using blur */
-
- /* Pick a random point on the surface of a unit sphere.
- Uses a method called the "trig method" explained in the
- comp.graphics.algorithms FAQ. */
- z = (FRAND() * 2) - 1;
- t = FRAND() * M_PI * 2;
- r = sqrt(1 - z*z);
- x = r * cos(t);
- y = r * sin(t);
- Make_Vector(Jitter_Offset, x, y, z);
-
- /* Add the jittering to the normal */
- VAddScaledEq(Jitter_Normal, Blur, Jitter_Offset);
- VAddScaledEq(Jitter_Raw_Normal, Blur, Jitter_Offset );
- }
-
- /* Normals must always have length 1 or weird things happen in color calculations. */
- VNormalizeEq(Jitter_Normal);
- VNormalizeEq(Jitter_Raw_Normal);
-
- /* The rest of this is essentally what was originally here, with small changes. */
- VDot(n,Ray->Direction, Jitter_Normal);
- n *= -2.0;
- VAddScaled(New_Ray.Direction, Ray->Direction, n, Jitter_Normal);
-
- /* Nathan Kopp & CEY 1998 - Reflection bugfix
- if the new ray is going the opposet direction as raw normal, we
- need to fix it.
- */
-
- VDot(n, New_Ray.Direction, Jitter_Raw_Normal);
-
- if (n < 0.0)
- {
- /* It needs fixing. Which kind? */
-
- VDot(n2,New_Ray.Direction,Jitter_Normal);
-
- if (n2 < 0.0)
- {
- /* reflected inside rear virtual surface. Reflect Ray using Raw_Normal */
- VDot(n,Ray->Direction,Jitter_Raw_Normal);
- n *= -2.0;
- VAddScaled(New_Ray.Direction, Ray->Direction, n,Jitter_Raw_Normal);
- }
- else
- {
- /* Double reflect NRay using Raw_Normal */
- /*VDot(n,New_Ray.Direction,Jitter_Raw_Normal); - kept the old n around */
- n *= -2.0;
- VAddScaledEq(New_Ray.Direction, n, Jitter_Raw_Normal);
- }
- }
- VNormalizeEq(New_Ray.Direction);
- /* NK & CEY ---- */
-
- Assign_Vector(New_Ray.Initial, IPoint);
-
- Copy_Ray_Containers(&New_Ray, Ray);
-
- Increase_Counter(stats[Reflected_Rays_Traced]);
-
- /* Trace reflected ray. */
- /* NK phmap - added checking for backtraceFlag */
- if(!backtraceFlag)
- {
- Trace (&New_Ray, Temp_Colour2, Weight, NULL);
- VAddEq(Colour, Temp_Colour2);
- }
- else
- {
- #ifdef MotionBlurPatch
- Trace_With_Blur(&New_Ray, Colour, Weight, NULL);
- #else
- Trace(&New_Ray, Colour, Weight, NULL);
- #endif
- }
- }
- Trace_Level--;
-
- /* if we started the blur, then let's un-start it */
- if (startBlur)
- {
- alreadyBlurred = FALSE;
- }
-
- /* NK phmap - added checking for backtraceFlag */
- if(!backtraceFlag)
- {
- VInverseScaleEq(Colour, samples);
- }
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Refract
- *
- * INPUT
- *
- * Interior - interior of the current object containing the ior to use
- * IPoint - current intersection point (here the new ray starts)
- * Ray - current incoming ray that will be refracted, transmitted
- * or reflected (due to total internal reflection)
- * Normal - surface normal at the current intersection point
- * Colour - current color emitted back along the ray
- * Weight - current weight used by the adaptive tree depth control
- *
- * OUTPUT
- *
- * Colour - current color including the light due to refraction,
- * transmission or total internal reflection
- *
- * RETURNS
- *
- * int - TRUE, if total internal reflection occured
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * Trace a transmitted ray (either refracted or reflected due to total
- * internal reflection) and return the light intesity coming from the
- * direction of the transmitted ray.
- *
- * CHANGES
- *
- * Aug 1995 : Modified to correctly handle the contained texture
- * list in the transmit only case. [DB]
- *
- * Jun 1997 : Rewritten to use interior structure. [DB]
- *
- * Spring 1998 : Rewritten to incorporate Daren Wilson's dispersion AND photon
- * mapping.
- *
- ******************************************************************************/
- /* NK phmap ------------
- the Refract function here is highly modified and probably quite
- messy right now. The primary reason is the inclusion of Daren
- Wilson's dispersion code.
-
- This needs MUCH better comments for the whole thing.
- Mr. Wilson & Mr. Parker: if you want to help clean this up and add
- comments, you're very much welcome to. ;-)
- */
- /* NK phmap */
- static COLOUR GFilCol; /* not thread safe */
- /* NK ---- */
-
-
- /*__inline double sqr(double x) { return x*x; }*/
- #define sqr(x) ((x)*(x))
-
- static void Dispersion_Element_Hue(COLOUR Hue, int elem, int nelems)
- {
- /*
- Gives color to a dispersion element.
-
- Requirements:
- * Sum of all hues must add to white (or white*constand)
- (white tiles seen through glass should still be white)
-
- * Each hue must be maximally saturated, bright
- (The code shown here cheats a little)
-
- * colors must range from red at h=0 to violet at h=1
-
- This code is not necessarily the best, just proof-of-concept
- EXPERIMENTAL AND DELICATE
- Better code could be written with look-up tables of the
- famous CIE colour matching functions.
- */
-
- float h, coh;
- float ybulge;
-
- /* h goes from 0 at red end to 1.0 at blue end */
- h = (elem-1)*1.0/(nelems-1);
-
- /* co-h goes from 1.0 at red end to 0.0 at blue end */
- coh = 1.0 - h;
-
- Hue[RED] = 0.9 - (h/0.5);
- Hue[BLUE] = 1.0 - (coh/0.6);
-
- if (Hue[RED] < 0.0) Hue[RED] = 0.0;
- if (Hue[BLUE] < 0.0) Hue[BLUE] = 0.0;
-
-
- Hue[RED]=1.0 - sqr(1.0-Hue[RED]);
- Hue[BLUE]=1.0-sqr(1.0-Hue[BLUE]);
-
-
- Hue[GREEN] = 1.0 - Hue[RED] - Hue[BLUE];
-
- if (h>0.85)
- Hue[RED] = 8*(h-0.85); /* was 4 */
-
- ybulge = -4.0*(h-0.1)*(h-0.6);
- if (ybulge<0) ybulge=0;
- Hue[RED] += ybulge * 0.5; /* added * 0.5 */
- Hue[GREEN] += ybulge;
- }
-
- static double Element_IOR(double ior, double disp, int e, int nelems)
- {
- return ior * pow(disp, (e-1)*1.0/(nelems-1)-0.5);
- }
-
-
- static int Refract_Guts(COLOUR Colour,
- DBL ior,
- VECTOR IPoint,
- VECTOR Normal, VECTOR Local_Normal,
- DBL n,
- RAY *Ray, RAY *NRay,
- DBL Weight,
- VECTOR Raw_Normal
- )
- {
- /* Adds result of refracted ray to Colour */
- /* All other args are input args - don't change them */
- /* Pass by value the RAYs and maybe make local copy of normals? */
- DBL t;
-
- /* Compute refrated ray direction using Heckbert's method. */
- t = 1.0 + Sqr(ior) * (Sqr(n) - 1.0);
-
- if (t < 0.0)
- {
- /* Total internal reflection occures. */
- Increase_Counter(stats[Internal_Reflected_Rays_Traced]);
- Reflect(IPoint, /*N?*/ Ray, /*L?*/ Normal, Raw_Normal, Colour, Weight, 0, 1); /* ???? */
- return 1;
- }
-
- t = ior * n - sqrt(t);
- VLinComb2(NRay->Direction, ior, /*N?*/Ray->Direction, t, Local_Normal);
-
- /* Trace a refracted ray. */
- Increase_Counter(stats[Refracted_Rays_Traced]);
-
- Trace_Level++;
- #ifdef MotionBlurPatch
- Trace_With_Blur(NRay, Colour, Weight, NULL);
- #else
- Trace(NRay, Colour, Weight, NULL);
- #endif
- Trace_Level--;
-
- return 0;
- }
-
-
- static int BacktraceRefract(INTERIOR *Interior, VECTOR IPoint, RAY *Ray, VECTOR Normal, VECTOR Raw_Normal, COLOUR Colour, DBL Weight)
- {
- int nr;
- DBL n, ior, disp;
- VECTOR Local_Normal;
- RAY NRay;
- COLOUR Hue, Elem;
- int i;
-
- /* Set up new ray. */
- Copy_Ray_Containers(&NRay, Ray);
- Assign_Vector(NRay.Initial, IPoint);
-
- /* get the dispersion elements from the light's blend map */
- if ((disp_elem == 0) && (photonOptions.Light->blend_map))
- disp_nelems = photonOptions.Light->blend_map->Number_Of_Entries;
-
- /* Get ratio of iors depending on the interiors the ray is traversing. */
- if (Ray->Index == -1)
- {
- /* The ray is entering from the atmosphere. */
- Ray_Enter(&NRay, Interior);
- ior = Frame.Atmosphere_IOR / Interior->IOR;
- disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
- }
- else
- {
- /* The ray is currently inside an object. */
- if ((nr = Interior_In_Ray_Container(&NRay, Interior)) >= 0)
- {
- /* The ray is leaving the current object. */
- Ray_Exit(&NRay, nr);
-
- if (NRay.Index == -1)
- {
- /* The ray is leaving into the atmosphere. */
- ior = Interior->IOR / Frame.Atmosphere_IOR;
- disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
- }
- else
- {
- /* The ray is leaving into another object. */
- ior = Interior->IOR / NRay.Interiors[NRay.Index]->IOR;
- disp = Interior->Dispersion / NRay.Interiors[NRay.Index]->Dispersion;
-
- /* Use the largest disp_nelems of the two interiors */
- if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
- disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
- }
- }
- else
- {
- /* The ray is entering a new object. */
- ior = NRay.Interiors[NRay.Index]->IOR / Interior->IOR;
- disp = NRay.Interiors[NRay.Index]->Dispersion / Interior->Dispersion;
-
- /* Use the largest disp_nelems of the two interiors */
- if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
- disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
-
- Ray_Enter(&NRay, Interior);
-
- }
- }
-
- /* Do the two mediums traversed have the sampe indices of refraction? */
- /* DSW: they must also match in dispersion ratios */
- if (fabs(ior - 1.0) < EPSILON
- && fabs(disp - 1.0) < EPSILON)
- {
- COLOUR lc;
-
- /* Only transmit the ray. */
- Assign_Vector(NRay.Direction, Ray->Direction);
-
- /* Trace a transmitted ray. */
- Increase_Counter(stats[Transmitted_Rays_Traced]);
-
- lc[0] = Colour[0]*(GFilCol[0] * GFilCol[FILTER] + GFilCol[TRANSM]);
- lc[1] = Colour[1]*(GFilCol[1] * GFilCol[FILTER] + GFilCol[TRANSM]);
- lc[2] = Colour[2]*(GFilCol[2] * GFilCol[FILTER] + GFilCol[TRANSM]);
-
- Trace_Level++;
- #ifdef MotionBlurPatch
- Trace_With_Blur(&NRay, lc, Weight, NULL);
- #else
- Trace(&NRay, lc, Weight, NULL);
- #endif
- Trace_Level--;
- }
- else /* different media */
- {
- /* Refract the ray. */
- VDot(n, Ray->Direction, Normal);
-
- if (n <= 0.0)
- {
- Assign_Vector(Local_Normal, Normal);
- n = -n;
- }
- else
- {
- Local_Normal[X] = -Normal[X];
- Local_Normal[Y] = -Normal[Y];
- Local_Normal[Z] = -Normal[Z];
- }
-
- /* DSW: If this is the first time this ray is encountering */
- /* a dispersive medium, we need to loop over the color components. */
- /* If the ray has already been dispersed, use trace a monochromatic */
- /* ray, with no further looping. */
-
- if (disp_elem>0 || disp_nelems <= 1 || fabs(disp-1.0)<EPSILON || firstRadiosityPass)
- {
- DBL ior2;
- /* We're already tracing an element */
- /* NK phmap */
- COLOUR lc;
- lc[0] = Colour[0]*(GFilCol[0] * GFilCol[FILTER] + GFilCol[TRANSM]);
- lc[1] = Colour[1]*(GFilCol[1] * GFilCol[FILTER] + GFilCol[TRANSM]);
- lc[2] = Colour[2]*(GFilCol[2] * GFilCol[FILTER] + GFilCol[TRANSM]);
- ior2 = ior /sqrt(disp) * pow(disp, RGBtoHue(lc));
- return Refract_Guts(lc, ior2, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
- }
-
- else
- {
- /* An undispersed ray needs to be broken into elements */
-
- /* Trace each element */
- COLOUR lc;
- DBL ior2;
- BLEND_MAP *Map = photonOptions.Light->blend_map;
- SNGL Value;
-
- /* NK phmap */
- lc[0] = Colour[0]*(GFilCol[0] * GFilCol[FILTER] + GFilCol[TRANSM]);
- lc[1] = Colour[1]*(GFilCol[1] * GFilCol[FILTER] + GFilCol[TRANSM]);
- lc[2] = Colour[2]*(GFilCol[2] * GFilCol[FILTER] + GFilCol[TRANSM]);
-
- #define MONTE_CARLO_DISP_PHOT_SPLIT 0
- #if MONTE_CARLO_DISP_PHOT_SPLIT
- i = rand()%Map->Number_Of_Entries;
- #else
- for (i = 0; i < Map->Number_Of_Entries; i++)
- #endif
- {
- disp_elem = i+1;
-
- #define USE_BLEND_MAP 1
- #if USE_BLEND_MAP
- /* get the dispersion elements from the light's blend map */
- Value = Map->Blend_Map_Entries[i].value;
- #if MONTE_CARLO_DISP_PHOT_SPLIT
- Value *= Map->Number_Of_Entries;
- #endif
- VScale(Hue,Map->Blend_Map_Entries[i].Vals.Colour,Value);
-
- /* we really want to use just the hue that we got from the
- color_map, but we still want it to be filtered by previous
- surfaces */
- if(photonOptions.Light->Colour[0])
- Elem[0] = Hue[0] * lc[0] / photonOptions.Light->Colour[0];
- else
- Elem[0] = 0;
- if(photonOptions.Light->Colour[1])
- Elem[1] = Hue[1] * lc[1] / photonOptions.Light->Colour[1];
- else
- Elem[1] = 0;
- if(photonOptions.Light->Colour[2])
- Elem[2] = Hue[2] * lc[2] / photonOptions.Light->Colour[2];
- else
- Elem[2] = 0;
- #else
- Dispersion_Element_Hue(Hue, disp_elem, disp_nelems+1);
- /*Dispersion_Element_Hue(Hue, rand()%1000, 1000);*/
- Elem[RED] = lc[RED] * Hue[RED];
- Elem[GREEN] = lc[GREEN] * Hue[GREEN];
- Elem[BLUE] = lc[BLUE] * Hue[BLUE];
- #endif
-
-
- ior2 = ior /sqrt(disp) * pow(disp, RGBtoHue(Elem));
-
- if (RGBtoHue(Elem)<0)
- {
- Make_Colour(Elem, 0,1,0);
- }
- else if (RGBtoHue(Elem)>1)
- {
- Make_Colour(Elem, 0,0,1);
- }
-
- Refract_Guts(Elem, ior2, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
-
- /*ior *= ior_mult;*/
- }
- /* NK ---- */
- disp_elem = 0; /* reset this for next pixel's tracing */
- disp_nelems = 0; /* reset this for next pixel's tracing */
- }
-
-
- } /* end of different media */
-
- return(0);
- }
-
- static int Refract(INTERIOR *Interior, VECTOR IPoint, RAY *Ray, VECTOR Normal, VECTOR Raw_Normal, COLOUR Colour, DBL Weight)
- {
- int nr;
- DBL n, ior, disp, ior_mult;
- VECTOR Local_Normal;
- RAY NRay;
- COLOUR Hue, Sum, Elem;
- #ifdef PostProcessPatch2
- DBL depth;
- #endif
-
- /* Set up new ray. */
- Copy_Ray_Containers(&NRay, Ray);
- Assign_Vector(NRay.Initial, IPoint);
-
- if (disp_elem == 0)
- disp_nelems = Interior->Disp_NElems;
-
- disp = 1.0;
-
- /* Get ratio of iors depending on the interiors the ray is traversing. */
- if (Ray->Index == -1)
- {
- /* The ray is entering from the atmosphere. */
- Ray_Enter(&NRay, Interior);
- ior = Frame.Atmosphere_IOR / Interior->IOR;
- if (disp_nelems>1)
- disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
- }
- else
- {
- /* The ray is currently inside an object. */
- if ((nr = Interior_In_Ray_Container(&NRay, Interior)) >= 0)
- {
- /* The ray is leaving the current object. */
- Ray_Exit(&NRay, nr);
-
- if (NRay.Index == -1)
- {
- /* The ray is leaving into the atmosphere. */
- ior = Interior->IOR / Frame.Atmosphere_IOR;
- if (disp_nelems>1)
- disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
- }
- else
- {
- /* The ray is leaving into another object. */
- ior = Interior->IOR / NRay.Interiors[NRay.Index]->IOR;
-
- /* Use the largest disp_nelems of the two interiors */
- if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
- disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
-
- if (disp_nelems>1)
- disp = Interior->Dispersion / NRay.Interiors[NRay.Index]->Dispersion;
- }
- }
- else
- {
- /* The ray is entering a new object. */
- ior = NRay.Interiors[NRay.Index]->IOR / Interior->IOR;
-
- /* Use the largest disp_nelems of the two interiors */
- if (NRay.Interiors[NRay.Index]->Disp_NElems > disp_nelems && disp_elem == 0)
- disp_nelems = NRay.Interiors[NRay.Index]->Disp_NElems;
-
- if (disp_nelems>1)
- disp = NRay.Interiors[NRay.Index]->Dispersion / Interior->Dispersion;
-
- Ray_Enter(&NRay, Interior);
-
- }
- }
-
- /* Do the two mediums traversed have the sampe indices of refraction? */
- /* DSW: they must also match in dispersion ratios */
- if (fabs(ior - 1.0) < EPSILON
- && fabs(disp - 1.0) < EPSILON)
- {
- /* Only transmit the ray. */
- Assign_Vector(NRay.Direction, Ray->Direction);
-
- /* Trace a transmitted ray. */
- Increase_Counter(stats[Transmitted_Rays_Traced]);
-
- Trace_Level++;
- #ifdef PostProcessPatch2
- depth =
- #endif
- #ifdef MotionBlurPatch
- Trace_With_Blur(&NRay, Colour, Weight, NULL);
- #else
- Trace(&NRay, Colour, Weight, NULL);
- #endif
- #ifdef PostProcessPatch2
- if (fabs(Weight-1.0)<EPSILON)
- savedRefractDepth = depth;
- #endif
- Trace_Level--;
- }
- else /* different media */
- {
- /* Refract the ray. */
- VDot(n, Ray->Direction, Normal);
-
- if (n <= 0.0)
- {
- Assign_Vector(Local_Normal, Normal);
- n = -n;
- }
- else
- {
- Local_Normal[X] = -Normal[X];
- Local_Normal[Y] = -Normal[Y];
- Local_Normal[Z] = -Normal[Z];
- }
-
- /* DSW: If this is the first time this ray is encountering */
- /* a dispersive medium, we need to loop over the color components. */
- /* If the ray has already been dispersed, use trace a monochromatic */
- /* ray, with no further looping. */
-
- if (disp_elem>0 || disp_nelems <= 1 || fabs(disp-1.0)<EPSILON || firstRadiosityPass)
- {
- /* We're already tracing an element */
- if (disp_nelems>1 && disp_elem > 0)
- ior = Element_IOR(ior, disp, disp_elem, disp_nelems);
-
- return Refract_Guts(Colour, ior, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
- }
-
- else
- {
- /* An undispersed ray needs to be broken into elements */
-
- /*if (disp_nelems==0) disp_nelems = DEFAULT_DISP_NELEMS;*/
- /* or use an adaptive formula? */
-
- /* Trace each element */
-
- ior = ior /sqrt(disp);
- ior_mult = pow(disp, 1.0/(disp_nelems-1));
-
- Sum[RED]=0.0f;
- Sum[GREEN]=0.0f;
- Sum[BLUE]=0.0f;
-
- for (disp_elem = 1; disp_elem < disp_nelems; disp_elem++)
- {
- /* Call an arbitrary C lib function, to avoid a GCC 2.8.1 optimizer bug */
- /*strchr("A", 'A');*/
- Refract_Guts(Elem, ior, IPoint, Normal, Local_Normal, n, Ray, &NRay, Weight, Raw_Normal);
-
- Dispersion_Element_Hue(Hue, disp_elem, disp_nelems);
- /* speed it up by building a lookup table at povray init */
- /* or no: need to recalc if disp_nelems is adaptive, */
- /* then we'd need a bunch of tables or calc fresh */
-
- Sum[RED] += Elem[RED] * Hue[RED];
- Sum[GREEN] += Elem[GREEN] * Hue[GREEN];
- Sum[BLUE] += Elem[BLUE] * Hue[BLUE];
-
- ior *= ior_mult;
- }
-
- /* compute final color, with fudge factor */
- Colour[RED] = Sum[RED] /disp_nelems *3.0;
- Colour[GREEN] = Sum[GREEN] /disp_nelems *3.0;
- Colour[BLUE] = Sum[BLUE] /disp_nelems *3.0;
-
- disp_elem = 0; /* reset this for next pixel's tracing */
- disp_nelems = 0; /* reset this for next pixel's tracing */
- }
-
-
- } /* end of different media */
-
- return(0);
- }
-
- /* NK ---- */
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * create_texture_list
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Chris Young based on Dieter Bayer code
- *
- * DESCRIPTION
- *
- * Get the list of textures used by current object and the list of
- * appropriate weights for each texture. Only multi-colored objects
- * will have more than one texture.
- *
- * CHANGES
- *
- * Feb 1995 : Added code for triangle mesh texturing. [DB]
- *
- * Jul 1995 : Modified code to use pre-allocated lists. [DB]
- *
- ******************************************************************************/
-
- static int create_texture_list(INTERSECTION *Ray_Intersection
- #ifdef InteriorTexturePatch
- , DBL realNormDir
- #endif
- )
- {
- int Texture_Count;
- BLOB *Blob;
- #ifdef IsoBlobPatch
- ISOBLOB *Isoblob; /* Lummox JR, July 1999 -- for the code below */
- #endif
- MESH_TRIANGLE *Triangle;
- #ifdef InteriorTexturePatch
- int useInteriorTexture = FALSE;/*Chris Huff: Interior Texture patch*/
- if((realNormDir > 0)&&(Ray_Intersection->Object->Interior_Texture != NULL))/*Chris Huff: Interior Texture patch*/
- useInteriorTexture = TRUE;
- #endif
- /* Test, if object is multi-textured. */
-
- if (Test_Flag(Ray_Intersection->Object, MULTITEXTURE_FLAG))
- {
- /* Handle blobs. */
-
- if (Ray_Intersection->Object->Methods == &Blob_Methods)
- {
- Blob = (BLOB *)Ray_Intersection->Object;
-
- /* Get list of weighted textures. */
-
- Determine_Blob_Textures(Blob, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
- }
- #ifdef IsoBlobPatch
- /* Handle isoblobs-- Lummox JR, July 1999. */
-
- if (Ray_Intersection->Object->Methods == &Isoblob_Methods)
- {
- Isoblob = (ISOBLOB *)Ray_Intersection->Object;
-
- /* Get list of weighted textures. */
-
- Determine_Isoblob_Textures(Isoblob, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
- }
- /* End Lummox JR's addition */
- #endif
-
- /* Handle meshes. */
-
- if (Ray_Intersection->Object->Methods == &Mesh_Methods)
- {
- /* Set texture to triangle's or object's texture. */
-
- Triangle = (MESH_TRIANGLE *)Ray_Intersection->Pointer;
-
- #ifdef ColorTrianglePatch
- /* NK */
- if (Triangle->ThreeTex)
- {
- VECTOR Weights;
- Mesh_Interpolate(Weights, Ray_Intersection->IPoint,
- (MESH *)Ray_Intersection->Object, Triangle);
-
- if (Triangle->Texture >= 0)
- Texture_List[0] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture];
- else
- Texture_List[0] = Ray_Intersection->Object->Texture;
-
- if (Triangle->Texture2 >= 0)
- Texture_List[1] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture2];
- else
- Texture_List[1] = Ray_Intersection->Object->Texture;
-
- if (Triangle->Texture3 >= 0)
- Texture_List[2] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture3];
- else
- Texture_List[2] = Ray_Intersection->Object->Texture;
-
- Weight_List[0] = Weights[0];
- Weight_List[1] = Weights[1];
- Weight_List[2] = Weights[2];
-
- Texture_Count = 3;
- }
- else
- {
- /* NK ---- */
- #endif
- if (Triangle->Texture >= 0)
- {
- /* NK 1999 moved textures from Mesh_Data_Struct to Mesh_Struct */
- Texture_List[0] = ((MESH *)Ray_Intersection->Object)->Textures[Triangle->Texture];
- /* NK ---- */
- }
- else
- {
- Texture_List[0] = Ray_Intersection->Object->Texture;
- }
-
- Weight_List[0] = 1.0;
-
- Texture_Count = 1;
- #ifdef ColorTrianglePatch
- }
- #endif
- }
-
- }
- #ifdef MultiTextureCsgPatch
- else if(Ray_Intersection->Object->Texture == NULL)
- {
- CSG* Csg;
- /* this should only happen with a multi-tex CSG object */
- if (!Ray_Intersection->Pointer)
- Error("Object has no texture");
-
- Csg = (CSG*)Ray_Intersection->Pointer;
- Determine_CSG_Textures(Csg, Ray_Intersection->IPoint, &Texture_Count, Texture_List, Weight_List);
- }
- #endif
- else
- {
-
- /* Set texture to object's texture. */
-
- #ifdef InteriorTexturePatch
- /* Set texture to object's texture. */
- if(useInteriorTexture == TRUE)/*Chris Huff: Interior Texture patch*/
- {
- Texture_List[0] = Ray_Intersection->Object->Interior_Texture;
- }
- else
- {
- Texture_List[0] = Ray_Intersection->Object->Texture;
- }
- #else
- Texture_List[0] = Ray_Intersection->Object->Texture;
- #endif
- Weight_List[0] = 1.0;
-
- Texture_Count = 1;
- }
-
- return(Texture_Count);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_texture_map
- *
- * INPUT
- *
- * Texture - possibly texture_mapped texture to be evaluated
- * IPoint - point to be evaluated
- * Raw_Normal - non-purturbed surface normal
- * Ray - view ray needed for reflection and highlighs
- * light source ray needed for caustics
- * Weight - ADC control value
- * Ray_Intersection - only Ray_Int..->Object->Type actually
- * needed. Will clean-up later.
- * Shadow_Flag - tells if computation should use
- * compute_lighted_texture or compute_shadow_texture
- *
- * OUTPUT
- *
- * Result_Colour - If Shadow_Flag true then the illuminated
- * color (RGB only) of IPoint is returned.
- * If false, the amount by which a shadow ray is
- * filtered and attenuated is returned.
- * Includes RGB and T.
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * This routine recursively calls itself until it gets a
- * non-texture_mapped texture that is potentially layered.
- * It then calls compute_lighted_texture or compute_shadow_texture
- * to compute the color which is returned in the argument Result_Colour.
- *
- * CHANGES
- *
- ******************************************************************************/
-
- static void do_texture_map(COLOUR Result_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal,
- RAY *Ray, DBL Weight, INTERSECTION *Ray_Intersection, int Shadow_Flag)
- {
- BLEND_MAP *Blend_Map = Texture->Blend_Map;
- BLEND_MAP_ENTRY *Prev, *Cur;
- DBL value1, value2;
- COLOUR C2;
- VECTOR CPoint, TPoint;
- /* NK 1998 reset_children - added CPoint above
-
- ipoint - interseciton point (and evaluation point)
- epoint - evaluation point
- tpoint - turbulated/transformed point
- cpoint - epoint for children textures
- */
-
- if (Texture->Type <= LAST_SPECIAL_PATTERN)
- {
- switch (Texture->Type)
- {
- case NO_PATTERN:
-
- Make_ColourA(Result_Colour, 1.0, 1.0, 1.0, 1.0, 1.0);
-
- break;
-
- case AVERAGE_PATTERN:
-
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- if(warpNormalTextures>MAX_NESTED_TEXTURES)
- Error("Too many nested textures.");
- warpNormalTextureList[warpNormalTextures++] = Texture;
- }
- #endif
- /* NK 1998 reset_children - added ", TRUE" & changed tpoint to cpoint */
- Warp_EPoint(CPoint, IPoint, (TPATTERN *)Texture, TRUE);
-
- /* NK phmap */
- if (backtraceFlag)
- backtrace_average_textures(Result_Colour, Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
- else
- /* NK ---- */
- average_textures(Result_Colour, Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- warpNormalTextures--;
- }
- #endif
-
- break;
-
- case BITMAP_PATTERN:
-
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- if(warpNormalTextures>MAX_NESTED_TEXTURES)
- Error("Too many nested textures.");
- warpNormalTextureList[warpNormalTextures++] = Texture;
- }
- #endif
- /* NK 1998 reset_children - added ", FALSE" and second call to warp_epoint */
- Warp_EPoint (TPoint, IPoint, (TPATTERN *)Texture, FALSE);
- Warp_EPoint (CPoint, IPoint, (TPATTERN *)Texture, TRUE);
- /* NK ---- */
-
- Texture = material_map(TPoint, Texture);
-
- /* NK 1998 reset_children - changed TPoint to CPoint */
- do_texture_map(Result_Colour, Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- warpNormalTextures--;
- }
- #endif
-
- break;
-
- case PLAIN_PATTERN:
-
- /* nk phmap */
- if (backtraceFlag)
- {
- compute_backtrace_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection);
- }
- else
- /* NK ---- */
-
- if (Shadow_Flag)
- {
- compute_shadow_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Ray_Intersection);
- }
- else
- {
- compute_lighted_texture(Result_Colour, Texture, IPoint, Raw_Normal, Ray, Weight, Ray_Intersection);
- }
-
- break;
-
- default:
-
- Error("Bad texture type in do_texture_map()\n");
- }
- }
- else
- {
- /* call warp_epoint with "warping_children" set to
- FALSE, so any RESET_CHILDREN warps will not be applied */
- /* NK 19 Nov 1999 added Warp_EPoint */
- Warp_EPoint (TPoint, IPoint, (TPATTERN *)Texture, FALSE);
- value1 = Evaluate_TPat ((TPATTERN *)Texture,TPoint,Ray_Intersection);
-
- Search_Blend_Map (value1, Blend_Map, &Prev, &Cur);
-
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- if(warpNormalTextures>MAX_NESTED_TEXTURES)
- Error("Too many nested textures.");
- warpNormalTextureList[warpNormalTextures++] = Texture;
- }
- #endif
- /* NK 1998 reset_children - changed TPoint to CPoint and added ", TRUE" */
- Warp_EPoint (CPoint, IPoint, (TPATTERN *)Texture, TRUE);
-
- /* NK phmap */
- if(backtraceFlag)
- {
- if (Prev == Cur)
- {
- do_texture_map(Result_Colour, Cur->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
- }
- else
- {
- value1 = (value1 - Prev->value) / (Cur->value - Prev->value);
- value2 = 1.0 - value1;
- VScale(C2, Result_Colour, value1);
- do_texture_map(C2, Cur->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
- VScale(C2, Result_Colour, value2);
- do_texture_map(C2, Prev->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
- }
- }
- else
- {
- /* NK ---- */
- do_texture_map(Result_Colour, Cur->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
-
- if (Prev != Cur)
- {
- do_texture_map(C2, Prev->Vals.Texture, CPoint, Raw_Normal, Ray, Weight, Ray_Intersection, Shadow_Flag);
-
- value1 = (value1 - Prev->value) / (Cur->value - Prev->value);
- value2 = 1.0 - value1;
-
- CLinComb2(Result_Colour,value1,Result_Colour,value2,C2);
- }
- /* NK phmap */
- }
- /* NK ---- */
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- warpNormalTextures--;
- }
- #endif
- }
- }
-
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * compute_lighted_texture
- *
- * INPUT
- *
- * Texture - a linked list of texture layers
- * IPoint - point to be evaluated
- * Raw_Normal - non-purturbed surface normal
- * Ray - needed for reflection and highlighs
- * Weight - ADC control value
- * Intersection - current intersection (need object type and depth)
- *
- * OUTPUT
- *
- * ResCol - illuminated color of IPoint
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * This routine loops through all layers of a texture and computes
- * the appearent color of the point with illumination, shadows,
- * reflection, refraction... everything. This piece of code was broken out
- * of Determine_Appearent_Colour because texture_map needs to call it twice.
- *
- * CHANGES
- *
- * Jul 1995 : Added code to support alpha channel. [DB]
- *
- * Jul 1995 : Moved code for save list allocation. [DB]
- *
- * Aug 1995 : Added code for distance based attenuation in translucent
- * objects and halos. [DB]
- *
- * Oct 1996 : Replaced halo code by participating media code. [DB]
- *
- * Sep 1999 : Expanded distance based attenuation to include colour.
- * Edward Coffey
- *
- ******************************************************************************/
-
- static void compute_lighted_texture(COLOUR ResCol, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight, INTERSECTION *Intersection)
- {
- int i, radiosity_done, radiosity_needed;
- int layer_number;
- int inside_hollow_object;
- int one_colour_found, colour_found;
- DBL w1;/*, w2;*/
- DBL /*Normal_Direction, */New_Weight;/*, TempWeight;*/
- DBL Att, Trans, Max_Radiosity_Contribution;
- VECTOR LayNormal, TopNormal;
- COLOUR AttCol, LayCol, RflCol, RfrCol, FilCol;
- COLOUR TmpCol, AmbCol, Tmp;
- INTERIOR *Interior;
- IMEDIA **TmpMedia, **MediaList;
- DBL Cos_Angle_Incidence;
- TEXTURE *Layer;
-
- #define MAX_LAYERS 20
-
- int TIR_occured;
-
- DBL ListWeight[MAX_LAYERS];
- DBL ListReflecBlur[MAX_LAYERS];
- int ListReflecSamples[MAX_LAYERS];
- VECTOR ListNormal[MAX_LAYERS];
- COLOUR ListReflec[MAX_LAYERS];
- SNGL ListReflEx[MAX_LAYERS];
-
- /*
- * ResCol builds up the apparent visible color of the point.
- * Only RGB components are significant. You can't "see" transparency --
- * you see the color of whatever is behind the transparent surface.
- * This color includes the visible appearence of what is behind the
- * transparency so only RGB is needed.
- */
-
- Make_ColourA(ResCol, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- /*
- * FilCol serves two purposes. It accumulates the filter properties
- * of a multi-layer texture so that if a ray makes it all the way through
- * all layers, the color of object behind is filtered by this object.
- * It also is used to attenuate how much of an underlayer you
- * can see in a layered texture. Note that when computing the reflective
- * properties of a layered texture, the upper layers don't filter the
- * light from the lower layers -- the layer colors add together (even
- * before we added additive transparency via the "transmit" 5th
- * color channel). However when computing the transmitted rays, all layers
- * filter the light from any objects behind this object. [CY 1/95]
- */
-
- /* NK layers - switched transmit component to zero */
- Make_ColourA(FilCol, 1.0, 1.0, 1.0, 1.0, 0.0);
- /* NK ---- */
-
- Trans = 1.0;
-
- /* Add in radiosity (stochastic interreflection-based ambient light) if desired */
-
- radiosity_done = FALSE;
-
- /* Note that there is no gathering of filter or transparency */
-
- Make_ColourA(AmbCol, 1., 1., 1., 0., 0.);
-
- if ((opts.Options & RADIOSITY && opts.Radiosity_Enabled) &&
- /*(Trace_Level == Radiosity_Trace_Level) &&*/ /* NK rad - allow rad on reflection */
- (Radiosity_Trace_Level <= opts.Radiosity_Recursion_Limit))
- {
- /*
- * For "real" (physically-based) diffuse interreflections, the
- * ambient light level is independent of any surface properties, so
- * the light gathering is done only once. This block just sets up
- * for the code inside the loop, which is first-time-through.
- */
-
- radiosity_needed = 1;
- }
- else
- {
- radiosity_needed = 0;
- }
-
- /*
- * Loop through the layers and compute the ambient, diffuse,
- * phong and specular for these textures.
- */
-
- one_colour_found = FALSE;
-
- for (layer_number = 0, Layer = Texture;
- (Layer != NULL) && (Trans > BLACK_LEVEL);
- layer_number++, Layer = (TEXTURE *)Layer->Next)
- {
- /* Get perturbed surface normal. */
-
- Assign_Vector(LayNormal, Raw_Normal);
-
- if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
- {
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- for(i=0; i<warpNormalTextures; i++)
- {
- Warp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
- TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
- }
- }
- #endif
- Perturb_Normal(LayNormal, Layer->Tnormal, IPoint, Intersection);
- if((Test_Flag(Layer->Tnormal,DONT_SCALE_BUMPS_FLAG)))
- VNormalizeEq(LayNormal);
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- for(i=warpNormalTextures-1; i>=0; i--)
- {
- UnWarp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
- TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
- }
- }
- #endif
- }
-
- /* NK 1998 Reflection Bugfix - removed normal flipping code.. it is
- done earlier in this function. This change also fixes the
- infamous "normal average" bug */
-
- /* Store top layer normal.*/
-
- if (!layer_number)
- {
- Assign_Vector(TopNormal, LayNormal);
- }
-
- /* Get surface colour. */
-
- New_Weight = Weight * Trans;
-
- /* NK 1998 - added Intersection */
- colour_found = Compute_Pigment (LayCol, Layer->Pigment, IPoint, Intersection);
-
- /*
- * If a valid color was returned set one_colour_found to TRUE.
- * An invalid color is returned if a surface point is outside
- * an image map used just once.
- */
-
- if (colour_found)
- {
- one_colour_found = TRUE;
- }
-
- /*
- * This section of code used to be the routine Compute_Reflected_Colour.
- * I copied it in here to rearrange some of it more easily and to
- * see if we could eliminate passing a zillion parameters for no
- * good reason. [CY 1/95]
- */
-
- if (opts.Quality_Flags & Q_FULL_AMBIENT)
- {
- /* Only use top layer and kill transparency if low quality. */
-
- Assign_Colour(ResCol, LayCol);
-
- ResCol[FILTER] =
- ResCol[TRANSM] = 0.0;
- }
- else
- {
- /* --------------------------------------------- */
- /* Store vital information for later reflection. */
- if (layer_number == MAX_LAYERS)
- {
- Error("Too many texture layers.");
- }
-
- ListReflEx[layer_number] = Layer->Finish->Reflect_Exp;
- ListWeight[layer_number] = New_Weight;
- ListReflecBlur[layer_number] = Layer->Finish->Reflection_Blur;
- ListReflecSamples[layer_number]=Layer->Finish->Reflection_Samples;
-
- /* NK 1999 moved here */
- /* Added by MBP for angle-dependent reflectivity */
- VDot(Cos_Angle_Incidence, Ray->Direction, LayNormal);
- Cos_Angle_Incidence *= -1.0;
-
- if (Intersection->Object->Interior ||
- (Layer->Finish->Reflection_Type != 1))
- {
- determine_reflectivity (&ListWeight[layer_number], ListReflec[layer_number],
- Layer->Finish->Reflection_Max, Layer->Finish->Reflection_Min,
- Layer->Finish->Reflection_Type, Layer->Finish->Reflection_Falloff,
- Cos_Angle_Incidence, Ray, Intersection->Object->Interior);
- }
- else
- {
- Error("Reflection_Type 1 used with no interior.\n");
- }
-
- /* Added by MBP for metallic reflection */
- if (Layer->Finish->Reflect_Metallic != 0.0)
- {
- DBL R_M=Layer->Finish->Reflect_Metallic;
-
- DBL x = fabs(acos(Cos_Angle_Incidence)) / M_PI_2;
- DBL F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
- F=min(1.0,max(0.0,F));
-
- ListReflec[layer_number][0]*=
- (1.0 + R_M * (1.0 - F) * (LayCol[0] - 1.0));
- ListReflec[layer_number][1]*=
- (1.0 + R_M * (1.0 - F) * (LayCol[1] - 1.0));
- ListReflec[layer_number][2]*=
- (1.0 + R_M * (1.0 - F) * (LayCol[2] - 1.0));
- /*
- ListReflec[layer_number][0]*=
- (1.0 + R_M*LayCol[0] - R_M);
- ListReflec[layer_number][1]*=
- (1.0 + R_M*LayCol[1] - R_M);
- ListReflec[layer_number][2]*=
- (1.0 + R_M*LayCol[2] - R_M);
- */
- }
- /* NK ---- */
-
- /* NK - SHOULD do something like this:*/
- /*
- ListReflec[layer_number][0]*=FilCol[0];
- ListReflec[layer_number][1]*=FilCol[1];
- ListReflec[layer_number][2]*=FilCol[2];
- */
-
- /* --------------------------------------------- */
- /* now compute the BRDF contribution ----------- */
-
- Att = (1.0 - min(1.0, fabs(LayCol[FILTER]*max3(LayCol[0],LayCol[1],LayCol[2])) + LayCol[TRANSM]));
-
- Make_Colour (TmpCol, 0.0, 0.0, 0.0);
-
- /* if radiosity calculation needed, but not yet done, do it now */
- if (radiosity_needed && !radiosity_done)
- {
- /* This check eliminates radiosity calculations on "luminous" objects with ambient=1 */
-
- /*if ((Layer->Finish->Ambient[0] != 1.0) ||
- (Layer->Finish->Ambient[1] != 1.0) ||
- (Layer->Finish->Ambient[2] != 1.0))
- {*/
- /* calculate max possible contribution of radiosity, to see if calculating it is worthwhile */
-
- Tmp[0] = FilCol[0]*Att * LayCol[0] * Layer->Finish->Diffuse;
- Tmp[1] = FilCol[1]*Att * LayCol[1] * Layer->Finish->Diffuse;
- Tmp[2] = FilCol[2]*Att * LayCol[2] * Layer->Finish->Diffuse;
-
- Max_Radiosity_Contribution = Tmp[0] *.287 + Tmp[1] *.589 + Tmp[2] * .114;
-
- if (Max_Radiosity_Contribution > BLACK_LEVEL * 3.0)
- {
- /* NK rad 22 Nov 1999 - added LayNormal */
- if (opts.Radiosity_Use_Normal)
- (void)Compute_Ambient(Intersection->IPoint, Raw_Normal, LayNormal, AmbCol, Weight * Max_Radiosity_Contribution);
- else
- (void)Compute_Ambient(Intersection->IPoint, Raw_Normal, Raw_Normal, AmbCol, Weight * Max_Radiosity_Contribution);
-
- radiosity_done = TRUE;
- }
- }
-
- /* Add ambient contribution. */
-
- if(radiosity_needed)
- {
- TmpCol[0] += FilCol[0]*Att * LayCol[0] * AmbCol[0] * Layer->Finish->Diffuse;
- TmpCol[1] += FilCol[1]*Att * LayCol[1] * AmbCol[1] * Layer->Finish->Diffuse;
- TmpCol[2] += FilCol[2]*Att * LayCol[2] * AmbCol[2] * Layer->Finish->Diffuse;
- }
- TmpCol[0] += FilCol[0]*Att * LayCol[0] * Layer->Finish->Ambient[0] * Frame.Ambient_Light[0];
- TmpCol[1] += FilCol[1]*Att * LayCol[1] * Layer->Finish->Ambient[1] * Frame.Ambient_Light[1];
- TmpCol[2] += FilCol[2]*Att * LayCol[2] * Layer->Finish->Ambient[2] * Frame.Ambient_Light[2];
-
- /*
- fix this bug so radiosity/ambient doesn't get multiplied by
- FilCol[] twice
- */
- VAddEq(ResCol, TmpCol);
- Make_Colour(TmpCol,0.0,0.0,0.0);
-
- /* NK phmap */
- /* this is needed so blocking light sources know if I am ignoring
- photons (or other valuable information */
- photonOptions.objectFlags = Intersection->Object->Ph_Flags;
- /* NK ---- */
-
- /* Add diffuse, phong, specular, and iridescence contribution. */
- Diffuse(Layer->Finish, Intersection->IPoint, Ray, LayNormal, LayCol, TmpCol, Att, Intersection->Object);
- /* NK layers */
- TmpCol[0]*=FilCol[0];
- TmpCol[1]*=FilCol[1];
- TmpCol[2]*=FilCol[2];
- /* NK ---- */
- VAddEq(ResCol, TmpCol);
-
- /* NK phmap */
- /* now do the same for the photons in the area */
- if(!(Intersection->Object->Ph_Flags & PH_FLAG_IGNORE_PHOTONS))
- {
- PhotonDiffuse(Layer->Finish, Intersection->IPoint, Ray, LayNormal, Raw_Normal, LayCol, TmpCol, Att, Intersection->Object);
- /* NK layers */
- TmpCol[0]*=FilCol[0];
- TmpCol[1]*=FilCol[1];
- TmpCol[2]*=FilCol[2];
- /* NK ---- */
- VAddEq(ResCol, TmpCol);
- }
- /* NK ---- */
- /*GlobalPhotonDiffuse(Layer->Finish, Intersection->IPoint, Ray, LayNormal, LayCol, TmpCol, Att, Intersection->Object);*/
- /*TmpCol[0]*=FilCol[0];
- TmpCol[1]*=FilCol[1];
- TmpCol[2]*=FilCol[2];
- */
- /*VAddEq(ResCol, TmpCol);*/
-
- }
-
- /* Get new filter color. */
-
- if (colour_found)
- {
- FilCol[0] *= (LayCol[0]*LayCol[3]+LayCol[4]);
- FilCol[1] *= (LayCol[1]*LayCol[3]+LayCol[4]);
- FilCol[2] *= (LayCol[2]*LayCol[3]+LayCol[4]);
- /* note FilCol[3] stays at 1.0, [4] stays at 0.0 */
-
- if(Layer->Finish->Conserve_Energy)
- {
- /* adjust filcol based on reflection */
- /* this would work so much better with r,g,b,rt,gt,bt */
- FilCol[0]*=min(1.0,1.0-ListReflec[layer_number][0]);
- FilCol[1]*=min(1.0,1.0-ListReflec[layer_number][1]);
- FilCol[2]*=min(1.0,1.0-ListReflec[layer_number][2]);
- }
- }
-
- /* Get new remaining translucency. */
-
- /* NK layers - changed this */
- Trans = min(1.0, fabs(FilCol[FILTER]*GREY_SCALE(FilCol)) + fabs(FilCol[TRANSM]));
- /* NK ---- */
- }
-
- /*
- * Calculate transmitted component.
- *
- * If the surface is translucent a transmitted ray is traced
- * and its contribution is added to the total ResCol after
- * filtering it by FilCol.
- */
-
- TIR_occured = FALSE;
-
- if (((Interior = Intersection->Object->Interior) != NULL) && (Trans > BLACK_LEVEL) && (opts.Quality_Flags & Q_REFRACT))
- {
- w1 = fabs(FilCol[FILTER]) * max3(FilCol[0], FilCol[1], FilCol[2]);
- /* NK layers
- w2 = 0.0; fabs(FilCol[TRANSM]);
-
- New_Weight = Weight * max(w1, w2);
- */
- New_Weight = Weight * w1;
-
- /* Trace refracted ray. */
-
- TIR_occured = Refract(Interior, Intersection->IPoint, Ray, TopNormal, Raw_Normal, RfrCol, New_Weight);
-
- /* Get distance based attenuation. */
-
- AttCol[0] = AttCol[1] = AttCol[2] = Interior->Old_Refract;
-
- if ((Interior != NULL) && Interior_In_Ray_Container(Ray, Interior) >= 0)
- {
- if (fabs(Interior->Fade_Distance) > EPSILON)
- {
- /* NK attenuate */
- if (Interior->Fade_Power>=1000)
- {
- AttCol[0] *= exp(-(1.0-Interior->Fade_Colour[0])*Intersection->Depth/Interior->Fade_Distance);
- AttCol[1] *= exp(-(1.0-Interior->Fade_Colour[1])*Intersection->Depth/Interior->Fade_Distance);
- AttCol[2] *= exp(-(1.0-Interior->Fade_Colour[2])*Intersection->Depth/Interior->Fade_Distance);
- }
- else
- {
- Att = 1.0 + pow(Intersection->Depth / Interior->Fade_Distance, Interior->Fade_Power);
- AttCol[0] *= Interior->Fade_Colour[0] + (1.0 - Interior->Fade_Colour[0]) / Att;
- AttCol[1] *= Interior->Fade_Colour[1] + (1.0 - Interior->Fade_Colour[1]) / Att;
- AttCol[2] *= Interior->Fade_Colour[2] + (1.0 - Interior->Fade_Colour[2]) / Att;
- }
- }
- }
-
- /* If total internal reflection occured the transmitted light is not filtered. */
-
- if (TIR_occured)
- {
- ResCol[0] += AttCol[0] * RfrCol[0];
- ResCol[1] += AttCol[1] * RfrCol[1];
- ResCol[2] += AttCol[2] * RfrCol[2];
- }
- else
- {
- if (one_colour_found)
- {
- ResCol[0] += AttCol[0] * RfrCol[0] * (FilCol[0] * FilCol[FILTER] + FilCol[TRANSM]);
- ResCol[1] += AttCol[1] * RfrCol[1] * (FilCol[1] * FilCol[FILTER] + FilCol[TRANSM]);
- ResCol[2] += AttCol[2] * RfrCol[2] * (FilCol[2] * FilCol[FILTER] + FilCol[TRANSM]);
- }
- else
- {
- ResCol[0] += AttCol[0] * RfrCol[0];
- ResCol[1] += AttCol[1] * RfrCol[1];
- ResCol[2] += AttCol[2] * RfrCol[2];
- }
- }
-
- /* We need to know the transmittance value for the alpha channel. [DB] */
-
- ResCol[TRANSM] = (0.30*AttCol[0] + 0.59*AttCol[1] + 0.11*AttCol[2]) * FilCol[TRANSM];
- }
-
- /*
- * Calculate reflected component.
- *
- * If total internal reflection occured all reflections using
- * TopNormal are skipped.
- */
-
- if (opts.Quality_Flags & Q_REFLECT)
- {
- for (i = 0; i < layer_number; i++)
- {
- if ((!TIR_occured) ||
- (fabs(TopNormal[0]-ListNormal[i][0]) > EPSILON) ||
- (fabs(TopNormal[1]-ListNormal[i][1]) > EPSILON) ||
- (fabs(TopNormal[2]-ListNormal[i][2]) > EPSILON))
- {
- if ((ListReflec[i][0] != 0.0) ||
- (ListReflec[i][1] != 0.0) ||
- (ListReflec[i][2] != 0.0))
- {
- Reflect(Intersection->IPoint, Ray,
- LayNormal, Raw_Normal, RflCol, ListWeight[i],
- ListReflecBlur[i], ListReflecSamples[i]);
-
- if (ListReflEx[i] != 1.0)
- {
- ResCol[0] += ListReflec[i][0] * pow(RflCol[0],ListReflEx[i]);
- ResCol[1] += ListReflec[i][1] * pow(RflCol[1],ListReflEx[i]);
- ResCol[2] += ListReflec[i][2] * pow(RflCol[2],ListReflEx[i]);
- }
- else
- {
- ResCol[0] += ListReflec[i][0] * RflCol[0];
- ResCol[1] += ListReflec[i][1] * RflCol[1];
- ResCol[2] += ListReflec[i][2] * RflCol[2];
- }
- }
- }
- }
- }
-
- /*
- * Calculate participating media effects.
- */
-
- if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Index > -1))
- {
- inside_hollow_object = TRUE;
-
- /* Test for any solid object. */
-
- for (i = 0; i <= Ray->Index; i++)
- {
- if (!Ray->Interiors[i]->hollow)
- {
- inside_hollow_object = FALSE;
-
- break;
- }
- }
-
- /* Calculate effects of all media we're currently in. */
-
- if (inside_hollow_object)
- {
- #ifdef UseMediaAndLightCache
- LightingMediaListIndex++;
- #ifdef AccumulateCacheStatistics
- MaxLightedTexture=max(MaxLightedTexture,LightingMediaListIndex);
- #endif
-
- if ( LightingMediaListIndex >= MaxMediaCacheDepth)
- {
- ResizeMediaMallocCaches(MaxMediaCacheDepth*2);
- }
-
- if ( Ray->Index+2 >= LightingMediaListCacheSize[LightingMediaListIndex])
- {
- POV_FREE(LightingMediaListCache[LightingMediaListIndex]);
- LightingMediaListCache[LightingMediaListIndex] = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
- LightingMediaListCacheSize[LightingMediaListIndex] = Ray->Index+2;
- }
-
- MediaList=LightingMediaListCache[LightingMediaListIndex];
- #else
- MediaList = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
- #endif
-
- TmpMedia = MediaList;
-
- for (i = 0; i <= Ray->Index; i++)
- {
- if (Ray->Interiors[i]->hollow)
- {
- if (Ray->Interiors[i]->IMedia != NULL)
- {
- *TmpMedia = Ray->Interiors[i]->IMedia;
-
- TmpMedia++;
- }
- }
- }
-
- *TmpMedia = NULL;
-
- #ifdef UseMediaAndLightCache
- if ( *MediaList != NULL)
- Simulate_Media(MediaList, Ray, Intersection, ResCol, FALSE);
-
- LightingMediaListIndex--;
- #else
- Simulate_Media(MediaList, Ray, Intersection, ResCol, FALSE);
- POV_FREE(MediaList);
- #endif
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * compute_shadow_texture
- *
- * INPUT
- *
- * Texture - layered texture through which shadow ray passes
- * IPoint - point through which shadow ray passes
- * Raw_Normal - non-purturbed surface normal
- * Ray - light source ray
- * Ray_Intersection - current intersection (need intersection depth)
- *
- * OUTPUT
- *
- * Filter_Colour - returned filter for shadow ray
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * CHANGES
- *
- * Dec 1994 : Separated from filter_shadow_ray to do texture_map [CEY]
- *
- * May 1995 : Added caustic code by Steve Anger. [DB]
- *
- * Aug 1995 : Caustic code moved here from filter_shadow_ray. [CEY]
- *
- * Oct 1996 : Replaced halo code by participating media code. [DB]
- *
- ******************************************************************************/
- static void compute_shadow_texture (COLOUR Filter_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, INTERSECTION *Ray_Intersection)
- {
- int i, inside_hollow_object, colour_found, one_colour_found;
- DBL Caustics, dot, k;
- VECTOR Layer_Normal;
- COLOUR Refraction, Layer_Pigment_Colour;
- IMEDIA **Media_List, **Tmp;
- TEXTURE *Layer;
- INTERIOR *Interior = Ray_Intersection->Object->Interior;
-
- /* NK layers - switched transmit component to zero */
- Make_ColourA(Filter_Colour, 1.0, 1.0, 1.0, 1.0, 0.0);
-
- one_colour_found = FALSE;
-
- for (Layer = Texture; (Layer != NULL) &&
- (fabs(Filter_Colour[FILTER]) + fabs(Filter_Colour[TRANSM]) > BLACK_LEVEL);
- Layer = (TEXTURE *)Layer->Next)
- {
- /* NK 1998 - added Intersection */
- colour_found = Compute_Pigment (Layer_Pigment_Colour, Layer->Pigment, IPoint, Ray_Intersection);
-
- if (colour_found)
- {
- one_colour_found = TRUE;
-
- /*
- Filter_Colour[RED] *= Layer_Pigment_Colour[RED];
- Filter_Colour[GREEN] *= Layer_Pigment_Colour[GREEN];
- Filter_Colour[BLUE] *= Layer_Pigment_Colour[BLUE];
- Filter_Colour[FILTER] *= Layer_Pigment_Colour[FILTER];
- Filter_Colour[TRANSM] *= Layer_Pigment_Colour[TRANSM];
- */
- /* NK layers - changed this */
- Filter_Colour[RED] *= Layer_Pigment_Colour[RED]*Layer_Pigment_Colour[FILTER]+Layer_Pigment_Colour[TRANSM];
- Filter_Colour[GREEN] *= Layer_Pigment_Colour[GREEN]*Layer_Pigment_Colour[FILTER]+Layer_Pigment_Colour[TRANSM];
- Filter_Colour[BLUE] *= Layer_Pigment_Colour[BLUE]*Layer_Pigment_Colour[FILTER]+Layer_Pigment_Colour[TRANSM];
- /*Filter_Colour[FILTER] *= Layer_Pigment_Colour[FILTER];*/
- /*Filter_Colour[TRANSM] *= Layer_Pigment_Colour[TRANSM];*/
- /* NK ---- */
- }
-
- /* Get normal for faked caustics. (Will rewrite later to cache) */
-
- if ((Interior != NULL) && ((Caustics = Interior->Caustics) != 0.0))
- {
- Assign_Vector(Layer_Normal, Raw_Normal);
-
- if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
- {
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- for(i=0; i<warpNormalTextures; i++)
- {
- Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)warpNormalTextureList[i],
- TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
- }
- }
- #endif
- Perturb_Normal(Layer_Normal, Layer->Tnormal, IPoint, Ray_Intersection);
- if((Test_Flag(Layer->Tnormal,DONT_SCALE_BUMPS_FLAG)))
- VNormalizeEq(Layer_Normal);
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- for(i=warpNormalTextures-1; i>=0; i--)
- {
- UnWarp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)warpNormalTextureList[i],
- TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
- }
- }
- #endif
- }
-
- /* Get new filter/transmit values. */
-
- VDot (dot, Layer_Normal, Ray->Direction);
-
- k = (1.0 + pow(fabs(dot), Caustics));
-
- /*Filter_Colour[FILTER] *= k;
- Filter_Colour[TRANSM] *= k;
- */
- Filter_Colour[RED] *= k;
- Filter_Colour[GREEN] *= k;
- Filter_Colour[BLUE] *= k;
- }
- }
-
- /* Get distance based attenuation. */
-
- if (Interior != NULL)
- {
- Make_Colour(Refraction, 1.0, 1.0, 1.0);
-
- if (Interior_In_Ray_Container(Ray, Interior) >= 0)
- {
- if ((Interior->Fade_Power > 0.0) && (fabs(Interior->Fade_Distance) > EPSILON))
- {
- /* NK - attenuation */
- if (Interior->Fade_Power>=1000)
- {
- Refraction[0] *= exp(-(1.0-Interior->Fade_Colour[0])*Ray_Intersection->Depth/Interior->Fade_Distance);
- Refraction[1] *= exp(-(1.0-Interior->Fade_Colour[1])*Ray_Intersection->Depth/Interior->Fade_Distance);
- Refraction[2] *= exp(-(1.0-Interior->Fade_Colour[2])*Ray_Intersection->Depth/Interior->Fade_Distance);
- }
- else
- {
- k = 1.0 + pow(Ray_Intersection->Depth / Interior->Fade_Distance, Interior->Fade_Power);
- Refraction[0] *= Interior->Fade_Colour[0] + (1 - Interior->Fade_Colour[0]) / k;
- Refraction[1] *= Interior->Fade_Colour[1] + (1 - Interior->Fade_Colour[1]) / k;
- Refraction[2] *= Interior->Fade_Colour[2] + (1 - Interior->Fade_Colour[2]) / k;
- }
- }
- }
- }
- else
- {
- Make_Colour(Refraction, 0.0, 0.0, 0.0);
- }
-
- /* Get distance based attenuation. */
-
- Filter_Colour[RED] *= Refraction[0];
- Filter_Colour[GREEN] *= Refraction[1];
- Filter_Colour[BLUE] *= Refraction[2];
- /*Filter_Colour[FILTER] *= Refraction;*/ /* NK layers - commented this */
- /*Filter_Colour[TRANSM] *= Refraction;*/
-
- /*
- * If no valid color was found we set the filtering channel
- * to zero to make sure that no light amplification occures.
- * That would happen if both the filter and transmit channel
- * were used.
- */
-
- if (!one_colour_found)
- {
- Filter_Colour[FILTER] = 0.0;
- }
-
- /* Calculate participating media effects. */
-
- if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Index > -1))
- {
- inside_hollow_object = TRUE;
-
- /* Test for any solid object. */
-
- for (i = 0; i <= Ray->Index; i++)
- {
- if (!Ray->Interiors[i]->hollow)
- {
- inside_hollow_object = FALSE;
-
- break;
- }
- }
-
- /* Calculate effects of all participating media we're currently in. */
-
- if (inside_hollow_object)
- {
- #ifdef UseMediaAndLightCache
- ShadowMediaListIndex++;
-
- #ifdef AccumulateCacheStatistics
- MaxShadowTextRecCntr=max(MaxShadowTextRecCntr,ShadowMediaListIndex);
- #endif
- if ( ShadowMediaListIndex >= MaxMediaCacheDepth)
- {
- ResizeMediaMallocCaches(MaxMediaCacheDepth*2);
- }
-
- if ( Ray->Index+2 >= ShadowMediaListCacheSize[ShadowMediaListIndex])
- {
- POV_FREE(ShadowMediaListCache[ShadowMediaListIndex]);
- ShadowMediaListCache[ShadowMediaListIndex] = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
- ShadowMediaListCacheSize[ShadowMediaListIndex]=Ray->Index+2;
- }
-
- Media_List=ShadowMediaListCache[ShadowMediaListIndex];
- #else
- Media_List = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
- #endif
- Tmp = Media_List;
-
- for (i = 0; i <= Ray->Index; i++)
- {
- if (Ray->Interiors[i]->hollow)
- {
- if (Ray->Interiors[i]->IMedia != NULL)
- {
- *Tmp = Ray->Interiors[i]->IMedia;
-
- Tmp++;
- }
- }
- }
-
- *Tmp = NULL;
- #ifdef UseMediaAndLightCache
- if ( *Media_List != NULL)
- Simulate_Media(Media_List, Ray, Ray_Intersection, Filter_Colour, TRUE);
-
- ShadowMediaListIndex--;
- #else
- Simulate_Media(Media_List, Ray, Ray_Intersection, Filter_Colour, TRUE);
- POV_FREE(Media_List);
- #endif
- }
- }
- }
-
- /* NK phmap */
- /*****************************************************************************
- *
- * FUNCTION
- *
- * BacktraceDiffuse - currently unused
- *
- * This was intended for using photon mapping as an estimation of radiance
- * to replace or supplement the radiosity feature, but it hasn't been
- * implemented yet.
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * -
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- 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)
- {
- VECTOR REye;
-
- Make_ColourA(Colour, 0,0,0,0,0);
-
- if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
- {
- return;
- }
-
- if (Finish->Specular != 0.0)
- {
- REye[X] = -Out->Direction[X];
- REye[Y] = -Out->Direction[Y];
- REye[Z] = -Out->Direction[Z];
- }
-
- if ((fabs(Light_Colour[RED]) > BLACK_LEVEL) ||
- (fabs(Light_Colour[GREEN]) > BLACK_LEVEL) ||
- (fabs(Light_Colour[BLUE]) > BLACK_LEVEL))
- {
- if (Finish->Diffuse > 0.0)
- {
- do_diffuse(Finish,Light_Source_Ray,Layer_Normal,Colour,Light_Colour,Layer_Pigment_Colour, Attenuation);
- }
-
- if (Finish->Phong > 0.0)
- {
- do_phong(Finish,Light_Source_Ray,Out->Direction,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
- }
-
- if (Finish->Specular > 0.0)
- {
- do_specular(Finish,Light_Source_Ray,REye,Layer_Normal,Colour,Light_Colour, Layer_Pigment_Colour);
- }
-
- if (Finish->Irid > 0.0)
- {
- do_irid(Finish,Light_Source_Ray,Layer_Normal,IPoint,Colour);
- }
-
- }
- }
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * compute_backtrace_texture
- *
- * INPUT
- *
- * Texture - a linked list of texture layers
- * IPoint - point to be evaluated
- * Raw_Normal - non-purturbed surface normal
- * Ray - needed for reflection and highlighs
- * Weight - ADC control value
- * Intersection - current intersection (need object type and depth)
- * ResCol - color of light beam
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Nathan Kopp - adpated from compute_lighted_texture by POV-Ray Team
- *
- * DESCRIPTION
- *
- * MUST CHANGE THIS DESCRIPTION
- * This routine loops through all layers of a texture and computes
- * the appearent color of the point with illumination, shadows,
- * reflection, refraction... everything. This piece of code was broken out
- * of Determine_Appearent_Colour because texture_map needs to call it twice.
- *
- * CHANGES
- *
- *
- ******************************************************************************/
-
- static void compute_backtrace_texture(COLOUR LightCol, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal, RAY *Ray, DBL Weight, INTERSECTION *Intersection)
- {
- int i;
- int layer_number;
- int one_colour_found, colour_found;
- DBL w1, w2;
- DBL New_Weight, TempWeight;
- DBL Att, Trans;
- VECTOR LayNormal, TopNormal;
- COLOUR LayCol, FilCol;
- COLOUR AttCol, TmpCol, ResCol, CurLightCol;
- INTERIOR *Interior;
- /* IMEDIA **TmpMedia, **MediaList; */
- TEXTURE *Layer;
- RAY NewRay;
- int doReflection, doDiffuse, doRefraction;
- DBL reflectionWeight, refractionWeight, diffuseWeight, dieWeight, totalWeight;
- DBL choice;
- int inside_hollow_object;
- IMEDIA ** MediaList, **TmpMedia;
- DBL Cos_Angle_Incidence;
-
- #define MAX_LAYERS 20
-
- int TIR_occured;
-
- DBL ListWeight[MAX_LAYERS];
- DBL ListReflecBlur[MAX_LAYERS];
- int ListReflecSamples[MAX_LAYERS];
- VECTOR ListNormal[MAX_LAYERS];
- COLOUR ListReflec[MAX_LAYERS];
- SNGL ListReflEx[MAX_LAYERS];
-
- /*
- * LightCol is the color of the light beam.
- */
-
- /* result color for doing diffuse */
- Make_ColourA(ResCol, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- /* NK 1998 - switched transmit component to zero */
- Make_ColourA(FilCol, 1.0, 1.0, 1.0, 1.0, 0.0);
-
- Trans = 1.0;
-
- /* initialize the new ray... we will probably end up using it */
- Assign_Vector(NewRay.Initial, Intersection->IPoint);
- Copy_Ray_Containers(&NewRay, Ray);
-
-
- #define MEDIA_BACKTRACE
- #ifdef MEDIA_BACKTRACE
- /*
- * what I've got here for media might work, but maybe not... needs
- * testing. Plus, we really want to optionally store photons in
- * the media... but how do we do that???
- */
-
- /*
- * Calculate participating media effects.
- */
- if ((opts.Quality_Flags & Q_VOLUME) && (Ray->Index > -1))
- {
- /* DBL dist;*/
- /* VECTOR TempPoint;*/
-
- inside_hollow_object = TRUE;
-
- /* Test for any solid object. */
-
- for (i = 0; i <= Ray->Index; i++)
- {
- if (!Ray->Interiors[i]->hollow)
- {
- inside_hollow_object = FALSE;
-
- break;
- }
- }
-
- /* Calculate effects of all media we're currently in. */
-
- if (inside_hollow_object)
- {
- MediaList = (IMEDIA **)POV_MALLOC((Ray->Index+2)*sizeof(IMEDIA *), "temp media list");
-
- TmpMedia = MediaList;
-
- for (i = 0; i <= Ray->Index; i++)
- {
- if (Ray->Interiors[i]->hollow)
- {
- if (Ray->Interiors[i]->IMedia != NULL)
- {
- *TmpMedia = Ray->Interiors[i]->IMedia;
-
- TmpMedia++;
- }
- }
- }
-
- *TmpMedia = NULL;
-
- #if MEDIA_INTERACTION
- /*
- if ((Trace_Level > 1) &&
- !photonOptions.passThruPrev && photonOptions.maxMediaSteps>0 &&
- !(Intersection->Object->Ph_Flags & PH_FLAG_IGNORE_PHOTONS) &&
- Check_Light_Group(Intersection->Object,photonOptions.Light))
- */
- if ((Trace_Level > 1) &&
- !photonOptions.passThruPrev && photonOptions.maxMediaSteps>0)
- {
- Backtrace_Simulate_Media(MediaList, Ray, Intersection, LightCol);
- }
- else
- {
- Simulate_Media(MediaList, Ray, Intersection, LightCol, TRUE); /* light ray */
- }
- #else
- Simulate_Media(MediaList, Ray, Intersection, LightCol, TRUE); /* light ray */
- #endif
-
- POV_FREE(MediaList);
- }
- }
-
- /* atmosphere attenuation */
- /* - this is already done in Trace?!???! (Do_Finite_Atmosphere)
- if ((photonOptions.Light->Media_Interaction) &&
- (photonOptions.Light->Media_Attenuation))
- {
- do_light_ray_atmosphere(Ray, Intersection, LightCol, TRUE);
- }
- */
- #endif
-
- /* Get distance based attenuation. */
- Interior = Intersection->Object->Interior;
- AttCol[0] = AttCol[1] = AttCol[2] = Interior->Old_Refract;
-
- if (Interior != NULL)
- {
- if (Interior_In_Ray_Container(Ray, Interior) >= 0)
- {
- if ((Interior->Fade_Power > 0.0) && (fabs(Interior->Fade_Distance) > EPSILON))
- {
- /* NK attenuate */
- if (Interior->Fade_Power>=1000)
- {
- AttCol[0] *= exp(-(1.0-Interior->Fade_Colour[0])*Intersection->Depth/Interior->Fade_Distance);
- AttCol[1] *= exp(-(1.0-Interior->Fade_Colour[1])*Intersection->Depth/Interior->Fade_Distance);
- AttCol[2] *= exp(-(1.0-Interior->Fade_Colour[2])*Intersection->Depth/Interior->Fade_Distance);
- }
- else
- {
- Att = 1.0 + pow(Intersection->Depth / Interior->Fade_Distance, Interior->Fade_Power);
- AttCol[0] *= Interior->Fade_Colour[0] + (1.0 - Interior->Fade_Colour[0]) / Att;
- AttCol[1] *= Interior->Fade_Colour[1] + (1.0 - Interior->Fade_Colour[1]) / Att;
- AttCol[2] *= Interior->Fade_Colour[2] + (1.0 - Interior->Fade_Colour[2]) / Att;
- }
- }
- }
- }
- LightCol[0] *= AttCol[0];
- LightCol[1] *= AttCol[1];
- LightCol[2] *= AttCol[2];
-
- /* set size here */
- photonOptions.photonDepth += Intersection->Depth;
-
-
- /* First, we should save this photon! */
- if ((Trace_Level > 1) && !photonOptions.passThruPrev &&
- !(Intersection->Object->Ph_Flags & PH_FLAG_IGNORE_PHOTONS) &&
- Check_Light_Group(Intersection->Object,photonOptions.Light))
- {
- addSurfacePhoton(Intersection->IPoint, Ray->Initial, LightCol, Raw_Normal);
- }
-
- if (photonOptions.passThruThis)
- {
- RAY NRay;
-
- Copy_Ray_Containers(&NRay, Ray);
- Assign_Vector(NRay.Initial, IPoint);
- Assign_Vector(NRay.Direction, Ray->Direction);
-
- Trace_Level++;
- #ifdef MotionBlurPatch
- Trace_With_Blur(&NRay, LightCol, Weight, NULL);
- #else
- Trace(&NRay, LightCol, Weight, NULL);
- #endif
- Trace_Level--;
- }
-
- /*
- * Loop through the layers and compute the ambient, diffuse,
- * phong and specular for these textures.
- */
- one_colour_found = FALSE;
- for (layer_number = 0, Layer = Texture;
- (Layer != NULL) && (Trans > BLACK_LEVEL);
- layer_number++, Layer = (TEXTURE *)Layer->Next)
- {
- /* Get perturbed surface normal. */
- Assign_Vector(LayNormal, Raw_Normal);
-
- if ((opts.Quality_Flags & Q_NORMAL) && (Layer->Tnormal != NULL))
- {
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- for(i=0; i<warpNormalTextures; i++)
- {
- Warp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
- TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
- }
- }
- #endif
- Perturb_Normal(LayNormal, Layer->Tnormal, IPoint, Intersection);
- if((Test_Flag(Layer->Tnormal,DONT_SCALE_BUMPS_FLAG)))
- VNormalizeEq(LayNormal);
- #ifdef NormalBugFix
- #ifdef UnofficialBlocking
- if(opts.unofficialVersion>=30)
- #else
- if(opts.Language_Version>310)
- #endif
- {
- for(i=warpNormalTextures-1; i>=0; i--)
- {
- UnWarp_Normal(LayNormal,LayNormal, (TPATTERN *)warpNormalTextureList[i],
- TRUE, Test_Flag(warpNormalTextureList[i],DONT_SCALE_BUMPS_FLAG));
- }
- }
- #endif
- }
-
- /* Store top layer normal.*/
- if (!layer_number)
- {
- Assign_Vector(TopNormal, LayNormal);
- }
-
- /* Get surface colour. */
- New_Weight = Weight * Trans;
- colour_found = Compute_Pigment (LayCol, Layer->Pigment, IPoint, Intersection);
-
- Att = Trans * (1.0 - min(1.0, LayCol[FILTER] + LayCol[TRANSM]));
-
- LayCol[0]*=FilCol[0];
- LayCol[1]*=FilCol[1];
- LayCol[2]*=FilCol[2];
- VAddScaledEq(ResCol, Att, LayCol);
-
- /*
- * If a valid color was returned set one_colour_found to TRUE.
- * An invalid color is returned if a surface point is outside
- * an image map used just once.
- */
- if (colour_found)
- {
- one_colour_found = TRUE;
- }
-
- /* Store vital information for later reflection. */
- if (layer_number == MAX_LAYERS)
- {
- Error("Too many texture layers.");
- }
-
- ListReflEx[layer_number] = Layer->Finish->Reflect_Exp;
- ListWeight[layer_number] = New_Weight;
- ListReflecBlur[layer_number] = Layer->Finish->Reflection_Blur;
- ListReflecSamples[layer_number]=Layer->Finish->Reflection_Samples;
-
- /* NK 1999 moved here */
- /* Added by MBP for angle-dependent reflectivity */
- VDot(Cos_Angle_Incidence, Ray->Direction, LayNormal);
- Cos_Angle_Incidence *= -1.0;
-
- if (Intersection->Object->Interior ||
- (Layer->Finish->Reflection_Type != 1))
- {
- determine_reflectivity (&ListWeight[layer_number], ListReflec[layer_number],
- Layer->Finish->Reflection_Max, Layer->Finish->Reflection_Min,
- Layer->Finish->Reflection_Type, Layer->Finish->Reflection_Falloff,
- Cos_Angle_Incidence, Ray, Intersection->Object->Interior);
- }
- else
- {
- Error("Reflection_Type 1 used with no interior.\n");
- }
-
- /* Added by MBP for metallic reflection */
- if (Layer->Finish->Reflect_Metallic != 0.0)
- {
- DBL R_M=Layer->Finish->Reflect_Metallic;
-
- DBL x = fabs(acos(Cos_Angle_Incidence)) / M_PI_2;
- DBL F = 0.014567225 / Sqr(x - 1.12) - 0.011612903;
- F=min(1.0,max(0.0,F));
-
- ListReflec[layer_number][0]*=
- (1.0 + R_M * (1.0 - F) * (LayCol[0] - 1.0));
- ListReflec[layer_number][1]*=
- (1.0 + R_M * (1.0 - F) * (LayCol[1] - 1.0));
- ListReflec[layer_number][2]*=
- (1.0 + R_M * (1.0 - F) * (LayCol[2] - 1.0));
- /*
- ListReflec[layer_number][0]*=
- (1.0 + R_M*LayCol[0] - R_M);
- ListReflec[layer_number][1]*=
- (1.0 + R_M*LayCol[1] - R_M);
- ListReflec[layer_number][2]*=
- (1.0 + R_M*LayCol[2] - R_M);
- */
- }
- /* NK ---- */
-
- /* NK - SOULD do something like this:*/
- /*
- ListReflec[layer_number][0]*=FilCol[0];
- ListReflec[layer_number][1]*=FilCol[1];
- ListReflec[layer_number][2]*=FilCol[2];
- */
-
- /* Get new filter color. */
- if (colour_found)
- {
- FilCol[0] *= (LayCol[0]*LayCol[3]+LayCol[4]);
- FilCol[1] *= (LayCol[1]*LayCol[3]+LayCol[4]);
- FilCol[2] *= (LayCol[2]*LayCol[3]+LayCol[4]);
- /* note FilCol[3] stays at 1.0 , [4] stays at 0.0 */
- if(Layer->Finish->Conserve_Energy)
- {
- /* adjust filcol based on reflection */
- /* this would work so much better with r,g,b,rt,gt,bt */
- FilCol[0]*=min(1.0,1.0-ListReflec[layer_number][0]);
- FilCol[1]*=min(1.0,1.0-ListReflec[layer_number][1]);
- FilCol[2]*=min(1.0,1.0-ListReflec[layer_number][2]);
- }
- }
-
- /* Get new remaining translucency. */
- Trans = min(1.0, fabs(FilCol[FILTER]*GREY_SCALE(FilCol)));
- }
-
- /*******************
- now that we have color info, we can determine what we want to do next
- ********************/
-
- if (photonOptions.photonObject)
- {
- /* if photon is for caustic map, then do
- reflection/refraction always
- diffuse never
- */
- doReflection = 1;
- doRefraction = 1;
- doDiffuse = 0;
- }
- else
- {
- /* if photon is for global map, then decide which we want to do
- */
- diffuseWeight = max(0.0, fabs(GREY_SCALE(ResCol)));
- /* use top-layer finish only */
- if(Texture->Finish)
- diffuseWeight*=Texture->Finish->Diffuse;
- refractionWeight = Trans;
- /* reflection only for top layer!!!!!! */
- reflectionWeight = max(0.0, fabs(GREY_SCALE(ListReflec[0])));
- dieWeight = max(0.0,(1.0-diffuseWeight));
-
- /* normalize weights: make sum be 1.0 */
- totalWeight = reflectionWeight + refractionWeight + diffuseWeight + dieWeight;
- if (reflectionWeight + refractionWeight + diffuseWeight>BLACK_LEVEL)
- {
- diffuseWeight /= totalWeight;
- refractionWeight /= totalWeight;
- reflectionWeight /= totalWeight;
- dieWeight /= totalWeight;
-
- /* now, determine which we want to use */
- choice = FRAND();
- if (choice<diffuseWeight)
- {
- /* do diffuse */
- VScaleEq(ResCol,1.0/diffuseWeight);
- /*if (diffuseWeight<.999)
- {
- VScaleEq(ResCol,20.0);
- }
- else
- {
- VScaleEq(ResCol,2.0);
- }*/
- doReflection = 0;
- doRefraction = 0;
- doDiffuse = 1;
- photonOptions.passThruPrev = FALSE;
- }
- else if (choice<diffuseWeight+refractionWeight)
- {
- /* do refraction */
- VScaleEq(FilCol,1.0/refractionWeight);
- doReflection = 0;
- doRefraction = 1;
- doDiffuse = 0;
- photonOptions.passThruPrev = TRUE;
- }
- else if (choice<diffuseWeight+refractionWeight+reflectionWeight)
- {
- /* do reflection */
- VScaleEq(ListReflec[0],1.0/reflectionWeight);
- doReflection = 1;
- doRefraction = 0;
- doDiffuse = 0;
- photonOptions.passThruPrev = TRUE;
- }
- /* else die */
- }
- else
- {
- doReflection = 0;
- doRefraction = 0;
- doDiffuse = 0;
- }
-
- }
-
- if (doDiffuse)
- {
- ChooseRay(&NewRay, LayNormal, Ray, Raw_Normal, rand()%400);
-
- CurLightCol[0] = LightCol[0]*ResCol[0];
- CurLightCol[1] = LightCol[1]*ResCol[1];
- CurLightCol[2] = LightCol[2]*ResCol[2];
-
- /* don't trace if < BLACK_LEVEL */
-
- /* now trace it */
- Trace_Level++;
- Trace(&NewRay, CurLightCol, 1.0, NULL);
- Trace_Level--;
- }
-
- /*
- * Calculate transmitted component.
- *
- * If the surface is translucent a transmitted ray is traced
- * and its illunination is filtered by FilCol.
- */
- if (doRefraction)
- {
- TIR_occured = FALSE;
- if ( ((Intersection->Object->Ph_Flags & PH_FLAG_RFR_ON) &&
- !(photonOptions.lightFlags & PH_FLAG_RFR_OFF)) ||
- (!(Intersection->Object->Ph_Flags & PH_FLAG_RFR_OFF) &&
- (photonOptions.lightFlags & PH_FLAG_RFR_ON)) ||
- photonOptions.passThruThis)
- if (((Interior = Intersection->Object->Interior) != NULL) && (Trans > BLACK_LEVEL) && (opts.Quality_Flags & Q_REFRACT))
- {
- w1 = fabs(FilCol[FILTER]) * max3(FilCol[0], FilCol[1], FilCol[2]);
- w2 = fabs(FilCol[TRANSM]);
-
- New_Weight = Weight * max(w1, w2);
-
- /* Trace refracted ray. */
- Assign_Colour(GFilCol, FilCol);
- TIR_occured = BacktraceRefract(Interior, Intersection->IPoint, Ray, TopNormal, Raw_Normal, LightCol, New_Weight);
- }
- }
-
- /*
- * Calculate reflected component.
- *
- * If total internal reflection occured all reflections using
- * TopNormal are skipped.
- */
- if(doReflection)
- {
- if ( (((Intersection->Object->Ph_Flags & PH_FLAG_RFL_ON) &&
- !(photonOptions.lightFlags & PH_FLAG_RFL_OFF)) ||
- (!(Intersection->Object->Ph_Flags & PH_FLAG_RFL_OFF) &&
- (photonOptions.lightFlags & PH_FLAG_RFL_ON))) &&
- !photonOptions.passThruThis)
- if (opts.Quality_Flags & Q_REFLECT)
- {
- for (i = 0; i < layer_number; i++)
- {
- if ((!TIR_occured) ||
- (fabs(TopNormal[0]-ListNormal[i][0]) > EPSILON) ||
- (fabs(TopNormal[1]-ListNormal[i][1]) > EPSILON) ||
- (fabs(TopNormal[2]-ListNormal[i][2]) > EPSILON))
- {
- if ((ListReflec[i][0] != 0.0) ||
- (ListReflec[i][1] != 0.0) ||
- (ListReflec[i][2] != 0.0))
- {
- /* Added by MBP for metallic reflection */
- TmpCol[0]=LightCol[0];
- TmpCol[1]=LightCol[1];
- TmpCol[2]=LightCol[2];
-
- if (ListReflEx[i] != 1.0)
- {
- TmpCol[0] = ListReflec[i][0] * pow(TmpCol[0],ListReflEx[i]);
- TmpCol[1] = ListReflec[i][1] * pow(TmpCol[1],ListReflEx[i]);
- TmpCol[2] = ListReflec[i][2] * pow(TmpCol[2],ListReflEx[i]);
- }
- else
- {
- TmpCol[0] = ListReflec[i][0] * TmpCol[0];
- TmpCol[1] = ListReflec[i][1] * TmpCol[1];
- TmpCol[2] = ListReflec[i][2] * TmpCol[2];
- }
-
- TempWeight = ListWeight[i] * max3(ListReflec[i][0], ListReflec[i][1], ListReflec[i][2]);
-
- if (photonOptions.photonReflectionBlur)
- {
- Reflect(Intersection->IPoint, Ray,
- LayNormal, Raw_Normal, TmpCol, TempWeight,
- ListReflecBlur[i], ListReflecSamples[i]);
- }
- else
- {
- Reflect(Intersection->IPoint, Ray,
- LayNormal, Raw_Normal, TmpCol, TempWeight,
- 0.0,1);
- }
-
- }
- }
-
- /* if global photons, the stop after first layer */
- if (photonOptions.photonObject==NULL)
- i=layer_number;
- }
- }
- }
-
- /* now reset the depth! */
- photonOptions.photonDepth -= Intersection->Depth;
- }
-
- /* NK ---- */
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * filter_shadow_ray
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Aug 1994 : Code for early exit due to opaque object added. [DB]
- *
- * Sep 1994 : Code for multi-textured blobs added. [DB]
- *
- * May 1995 : Added caustic code by Steve Anger. [DB]
- *
- * Aug 1995 : Added code to attenuate light source color
- * due to atmospheric effects. [DB]
- *
- ******************************************************************************/
- static void filter_shadow_ray(INTERSECTION *Ray_Intersection, RAY *Light_Source_Ray, COLOUR Colour)
- {
- int i, Texture_Count;
- VECTOR IPoint;
- VECTOR Raw_Normal;
- COLOUR FC1, Temp_Colour;
- TEXTURE *Texture = NULL; /* To remove uninitialized use warning [AED] */
- size_t save_tw_size;
- DBL *save_Weights = NULL;
- TEXTURE **save_Textures = NULL;
- /* NK 1998 */
- UV_VECT UV_Coords;
- /* NK ---- */
- DBL Normal_Direction;
-
- #ifdef MotionBlurPatch
- if (!backtraceFlag)
- {
- if (!TimeStamp && Ray_Intersection->Object->TimeStamp)
- TimeStamp = Ray_Intersection->Object->TimeStamp;
- }
- #endif
-
- /* NK phmap */
- if ((photonOptions.photonsEnabled) &&
- (Ray_Intersection->Object->Ph_Flags & PH_FLAG_TARGET) &&
- !(photonOptions.objectFlags & PH_FLAG_IGNORE_PHOTONS))
- {
- if( ((Ray_Intersection->Object->Ph_Flags & PH_FLAG_RFR_ON) &&
- !(photonOptions.lightFlags & PH_FLAG_RFR_OFF)) ||
- (!(Ray_Intersection->Object->Ph_Flags & PH_FLAG_RFR_OFF) &&
- (photonOptions.lightFlags & PH_FLAG_RFR_ON)) )
- {
- Make_Colour(Colour, 0.0, 0.0, 0.0);
- return;
- }
- }
- /* NK ---- */
-
- Assign_Vector(IPoint, Ray_Intersection->IPoint);
-
- if (!(opts.Quality_Flags & Q_SHADOW))
- {
- return;
- }
-
- /* If the object is opaque there's no need to go any further. [DB 8/94] */
-
- if (Test_Flag(Ray_Intersection->Object, OPAQUE_FLAG))
- {
- Make_Colour(Colour, 0.0, 0.0, 0.0);
- return;
- }
-
- /* Get the normal to the surface */
-
- Normal(Raw_Normal, Ray_Intersection->Object, Ray_Intersection);
- /* If the surface normal points away, flip its direction. */
- VDot(Normal_Direction, Raw_Normal, Light_Source_Ray->Direction);
- if (Normal_Direction > 0.0)
- {
- VScaleEq(Raw_Normal, -1.0);
- }
-
- Assign_Vector(Ray_Intersection->INormal, Raw_Normal);
- /* and save to intersection -hdf- */
- Assign_Vector(Ray_Intersection->PNormal, Raw_Normal);
-
- if (Test_Flag(Ray_Intersection->Object, UV_FLAG) ||
- (opts.postProcessFlags & PP_FLAG_IUV))
- {
- /* get the UV vect of the intersection */
- UVCoord(UV_Coords, Ray_Intersection->Object, Ray_Intersection);
- /* save the normal and UV coords into Intersection */
- Assign_UV_Vect(Ray_Intersection->Iuv, UV_Coords);
- }
-
- /* now switch to UV mapping if we need to */
- if (Test_Flag(Ray_Intersection->Object, UV_FLAG))
- {
- IPoint[X] = UV_Coords[U];
- IPoint[Y] = UV_Coords[V];
- IPoint[Z] = 0;
- }
-
- /*
- * Save texture and weight lists.
- */
-
- save_tw_size = (size_t)Number_Of_Textures_And_Weights;
- #ifdef UseMediaAndLightCache
- LightingCacheIndex++;
- if ( LightingCacheIndex >= MaxLightCacheDepth)
- {
- ResizeLightMallocCaches(MaxLightCacheDepth*2);
- }
-
- #ifdef AccumulateCacheStatistics
- MaxAppColourRecCntr=max(MaxAppColourRecCntr,LightingCacheIndex);
- #endif
-
- Weight_List=WeightListCache[LightingCacheIndex];
- Light_List=LightListCache[LightingCacheIndex];
- Texture_List=TextureListCache[LightingCacheIndex];
-
- #else
- if (save_tw_size > 0)
- {
- save_Weights = (DBL *)POV_MALLOC(save_tw_size * sizeof(DBL), "Weight list stack");
- memcpy(save_Weights, Weight_List, save_tw_size * sizeof(DBL));
- save_Textures = (TEXTURE **)POV_MALLOC(save_tw_size * sizeof(TEXTURE *), "Weight list stack");
- memcpy(save_Textures, Texture_List, save_tw_size * sizeof(TEXTURE *));
- }
- #endif
- /* Get texture list and weights. */
-
- #ifdef InteriorTexturePatch
- Texture_Count = create_texture_list(Ray_Intersection, Normal_Direction);
- #else
- Texture_Count = create_texture_list(Ray_Intersection);
- #endif
- Make_ColourA(Temp_Colour, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- for (i = 0; i < Texture_Count; i++)
- {
- /* If contribution of this texture is neglectable skip ahead. */
-
- if (Weight_List[i] < BLACK_LEVEL)
- {
- continue;
- }
-
- Texture = Texture_List[i];
-
- do_texture_map(FC1, Texture, IPoint, Raw_Normal, Light_Source_Ray, 0.0, Ray_Intersection, TRUE);
-
- Temp_Colour[RED] += Weight_List[i] * FC1[RED];
- Temp_Colour[GREEN] += Weight_List[i] * FC1[GREEN];
- Temp_Colour[BLUE] += Weight_List[i] * FC1[BLUE];
- Temp_Colour[FILTER] += Weight_List[i] * FC1[FILTER];
- Temp_Colour[TRANSM] += Weight_List[i] * FC1[TRANSM];
- }
-
- /* Restore the weight and texture list. */
-
- #ifdef UseMediaAndLightCache
- LightingCacheIndex--;
- Weight_List=WeightListCache[LightingCacheIndex];
- Light_List=LightListCache[LightingCacheIndex];
- Texture_List=TextureListCache[LightingCacheIndex];
- #else
- if (save_tw_size > 0)
- {
- memcpy(Weight_List, save_Weights, save_tw_size * sizeof(DBL));
- memcpy(Texture_List, save_Textures, save_tw_size * sizeof(TEXTURE *));
- POV_FREE(save_Weights);
- POV_FREE(save_Textures);
- }
- #endif
- if (fabs(Temp_Colour[FILTER]) + fabs(Temp_Colour[TRANSM]) < BLACK_LEVEL)
- {
- Make_Colour(Colour, 0.0, 0.0, 0.0);
- }
- else
- {
- Colour[RED] *= Temp_Colour[FILTER] * Temp_Colour[RED] + Temp_Colour[TRANSM];
- Colour[GREEN] *= Temp_Colour[FILTER] * Temp_Colour[GREEN]+ Temp_Colour[TRANSM];
- Colour[BLUE] *= Temp_Colour[FILTER] * Temp_Colour[BLUE] + Temp_Colour[TRANSM];
- }
-
- /* Get atmospheric attenuation. */
-
- do_light_ray_atmosphere(Light_Source_Ray, Ray_Intersection, Colour, TRUE);
-
- }
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_blocking
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int do_blocking(INTERSECTION *Local_Intersection, RAY *Light_Source_Ray, COLOUR Light_Colour, ISTACK *Local_Stack)
- {
- Increase_Counter(stats[Shadow_Rays_Succeeded]);
-
- filter_shadow_ray(Local_Intersection, Light_Source_Ray, Light_Colour);
-
- if ((fabs(Light_Colour[RED]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[GREEN]) < BLACK_LEVEL) &&
- (fabs(Light_Colour[BLUE]) < BLACK_LEVEL))
- {
- while ((Local_Intersection = pop_entry(Local_Stack)) != NULL)
- {
- }
-
- return(TRUE);
- }
-
- return(FALSE);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * block_light_source
- *
- * INPUT
- *
- * Light - Light source
- * Depth - Distance to light source
- * Light_Source_Ray - Light ray
- * Eye_Ray - Ray from eye to current intersection point
- * P - Surface point to shade
- *
- * OUTPUT
- *
- * Colour - Light color reaching point P
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Determine how much light from the given light source reaches
- * the given point. This includes attenuation due to blocking
- * and translucent objects and atmospheric effects.
- *
- * CHANGES
- *
- * Jan 1995 : Creation (Extracted from common code).
- *
- * Aug 1995 : Added code to support atmospheric effects. [DB]
- *
- ******************************************************************************/
-
- static void block_light_source(LIGHT_SOURCE *Light, DBL Depth, RAY *Light_Source_Ray, RAY *Eye_Ray, VECTOR P, COLOUR Colour)
- {
- DBL New_Depth;
- INTERSECTION Intersection;
- RAY New_Ray;
-
- /* NK phmap */
- /* save the light's flags so we know if we used real caustics */
- photonOptions.lightFlags = Light->Ph_Flags;
- /* NK ---- */
-
- #ifdef MotionBlurPatch
- /* NK Apr 2000 - allow light sources inside motion blur */
- if (TimeStamp)
- {
- if (Light->TimeStamp && TimeStamp != Light->TimeStamp)
- {
- Make_Colour(Colour,0.0,0.0,0.0);
- return;
- }
- }
- else
- {
- if (Light->TimeStamp) TimeStamp = Light->TimeStamp;
- }
- #endif
-
- /* Store current depth and ray because they will be modified. */
-
- New_Depth = Depth;
-
- New_Ray = *Light_Source_Ray;
-
- /* Get shadows from current light source. */
-
- if ((Light->Area_Light) && (opts.Quality_Flags & Q_AREA_LIGHT))
- {
- block_area_light(Light, &New_Depth, &New_Ray, Eye_Ray, P, Colour, 0, 0, 0, 0, 0);
- }
- else
- {
- /* NK parallel - can't use light buffer with parallel lights */
- if ((opts.Options & USE_LIGHT_BUFFER) && (Light->Light_Type!=CYLINDER_SOURCE) &&
- !(Light->Parallel))
- /* NK ---- */
- {
- #ifdef MotionBlurPatch
- block_point_light_LBuffer_with_blur(Light, &New_Depth, &New_Ray, Colour);
- #else
- block_point_light_LBuffer(Light, &New_Depth, &New_Ray, Colour);
- #endif
- }
- else
- {
- #ifdef MotionBlurPatch
- block_point_light_with_blur(Light, &New_Depth, &New_Ray, Colour);
- #else
- block_point_light(Light, &New_Depth, &New_Ray, Colour);
- #endif
- }
- }
-
- /*
- * If there's some distance left for the ray to reach the light source
- * we have to apply atmospheric stuff to this part of the ray.
- */
-
- if ((New_Depth > SHADOW_TOLERANCE) &&
- (Light->Media_Interaction) &&
- (Light->Media_Attenuation))
- {
- Intersection.Depth = New_Depth;
- Set_Media_Light(Light); /* Needed to test Light group against medias */
-
- do_light_ray_atmosphere(&New_Ray, &Intersection, Colour, FALSE);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * average_textures
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * POV-Ray Team
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void average_textures (COLOUR Result_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal,
- RAY *Ray, DBL Weight, INTERSECTION *Ray_Intersection, int Shadow_Flag)
- {
- int i;
- COLOUR LC;
- BLEND_MAP *Map = Texture->Blend_Map;
- SNGL Value;
- SNGL Total = 0.0;
-
- Make_Colour (Result_Colour, 0.0, 0.0, 0.0);
-
- for (i = 0; i < Map->Number_Of_Entries; i++)
- {
- Value = Map->Blend_Map_Entries[i].value;
-
- do_texture_map (LC,Map->Blend_Map_Entries[i].Vals.Texture, IPoint,Raw_Normal,Ray,Weight,Ray_Intersection,Shadow_Flag);
-
- Result_Colour[RED] += LC[RED] *Value;
- Result_Colour[GREEN] += LC[GREEN] *Value;
- Result_Colour[BLUE] += LC[BLUE] *Value;
- Result_Colour[FILTER]+= LC[FILTER]*Value;
- Result_Colour[TRANSM]+= LC[TRANSM]*Value;
-
- Total += Value;
- }
-
- Result_Colour[RED] /= Total;
- Result_Colour[GREEN] /= Total;
- Result_Colour[BLUE] /= Total;
- Result_Colour[FILTER]/= Total;
- Result_Colour[TRANSM]/= Total;
- }
-
- /* NK phmap */
- /*****************************************************************************
- *
- * FUNCTION
- *
- * backtrace_average_textures
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Nathan Kopp
- * based on average_textures by the POV-Ray Team
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void backtrace_average_textures (COLOUR Result_Colour, TEXTURE *Texture, VECTOR IPoint, VECTOR Raw_Normal,
- RAY *Ray, DBL Weight, INTERSECTION *Ray_Intersection, int Shadow_Flag)
- {
- int i;
- COLOUR LC;
- BLEND_MAP *Map = Texture->Blend_Map;
- SNGL Value;
- SNGL Total = 0.0;
-
- /*Make_Colour (Result_Colour, 0.0, 0.0, 0.0);*/
-
- for (i = 0; i < Map->Number_Of_Entries; i++)
- {
- Value = Map->Blend_Map_Entries[i].value;
- Total += Value;
- }
-
- for (i = 0; i < Map->Number_Of_Entries; i++)
- {
- Value = Map->Blend_Map_Entries[i].value / Total;
- VScale(LC, Result_Colour, Value);
-
- do_texture_map (LC,Map->Blend_Map_Entries[i].Vals.Texture, IPoint,Raw_Normal,Ray,Weight,Ray_Intersection,Shadow_Flag);
- }
- }
- /* NK ---- */
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * do_light_ray_atmosphere
- *
- * INPUT
- *
- * Light_Source_Ray - Current ray towards light source
- * Ray_Intersection - Current intersection with a blocking object
- * Texture - Current PNFH texture
- * Valid_Object - Flag: 1=a valid object is in the intersection struct
- *
- * OUTPUT
- *
- * Colour - Attenuated light source color
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Determine the influence of atmospheric effects on a light source ray.
- *
- * CHANGES
- *
- * Aug 1995 : Creation.
- *
- ******************************************************************************/
-
- static void do_light_ray_atmosphere(RAY *Light_Source_Ray, INTERSECTION *Ray_Intersection, COLOUR Colour, int Valid_Object)
- {
- int interior_nr;
- int i, all_hollow;
-
- /* Why are we here? */
-
- if ((Colour[RED] < BLACK_LEVEL) && (Colour[GREEN] < BLACK_LEVEL) && (Colour[BLUE] < BLACK_LEVEL))
- {
- return;
- }
-
- all_hollow = TRUE;
-
- for (i = 0; i <= Light_Source_Ray->Index; i++)
- {
- if (!Light_Source_Ray->Interiors[i]->hollow)
- {
- all_hollow = FALSE;
-
- break;
- }
- }
-
- /* Apply atmospheric effects inside and/or outside any object. */
-
- if ((opts.Quality_Flags & Q_VOLUME) && (all_hollow || (Valid_Object && Ray_Intersection->Object->Interior != NULL)))
- {
- Do_Finite_Atmosphere(Light_Source_Ray, Ray_Intersection, Colour, TRUE);
- }
-
- /* Handle contained textures. */
-
- if (Valid_Object)
- {
- if (Light_Source_Ray->Index == -1)
- {
- /* The ray is entering from the atmosphere */
-
- Ray_Enter(Light_Source_Ray, Ray_Intersection->Object->Interior);
- }
- else
- {
- /* The ray is currently inside an object */
-
- if ((interior_nr = Interior_In_Ray_Container(Light_Source_Ray, Ray_Intersection->Object->Interior)) >= 0)
- {
- /* The ray is leaving the current object */
-
- Ray_Exit(Light_Source_Ray, interior_nr);
- }
- else
- {
- /* The ray is entering a new object */
-
- Ray_Enter(Light_Source_Ray, Ray_Intersection->Object->Interior);
- }
- }
- }
- }
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * determine_reflectivity
- *
- * INPUT
- *
- * OUTPUT
- *
- * weight - ADC weight of reflected ray
- * reflection - Reflectivity value to be passed to Reflect()
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Michael Paul <mbp@locke.ccil.org>
- *
- * DESCRIPTION
- *
- * Determine the reflecivity of a surface at a point, taking into account the
- * surface's reflectivity and the viewing angle
- *
- * CHANGES
- *
- * Sep 1998 : Creation
- *
- ******************************************************************************/
-
- void determine_reflectivity(DBL *weight, RGB reflectivity, COLOUR Reflection_Max,
- COLOUR Reflection_Min, int Reflection_Type, DBL Reflection_Falloff,
- DBL cos_angle, RAY *Ray, INTERIOR *Interior)
- {
- DBL Temp_Weight_Min, Temp_Weight_Max;
- DBL Reflection_Frac;
- DBL g, F;
- int i;
-
- DBL ior, ior2, disp;
-
- if (Reflection_Type==1)
- {
- /* Get ratio of iors depending on the interiors the ray is traversing. */
- if (Ray->Index == -1)
- {
- /* The ray is entering from the atmosphere. */
- ior = Frame.Atmosphere_IOR / Interior->IOR;
- disp = Frame.Atmosphere_Dispersion / Interior->Dispersion;
- }
- else
- {
- /* The ray is currently inside an object. */
- if ((Interior_In_Ray_Container(Ray, Interior)) >= 0)
- {
- if (Ray->Index == 0)
- {
- /* The ray is leaving into the atmosphere. */
- ior = Interior->IOR / Frame.Atmosphere_IOR;
- disp = Interior->Dispersion / Frame.Atmosphere_Dispersion;
- }
- else
- {
- /* The ray is leaving into another object. */
- ior = Interior->IOR / Ray->Interiors[Ray->Index]->IOR;
- disp = Interior->Dispersion / Ray->Interiors[Ray->Index]->Dispersion;
- }
- }
- else
- {
- /* The ray is entering a new object. */
- ior = Ray->Interiors[Ray->Index]->IOR / Interior->IOR;
- disp = Ray->Interiors[Ray->Index]->Dispersion / Interior->Dispersion;
- }
- }
-
- ior = 1.0/ior;
- disp = 1.0/disp;
- }
-
-
- switch (Reflection_Type)
- {
- case 0: /* Standard reflection */
- Temp_Weight_Max = max3(Reflection_Max[RED], Reflection_Max[GREEN], Reflection_Max[BLUE]);
- Temp_Weight_Min = max3(Reflection_Min[RED], Reflection_Min[GREEN], Reflection_Min[BLUE]);
- *weight = *weight * max(Temp_Weight_Max, Temp_Weight_Min);
-
- if(fabs(Reflection_Falloff-1.0)>EPSILON)
- {
- Reflection_Frac = pow(1.0 - cos_angle, Reflection_Falloff);
- }
- else
- {
- Reflection_Frac = 1.0 - cos_angle;
- }
- if(fabs(Reflection_Frac)<EPSILON)
- {
- Assign_Vector(reflectivity, Reflection_Min);
- }
- else if (fabs(Reflection_Frac-1.0)<EPSILON)
- {
- Assign_Vector(reflectivity, Reflection_Max);
- }
- else
- {
- VLinComb2(reflectivity, Reflection_Frac, Reflection_Max, (1 - Reflection_Frac), Reflection_Min);
- }
- break;
-
- case 1: /* Fresnel */
- if(fabs(disp - 1.0) < EPSILON)
- {
- g = sqrt(Sqr(ior) + Sqr(cos_angle) - 1);
- F = 0.5 * (Sqr(g - cos_angle) / Sqr(g + cos_angle));
- F = F * (1 + Sqr(cos_angle * (g + cos_angle) - 1) / Sqr(cos_angle * (g - cos_angle) + 1));
-
- F=min(1.0,max(0.0,F));
- /* NK - changed - not always monochromatic anymore */
- if(Reflection_Max[0]==0.0 && Reflection_Max[1]==0.0 && Reflection_Max[2]==0.0)
- {
- Make_RGB(reflectivity,F,F,F);
- }
- else
- {
- VLinComb2(reflectivity,F,Reflection_Max,(1.0-F),Reflection_Min);
- }
- }
- for (i=0;i<3; i++)
- {
- ior2 = ior /sqrt(disp) * pow(disp,(DBL)i/2.5);
- g = sqrt(Sqr(ior2) + Sqr(cos_angle) - 1.0);
- F = 0.5 * (Sqr(g - cos_angle) / Sqr(g + cos_angle));
- F = F * (1.0 + Sqr(cos_angle * (g + cos_angle) - 1.0) / Sqr(cos_angle * (g - cos_angle) + 1.0));
-
- F=min(1.0,max(0.0,F));
- /* NK - changed - not always monochromatic anymore */
- if(Reflection_Max[0]==0.0 && Reflection_Max[1]==0.0 && Reflection_Max[2]==0.0)
- {
- reflectivity[i]=F;
- }
- else
- {
- reflectivity[i] = F*Reflection_Max[i] + (1.0-F)*Reflection_Min[i];
- }
- }
-
- *weight = *weight * max3(reflectivity[0],reflectivity[1],reflectivity[2]);
- break;
-
- default:
- Error("Illegal reflection_type.\n");
- }
- }
-
- /* NK phmap */
- /*****************************************************************************
- *
- * FUNCTION
- *
- * GlobalPhotonDiffuse (based on Diffuse)
- *
- * Preconditions:
- * same as Diffuse() with this addition:
- *
- * If photonOptions.photonsEnabled is true now, then
- * InitBacktraceEverything must have been called with
- * photonOptions.photonsEnabled true.
- *
- *
- * AUTHOR
- *
- * Nathan Kopp (this is based on Diffuse)
- *
- * DESCRIPTION
- *
- * Computes diffuse, phong, specular, etc. based on the incoming photons
- * stored in the various photon maps.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void GlobalPhotonDiffuse (FINISH *Finish, VECTOR IPoint, RAY *Eye, VECTOR Layer_Normal, COLOUR Layer_Pigment_Colour, COLOUR Colour, DBL Attenuation, OBJECT *Object)
- {
- DBL Cos_Shadow_Angle;
- RAY Light_Source_Ray;
- VECTOR REye;
- COLOUR Light_Colour, TempCol, Colour2;
- DBL Size, r, tempr;
- int n, tempn;
- int j;
- /*int step;*/
- DBL thisDensity=0;
- DBL prevDensity=0.0000000000000001; /* avoid div-by-zero error */
- int expanded = FALSE;
- DBL att; /* attenuation for lambertian compensation & filters */
-
- if (!photonOptions.globalPhotonMap.numPhotons)
- {
- Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
- return;
- }
-
- if ((Finish->Diffuse == 0.0) && (Finish->Specular == 0.0) && (Finish->Phong == 0.0))
- {
- Make_ColourA(Colour,0.0,0.0,0.0,0.0,0.0);
- return;
- }
-
- /* statistics */
- Increase_Counter(stats[Gather_Performed_Count]);
-
- if (Finish->Specular != 0.0)
- {
- REye[X] = -Eye->Direction[X];
- REye[Y] = -Eye->Direction[Y];
- REye[Z] = -Eye->Direction[Z];
- }
-
- Make_Colour(Colour,0,0,0);
- Make_Colour(Colour2,0,0,0);
- Make_Colour(TempCol,0,0,0);
-
- /*Size = photonOptions.globalGatherRad;*/
- Size = 2.0;
-
- tempr = 0;
-
- /* gather the photons */
- tempn=gatherPhotons(IPoint, Size, &tempr,Layer_Normal,TRUE,&photonOptions.globalPhotonMap);
-
- /* now go through these photons and add up their contribution */
- for(j=0; j<tempn; j++)
- {
- SMALL_COLOUR col;
- /*DBL theta,phi;*/
- int theta,phi;
-
- /* convert small color to normal color */
- col = photonOptions.photonGatherList[j]->Colour;
- UNPACK_COLOUR(Light_Colour, col, photonOptions.globalPhotonMap);
-
- /* convert theta/phi to vector direction
- Use a pre-computed array of sin/cos to avoid many calls to the
- sin() and cos() functions. These arrays were initialized in
- InitBacktraceEverything.
- */
- theta = photonOptions.photonGatherList[j]->theta+127;
- phi = photonOptions.photonGatherList[j]->phi+127;
-
- Light_Source_Ray.Direction[Y] = photonOptions.sinTheta[theta];
- Light_Source_Ray.Direction[X] = photonOptions.cosTheta[theta];
-
- Light_Source_Ray.Direction[Z] = Light_Source_Ray.Direction[X]*photonOptions.sinTheta[phi];
- Light_Source_Ray.Direction[X] = Light_Source_Ray.Direction[X]*photonOptions.cosTheta[phi];
-
- VSub(Light_Source_Ray.Initial, photonOptions.photonGatherList[j]->Loc, Light_Source_Ray.Direction);
-
- /* this compensates for real lambertian (diffuse) lighting (see paper) */
- VDot(att, Layer_Normal, Light_Source_Ray.Direction);
- if (att>1) att=1.0;
- if (att<.1) att = 0.1; /* limit to 10x - otherwise we get bright dots */
- att = 1.0 / fabs(att);
-
- /* do gaussian filter */
- /*att *= 0.918*(1.0-(1.0-exp((-1.953) * photonOptions.photonDistances[j])) / (1.0-exp(-1.953)) );*/
- /* do cone filter */
- /*att *= 1.0-(sqrt(photonOptions.photonDistances[j])/(4.0 * tempr)) / (1.0-2.0/(3.0*4.0));*/
-
- VScaleEq(Light_Colour,att);
-
- /* See if light on far side of surface from camera. */
- if (!(Test_Flag(Object, DOUBLE_ILLUMINATE_FLAG)))
- {
- VDot(Cos_Shadow_Angle, Layer_Normal, Light_Source_Ray.Direction);
- if (Cos_Shadow_Angle < EPSILON)
- continue;
- }
-
- /* now add diffuse, phong, specular, irid contribution */
- if (Finish->Diffuse > 0.0)
- {
- do_diffuse(Finish,&Light_Source_Ray,Layer_Normal,TempCol,Light_Colour,Layer_Pigment_Colour, Attenuation);
- }
- if (Finish->Phong > 0.0)
- {
- do_phong(Finish,&Light_Source_Ray,Eye->Direction,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
- }
- if (Finish->Specular > 0.0)
- {
- do_specular(Finish,&Light_Source_Ray,REye,Layer_Normal,TempCol,Light_Colour, Layer_Pigment_Colour);
- }
- if (Finish->Irid > 0.0)
- {
- do_irid(Finish,&Light_Source_Ray,Layer_Normal,IPoint,TempCol);
- }
-
- }
-
- /* density of this search */
- thisDensity = tempn / (tempr*tempr);
-
- r = tempr;
- n = tempn;
- Assign_Colour(Colour2, TempCol);
-
- /* finish the photons equation */
- VScaleEq(Colour2, (DBL)(1.0)/(M_PI*r*r));
-
- /* add photon contribution to total lighting */
- VAddEq(Colour, Colour2);
- }
- /* NK ---- */
-
-
-
-
-
-
-
-
- #ifdef UseMediaAndLightCache
-
- static void InitMallocCaches(void)
- {
- int i;
- long DBLSize = Number_Of_Textures_And_Weights * sizeof(DBL);
- long TEXTURESize = Number_Of_Textures_And_Weights * sizeof(TEXTURE *);
- int NumberOfLightSources = Frame.Number_Of_Light_Sources;
-
- MaxMediaCacheDepth = DEFAULT_MEDIA_BUF_DEPTH;
- MaxLightCacheDepth = DEFAULT_LIGHT_BUF_DEPTH;
-
- MediaMallocCacheSize=0;
- TotalMallocCacheSize=0;
-
- #ifdef AccumulateCacheStatistics
- MaxShadowTextRecCntr=-1;
- MaxLightedTexture=-1;
- MaxAppColourRecCntr=-1;
- MaxSimMediatRecCntr=-1;
- #endif
-
- ShadowMediaListIndex=-1;
- LightingMediaListIndex=-1;
- MediaCacheIndex=-1;
- LightingCacheIndex=-1;
-
- if ( NumberOfLightSources==0 )
- NumberOfLightSources = 2;
-
- s0 = (DBL *)POV_MALLOC(NumberOfLightSources*sizeof(DBL), "temp data");
- s1 = (DBL *)POV_MALLOC(NumberOfLightSources*sizeof(DBL), "temp data");
-
- ShadowMediaListCacheSize = (long *)POV_MALLOC(MaxMediaCacheDepth*sizeof(long *), "temp media list");
- LightingMediaListCacheSize = (long *)POV_MALLOC(MaxMediaCacheDepth*sizeof(long *), "temp media list");
- MediaIntervalCacheSize = (long *)POV_MALLOC(MaxMediaCacheDepth*sizeof(long *), "temp media list");
- ShadowMediaListCache = (IMEDIA ***)POV_MALLOC(MaxMediaCacheDepth*sizeof(IMEDIA **), "temp media list");
- LightingMediaListCache = (IMEDIA ***)POV_MALLOC(MaxMediaCacheDepth*sizeof(IMEDIA **), "temp media list");
- MediaLightListCache = (LIGHT_LIST **)POV_MALLOC(MaxMediaCacheDepth*sizeof(LIGHT_LIST *), "light list");
- MediaLitIntervalCache = (LIT_INTERVAL **)POV_MALLOC(MaxMediaCacheDepth*sizeof(LIT_INTERVAL *), "lit interval");
- MediaIntervalCache = (MEDIA_INTERVAL **)POV_MALLOC(MaxMediaCacheDepth*sizeof(MEDIA_INTERVAL *), "media intervals");
-
- for ( i=0; i<MaxMediaCacheDepth; i++)
- {
- ShadowMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
- ShadowMediaListCacheSize[i]=10;
- LightingMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
- LightingMediaListCacheSize[i]=10;
- MediaLightListCache[i] = (LIGHT_LIST *)POV_MALLOC(NumberOfLightSources*sizeof(LIGHT_LIST), "light list");
- MediaLitIntervalCache[i] = (LIT_INTERVAL *)POV_MALLOC((2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL), "lit interval");
- MediaIntervalCache[i]= (MEDIA_INTERVAL *)POV_MALLOC(10*sizeof(MEDIA_INTERVAL), "media intervals");
- MediaIntervalCacheSize[i]=10;
-
- MediaMallocCacheSize+=10*sizeof(IMEDIA *)+10*sizeof(IMEDIA *)+NumberOfLightSources*sizeof(LIGHT_LIST)+
- (2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL)+10*sizeof(MEDIA_INTERVAL);
- }
-
- TotalMallocCacheSize += MediaMallocCacheSize;
-
- WeightListCache = (DBL **)POV_MALLOC(MaxLightCacheDepth*sizeof(DBL *), "Weight list stack");
- TextureListCache = (TEXTURE ***)POV_MALLOC(MaxLightCacheDepth*sizeof(TEXTURE **), "Weight list stack");
- LightListCache = (LIGHT_TESTED **)POV_MALLOC(MaxLightCacheDepth*sizeof(LIGHT_TESTED *), "Weight list stack");
-
- for ( i=0; i<MaxLightCacheDepth; i++)
- {
- WeightListCache[i]= (DBL *)POV_MALLOC(DBLSize, "Weight list stack");
- TextureListCache[i]= (TEXTURE **)POV_MALLOC(TEXTURESize, "Weight list stack");
- LightListCache[i] = (LIGHT_TESTED *)POV_MALLOC(max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED), "Weight list stack");
- TotalMallocCacheSize += DBLSize+ TEXTURESize+ DBLSize+ TEXTURESize+
- max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED);
- }
- }
-
-
- static void DeInitMallocCaches(void)
- {
- int i;
-
- if ( s0 != NULL) POV_FREE(s0); s0=NULL;
- if ( s1 != NULL) POV_FREE(s1); s1=NULL;
-
- if (ShadowMediaListCache)
- {
- for (i=0; i<MaxMediaCacheDepth; i++)
- {
- if ( ShadowMediaListCache[i] != NULL) POV_FREE(ShadowMediaListCache[i]);
- ShadowMediaListCache[i]=NULL;
-
- if ( LightingMediaListCache[i] != NULL) POV_FREE(LightingMediaListCache[i]);
- LightingMediaListCache[i]=NULL;
-
- if ( MediaLightListCache[i] != NULL) POV_FREE(MediaLightListCache[i]);
- MediaLightListCache[i]=NULL;
-
- if ( MediaLitIntervalCache[i] != NULL) POV_FREE(MediaLitIntervalCache[i]);
- MediaLitIntervalCache[i]=NULL;
-
- if ( MediaIntervalCache[i] != NULL) POV_FREE(MediaIntervalCache[i]);
- MediaIntervalCache[i]=NULL;
- }
- }
-
- if (ShadowMediaListCache != NULL) POV_FREE(ShadowMediaListCache);
- ShadowMediaListCache=NULL;
-
- if ( LightingMediaListCache != NULL) POV_FREE(LightingMediaListCache);
- LightingMediaListCache=NULL;
-
- if ( MediaLightListCache != NULL) POV_FREE(MediaLightListCache);
- MediaLightListCache=NULL;
-
- if ( MediaLitIntervalCache != NULL) POV_FREE(MediaLitIntervalCache);
- MediaLitIntervalCache=NULL;
-
- if ( MediaIntervalCache != NULL) POV_FREE(MediaIntervalCache);
- MediaIntervalCache=NULL;
-
-
- if (LightListCache)
- {
- for (i=0; i<MaxLightCacheDepth; i++)
- {
- if ( LightListCache[i] != NULL) POV_FREE(LightListCache[i]);
- LightListCache[i]=NULL;
-
- if ( WeightListCache[i] != NULL) POV_FREE(WeightListCache[i]);
- WeightListCache[i]=NULL;
-
- if ( TextureListCache[i] != NULL) POV_FREE(TextureListCache[i]);
- TextureListCache[i]=NULL;
- }
- }
- /*YS sept 17 2000 memory leak fix */
- if ( ShadowMediaListCacheSize != NULL) POV_FREE(ShadowMediaListCacheSize);
- ShadowMediaListCacheSize=NULL;
- if ( LightingMediaListCacheSize != NULL) POV_FREE(LightingMediaListCacheSize);
- LightingMediaListCacheSize=NULL;
- if ( MediaIntervalCacheSize != NULL) POV_FREE(MediaIntervalCacheSize);
- MediaIntervalCacheSize=NULL;
- /*YS*/
-
- if ( LightListCache != NULL) POV_FREE(LightListCache);
- LightListCache=NULL;
-
- if ( WeightListCache != NULL) POV_FREE(WeightListCache);
- WeightListCache=NULL;
-
- if ( TextureListCache != NULL) POV_FREE(TextureListCache);
- TextureListCache=NULL;
- }
-
- static void ReInitMallocCaches(void)
- {
- int i;
- long DBLSize=Number_Of_Textures_And_Weights * sizeof(DBL);
- long TEXTURESize=Number_Of_Textures_And_Weights * sizeof(TEXTURE *);
-
- TotalMallocCacheSize=MediaMallocCacheSize;
-
- for ( i=0; i<MaxLightCacheDepth; i++)
- {
- WeightListCache[i]= (DBL *)POV_REALLOC(WeightListCache[i],DBLSize, "Weight list stack");
- TextureListCache[i]= (TEXTURE **)POV_REALLOC(TextureListCache[i],TEXTURESize, "Weight list stack");
- LightListCache[i] = (LIGHT_TESTED *)POV_REALLOC(LightListCache[i],max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED), "Weight list stack");
- TotalMallocCacheSize+=DBLSize+ TEXTURESize+ DBLSize+TEXTURESize+
- max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED);
- }
- }
-
-
- void ResizeMediaMallocCaches(long newSize)
- {
- int i;
- int NumberOfLightSources = Frame.Number_Of_Light_Sources;
- if ( NumberOfLightSources==0 ) NumberOfLightSources = 2;
- /* subtract this... we'll add it back later */
- TotalMallocCacheSize -= MediaMallocCacheSize;
- ShadowMediaListCacheSize = (long *)POV_REALLOC(ShadowMediaListCacheSize, newSize*sizeof(long *), "temp media list");
- LightingMediaListCacheSize = (long *)POV_REALLOC(LightingMediaListCacheSize, newSize*sizeof(long *), "temp media list");
- MediaIntervalCacheSize = (long *)POV_REALLOC(MediaIntervalCacheSize, newSize*sizeof(long *), "temp media list");
- ShadowMediaListCache = (IMEDIA ***)POV_REALLOC(ShadowMediaListCache, newSize*sizeof(IMEDIA **), "temp media list");
- LightingMediaListCache = (IMEDIA ***)POV_REALLOC(LightingMediaListCache, newSize*sizeof(IMEDIA **), "temp media list");
- MediaLightListCache = (LIGHT_LIST **)POV_REALLOC(MediaLightListCache, newSize*sizeof(LIGHT_LIST *), "light list");
- MediaLitIntervalCache = (LIT_INTERVAL **)POV_REALLOC(MediaLitIntervalCache, newSize*sizeof(LIT_INTERVAL *), "lit interval");
- MediaIntervalCache = (MEDIA_INTERVAL **)POV_REALLOC(MediaIntervalCache, newSize*sizeof(MEDIA_INTERVAL *), "media intervals");
-
-
- for ( i=MaxMediaCacheDepth; i<newSize; i++)
- {
- ShadowMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
- ShadowMediaListCacheSize[i]=10;
- LightingMediaListCache[i] = (IMEDIA **)POV_MALLOC(10*sizeof(IMEDIA *), "temp media list");
- LightingMediaListCacheSize[i]=10;
- MediaLightListCache[i] = (LIGHT_LIST *)POV_MALLOC(NumberOfLightSources*sizeof(LIGHT_LIST), "light list");
- MediaLitIntervalCache[i] = (LIT_INTERVAL *)POV_MALLOC((2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL), "lit interval");
- MediaIntervalCache[i]= (MEDIA_INTERVAL *)POV_MALLOC(10*sizeof(MEDIA_INTERVAL), "media intervals");
- MediaIntervalCacheSize[i]=10;
-
- MediaMallocCacheSize+=10*sizeof(IMEDIA *)+10*sizeof(IMEDIA *)+NumberOfLightSources*sizeof(LIGHT_LIST)+
- (2*NumberOfLightSources+1)*sizeof(LIT_INTERVAL)+10*sizeof(MEDIA_INTERVAL);
- }
- MaxMediaCacheDepth=newSize;
-
- /* add media stuff back on now */
- TotalMallocCacheSize += MediaMallocCacheSize;
- }
-
- void ResizeLightMallocCaches(long newSize)
- {
- int i;
- long DBLSize = Number_Of_Textures_And_Weights * sizeof(DBL);
- long TEXTURESize = Number_Of_Textures_And_Weights * sizeof(TEXTURE *);
- int NumberOfLightSources = Frame.Number_Of_Light_Sources;
- if ( NumberOfLightSources==0 ) NumberOfLightSources = 2;
-
- WeightListCache = (DBL **)POV_REALLOC(WeightListCache, newSize*sizeof(DBL *), "Weight list stack");
- TextureListCache = (TEXTURE ***)POV_REALLOC(TextureListCache, newSize*sizeof(TEXTURE **), "Weight list stack");
- LightListCache = (LIGHT_TESTED **)POV_REALLOC(LightListCache, newSize*sizeof(LIGHT_TESTED *), "Weight list stack");
-
- for ( i=MaxLightCacheDepth; i<newSize; i++)
- {
- WeightListCache[i]= (DBL *)POV_MALLOC(DBLSize, "Weight list stack");
- TextureListCache[i]= (TEXTURE **)POV_MALLOC(TEXTURESize, "Weight list stack");
- LightListCache[i] = (LIGHT_TESTED *)POV_MALLOC(max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED), "Weight list stack");
- TotalMallocCacheSize += DBLSize+ TEXTURESize+ DBLSize+ TEXTURESize+
- max(1,Frame.Number_Of_Light_Sources)*sizeof(LIGHT_TESTED);
- }
- MaxLightCacheDepth=newSize;
-
- }
-
- #pragma peephole off
-
- #endif
-
-