//#extension GL_ARB_texture_rectangle : enable

uniform sampler2D pgmlandMap;


uniform sampler2D cMap;
uniform vec2 cMapWH;

uniform sampler2D hMap;
uniform vec2 hMapWH;

uniform sampler2D sandMap;
uniform vec2 sandMapWH;

uniform sampler2DShadow shadowMap;

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_below;
uniform float slice_nr;
varying vec4 worldpos_vert;


varying vec4 shadow_tex_coord;

varying float vertex_height;

uniform float waterlevel_frac;

uniform float light_still_in_shadowed_region;

float water_height(vec2 pos2D)
{
  vec2 texCoords = texLookupScaleWave3D.st*pos2D.xy;
  
  //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(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);

  /*
  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 eps = (waveScale+abs(waveOff));

float water_h = water_height(worldpos_vert.xz);


  if(worldpos_vert.y > water_h+eps) //part below the watersurface (refraction)
    {
      discard;
    }
  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);
    vec4 ground_mix_color = texture2D(cMap, tc.xy*cMapWH*.025); //hide repetivtive pattern on the ground in the sea



      //  float water_h_highfrequ = (texture3D(wave3D, vec3(worldpos_vert.xz*4.25*texLookupScaleWave3D.st, 18.0*(slice_nr/16.0)), -1.25).r * waveScale + waveOff);

    //  float water_h_highfrequ = (texture3D(wave3D, vec3(worldpos_vert.xz*4.25*texLookupScaleWave3D.st, 26.0*(slice_nr/16.0)), -1.25).r * waveScale + waveOff);

    //  float water_h_highfrequ = (texture3D(wave3D, vec3(worldpos_vert.xz*2.25*texLookupScaleWave3D.st, 26.0*(slice_nr/16.0)), -1.25).r * waveScale + waveOff);
  float water_h_highfrequ = (texture3D(wave3D, vec3(worldpos_vert.xz*2.0*texLookupScaleWave3D.st, 26.0*(slice_nr/16.0)), -1.25).r * waveScale + waveOff);

  /*
  water_h_highfrequ *= 0.75;
  water_h_highfrequ += water_h*.25;
  */

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

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


  float Id = max(dot(N, lightDir), 0.0)*kD;

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

  color = vec4(Id);

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


  //  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);
  // color += ((texture2D(noiseMap, tc.xy*noiseMapWH)).rrra-vec4(0.5,0.5,0.5,0.0))*vec4(.35, .35, .35, 1.0);






  float depth = max(0.0, water_h-worldpos_vert.y);
  vec4 wat_col;

  /*
  wat_col.r = 0.3;
  wat_col.g = 0.53;
  wat_col.b = 0.56;
  wat_col.a = 1.0;
  */
  wat_col.r = 0.25;
  wat_col.g = 0.75;
  wat_col.b = 0.4;
  wat_col.a = 1.0;

  vec3 ivec = normalize(worldpos_vert.xyz - camPos.xyz);
  float dist = depth / ivec.y;

  float t = (water_h - worldpos_vert.y)/(-ivec.y);
  vec3 pos_cam_water_land;
  pos_cam_water_land.y = water_h;
  pos_cam_water_land.xz = worldpos_vert.xz - t*(ivec.xz);

  float dist_cam_in_water = distance(pos_cam_water_land, worldpos_vert.xyz);

  float dist_cam_in_water_mixfactor = clamp(pow(dist_cam_in_water*0.001125, 1.15), 0.0, 0.35);

  color = mix(color, wat_col, dist_cam_in_water_mixfactor);


  //  float caustic_factor = clamp(0.42*pow((water_h_highfrequ-waveOff)/waveScale, 3.0), 0.0, 1.0);
  //  float caustic_factor = clamp(0.42*pow((water_h_highfrequ-waveOff)/waveScale, 2.0), 0.0, 1.0);
  float caustic_factor = abs(0.9*pow((water_h_highfrequ-waveOff)/waveScale, 4.0));

  //    float mix_factor = 1.0-clamp(exp(-depth*0.004), 0.0, 1.0);
    float mix_factor = 1.0-clamp(exp(-depth*0.0015), 0.0, 1.0);

    vec3 mixcolor = mix(vec3(1.0, 1.0, 1.0), wat_col.rgb, mix_factor);


      color.xyz = mix(color.xyz, mixcolor, caustic_factor);


    //make deep water homogeneous
      /*
      //    float border = -20.0; //ORIG

      //
    float border = -100.0; //ORIG
      //    float border = -1000.0; //ORIG
      //    float border = -2250.0; //ORIG

    float val = (worldpos_vert.y) - border;
      */


    /*
!!!
    //FIX WATER COLOR
    //// 
   color.xyz = mix( color.xyz, cc_below.xyz, mix_factor );
    */

   
   // 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, light_still_in_shadowed_region);


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

   //   color.rgb *= max(in_shadow, 0.9);
     }
   

    //FIX WATER COLOR - AFTER SHADOW
    //// 
   color.xyz = mix( color.xyz, cc_below.xyz, mix_factor );




  gl_FragColor = color;
    }
}
