// This is C5E7_attenuateLighting from "The Cg Tutorial" (Addison-Wesley, ISBN
// 0321194969) by Randima Fernando and Mark J. Kilgard.  See page 135.

// From page 128
struct Material {
  float3 Ke;
  float3 Ka;
  float3 Kd;
  float3 Ks;
  float shininess;
};

// From page 129
struct Light {
  float3 position;
  float3 color;
  float kC, kL, kQ;  // Extra constant, linear, and quadric attenuation factors
};

// From page 135
float C5E6_attenuation(float3 P, 
                       Light light) 
{
  float d = distance(P, light.position);
  return 1 / (light.kC + light.kL * d + light.kQ * d * d); 
}

void C5E7_attenuateLighting(Light light, 
                            float3 P,
                            float3 N,
                            float3 eyePosition,
                            float  shininess,

                        out float3 diffuseResult,
                        out float3 specularResult) 
{
  // Compute attenuation
  float attenuation = C5E6_attenuation(P, light);

  // Compute the diffuse lighting
  float3 L = normalize(light.position - P);
  float diffuseLight = max(dot(L, N), 0);
  diffuseResult = attenuation * 
                  light.color * diffuseLight;

  // Compute the specular lighting
  float3 V = normalize(eyePosition - P);
  float3 H = normalize(L + V);
  float specularLight = pow(max(dot(H, N), 0), 
                            shininess);
  if (diffuseLight <= 0) specularLight = 0;
  specularResult = attenuation * 
                   light.color * specularLight;
}

// Based on C5E4v_twoLights (page 131) but for just one per-fragment light
void oneLight(float4 position : TEXCOORD0,
              float3 normal   : TEXCOORD1,

          out float4 color     : COLOR,

      uniform float3   eyePosition,
      uniform float3   globalAmbient,
      uniform Light    lights[1],
      uniform Material material)
{
  // Calculate emissive and ambient terms
  float3 emissive = material.Ke;
  float3 ambient = material.Ka * globalAmbient;

  // Loop over diffuse and specular contributions for each light
  float3 diffuseLight;
  float3 specularLight;
  float3 diffuseSum  = 0;
  float3 specularSum = 0;
  for (int i = 0; i < 1; i++) {
    C5E7_attenuateLighting(lights[i], position.xyz, normal, 
                           eyePosition, material.shininess,
                           diffuseLight, specularLight);
    diffuseSum += diffuseLight;
    specularSum += specularLight;
  }

  // Now modulate diffuse and specular by material color
  float3 diffuse = material.Kd * diffuseSum;
  float3 specular = material.Ks * specularSum;

  color.xyz = emissive + ambient + diffuse + specular;
  color.w = 1;
}
