in  vec4 dir;
out vec4 fragColor;
uniform vec4 camera; // xyz- camera origin(LY)  , w - 1/rad(LY)
uniform sampler2D tex0;

#define  iChannel0 tex0

const vec3 rad1=vec3(1.0,.9,1.);
const vec3 rad2=vec3(.7,.65,.7);

float noise_3( 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 = texture( 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=160.;
  float f=0.0;
  for (float k=1.;k<5.;k++)
  {
     float k1 = k*scale;
     f += noise_3( k1*p)/k;
     p = mx*p;
  }
  f=.02/(f*f);
  return f;
}


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.x=(-b - d)*k;
  res.y=(-b + d)*k;
  return true;
}

float sdTorus( vec3 p, vec3 t )
{
  return length( vec2(length(p.xz)-t.x,p.y*t.z) )-t.y;
}


vec4 castray( in vec3 ro, vec3 rd)
{
  vec2 tt;
  if (!RSI(ro,rd,1.0/rad1,tt)) discard;
  const float dt = 0.02;
  float t=max(tt.x,0.0);
  vec3  acc=vec3(0.0);
  float a=(tt.y-t)*.5;
  for(float i=0.;i<1.5;i+=dt  )
  {
   vec3 pos = ro+t*rd;
   float c1=fbm(pos);
   float tr=sdTorus(pos,vec3(0.5,0.25,2.));
   float w1=smoothstep(0.8,1.,length(pos/rad2));
   float w2=smoothstep(-.25,0.25,-tr);
   c1=max(w1,w2)*c1+ c1*w2*1.5;
   float c2=c1*c1;
   acc+=vec3(c2*c2,c2*c1,c2);
   t+=dt;
   if (t>tt.y) break;
  }
  vec3 col=acc.rgb*vec3(10.,10.,1.);
  return vec4(col,a*a*.3 );
}


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