#include "common.inc"

#define GBUFFER_BASIC_SINGLE  1
#define GBUFFER_DUAL          2
#define GBUFFER_SINGLE        3

#ifdef VS

  #if defined(USE_BINDING)
  layout( binding = VSCB0Index, std140 ) uniform VSCB0
  #else
  layout (std140) uniform VSCB0
  #endif
  {
    float4x4 g_matViewProjection;
    float4x4 g_matView;
  };

  #if defined(USE_BINDING)
  layout( binding = VSCB1Index, std140 ) uniform VSCB1
  #else
  layout (std140) uniform VSCB1
  #endif
  {
    float3  g_LightPosition;
    float   g_LightSize;
  };

  layout ( location = attrPosLoc ) in float4 aPosition;
  
  out float4 vPositionCS;
  out float4 vPositionES;


  void main()
  {
    float4 positionWS = float4( (aPosition.xyz * g_LightSize) + g_LightPosition.xyz, 1.f );
    float4 positionCS = positionWS * g_matViewProjection;
    float4 positionES = positionWS * g_matView;

    gl_Position = positionCS;
    vPositionCS = positionCS;
    vPositionES = positionES;
  }

#endif //VS

#ifdef PS
  
  layout ( location = 0 ) out float4 FragColor;
  
  in float4 vPositionCS;
  in float4 vPositionES;
  
  #if defined(USE_BINDING)
  layout( binding = PSCB0Index, std140 ) uniform PSCB0
  #else
  layout (std140) uniform PSCB0
  #endif
  {
    float4x4  g_InvProjMatrix;
    float4x4  g_InvViewMatrix;
    float4x4  g_InvViewProj;
    float3    g_CameraPos;
    float     g_FarZ;
  };

  #if defined(USE_BINDING)
  layout( binding = PSCB1Index, std140 ) uniform PSCB1
  #else
  layout (std140) uniform PSCB1
  #endif
  {
    float3  g_LightPos;
    float   padding0;
    float3  g_LightColor;
    float   padding1;
    float4  g_AttenuationConsts;
  };
  
  #if defined(USE_BINDING)
  layout( binding = 0 ) uniform sampler2D sTexGBuffer0;
  #else
  uniform sampler2D sTexGBuffer0;
  #endif

  #if GBUFFERTYPE == GBUFFER_DUAL
  #if defined(USE_BINDING)
  layout( binding = 1 ) uniform sampler2D sTexGBuffer1;
  #else
  uniform sampler2D sTexGBuffer1;
  #endif
  #endif

  #if GBUFFERTYPE == GBUFFER_SINGLE
  #if defined(USE_BINDING)
  layout( binding = 2 ) uniform sampler2D sTexDepthBuffer;
  #else
  uniform sampler2D sTexDepthBuffer;
  #endif
  #endif


  float4 PositionFromDepth(float depth, float3 vPositionVS)
  {
    // Calculate the frustum ray using the view-space position.
    // g_fFarCip is the distance to the camera's far clipping plane.
    // Negating the Z component only necessary for right-handed coordinates
    float3 vFrustumRayVS = vPositionVS.xyz * (g_FarZ/vPositionVS.z);

    return float4(depth * vFrustumRayVS, 1);
  }

  void main()
  {
    float2 projCoords = vPositionCS.xy / vPositionCS.ww;
    float2 uv = projCoords * float2( 0.5, 0.5 ) + float2( 0.5, 0.5 );

    float4 gbuffer0 = texture( sTexGBuffer0, uv );

  #if GBUFFERTYPE == GBUFFER_SINGLE

    float depth = texture( sTexDepthBuffer, uv ).x * 2.0 - 1.0;
    float3 normalWS = normalize( gbuffer0.xyz * 2.f - 1.f );
    
    float4 posWS = float4( projCoords.xy, depth, 1.f ) * g_InvViewProj;
    posWS /= posWS.w;

  #else

    #error

  #endif

    float3 lightDir = g_LightPos.xyz - posWS.xyz;

    float dist = length( lightDir );
    lightDir /= dist;

  #if BENDNORMALS
    normalWS.xyz = normalize( ( lightDir * 1.05f ) + normalWS.xyz );
  #endif

    float linearFadeCurve = saturate( dist * g_AttenuationConsts.x + g_AttenuationConsts.y );
    float fadeCurve = linearFadeCurve * ( g_AttenuationConsts.z + linearFadeCurve * g_AttenuationConsts.w );

    float NdotL = dot( lightDir, normalWS );
    float intensity = NdotL  * saturate( NdotL * 8.f ); //adds a toe and shoulder to curve
    intensity += intensity * fadeCurve;

    float3 diffuse = intensity * g_LightColor.rgb;

    float specular = 0;

  #if GBUFFERTYPE != GBUFFER_BASIC_SINGLE  

  #if (SPECULAR == 1)

    //Directional specular
    float3 V = normalize( g_CameraPos.xyz - posWS.xyz );
    float3 H = normalize( lightDir.xyz + V );
    float specPower = gbuffer0.w * 255.f;
    specular = pow( saturate( dot( normalWS.xyz, H ) ), specPower );  
    specular *= saturate( 2.f * ( 1.f + fadeCurve ) );

  #endif // SPECULAR

  #endif

    FragColor = float4( diffuse, specular ) * 0.5f;
  }

#endif //PS