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

#define  mode param[0].x

#define  iGlobalTime sparam.x
uniform  sampler2D tex0;
uniform  sampler2D tex1;
#define  iChannel0 tex0
#define  iChannel1 tex1

vec3 sundir = normalize( vec3(0.0,1.0,-1.0) );
vec3 suncolor = vec3(1.0, 0.6, 0.3)*2.;
vec3 ambcolor = vec3(0.65,0.67,.72);
const float density=.06,noise_level=1.0,thickness=1.,xy_scale=4.,noise_scale=8./xy_scale;

vec4 _map(vec3 p) { return texture2D( iChannel1,p.xy*.5/xy_scale+.5); }


bool RSI(in vec3 ro,in vec3 rd,in vec3 scale,out vec2 res)
{
  ro*=scale;
  rd*=scale;
  float k=1.0/length(rd);
  rd *=k;
  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)*k;
  return true;
}

float noise( in 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 = texture2D( iChannel0, (uv+ 0.5)/256.0, -100.0 ).yx;
  return mix( rg.x, rg.y, f.z );
}

float weight(vec3 p,vec4 tc)
{
  p.z/=max(.01,thickness*sqrt(tc.r));
  p=abs(p)/xy_scale;
  return 1.-max(max(p.x,p.y),p.z);
}

float map(vec3 p,vec4 tc)
{
  float w=weight(p,tc); if (w<-.4*noise_level) return w;
  vec3 q=p*noise_scale;
  q -= vec3(0.0,0.1,1.0)*iGlobalTime;
  float f=-0.375,k=.5; // f [-.375;.375]
  for (int i=0;i<5;i++)
  {
    f += k*noise( q );
    q *= 2.02;
    k*=.5;
  }
  return (w+f*noise_level);
}

vec4 integrate( in vec4 sum, in float dif, in float den, in float t,vec4 tc )
{
    vec4 col = vec4( mix( vec3(1.0,0.95,0.8), vec3(0.25,0.3,0.35), den ), den*density );
    col.xyz *= ambcolor + suncolor*clamp(dif,0.,1.);
    col.rgb *= col.a;
    col.rgb *= tc.rgb;
    return sum + col*(1.0-sum.a);
}

const float k=0.7071/(xy_scale*(1.+.375*noise_level));
vec4 raymarch( in vec3 ro, in vec3 rd)
{
  vec4 sum = vec4(0.0);
  vec2 tt;
  if (!RSI(ro,rd,vec3(k,k,k/thickness),tt)) discard;
  if (mode>0.0)
  {
   vec3 pos =  ro-rd*(ro.z/rd.z);
   vec4 col = _map(pos);
   return col.aaaa;
  }
  float t = max(0.,tt.x);
  t+=0.15*texture  (iChannel0,rd.xy*vec2(280.,270.)).r; // dithering
  for(int i=0; i<240; i++)
  {
   if( sum.a > 0.99 ) break;
   vec3  pos = ro + t*rd;
   vec4  tc  = _map(pos);
   float den = map( pos,tc );
   if( den>0. )
   {
     vec3 pos1 = pos+0.2*sundir;
     float dif = (den - map(pos1,_map(pos1)))*1.;
     sum = integrate( sum, dif, den, t ,tc);
     t += max(0.03,(0.01+0.02*sqrt(t))*(1.0-den));
   }
   else t += max(0.03,(0.01+0.02*sqrt(t))*2.);
   if (t>=tt.y) break;
  }
  return clamp( sum, 0.0, 1.0 );
}


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