text: ﻿#ifndef BABYLON_SHADERS_SHADERS_INCLUDE_LIGHTS_FRAGMENT_FUNCTIONS_FX_H
  #define BABYLON_SHADERS_SHADERS_INCLUDE_LIGHTS_FRAGMENT_FUNCTIONS_FX_H
  
  namespace BABYLON {
  
  extern const char* lightsFragmentFunctions;
  
  const char* lightsFragmentFunctions
    = R"ShaderCode(
  
  // Light Computing
  struct lightingInfo
  {
      vec3 diffuse;
  #ifdef SPECULARTERM
      vec3 specular;
  #endif
  #ifdef NDOTL
      float ndl;
  #endif
  };
  
  lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
      lightingInfo result;
  
      vec3 lightVectorW;
      float attenuation = 1.0;
      if (lightData.w == 0.)
      {
          vec3 direction = lightData.xyz - vPositionW;
  
          attenuation = max(0., 1.0 - length(direction) / range);
          lightVectorW = normalize(direction);
      }
      else
      {
          lightVectorW = normalize(-lightData.xyz);
      }
  
      // diffuse
      float ndl = max(0., dot(vNormal, lightVectorW));
  #ifdef NDOTL
      result.ndl = ndl;
  #endif
      result.diffuse = ndl * diffuseColor * attenuation;
  #ifdef SPECULARTERM
      // Specular
      vec3 angleW = normalize(viewDirectionW + lightVectorW);
      float specComp = max(0., dot(vNormal, angleW));
      specComp = pow(specComp, max(1., glossiness));
  
      result.specular = specComp * specularColor * attenuation;
  #endif
      return result;
  }
  
  lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, vec3 specularColor, float range, float glossiness) {
      lightingInfo result;
  
      vec3 direction = lightData.xyz - vPositionW;
      vec3 lightVectorW = normalize(direction);
      float attenuation = max(0., 1.0 - length(direction) / range);
  
      // diffuse
      float cosAngle = max(0., dot(lightDirection.xyz, -lightVectorW));
  
      if (cosAngle >= lightDirection.w)
      {
          cosAngle = max(0., pow(cosAngle, lightData.w));
          attenuation *= cosAngle;
  
          // Diffuse
          float ndl = max(0., dot(vNormal, lightVectorW));
  #ifdef NDOTL
          result.ndl = ndl;
  #endif
          result.diffuse = ndl * diffuseColor * attenuation;
  #ifdef SPECULARTERM
          // Specular
          vec3 angleW = normalize(viewDirectionW + lightVectorW);
          float specComp = max(0., dot(vNormal, angleW));
          specComp = pow(specComp, max(1., glossiness));
  
          result.specular = specComp * specularColor * attenuation;
  #endif
          return result;
      }
  
      result.diffuse = vec3(0.);
  #ifdef SPECULARTERM
      result.specular = vec3(0.);
  #endif
  #ifdef NDOTL
      result.ndl = 0.;
  #endif
  
      return result;
  }
  
  lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 specularColor, vec3 groundColor, float glossiness) {
      lightingInfo result;
  
      // Diffuse
      float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
  #ifdef NDOTL
      result.ndl = ndl;
  #endif
  
      result.diffuse = mix(groundColor, diffuseColor, ndl);
  
  #ifdef SPECULARTERM
      // Specular
      vec3 angleW = normalize(viewDirectionW + lightData.xyz);
      float specComp = max(0., dot(vNormal, angleW));
      specComp = pow(specComp, max(1., glossiness));
  
      result.specular = specComp * specularColor;
  #endif
          return result;
  }
  
  vec3 computeProjectionTextureDiffuseLighting(sampler2D projectionLightSampler, mat4 textureProjectionMatrix){
      vec4 strq = textureProjectionMatrix * vec4(vPositionW, 1.0);
      strq /= strq.w;
      vec3 textureColor = texture2D(projectionLightSampler, strq.xy).rgb;
      return textureColor;
  }
  
  )ShaderCode";
  
  } // end of namespace BABYLON
  
  #endif // end of BABYLON_SHADERS_SHADERS_INCLUDE_LIGHTS_FRAGMENT_FUNCTIONS_FX_H
  