//#extension GL_ARB_texture_rectangle : enable

//
uniform sampler2D cMap;
uniform vec2 cMapWH;

uniform sampler2D hMap;
uniform vec2 hMapWH;

uniform sampler2D sandMap;
uniform vec2 sandMapWH;

//
uniform sampler2D pgmlandMap;


uniform sampler2D noiseMap;
uniform vec2 noiseMapWH;

uniform float texW;
uniform float texH;

varying vec2 tc;

uniform vec2 texLookupScale;
uniform float hScale;
uniform float hOffset;


uniform vec3 lightDir;
uniform vec4 lightColor;

uniform float waterlevel_frac;

varying vec4 shadow_tex_coord;
uniform sampler2DShadow shadowMap;

varying float vertex_height;

varying vec3 V;

uniform float light_still_in_shadowed_region;


vec4 stone_color;


//x ... d_focus
//y ... d_near
//z ... d_far
//w ... clamp_far
uniform vec4 dof_params; 


float ComputeDepthBlur(float depth)
{
  float f;

  if(depth < dof_params.x) // if(depth < d_focus)
    {
      // distance between near blur distance and
      // focal distance
      // map range to [-1, 0]

      // f = (depth - d_focus) / (d_focus - d_near);
      f = (depth - dof_params.x) / (dof_params.x - dof_params.y);
    }
  else
    {
      // distance between focal distance and
      // far blur distance
      // map range to [0, 1]

      // f = (depth - d_focus) / (d_far - d_focus);
      f = (depth - dof_params.x) / (dof_params.z - dof_params.x);
      f = clamp(f, 0.0, dof_params.w);
    }

  // scale and bias into [0, 1] range
  return (f * 0.5 + 0.5);
}



float land_height(vec2 pos2D)
{
  vec2 texCoords = pos2D;

  //  return texture2D(pgmlandMap, tc*vec2(texLookupScale.s, texLookupScale.t)).r;

  //!
  return texture2D(pgmlandMap, texCoords).r*hScale; 

  /*
  float terr_h = texture2D(pgmlandMap, texCoords).r*hScale; 
  //float noise_h = (texture2D(noiseMap, tc*noiseMapWH).r*0.5-.5)*hScale;
float noise_h = (texture2D(noiseMap, tc*noiseMapWH).r*2.0-1.0)*hScale;

  return terr_h+noise_h;
  */

  //  return texture2D(pgmlandMap, texCoords, -0.5).r*hScale; 
  //  return texture2D(pgmlandMap, texCoords, 1.0).r*hScale; 
  //  return texture2D(pgmlandMap, texCoords, -2.0).r*hScale; 

  // doesn't work ... ???
  //  return texture2DLod(pgmlandMap, texCoords, 0.0).r*hScale; 
  //  return texture2DLod(pgmlandMap, texCoords, 10.0).r*hScale; 
  //  return texture2DLod(pgmlandMap, texCoords, 12.0).r*hScale; 
}

vec3 calc_normal(vec2 tc)
//vec3 calc_normal(vec2 tc, out vec3 dx, out vec3 dz)
{
  vec3 dx, dz;

  //somewhat smoother with "bigger steps" for differences

  /*
  vec2 diff_x = vec2(texLookupScale.s, 0.0);
  vec2 diff_z = vec2(0.0, texLookupScale.t);
  */
  
  //!!!
  vec2 diff_x = vec2(1.0/texW, 0.0);
  vec2 diff_z = vec2(0.0, 1.0/texH);
  

  /*
  vec2 diff_x = vec2(2.0/texW, 0.0);
  vec2 diff_z = vec2(0.0, 2.0/texH);
  */


  /* 
  dx = vec3(2.0,
	    0.5*(land_height(tc+diff_x) - land_height(tc-diff_x)),
	    0.0);

  dz = vec3(0.0,
	    0.5*(land_height(tc+diff_z) - land_height(tc-diff_z)),
	    2.0);
  */

  
  dx = vec3(2.0,
	    (land_height(tc+diff_x) - land_height(tc-diff_x)),
	    0.0);
  
  dz = vec3(0.0,
	    (land_height(tc+diff_z) - land_height(tc-diff_z)),
	    2.0);
  


	 //detail tex dynamic
  {  
    //  vec4 perturbation = texture2D(noiseMap, tc.xy*noiseMapWH.xy*.125)*2.0-1.0;
  vec4 perturbation = texture2D(noiseMap, tc.xy*noiseMapWH.xy*.0225)*2.0-1.0;
  //perturbation += texture2D(noiseMap, tc.xy*noiseMapWH.xy*.3)*2.0-1.0;
//perturbation += texture2D(noiseMap, tc.xy*noiseMapWH.xy)*2.0-1.0;
//!
  dx.xz += perturbation.xz;
  //  dx.y += 0.25*perturbation.y;

  //!
  dz.xz += (stone_color.rg-.5);
  //  dz.xz += 0.25*(stone_color.rg-.5);

  //  dz.xz += perturbation.xz;
  //  dz.y += 0.25*perturbation.y;
  }


  //
  return normalize(cross(dz, dx));

}  



void main() 
{
  vec4 color;

  vec4 sand_color = texture2D(sandMap, 0.25*tc.xy*sandMapWH);

  //use it as noise, gloss map and actual stone diffuse colortex
  //  vec4 stone_color = texture2D(noiseMap, 0.25*tc.xy*noiseMapWH);
  stone_color = texture2D(noiseMap, 0.25*tc.xy*noiseMapWH);

  vec4 m1 = texture2D(hMap, tc.xy*cMapWH*.125);

  //!!
  vec4 m2 = texture2D(cMap, tc.xy*hMapWH*.025);

  float in_shadow=1.0;
   // SM stable!!!
   // 0 ... if the object is in shadow 
   // 1 ... if it is not in shadow
   if(shadow_tex_coord.q > 0.0)
     {
   in_shadow = shadow2DProj(shadowMap, shadow_tex_coord).x;

   //   color.rgb *= max(in_shadow, 0.8); //will still be 80% of original color, if in shadow!!!

   //   color.rgb *= max(in_shadow, 0.4);
   //color.rgb *= max(in_shadow, light_still_in_shadowed_region);

in_shadow = max(in_shadow, light_still_in_shadowed_region);

     }


  //  color = texture2D(cMap, tc*vec2(1.0/texW, 1.0/texH));

  //  color = texture2D(pgmlandMap, tc*vec2(1.0/texW, 1.0/texH));
  //  color = texture2D(pgmlandMap, tc*vec2(texLookupScale.s, texLookupScale.t));

  //  vec3 N = calc_normal(tc*vec2(texLookupScale.s, texLookupScale.t));

  //  vec3 dx, dz;
  //already scaled in vs
  //  vec3 N = calc_normal(tc, dx, dz);
  vec3 N = calc_normal(tc);



  //!  float kA = 0.6;
  float kA = 0.35;

  //  float kD = 1.0;
  //  float kD = 0.3;
  float kD = 0.8;

  //    vec3 L = vec3(lightDir.x, -lightDir.y, lightDir.z);
  //  vec3 L = normalize(vec3(lightDir.x, -lightDir.y, lightDir.z));
  //  vec3 L = normalize(lightDir);

  //diffuse intensity
  //float Id = max(dot(norm, lightDir), 0.0)*kD;
  //float Id = max(dot(N, L), 0.0)*kD;
  float dp = max(dot(N, lightDir), 0.0);

float Id = dp*kD;



  //!  float decision = pow(cos(N.y*3.1415*.5), 28.0)*stone_color.r*stone_color.g;
//  float stone_decision = pow(cos(N.y*3.1415*.5), 50.0)*stone_color.r;
//!
float stone_decision = pow(cos(N.y*3.1415*0.5), 100.0)*stone_color.r;


  //!smooth  sand_decision = pow(cos(((vertex_height-hOffset)/hScale-.2)*3.1415*.5), 120.0);
  //!!  float sand_decision = pow(cos(((vertex_height-hOffset)/hScale-.2)*3.1415*.5), 180.0);
//  float sand_decision = pow(cos(((vertex_height-hOffset)/hScale-.2)*3.1415*.5), 80.0);
  float sand_decision = pow(cos(((vertex_height-hOffset)/hScale-waterlevel_frac)*3.1415*.5), 80.0);
    

  //  float kS = stone_decision*.33+((stone_color.r)*.3-.15);
  //  float kS = stone_decision*.33+((stone_color.r)*.33-0.16);
  //  float kS = stone_decision*stone_decision*.33+((stone_color.r)*.33-0.16);

  float stone_color2 = stone_color.r*stone_color.r;

  //  float kS = stone_decision*stone_decision*stone_color2; //+((stone_color.r)*.33-0.16);
  float kS = stone_decision*stone_color2; //+((stone_color.r)*.33-0.16);
  //  kS *= kS;
  //  kS *= .33;

  //  kS += 0.15 * (sand_decision*.2+((stone_color.r)*.3-.15));
  //  kS += (sand_decision*.2+((stone_color.r)*.3-.15));
  //  kS *= kS;
  //  kS += sand_decision*(1.0-stone_decision)*stone_color2;
  //  kS += 0.75*(sand_decision-0.5)*(1.0-stone_decision)*stone_color2;
  kS += 0.75*(sand_decision*.75-0.5)*(1.0-stone_decision)*stone_color2;

  // float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .5);
  // float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .35);
  // float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .275);
  // float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .25);
  // float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .225);
  // float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .2);
 float Is = kS * pow(max(dot(N, 0.5*(V+lightDir)), 0.0), .145);

 Id *= in_shadow;
 Is *= in_shadow;

  // float Is = kS * pow(max(dot(N, normalize(V+lightDir)), 0.0), .5);
  // float Is = kS * pow(max(dot(N, normalize(V+lightDir)), 0.0), .33);
  // float Is = kS * pow(max(dp*dot(N, 0.5*(V+lightDir)), 0.0), .25);
  // float Is = kS * pow(max(dp*dot(N, 0.5*(V+lightDir)), 0.0), .15);

 kS*=kS;

 //
 Id = clamp(Id+kA+Is*dp, 0.0, 1.0);
 // Id = clamp(+kA+ in_shadow*(Is*dp+Id), 0.0, 1.0);
 color = vec4(Id);



  //!!  vec4 ground_mix_color = mix(m1, m2, 0.5);
  vec4 ground_mix_color = mix(m1, m2, 0.225);
 //  vec4 ground_mix_color = mix(m1, m2, 0.35);
 //  vec4 ground_mix_color = mix(m1, m2, 0.65);
  //  vec4 ground_mix_color = m1;


  //!  ground_mix_color = mix(ground_mix_color, stone_color, decision*.5+(stone_color*.3-.1));
  ground_mix_color = mix(ground_mix_color, stone_color, stone_decision*.25+(stone_color.r*.3-.15));


  //  sand_color = mix(sand_color, stone_color, decision*.5+(stone_color*.3-.15));
  //  sand_color = mix(stone_color, sand_color, sand_decision*stone_decision);


  //  ground_mix_color = mix(ground_mix_color, sand_color, sand_decision*.5+(stone_color*.3-.1));
  //!  ground_mix_color = mix(ground_mix_color, sand_color, sand_decision+(stone_color.r*.3-.1));
  ground_mix_color = mix(ground_mix_color, sand_color, (1.0 - stone_decision)*(1.0 - stone_decision)*(sand_decision+(stone_color.r*.3-.1)));
  //  ground_mix_color = mix(ground_mix_color, sand_color, sand_decision*stone_decision);

  color *= ground_mix_color;
    
  
	 //detail tex static
  ///  color += ((texture2D(noiseMap, tc.xy*noiseMapWH)).rrra-vec4(0.5,0.5,0.5,0.0))*vec4(.35, .35, .35, 1.0);

  color += (stone_color-vec4(0.5,0.5,0.5,0.0))*vec4(.25, .25, .25, 1.0);
  


  color *= in_shadow;



   //
  gl_FragColor = color;

  gl_FragColor.a = ComputeDepthBlur(gl_TexCoord[4].q);
  //  gl_FragColor = sand_color;

   //   gl_FragColor = vec4(decision);
  
  //   gl_FragColor = vec4(Is);

   //  gl_FragColor = m2;
   //   gl_FragColor = vec4(N.y);
  //gl_FragColor = vec4(decision*.4+(stone_color*.5-.2));

  //  gl_FragColor = vec4(pow(N.y, 0.5));
  //  gl_FragColor = vec4(exp(N.y*2.0025));
}
