in  vec4 dir;
out vec4 fragColor;
uniform vec4  param;
uniform vec4  sparam;
uniform vec4 camera; // xyz- camera origin(LY)  , w - 1/object_rad(LY)
uniform sampler2D tex0;
#define  iChannel0 tex0
#define  iGlobalTime sparam.x
#define  lightvec     param.xyz


const  int   noctaves=5;
const  float lacunarity = 3.5;
const  float gain = .5;
const  float cloudness=.5;
const  float inv_cloudness=4.-cloudness*2.0;

#if 1
//vec3 ca=vec3(.20,.20,.25);
vec3 ca=vec3(.24,.10, .030)*.125;
vec3 cb=vec3(.24,.10, .030)*.5;
vec3 cc=vec3(.24,.10, .030);
vec3 cd=vec3(.46,.20, .060);
vec3 ce=vec3(.10,.03, .015);
#else
vec3 ca=vec3(.313*.313, .114*.114, .157*.157);
vec3 cb=vec3(.233,.054,.047)*.5;
vec3 cc=vec3(.24,.010, .000);
vec3 cd=vec3(.176,.037, .019);
vec3 ce=vec3(.063,.0062,.0124);
#endif

const vec4 atmosphereColor = vec4(2., 1.4, 1.,1.);


mat2 rot(float a)
{
  float sa = sin(a);
  float ca = cos(a);
  return mat2(ca,sa,-sa,ca);
}

float _noise3( in vec3 x )
{
    vec3 p = floor(x);
    vec3 f = fract(x);
  f = f*f*(3.0-2.0*f);

  vec2 uv = (p.xy+vec2(37.0,17.0)*p.z) + f.xy;
  vec2 rg = texture2D( iChannel0, (uv+0.5)/256.0).yx;
  float v=mix( rg.x, rg.y, f.z );
    return v;
}

const mat3 mx = mat3(0.,0.8,0.6,-0.8,0.36,-0.48,-0.6,-0.48,0.64);
float fbm( vec3 p)
{
  const float scale=6.;
  float f=0.0;
  for (float k=1.;k<5.;k++)
  {
     f += _noise3( (k*scale)*p)/(k);
     p = mx*p;
  }
  f=exp(-f*f*f*f)*.14;
  return f;
}

float fbm1( vec3 p)
{
  float  r=0.0,f = 1.0;
  vec3 pn=p;
  for (int i = 0; i < noctaves; i++ )
  {
   float n =  _noise3(p);
   r    -= f * (inv_cloudness * n - 1.0);
   f    *= gain;
   p   *= lacunarity;
  }
  return clamp((r+2.)/2.8,0.,1.);
}

bool RSI(in vec3 ro,in vec3 rd,in float scale,out vec2 res)
{
  ro/=scale;
  float b = dot(ro,rd);
  float c = dot(ro,ro) - 1.0;
  float d = b*b - c;

  if(d <= 0.0) return false;
  d = sqrt(d);
  res.x=(-b - d)*scale;
  res.y=(-b + d)*scale;
  return true;
}

vec4 castray( in vec3 ro, vec3 rd)
{
  vec2 tt;
  if (!RSI(ro,rd,1.,tt)) discard;
  vec3 ap=ro+max(0.,tt.x)*rd;
  vec3 n=normalize(ro);
  vec3 normal = normalize(ap);
  float light = clamp(dot(lightvec, normal),0.,1.);
  float ac=fbm(ap+iGlobalTime*.01);
  float aa=smoothstep(0.0,.4,tt.y-tt.x);
  aa*=aa;
  aa=aa*smoothstep(0.3,.65,aa);
  aa=aa*clamp(ac*2.+.145,0.,1.);
  vec4 col=(atmosphereColor)*aa;

  if (RSI(ro,rd,.97,tt))
  {
   vec3   lp = ro+tt.x*rd;
   float  lc = fbm1(lp);
   vec3 lnormal = normalize(lp);
   vec3 lcol;
   if (lc<0.25) lcol=mix(ca,cb,lc*4.-0.); else
   if (lc< 0.5) lcol=mix(cb,cc,lc*4.-1.); else
   if (lc<0.75) lcol=mix(cc,cd,lc*4.-2.); else
   if (lc<1.0 ) lcol=mix(cd,ce,lc*4.-3.); else
   lcol=ce;
   float la = dot(lnormal,n);
   la*=la;
   la*=la;
   lcol*=la*4.;
   col.rgb+=lcol;
   col.a   =1.;
  }
  col.rgb *= light*.95 + 0.05;
  return col;
}

void main()
{
  vec3 ro  =  camera.xyz*camera.w;
  vec3 rd  =  normalize(dir.xyz-camera.xyz);
  //------------------------------------------------
  fragColor = castray(ro,rd);
}


