struct Vert {
   float4 position  : POSITION;
   float3 ptpos     : TEXCOORD0;

   float2 texcoord1 : TEXCOORD1;
   float2 texcoord2 : TEXCOORD2;
   float2 texcoord3 : TEXCOORD3;
};

struct Pix {
      float4 col  : COLOR;
};

void getPointFromTexture
(
       float2    uv_in,
       sampler2D tex_prof,
       float4x4  inv,
   out float4    p,
   out float2    uv_out
)
{
   float4 pE;
   uv_out = uv_in;

   pE.z = tex2D( tex_prof, uv_out ).a;

   pE.z = pE.z * 2.0 - 1.0;
   pE.xy = ( uv_out * 2.0 ) - 1.0 ;
   pE.w = 1.0;
   p = mul( inv, pE );
   p /= p.w;
}

void computeFinalColor( out float4 couleur,
                        float4 normal,
                        float4 lightVec,
                        float4 camPos,
                        float4 p,
                        float4 diffuseColor,
                        float  specCoef,
                        float  specExp,
                        float4 ambientColor )
{
   // calculate half angle vector
   float4 eye   = camPos - p;
   float4 light = lightVec - p;
   float4 half  = normalize( light + eye );

   // diffuse component
   float diffuse = dot( normal, normalize(light) );

   // calculate specular component
   float specular = dot( normal, half );
   specular = pow( specular, specExp );

   // combine diffuse and specular contributions
   couleur = diffuse  * diffuseColor
           + specular * specCoef;
}

Pix main( Vert I,
          const uniform sampler2D tex0   : register(s0), // colors textures
          const uniform sampler2D tex1   : register(s1),
          const uniform sampler2D tex2   : register(s2),

          const uniform sampler2D tex0p  : register(s3), // depth textures
          const uniform sampler2D tex1p  : register(s4),
          const uniform sampler2D tex2p  : register(s5),

          const uniform sampler2D tex0n  : register(s7), // normals textures
          const uniform sampler2D tex1n  : register(s8),
          const uniform sampler2D tex2n  : register(s9),

#ifdef SHADOWS
          const uniform sampler2D texsm  : register(s6), // shadow map
#endif
          const uniform float4x4  inv0   : register(c4), // reference viewpoint
          const uniform float4x4  inv1   : register(c12),//  matrices
          const uniform float4x4  inv2   : register(c20),

          const uniform float4x4  mat    : register(c24), // camera matrices
          const uniform float4x4  inv    : register(c28),

          const uniform float4 lightPos  : register(c40),
          const uniform float4 camPos    : register(c41),

#ifdef SHADOWS
          const uniform float4x4  matLum : register(c32), // light camera for shadow projection
#endif
          const uniform float4 diffCol   : register(c42), // material properties
          const uniform float4 ambCol    : register(c43),
                uniform float4 specCoef  : register(c44),
                uniform float4 specExp   : register(c45)
)
{

   Pix OUT;

   float4 pS = float4( I.ptpos.x, I.ptpos.y, I.ptpos.z, 1.0 );

   float4 pS0, pS1, pS2;
   float2 uv0, uv1, uv2;

   getPointFromTexture( I.texcoord1, tex0p, inv0, pS0, uv0 );
   getPointFromTexture( I.texcoord2, tex1p, inv1, pS1, uv1 );
   getPointFromTexture( I.texcoord3, tex2p, inv2, pS2, uv2 );

   float
      d0 = distance( pS, pS0 ),
      d1 = distance( pS, pS1 ),
      d2 = distance( pS, pS2 );

   float4 couleur;
   float4 diffColor;
   float4 normale;

   if( d0 < d1 && d0 < d2 )
   {
         pS = pS0;
         normale   = tex2D( tex0n, uv0 );
         diffColor = tex2D( tex0, uv0 );
   }
   else
      if( d1 < d2 && d1 < d0 )
      {
         pS = pS1;
         normale   = tex2D( tex1n, uv1 );
         diffColor = tex2D( tex1, uv1 );
      }
      else
      {
         pS   = pS2;
         normale   = tex2D( tex2n, uv2 );
         diffColor = tex2D( tex2,  uv2 );
      }

   normale = ( normale * 2.0 ) - 1.0;
   computeFinalColor( couleur, normale, lightPos, camPos, pS,
   diffColor, specCoef.x, specExp.x, ambCol );

#ifdef SHADOWS
   pS = mul( matLum, pS );
   pS /= pS.w;
   pS.xyz = (pS.xyz + 1.0 ) / 2.0;
   float2 depthSM = tex2D( texsm, pS.xy ).rg;
   float depth =( ( depthSM.r  * 256.0 + depthSM.g ) * 256.0 ) / 65536.0;

   if( depth < pS.z )
   {
      specExp.x = 0.0; specCoef.x = 0.0; diffColor /= 2.0;
   }
#endif

   OUT.col = couleur;
   return OUT;
}