in  vec4 dir;
out vec4 fragColor;
uniform vec4 camera; // xyz- camera origin  , w - 1/rad
uniform vec4 sparam;
uniform vec4 param[3];

// #define  sundir      param[0].xyz
#define  suncolor    param[0].xyz
#define  ambcolor    param[1].xyz
#define  density     param[2].x
#define  noise_scale param[2].y
#define  sun_power   param[2].z
#define  seed        param[2].w

#define  iGlobalTime sparam.x

// vec3 sundir = normalize( vec3(0.0,0.0,-1.0) );
// vec3 suncolor = vec3(1.0, 0.3, 0.1);
// vec3 ambcolor = vec3(0.45,0.48,.55);
// const float density=1.,noise_scale=3.,sun_power=10.0,seed=3.;

bool RSI(in vec3 ro,in vec3 rd,out vec2 res)
{
  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=vec2(-b - d,-b + d);
  return true;
}

// #define _FAST

#ifdef _FAST

uniform  sampler3D tex4;

/*
_________________________________________________________*/
float perlin(vec3 q) // [-.4;.6]
{
 return texture(tex4,q*.125).r-.4;
}

#else

uniform  sampler2D tex0;

float noise(vec3 x) // [0;1]
{
  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 = texture( tex0, (uv+ 0.5)/256.0).yx;
  return mix( rg.x, rg.y, f.z );
}

float perlin(vec3 q) // [-.4;.6]
{
 //  q -= vec3(0.0,0.1,1.0)*iGlobalTime;
 float f=-0.4,k=.53;
 for (int i=0;i<4;i++)
 {
  f += k*noise( q );
  q *= 2.02;
  k*=.5;
 }
 return f;
}

#endif

float map(vec3 p)
{
 float w=1.-sqrt(length(p));  if (w<=0.0) return 0.0;
 float  f=perlin(p*noise_scale-vec3(seed));
 return w*f*density;
}

vec4 raymarch( in vec3 ro, in vec3 rd)
{
  vec4 sum = vec4(0.);
  vec2 tt;
  if (!RSI(ro,rd,tt)) discard;
  float t = max(0.,tt.x);
  for(int i=0; i<120; i++)
  {
   if( sum.a > 0.99 ) break;
   vec3  pos = ro + t*rd;
   float den = map(pos);
   if( den>0. )
   {
     vec3 pos1 = pos*(.8+.2/length(pos));
     // vec3 pos1 = pos+0.2*sundir;
     float dif = den - map(pos1);
     vec4 col = vec4( mix( vec3(1.0,0.95,0.8), vec3(0.25,0.3,0.35), den ), den );
     col.xyz *= ambcolor + suncolor*sun_power*clamp(dif,0.,1.);
     col.rgb *= col.a;
     sum += col*(1.0-sum.a);
   }
   t += max(0.03,(0.01+0.02*sqrt(t))*(1.0-den));
   if (t>=tt.y) break;
  }
  sum.rgb*=sum.rgb;
  return clamp( sum, 0.0, 1.0 );
}


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