/* ***************************  lollipop_glossySpecFresnel_001
 * Copyright (c) 2010 LOLLIPOPSHADERS. All rights reserved.  This program or
 * documentation contains proprietary confidential information and trade
 * secrets of LOLLIPOPSHADERS.  Reverse engineering of object code is prohibited.
 * Use of copyright notice is precautionary and does not imply
 * publication.                  
 *
 *
 *
 * Lollipopshaders
 * www.lollipopshaders.com
 * info@lollipopshaders.com
 *
 *
 * lollipop_glossySpecFresnel_001
 *
 * Combines Jerry Tessendorf's Fresnel with Glossy Specular
 * 
 **************************** */

/*
 * LocIllumGlossy - a possible replacement for specular(), with a
 * more uniformly bright core and a sharper falloff.  It's a nice
 * specular function to use for something made of glass or liquid.
 * Inputs:
 *  roughness - related to the size of the highlight, larger is bigger
 *  sharpness - 1 is infinitely sharp, 0 is very dull
 *
 *  From Advanced Renderman book. (p.231)
 */
color LocIllumGlossy ( normal N;  vector V; float roughness, sharpness; )
{
   color C = 0;
   float w = .18 * (1-sharpness);
   extern point P;
   illuminance (P, N, PI/2)
   {
           /* Must declare extern L & Cl because we're in a function */
           extern vector L;  extern color Cl;
           float nonspec = 0;
           lightsource ("__nonspecular", nonspec);
           if (nonspec < 1) {
               vector H = normalize(normalize(L)+V);
               C += Cl * ((1-nonspec) * smoothstep (.72-w, .72+w, pow(max(0,N.H), 1/roughness)));
           }
   }
   return C;
}


float JTessendorfFresnel(vector I; normal N; float nSnell)
{
               float reflectivity;
               vector In = normalize(I);
               normal Nn = normalize(N);
               float costhetai = abs(In . Nn);
               float thetai = acos(costhetai);
               float sinthetat = sin(thetai)/nSnell;
               float thetat = asin(sinthetat);

               if (thetai == 0.0)
           {
                   reflectivity = (nSnell - 1)/(nSnell + 1);
                   reflectivity = reflectivity * reflectivity;
               } else {
                   float fs = sin(thetat - thetai) / sin(thetat + thetai);
                   float ts = tan(thetat - thetai) / tan(thetat + thetai);
                   reflectivity = 0.5 * ( fs*fs + ts*ts );
               }

           return reflectivity;
}

surface lollipop_glossySpecFresnel_001
    (
        // Fresnel Index of Refraction (IOR) how much light is 
        // reflacted vs refracted (reflection falloff):
        float nSnell = 1.1;
        float reflectivity_amp=1;
        float reflectivity_pow=1;

        float Ks=0.35;
        float spec_roughness=0.1, spec_sharpness=0;
    )

{    

    float reflectivity = JTessendorfFresnel(I, N, nSnell);

    // Reflection-area brightness and contrast control
    reflectivity *= reflectivity_amp;
    reflectivity = pow(reflectivity, reflectivity_pow);
    if (reflectivity>1) reflectivity=1;

    normal Nf = faceforward(normalize(N), I);
    vector V = -normalize(I);
    color spec = Ks*LocIllumGlossy(Nf, V, spec_roughness, spec_sharpness );
    
    Ci = reflectivity + spec;
    Oi = 1;  
}