/**************************************************************************** * point.c * * This module implements the point & spot light source primitive. * * from Persistence of Vision(tm) Ray Tracer * Copyright 1996 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 leaving a message in CompuServe's Graphics Developer's * Forum. The latest version of POV-Ray may be found there as well. * * 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. * *****************************************************************************/ #include "frame.h" #include "vector.h" #include "povproto.h" #include "point.h" #include "matrices.h" #include "objects.h" #include "povray.h" /***************************************************************************** * Local preprocessor defines ******************************************************************************/ /***************************************************************************** * Local typedefs ******************************************************************************/ /***************************************************************************** * Static functions ******************************************************************************/ static DBL cubic_spline PARAMS(( DBL low,DBL high,DBL pos)); static int All_Light_Source_Intersections PARAMS((OBJECT *Object, RAY *Ray, ISTACK *Depth_Stack)); static int Inside_Light_Source PARAMS((VECTOR point, OBJECT *Object)); static void Light_Source_Normal PARAMS((VECTOR Result, OBJECT *Object, INTERSECTION *Inter)); static void Translate_Light_Source PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Rotate_Light_Source PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Scale_Light_Source PARAMS((OBJECT *Object, VECTOR Vector, TRANSFORM *Trans)); static void Transform_Light_Source PARAMS((OBJECT *Object, TRANSFORM *Trans)); static void Invert_Light_Source PARAMS((OBJECT *Object)); static void *Copy_Light_Source PARAMS((OBJECT *Object)); static void Destroy_Light_Source PARAMS((OBJECT *Object)); /***************************************************************************** * Local variables ******************************************************************************/ static METHODS Light_Source_Methods = { All_Light_Source_Intersections, Inside_Light_Source, Light_Source_Normal, Copy_Light_Source, Translate_Light_Source, Rotate_Light_Source, Scale_Light_Source, Transform_Light_Source, Invert_Light_Source, Destroy_Light_Source }; /***************************************************************************** * * FUNCTION * * All_Light_Source_Intersections * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static int All_Light_Source_Intersections (Object, Ray, Depth_Stack) OBJECT *Object; RAY *Ray; ISTACK *Depth_Stack; { if (((LIGHT_SOURCE *)Object)->Children != NULL) { if (Ray_In_Bound (Ray, ((LIGHT_SOURCE *)Object)->Children->Bound)) { if (All_Intersections (((LIGHT_SOURCE *)Object)->Children, Ray, Depth_Stack)) { return(TRUE); } } } return(FALSE); } /***************************************************************************** * * FUNCTION * * Inside_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static int Inside_Light_Source (IPoint, Object) VECTOR IPoint; OBJECT *Object; { if (((LIGHT_SOURCE *)Object)->Children != NULL) { if (Inside_Object (IPoint, ((LIGHT_SOURCE *)Object)->Children)) { return (TRUE); } } return (FALSE); } /***************************************************************************** * * FUNCTION * * Light_Source_Normal * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Light_Source_Normal (Result, Object, Inter) OBJECT *Object; VECTOR Result; INTERSECTION *Inter; { if (((LIGHT_SOURCE *)Object)->Children != NULL) { Normal (Result, ((LIGHT_SOURCE *)Object)->Children,Inter); } } /***************************************************************************** * * FUNCTION * * Translate_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Translate_Light_Source (Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { LIGHT_SOURCE *Light = (LIGHT_SOURCE *)Object; VAddEq (Light->Center, Vector); VAddEq (Light->Points_At, Vector); if (Light->Children != NULL) { Translate_Object (Light->Children, Vector, Trans); } } /***************************************************************************** * * FUNCTION * * Rotate_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Rotate_Light_Source (Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { Transform_Light_Source(Object, Trans); } /***************************************************************************** * * FUNCTION * * Scale_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Scale_Light_Source (Object, Vector, Trans) OBJECT *Object; VECTOR Vector; TRANSFORM *Trans; { Transform_Light_Source(Object, Trans); } /***************************************************************************** * * FUNCTION * * Transform_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Transform_Light_Source (Object, Trans) OBJECT *Object; TRANSFORM *Trans; { DBL len; LIGHT_SOURCE *Light = (LIGHT_SOURCE *)Object; MTransPoint (Light->Center, Light->Center, Trans); MTransPoint (Light->Points_At, Light->Points_At, Trans); MTransPoint (Light->Axis1, Light->Axis1, Trans); MTransPoint (Light->Axis2, Light->Axis2, Trans); MTransDirection (Light->Direction, Light->Direction, Trans); /* Make sure direction has unit length. */ VLength(len, Light->Direction); if (len > EPSILON) { VInverseScaleEq(Light->Direction, len); } if (Light->Children != NULL) { Transform_Object (Light->Children, Trans); } } /***************************************************************************** * * FUNCTION * * Invert_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Invert_Light_Source (Object) OBJECT *Object; { LIGHT_SOURCE *Light = (LIGHT_SOURCE *)Object; if (Light->Children != NULL) { Invert_Object (Light->Children); } } /***************************************************************************** * * FUNCTION * * Create_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ LIGHT_SOURCE *Create_Light_Source () { int i; LIGHT_SOURCE *New; New = (LIGHT_SOURCE *)POV_MALLOC(sizeof (LIGHT_SOURCE), "light_source"); INIT_OBJECT_FIELDS(New, LIGHT_OBJECT, &Light_Source_Methods) New->Children = NULL; Set_Flag(New, NO_SHADOW_FLAG); Make_Colour(New->Colour, 1.0, 1.0, 1.0); Make_Vector(New->Direction, 0.0, 0.0, 0.0); Make_Vector(New->Center, 0.0, 0.0, 0.0); Make_Vector(New->Points_At, 0.0, 0.0, 1.0); Make_Vector(New->Axis1, 0.0, 0.0, 1.0); Make_Vector(New->Axis2, 0.0, 1.0, 0.0); New->Coeff = 10.0; New->Radius = 0.35; New->Falloff = 0.35; New->Fade_Distance = 0.0; New->Fade_Power = 0.0; New->Next_Light_Source = NULL; New->Light_Grid = NULL; New->Shadow_Cached_Object = NULL; New->Light_Type = POINT_SOURCE; New->Area_Light = FALSE; New->Jitter = FALSE; New->Track = FALSE; New->Area_Size1 = 0; New->Area_Size2 = 0; New->Adaptive_Level = 100; New->Atmospheric_Attenuation = FALSE; New->Atmosphere_Interaction = TRUE; for (i = 0; i < 6; i++) { New->Light_Buffer[i] = NULL; } return (New); } /***************************************************************************** * * FUNCTION * * Copy_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void *Copy_Light_Source (Old) OBJECT *Old; { int i, j; LIGHT_SOURCE *New; LIGHT_SOURCE *Light = (LIGHT_SOURCE *)Old; New = Create_Light_Source(); /* Copy light source. */ *New = *(LIGHT_SOURCE *)Old; New->Next_Light_Source = NULL; New->Children = Copy_Object (((LIGHT_SOURCE *)Old)->Children); if (Light->Light_Grid != NULL) { New->Light_Grid = Create_Light_Grid(Light->Area_Size1, Light->Area_Size2); for (i = 0; i < Light->Area_Size1; i++) { for (j = 0; j < Light->Area_Size2; j++) { Assign_Colour(New->Light_Grid[i][j], Light->Light_Grid[i][j]); } } } return (New); } /***************************************************************************** * * FUNCTION * * Destroy_Light_Source * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ static void Destroy_Light_Source (Object) OBJECT *Object; { int i; LIGHT_SOURCE *Light = (LIGHT_SOURCE *)Object; if (Light->Light_Grid != NULL) { for (i = 0; i < Light->Area_Size1; i++) { POV_FREE(Light->Light_Grid[i]); } POV_FREE(Light->Light_Grid); } Destroy_Object(Light->Children); POV_FREE(Object); } /***************************************************************************** * * FUNCTION * * Create_Light_Grid * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * - * ******************************************************************************/ COLOUR **Create_Light_Grid (Size1, Size2) int Size1, Size2; { int i; COLOUR **New; New = (COLOUR **)POV_MALLOC(Size1 * sizeof (COLOUR *), "area light"); for (i = 0; i < Size1; i++) { New[i] = (COLOUR *)POV_MALLOC(Size2 * sizeof (COLOUR), "area light"); } return (New); } /***************************************************************************** * * FUNCTION * * cubic_spline * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * Cubic spline that has tangents of slope 0 at x == low and at x == high. * For a given value "pos" between low and high the spline value is returned. * * CHANGES * * - * ******************************************************************************/ static DBL cubic_spline(low, high, pos) DBL low, high, pos; { /* Check to see if the position is within the proper boundaries. */ if (pos < low) { return(0.0); } else { if (pos >= high) { return(1.0); } } /* This never happens. [DB] */ /* if (high == low) { return(0.0); } */ /* Normalize to the interval [0...1]. */ pos = (pos - low) / (high - low); /* See where it is on the cubic curve. */ return(3 - 2 * pos) * pos * pos; } /***************************************************************************** * * FUNCTION * * Attenuate_Light * * INPUT * * OUTPUT * * RETURNS * * AUTHOR * * POV-Ray Team * * DESCRIPTION * * - * * CHANGES * * Jan 1995 : Added attenuation due to atmospheric scattering and light * source distance. Added cylindrical light source. [DB] * ******************************************************************************/ DBL Attenuate_Light (Light, Ray, Distance) LIGHT_SOURCE *Light; RAY *Ray; DBL Distance; { DBL len, k, costheta; DBL Attenuation = 1.0; VECTOR P, V1; /* If this is a spotlight then attenuate based on the incidence angle. */ switch (Light->Light_Type) { case SPOT_SOURCE: VDot(costheta, Ray->Direction, Light->Direction); costheta *= -1.0; if (costheta > 0.0) { Attenuation = pow(costheta, Light->Coeff); /* * If there is a soft falloff region associated with the light then * do an interpolation of values between the hot center and the * direction at which light falls to nothing. */ if (Light->Radius > 0.0) { Attenuation *= cubic_spline(Light->Falloff, Light->Radius, costheta); } /* Debug_Info("Atten: %lg\n", Attenuation); */ } else { Attenuation = 0.0; } break; case CYLINDER_SOURCE: VSub(V1, Ray->Initial, Light->Center); VDot(k, V1, Light->Direction); if (k > 0.0) { VLinComb2(P, 1.0, V1, -k, Light->Direction); VLength(len, P); if (len < Light->Falloff) { len = 1.0 - len / Light->Falloff; Attenuation = pow(len, Light->Coeff); if (Light->Radius > 0.0) { Attenuation *= cubic_spline(1.0 - Light->Radius / Light->Falloff, 1.0, len); } } else { Attenuation = 0.0; } } else { Attenuation = 0.0; } break; } if (Attenuation > 0.0) { /* Attenuate light due to light source distance. */ if ((Light->Fade_Power > 0.0) && (fabs(Light->Fade_Distance) > EPSILON)) { Attenuation *= 2.0 / (1.0 + pow(Distance / Light->Fade_Distance, Light->Fade_Power)); } } return(Attenuation); }