// This is C5E4v_twoLights from "The Cg Tutorial" (Addison-Wesley, ISBN
// 0321194969) by Randima Fernando and Mark J. Kilgard.  See pages 128-132.

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

// From page 129
struct Light {
  float3 position;
  float3 color;
};

// From page 131
void C5E5_computeLighting(Light  light, 
                          float3 P,
                          float3 N,
                          float3 eyePosition,
                          float  shininess,

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

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

// From page 132 (corrected)
void C5E4v_twoLights(float4 position : POSITION,
                     float3 normal   : NORMAL,

                 out float4 oPosition : POSITION,
                 out float4 color     : COLOR,

             uniform float4x4 modelViewProj,
             uniform float3   eyePosition,
             uniform float3   globalAmbient,
             uniform Light    lights[2],
             uniform Material material)
{
  oPosition = mul(modelViewProj, position);

  // 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 < 2; i++) {
    C5E5_computeLighting(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;
}
