//#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 vec4 camPos;

uniform sampler3D wave3D;
uniform vec2 texLookupScaleWave3D;
uniform float waveScale;
uniform float waveOff;
uniform vec4 cc_above;
uniform float slice_nr;
varying vec4 worldpos_vert;

varying vec4 shadow_tex_coord;
uniform sampler2DShadow shadowMap;

varying float vertex_height;

uniform float waterlevel_frac;

uniform float light_still_in_shadowed_region;


float water_height(vec2 pos2D)
{
  ///  vec2 texCoords = vec2(pos2D.x*texLookupScale.s, pos2D.y*texLookupScale.t);
  vec2 texCoords = pos2D.xy * texLookupScaleWave3D.st;

  //maybe add some noise for the reflective part...
  //smaller performance-hit since FBO is quite small

  //  float z = (texture3D(wave3D, vec3(texCoords.xy, 12.0*(slice_nr/16.0))).r * waveScale + waveOff);

  //
  float z = -(texture3D(wave3D, vec3(texCoords.xy, 12.0*(slice_nr/16.0)), -0.9).r * waveScale + waveOff);


  
  return z;
}



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

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

  //  return texture2D(pgmlandMap, texCoords).r*hScale; 
  return texture2D(pgmlandMap, texCoords, 1.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)
{
  //somewhat smoother with "bigger steps" for differences
   //!
  vec2 diff_x = vec2(1.0/texW, 0.0);
  vec2 diff_z = vec2(0.0, 1.0/texH);
  
  /*
  vec2 diff_x = vec2(0.5/texW, 0.0);
  vec2 diff_z = vec2(0.0, 1.0/texH);
  */

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

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

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

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



  //  dx = normalize(dx);
  //  dx = normalize(-dx);
  //  dz = normalize(dz);
  //  dz = normalize(-dz); //flip z-coord

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

}  



void main() 
{
  vec4 color;

  float water_h = water_height(worldpos_vert.xz);

  if(worldpos_vert.y < water_h)
    {
      //      gl_FragColor.a = 0.0;

      //
      discard; //ORIGINAL

    }
  else
    {

  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);

  //!!!  vec4 m1 = texture2D(cMap, tc.xy*cMapWH*.125);
  //!!!  vec4 m2 = texture2D(hMap, tc.xy*hMapWH*.025);
vec4 ground_mix_color = texture2D(cMap, tc.xy*cMapWH*.125);



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

  /*
  float kA = 0.25;
  float kD = 0.6;
  */
  float kA = 0.25;
  float kD = 0.7;


  //    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 Id = max(dot(N, lightDir), 0.0)*kD;

  Id = clamp(Id+kA, 0.0, 1.0);

  color = vec4(Id, Id, Id, 1.0);

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

  //!!  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);


  ground_mix_color = mix(ground_mix_color, stone_color, stone_decision*.5+(stone_color.r*.3-.15));

  //!  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;

 color += (stone_color-vec4(0.5,0.5,0.5,0.0))*vec4(.35, .35, .35, 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)
     {
   float 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);

     }


  gl_FragColor = color;
    }
}
