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

//vec4 param=vec4(20000.,40000.,5.0e3,55.);   // O(30000—60000) blue star
//vec4 param=vec4(10000.,20000.,2.0e4,55.);   // B(10000—30000) blue star
//vec4 param=vec4(6000.,4000.,2.0e5,55.);     // A(7500—10000) white star
//vec4 param=vec4(5000.,2500.,5.0e5,55.);     // F(6000-7500)  white - yellow star
//vec4 param=vec4(2500.,3500.,6.0e6,55.);     // G (5000—6000) sun , yellow star
//vec4 param=vec4(2500.,2500.,1.0e7,35.);     // K (3500—5000) sun , orange star
//vec4 param=vec4(1500.,2000.,1.0e8,30.);     // M (2000—3500) red star

//vec4 param=vec4(30000.,40000.,3.0e3,70.); // W(70000)
//vec4 param=vec4(1500.,500.,10.0e8,5.); //L dwarf (1500—2000)
//vec4 param=vec4(700.,800.,2.0e12,3.);  //T dwarf  (700-1500)
//vec4 param=vec4(500.,200.,1.0e18,2.);    //Y dwarf (<700)
//vec4 param=vec4(700.,400.,1.0e14,38.);     // C,R,N
//vec4 param=vec4(3000.,1000.,9.0e6,35.);     // S type
//vec4 param=vec4(10000.,15000.,3.0e4,10.);   // D type, White dwarf


#define   T0         param.x
#define   Ts         param.y
#define   Exp        param.z
#define  sun_density param.w


// -- Common Tools ----------------------------------------------------

vec3 firePalette(float i)
{
    float T = T0 + Ts*i; // Temperature range (in Kelvin).
    vec3 L = vec3(7.4, 5.6, 4.4); // Red, green, blue wavelengths (in hundreds of nanometers).
    L = pow(L,vec3(5.0)) * (exp(1.43876719683e5/(T*L))-1.0);
    return 1.0-exp(-Exp/L); // Exposure level. Set to "50." For "70," change the "5" to a "7," etc.
}

float hash(in float n) { return fract(sin(n)*43758.5453123); }

float noise(in vec3 x)
{
  vec3 p = floor(x), f = fract(x);
  f = f*f*(3.-2.*f);
  vec2 rg = texture(iChannel0, (((p.xy+vec2(37.,17.)*p.z) + f.xy)+.5)/256., -100.).yx;
  return mix(rg.x, rg.y, f.z);
}

bool intersectSphere(in vec3 ro, in vec3 rd, in float r, out float dist, out float edge)
{
  float b = dot(rd,-ro),
  d = b*b - dot(ro,ro) + r*r;
  if (d < 0.) return false;
  edge = sqrt(d);
  dist = b - edge;
  return dist > 0.;
}


// +------------------------------------------------------+
// |                 Sun Eruption Effect                  |
// +------------------------------------------------------+

// original by nimitz https://www.shadertoy.com/view/lsSGzy#, slightly modified
// FLARING GENERATOR, A.K.A PURE AWESOME
mat2 m2 = mat2( .8,  .6, -.6,  .8);
float fbm( in vec2 p )
{
  float z=2.,        // EDIT THIS TO MODIFY THE INTENSITY OF RAYS
  rz = -.0005; // EDIT THIS TO MODIFY THE LENGTH OF RAYS
  p *= .525;         // EDIT THIS TO MODIFY THE FREQUENCY OF RAYS
  for (int i= 1; i<7; i++)
  {
    rz+= abs((texture(iChannel0, p*.01).x-.5)*2.)/z;
    z = z*2.;
    p = p*2.*m2;
  }
  return rz;
}

vec4 fireTexture(in vec2 uv, in float t, in float z)
{
  const float ray_brightness= 15.;
  const float GAMMA =6.;
  const float ray_density= 3.5;
  uv*= 1.5;
  uv.y -= 1.8;

  float gam = mix(GAMMA*2., 0., .5+.5*z);
  float   r = sqrt(dot(uv,uv)), // DISTANCE FROM CENTER, A.K.A CIRCLE
  x = dot(normalize(uv), vec2(.35,0.))+t,
  y = dot(normalize(uv), vec2(.0,.65))+t;

  float val = fbm(vec2(r + y *ray_density, x + ray_density)); // GENERATES THE FLARING
  val = smoothstep(gam*.02-.1,ray_brightness+(gam*0.02-.1)+.001, val);

  val = mix(1.,1.-val*3., 266.667 * r); // REMOVE THIS TO SEE THE FLARING
  vec3 col = firePalette(clamp(val*.5,0.,1.));
  uv.y= uv.y+1.2;
  r   = length(uv);
  col = col * (1. - clamp(.3*abs(r*r),0.,1.));
  return vec4(col, clamp(length(col),0.,1.));
}

struct Base {
  mat3 base;
  vec3 o;
};

Base basis(in vec3 o, in vec3 n) {
  Base b;
    float a=1./(1.+n.z), c=-n.x*n.y*a;
  b.base = mat3(n.x, n.y, n.z, 1.-n.x*n.x*a, c, -n.x,  c, 1.-n.y*n.y*a, -n.y);
  b.o = o;
  return b;
}

vec4 colorEruption(in vec3 ro, in vec3 rd, in float time,in float kMax, vec3 refVec, in float h, in vec2 scale) {
    refVec = normalize(refVec);
    vec3 pAnim = -(1.+h)*refVec;
    Base b = basis(pAnim, refVec);

    vec4 textColor,col = vec4(0);
    // Chang basis
  ro = (ro-b.o)*b.base;
  rd = rd*b.base;

  float k = (abs(rd.z)<.0001) ? -1. : -ro.z/rd.z;   // intersection avec plan y=0; dans base du fire
    float dk = abs(.003/rd.z);
    vec3 p = ro + k*rd;
    if (k>0. && abs(p.x)<.1*scale.x && abs(p.y)<.1*scale.y) {
        k = max(0., k-13.*dk);
        float tSun = 10.*scale.x -(time)*.04;
        for (int i=0;i<26;i++) {
            if (k>kMax) break;
            p = ro + k*rd;
            textColor = fireTexture(scale*p.yx, tSun, .75*float(i)*p.z/rd.z);
            col += .08*textColor;//col*(1.-textColor.a) + textColor*textColor.a;
            k+=dk;
        }
    }
  return col;
}



// +------------------------------------------------------+
// |                  Sun Lava effect                     |
// +------------------------------------------------------+

const mat3 msun = mat3(0., .8, .6, -.8, .36, -.48, -.6, -.48, .64);

float smoothNoise(in vec3 q)
{
  float   f  = .5000*noise(q); q=msun*q*2.01;
          f += .2500*noise(q); q=msun*q*2.02;
          f += .1250*noise(q);
       // q = msun*q*2.03;
       // f += .0625*noise(q);
  return f;
}

vec3 getSunColor(in vec3 p, in float time)
{
  float lava = smoothNoise((p+vec3(time*.01))*sun_density );
  vec3 color = firePalette(1. - sqrt(lava));
  return (color*color+color);
}


// +----------------------------------------+
// |           VOLUMIC SUN SURFACE          |
// +----------------------------------------+

const float VOLUMIC_SURFACE_TICKNESS  = .023; //.023;


const int   VOLUMIC_SURFACE_NB_STEP   = 40;//70;
const float VOLUMIC_SURFACE_RAY_STEP  = .0023; //.0023;
const float VOLUMIC_SURFACE_INTENSITY = .04; //.022;

vec4 getLightRays(vec3 ro, vec3 rd, in float time)
{
  vec3 p = vec3(0.0);
  float edge, dist, r = 1. + VOLUMIC_SURFACE_TICKNESS;
  bool hit = intersectSphere(ro - p, rd, r, dist, edge);
  vec2 uv;
  vec4 sampleCol, c = vec4(0);
  if (hit)
  {
    vec3 pos = ro + rd*dist;
    float light, d, rout;
    // ray-march into volume
    for(int i=0; i<VOLUMIC_SURFACE_NB_STEP; i++)
    {
     d = length(pos);
     if (d<1. || d>r+.001 || c.a>0.95 ) break;

     sampleCol.rgb = vec3(.5,.01,.08)+getSunColor(normalize(pos), time);
     light = length(sampleCol.rgb);
     //---------------
     rout = 1.+ VOLUMIC_SURFACE_TICKNESS*clamp(light*light,0.,1.);
     sampleCol.a = light*(rout-d)/(rout-1.);
     sampleCol.a *= sampleCol.a;
     sampleCol.rgb *= sampleCol.a;
     c += VOLUMIC_SURFACE_INTENSITY*sampleCol*(1. - c.a);
     pos += rd*VOLUMIC_SURFACE_RAY_STEP;
    }
  }
  return c;
}


// +----------------------------------------+
// |         CLASSICAL RAY TRACING          |
// +----------------------------------------+


vec4 render(in vec3 ro, in vec3 rd, in float time)
{
    float dist, edge;
    vec4 color;
    if (intersectSphere(ro, rd, 1., dist, edge))
    {
     vec3  pos = ro+rd*dist,
     nor = normalize(pos);
     float lDif = clamp(dot(nor, -rd), .01, 1.),
     a = smoothstep(0., .5, sqrt(edge));
     vec3 oCol = getSunColor(pos, time);
     // oCol = mix(oCol, vec3(1.8, .4, .4), 1.-a*.95); // atmosphere
     oCol = oCol*(.5+ .5*lDif);
     color = vec4(oCol*a, a);
    }
    else
    {
     color = vec4(0);
     dist = 1000.;
    }

// Sun special effects -------------------------------------------
  if (sun_density>20.)
  {
    vec4 textColor  = colorEruption(ro,rd,time, dist, vec3(-.4,.1,.35), .12, vec2(3.,6.));
    vec4 textColor2 = colorEruption(ro,rd,time, dist, vec3(.7,-1,0), .2, vec2(6.,4.1));
    color = color*(1.-.3*textColor .a) + .5*textColor *textColor .a;
    color = color*(1.-.3*textColor2.a) + .5*textColor2*textColor2.a;
  }
  vec4 textColor3 = getLightRays(ro, rd, time);
  color = color*(1.-.3*textColor3.a) + .5*textColor3*textColor3.a;
  if (color.a<0.01) discard;
  return color;
}

void main()
{
 vec3 ro  =  camera.xyz*camera.w;
 vec3 rd  =  normalize(dir.xyz-camera.xyz);
 vec4 color = render(ro,rd,iGlobalTime);
 fragColor = vec4(clamp(color.rgb*color.rgb,0.,1.)*dir.w,color.a);
}
