/////////////////////////////////////////////////////////////////////////////
// spotlight.osl - simple round spotlight
//
// Parameters:
//   intensity - overall scale on the intensity of the light
//   lightcolor - color of the light emitted
//   from - specifies the position of the light cone (default to origin
//                     of "shader" space)
//   to - specifies the direction of the light cone (points from 'from'
//                     to 'to').
//   falloff - the distance falloff exponent (2==1/r^2, 1==1/r, 0==no falloff)
//   coneangle - half-width (in radians) of the emission cone
//   conedeltaangle - controls the width (in radians) of the falloff
//        as the angle approaches coneangle.
//   beamdistribution - controls the angular falloff (from angular factors,
//        independent of coneangle/conedeltaangle)
//   shadowname - the name of the shadow map, or geometry set for ray
//                     tracing ("" indicates no shadows)
//   shadowsamples - how many samples for shadow map sampling (larger is more
//        expensive but higher quality)
//   shadowblur - extra additive blur for shadow edges
//   shadowbias - extra lookup bias to eliminate precision artifacts
//        Bias < 0 means use the value set by Attribute "shadow:bias"
//   __nonspecular - makes the light not appear in specular highlights
//        (actually, the light does nothing with this, but many surfaces
//        respect the request)
//   
/////////////////////////////////////////////////////////////////////////////
// Copyright 2004 NVIDIA Corporation.  All Rights Reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// 
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA nor the names of its contributors
//   may be used to endorse or promote products derived from this software
//   without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// (This is the Modified BSD License)
/////////////////////////////////////////////////////////////////////////////


light
spotlight
    [[ string help = "Spot light, simple, with shadows" ]]
(
    float  intensity = 1
        [[  string help = "Overall light intensity",
            float min=0 ]],
    color  lightcolor = 1
        [[  string help = "Overall light color" ]],
    point  from = point ("shader", 0, 0, 0)
        [[  string help = "Light origin (default: local origin)" ]],
    point  to = point ("shader", 0, 0, 1)
        [[  string help = "Light target (default: local +z)" ]],

    float  coneangle = radians(30)
        [[  string help = "Cone illumination angle",
            float min=0 ]],
    float  conedeltaangle = radians(5)
        [[  string help = "Cone falloff angle",
            float min=0 ]],
    float  beamdistribution = 2
        [[  string help = "Angular falloff exponent",
            float min=0 ]],
    float  falloff = 2
        [[ string help = "Distance falloff exponent",
           float min = 0, float max = 3 ]],

    string shadowname = ""
        [[  string help = "Shadow name (map or geomset)" ]],
    float  shadowsamples = 1
        [[  string help = "Shadow samples",
            int min=1, int max=256 ]],
    float  shadowblur = 0
        [[  string help = "Shadow blur",
             float min=0, float max=1 ]],
    float  shadowbias = -1
        [[  string help = "Shadow bias (-1 means default)",
            float min=0, float max=1 ]],

    float __nonspecular = 0 
        [[  string help = "Non-specular",
            float min = 0, float max = 1 ]]
  )
{
    vector axis = normalize(to-from);

    emit (from, axis, coneangle) {
		setmessage ("__nonspecular", __nonspecular);
        float Llen = length(L);
		float cosangle = dot (L, -axis) / Llen;
		float atten = pow (cosangle, beamdistribution) / pow (Llen, falloff);
		atten *= smoothstep (cos(coneangle), cos(coneangle-conedeltaangle),
					 cosangle);
		atten *= intensity;
		Cl = atten * lightcolor;

        // If shadowing, scale by the "unshadowed" amount.
        if (shadowname && atten > 0.0001)
            Cl *= transmission (Ps, from, "traceset", shadowname, "samples", (int)shadowsamples,
                                      "blur", shadowblur, "bias", shadowbias);
    }
}
