uniform mat4x3 modelview43;
flat  in vec3 lvec;
flat  in float rock,alpha,ratio,seed; // size of bilboard,meters
flat  in  vec4 camera;          // xyz- camera origin(LY)  , w - halfsize of bilboard,meters
flat  in  vec4 cs;

out vec4 fragColor;

in  vec2 vx;

#define FBM_Iteration 4
const vec3 amb=vec3(0.05);

vec4 hash4( vec4 n ) { return fract(sin(n)*(seed)); }

//Value Noise
float _noise3( in vec3 x )
{
    vec3 p = floor(x);
    vec3 f = fract(x);
    f = f*f*(3.0-2.0*f);
    float n = p.x + p.y*157.0 + 113.0*p.z;
    vec4 h1=hash4(vec4(n+0.,n+1.,n+157.,n+158.));
    vec4 h2=hash4(vec4(n+113.,n+114.,n+270.,n+271.));
    return mix(mix(mix( h1.x, h1.y,f.x),
                   mix( h1.z, h1.w,f.x),f.y),
               mix(mix( h2.x, h2.y,f.x),
                   mix( h2.z, h2.w,f.x),f.y),f.z);
}

float fbm3(vec3 p)
{
    float n=0.0;
    n= _noise3(p);

    float a=0.5;
    for (int i=0;i<FBM_Iteration;i++)
    {
        n+=a* _noise3(p);
        p=p*2.0;
        a=a*0.5;
    }
    return n*.7;
}

float map(vec3 p)
{
 p.x*=ratio;
 return length(p)- ((1.0-rock) + rock * fbm3( p * 2.8  ) ) ;
}


vec3 caclNormal(vec3 p)
{
    vec2 eps=vec2(0.001,0.0);
    return normalize( vec3(
            map(p+eps.xyy)- map(p-eps.xyy),
            map(p+eps.yxy)- map(p-eps.yxy),
            map(p+eps.yyx)- map(p-eps.yyx) ) );
}

const float precis=0.01;
vec3 raymarch(vec3 ro,vec3 rd)
{
    float ln=length(ro);
    float tmin=(ln-1.5);
    float tmax=(ln+1.5);
    float t=tmin;
    vec3  p;
    for(int i=0;i<64;i++)
    {
     p=ro+rd*t;
     float res=map(p);
     if (res<precis) break;
     if (t>tmax) discard;
     t+=res*0.5;
    }
    return p;
}


void main( )
{
  mat3 mx=mat3(modelview43);
  if (alpha<1.0)
  {
   vec3 n=vec3(vx,1.0-length(vx)); if (n.z<=0.0) discard;
   vec3 lv =mx*lvec;
   fragColor.a  =alpha;
   fragColor.rgb=vec3(clamp(dot(lv,n),0.,1.)+amb)*n.z;
   return;
  }
  vec3 ro =camera.xyz*camera.w;
  vec3 rd =normalize(vec3(vx,0.)-ro);
  ro=ro*mx;
  rd=rd*mx;
  ro=ro*1.5;
  mat2 rxz = mat2(-cs.w,cs.z,cs.z,cs.w);
  mat2 rxy = mat2(-cs.y,cs.x,cs.x,cs.y);
  vec3 lv=vec3(lvec.xy*rxy,lvec.z);
  ro.xy=ro.xy*rxy;
  rd.xy=rd.xy*rxy;
  ro.xz=ro.xz*rxz;
  rd.xz=rd.xz*rxz;
  lv.xz=lv.xz*rxz;
  vec3  hit     = raymarch(ro,rd);
  vec3  nor     = caclNormal(hit);
  vec3  ref     = reflect(-rd,nor);
  float diffuse = max(0.0,dot(lv.xyz,nor) );
  vec3  h       = normalize(lv.xyz-rd);
  float specular= max(0.0,dot(h, nor));
  fragColor = vec4(alpha*.2*(diffuse+specular)+amb,alpha);
}
