float clscale = 2.0;//4.0

uniform sampler2D shadowMap;
uniform sampler2D iChannel1;
uniform sampler2D fxMap;
uniform sampler2D depthMap;
uniform float iTime;
uniform float qscale;
uniform float testvalue;
uniform float testvalue2;

uniform mat4 fireLightProjectionMatrix;

uniform vec3 rayorigin;
uniform vec3 raydirection;
uniform vec3 upvector;
uniform float fov;
uniform mat4 glmatrix;

uniform mat4 rotmatrix;

#define inf 1000000.0
#define M_PI 3.1415926

uniform int cloudtype;
uniform int voronoitype;

float scf=5.4/12.0;






float sdBox( vec3 p, vec3 b )
{
    vec3 d = abs(p) - b;
    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}

vec2 opU( vec2 d1, vec2 d2 ) { 
if (d1.x<d2.x) return d1; else return d2;
//return min(d1,d2); 
}

float h_=0.0;
vec2 opUsc( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 + 0.5*(d2.x-d1.x)/k, 0.0, 1.0 );
    h_=clamp((d2.x-d1.x)/k, -1.0, 1.0 );
    //h_+=1.0; h_/=2.0;
    return vec2(mix( d2.x, d1.x, h ) - k*h*(1.0-h), d1.y); 
}

vec2 opSs( vec2 d1, vec2 d2, float k ) {
    float h = clamp( 0.5 + 0.5*(-d2.x-d1.x)/k, 0.0, 1.0 );
    //h_=h;
    h_=clamp((-d2.x-d1.x)/k, -1.0, 1.0 );
    //h_+=1.0; h_/=2.0;
    return vec2(mix( d1.x, -d2.x,  h ) + k*h*(1.0-h), d1.y);
}

vec2 cloudshape2(vec3 pos){
    pos.y+=-1.4;
    float scale=4.25*0.80;
    vec2 res;
    res=vec2(100.0,0.0);
    res = opUsc(res,vec2(sdBox(pos+vec3(0.0,0.0,0.0), vec3(4.5,6.5,4.5)/vec3(scale)),26.9),0.06);
    const float f=1.0;
    vec2 res2=vec2(100.0,0.0);
    //res2 = opU(res2,vec2(Helix(pos+vec3(0.0,0.0,0.0)),26.9));
    res = opSs(res,res2,(1.5+0.02)*0.81+0.6+0.2);

    return vec2(h_,0);
}

float cloudshape(vec3 pos){
pos=(rotmatrix*vec4(pos,1.0)).xyz;
//float scale=4.25;
float scale=1.0*6.779;
vec2 res;
res=vec2(100.0,0.0);
res = opUsc(res,vec2(sdBox(pos+vec3(0.0,0.0,0.0), vec3(4.5,4.5,4.5)/vec3(scale)),26.9),0.06);
float f = 1.0;
const float r_factor=0.35;
const float h_factor=1.0;
float r2=r_factor/6.0+f*4.55;
r2=1.0/7.0;
vec2 res2=vec2(100.0,0.0);
//float sx=iTime*0.9;
//res2 = opUsc(res2,vec2(sdBox(pos+vec3(2.0+4.0*sin(sx/2.0),0.0,0.0)/vec3(scale),vec3(0.25,0.0025,0.45)*vec3(r2)/vec3(scale)),26.9),0.05);
//res2 = opUsc(res2,vec2(sdBox(pos+vec3(-2.0,0.0,0.0+3.3*cos(sx/1.7))/vec3(scale),vec3(0.45,0.0025,0.25)*vec3(r2)/vec3(scale)),26.9),0.05);
res2 = opUsc(res2,vec2(sdBox(pos+vec3(0.0,0.0,0.0)/vec3(scale),vec3(1.0,1.0,1.0)*vec3(r2)/vec3(scale)),26.9),0.05*0.01);
res2 = opUsc(res2,vec2(sdBox(pos+vec3(0.0,0.0,0.0)/vec3(scale),vec3(1.0,1.0,1.0)*vec3(r2)/vec3(scale)),26.9),0.05*0.01);
res = opSs(res,res2,1.5);    
return h_;
}



vec4 mod289(vec4 x) {
  return x - floor(x * (1.0 / 289.0)) * 289.0; }

float mod289(float x) {
  return x - floor(x * (1.0 / 289.0)) * 289.0; }

vec4 permute(vec4 x) {
     return mod289(((x*34.0)+1.0)*x);
}

float permute(float x) {
     return mod289(((x*34.0)+1.0)*x);
}

vec4 taylorInvSqrt(vec4 r)
{
  return 1.79284291400159 - 0.85373472095314 * r;
}

float taylorInvSqrt(float r)
{
  return 1.79284291400159 - 0.85373472095314 * r;
}

vec4 grad4(float j, vec4 ip)
  {
  const vec4 ones = vec4(1.0, 1.0, 1.0, -1.0);
  vec4 p,s;

  p.xyz = floor( fract (vec3(j) * ip.xyz) * 7.0) * ip.z - 1.0;
  p.w = 1.5 - dot(abs(p.xyz), ones.xyz);
  s = vec4(lessThan(p, vec4(0.0)));
  p.xyz = p.xyz + (s.xyz*2.0 - 1.0) * s.www;

  return p;
  }


#define F4 0.309016994374947451

float snoise(vec4 v)
  {
  const vec4  C = vec4( 0.138196601125011,  
                        0.276393202250021,  
                        0.414589803375032,  
                       -0.447213595499958); 


  vec4 i  = floor(v + dot(v, vec4(F4)) );
  vec4 x0 = v -   i + dot(i, C.xxxx);




  vec4 i0;
  vec3 isX = step( x0.yzw, x0.xxx );
  vec3 isYZ = step( x0.zww, x0.yyz );

  i0.x = isX.x + isX.y + isX.z;
  i0.yzw = 1.0 - isX;

  i0.y += isYZ.x + isYZ.y;
  i0.zw += 1.0 - isYZ.xy;
  i0.z += isYZ.z;
  i0.w += 1.0 - isYZ.z;

  
  vec4 i3 = clamp( i0, 0.0, 1.0 );
  vec4 i2 = clamp( i0-1.0, 0.0, 1.0 );
  vec4 i1 = clamp( i0-2.0, 0.0, 1.0 );

  
  
  
  
  
  vec4 x1 = x0 - i1 + C.xxxx;
  vec4 x2 = x0 - i2 + C.yyyy;
  vec4 x3 = x0 - i3 + C.zzzz;
  vec4 x4 = x0 + C.wwww;


  i = mod289(i);
  float j0 = permute( permute( permute( permute(i.w) + i.z) + i.y) + i.x);
  vec4 j1 = permute( permute( permute( permute (
             i.w + vec4(i1.w, i2.w, i3.w, 1.0 ))
           + i.z + vec4(i1.z, i2.z, i3.z, 1.0 ))
           + i.y + vec4(i1.y, i2.y, i3.y, 1.0 ))
           + i.x + vec4(i1.x, i2.x, i3.x, 1.0 ));



  vec4 ip = vec4(1.0/294.0, 1.0/49.0, 1.0/7.0, 0.0) ;

  vec4 p0 = grad4(j0,   ip);
  vec4 p1 = grad4(j1.x, ip);
  vec4 p2 = grad4(j1.y, ip);
  vec4 p3 = grad4(j1.z, ip);
  vec4 p4 = grad4(j1.w, ip);


  vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3)));
  p0 *= norm.x;
  p1 *= norm.y;
  p2 *= norm.z;
  p3 *= norm.w;
  p4 *= taylorInvSqrt(dot(p4,p4));


  vec3 m0 = max(0.6 - vec3(dot(x0,x0), dot(x1,x1), dot(x2,x2)), 0.0);
  vec2 m1 = max(0.6 - vec2(dot(x3,x3), dot(x4,x4)            ), 0.0);
  m0 = m0 * m0;
  m1 = m1 * m1;
  return 49.0 * ( dot(m0*m0, vec3( dot( p0, x0 ), dot( p1, x1 ), dot( p2, x2 )))
               + dot(m1*m1, vec2( dot( p3, x3 ), dot( p4, x4 ) ) ) ) ;

  }


vec2 p;

float hash2(vec3 p)  
{
    p  = fract( p*0.3183099+.1 );
	p *= 17.0;
    return fract( p.x*p.y*p.z*(p.x+p.y+p.z) );
}

float noisefast2( in vec3 x )
{
    vec3 i = floor(x);
    vec3 f = fract(x);
    f = f*f*(3.0-2.0*f);
	
    return mix(mix(mix( hash2(i+vec3(0,0,0)), 
                        hash2(i+vec3(1,0,0)),f.x),
                   mix( hash2(i+vec3(0,1,0)), 
                        hash2(i+vec3(1,1,0)),f.x),f.y),
               mix(mix( hash2(i+vec3(0,0,1)), 
                        hash2(i+vec3(1,0,1)),f.x),
                   mix( hash2(i+vec3(0,1,1)), 
                        hash2(i+vec3(1,1,1)),f.x),f.y),f.z);
}

vec4 hash44(vec4 p4)
{
	p4 = fract(p4  * vec4(.1031, .1030, .0973, .1099));
    p4 += dot(p4, p4.wzxy+33.33);
    return fract((p4.xxyz+p4.yzzw)*p4.zywx);
}


float hash14(vec4 p4)
{
	p4 = fract(p4  * vec4(.1031, .1030, .0973, .1099));
    p4 += dot(p4, p4.wzxy+33.33);
    return fract((p4.x + p4.y) * (p4.z + p4.w));
}

float smoothnoise(in vec4 p, int i) {
    if (cloudtype==0){
        //return noisefast2(p.xyz/5.0+vec3(0,-float(i)*iTime/20.0,0))*1.2;
        return testvalue;
        return noisefast2(p.xyz/5.0+vec3(sin(float(i)*iTime/24.0),-float(i)*iTime/20.0,sin(float(i)*iTime/29.0)))*1.2;
        //return noisefast2(p.xyz/5.0+vec3(sin(float(i)*iTime/24.0+p.y/7.0),-float(i)*iTime/20.0,sin(float(i)*iTime/27.0+p.y/7.0)))*1.2;
    }else if (cloudtype==1)
    {
        float scale=70.0*70.0/2.0;
        vec4 col=texture2D(iChannel1,vec2(p.x/scale,p.z/scale)+vec2(iTime,iTime/1.2)/1000.0f/0.9).rgbb;
        return snoise((p+col)/3.0)*4.5;
    } else 
    {
        float scale=70.0*70.0/2.0;
        vec4 col=texture2D(iChannel1,vec2(p.x/scale,p.z/scale)).rgbb;
        float iTm=iTime/1.5; //10.0
        return snoise((p+col+vec4(sin(float(i)*iTm/240.0),-float(i)*iTm/10.0,sin(float(i)*iTm/290.0),sin(float(i)*iTm/2900.0))/3.0*3.3*scf))*-30.0;
        //return noisefast2(p.xyz*5.0+vec3(sin(float(i)*iTime/24.0),-float(i)*iTime/20.0,sin(float(i)*iTime/29.0)));
        //return noisefast2(p.xyz)*1.2/testvalue;
    }
}

float noise4d(in vec4 p) {

    float s = 0.;
    float pow2 = 1.;
    int am;
    if (cloudtype==0) am=8; else am=5;
    if (cloudtype==2) am=3;
    for (int i = 0; i < am; i++) {
        vec4 p_=p;
        
        if (cloudtype==0){
            p_*=2.5;
            p_.y-=iTime/4.6/10.0f;
        }
        float value=smoothnoise(p_ * pow2, i) / pow2;
	    s += value;
        pow2 *= 2.;
    }
    return clamp(s / 2.,-1.,2.);
}

float noise4d_(in vec4 p) {
        vec4 integer = floor(p);
        vec4 fractional = fract(p);

        fractional = 1.0 - fractional * fractional;
        fractional = 1.0 - fractional * fractional;

        vec2 uv = (integer.xy + integer.z * vec2(37., 17.) + integer.w * vec2(59., 83.)) + fractional.xy;

        
        vec4 rgba = hash44(vec4((uv+.5)*.00390625, 0., 0.));

        return mix(mix(rgba.x, rgba.y, fractional.z), mix(rgba.z, rgba.w, fractional.z), fractional.w);
}

float sdEllipsoid( in vec3 p, in vec3 r ) 
{
    float k0 = length(p/r);
    float k1 = length(p/(r*r));
    return k0*(k0-1.0)/k1;
}

float flevelRange(float color, float minInput, float maxInput){
    return min(max(color - minInput, 0.0) / (maxInput - minInput), 1.0);
}

// creates a sphere grid of the squared distance to the center
float sphereGrid(vec3 uv) {
    vec3 squaregrid = fract(uv) - .5; //rectangular grid with center in the middle
    float spheregrid = dot(squaregrid, squaregrid); //squared distance form scenter
    return spheregrid;
}

#define pi              3.1415926536
// makes a tiling cell pattern
float cellTiling3D(vec3 uvw, float degree, float scale, int level) {
    float c = sphereGrid(uvw); // first grid
    
    // choose a deg/scale and calculate it here desmos.com/calculator/refsu6mvlj
    float rad = (pi* degree)/180.; //degree to radians   
    // This is rotation matrix X * Z, because symtery no 3. rot needed
    float c_=cos(rad);
    float s_=sin(rad);
    /*
    mat3 m = mat3(cos(rad), -cos(rad)*sin(rad), pow(sin(rad),2.),
                 sin(rad), pow(cos(rad),2.), -cos(rad)*sin(rad),
                 0., sin(rad), cos(rad));
    */
    mat3 m = mat3(c_, -c_*s_, pow(s_,2.),
                 s_, pow(c_,2.), -c_*s_,
                 0., s_, c_);
    m *= scale;
    
    //If you want two indepented seperate rotations for X,Z use this
    /*mat3 mZ = mat3(cos(rad), -sin(rad), 0.,
                  sin(rad), cos(rad), 0.,
                  0., 0., 1.); // rotation matric Z Axis
    mat3 mX = mat3(1., 0., 0.,
                   0., cos(rad), -sin(rad),
                   0., sin(rad), cos(rad)); // rotation matric X Axis                                      
    mat3 m = mX * mZ * scale; //scale and rotate. */
    
    // precalculate the m*m for perfromance
    for (int i = 0; i < level-1; i++){    
        uvw *= m; //each iteration gets rotated and scaled one addional time
        c = min(c, sphereGrid(uvw)); // blending the voronoi with
    }
    
    return sqrt(c); //sqrt for center distance, 1.5 for 0-1 range
}


#define PI 3.1415926535897932384626433832795
vec4 permute_(vec4 x) { 
    return mod(((x*34.0)+1.0)*x, 289.0); 
}

vec3 fade(vec3 t) {
    return t*t*t*(t*(t*6.0-15.0)+10.0);
}

float hash1(vec4 p) {
    p = fract(p * 0.1031);
    p *= dot(p, p + 33.33);
    return fract((p.x + p.y) * p.z * p.w);
}

float voronoi4D(vec4 p) {
    const float speed = 10.0*4.0;
    const float downsize = 3.0;
    vec4 p_=p*3.14*0.32;
    p.x+=sin(iTime*speed/1000.0*6.28+p_.z)/downsize;
    p.y+=sin(iTime*speed/1111.0*6.28+p_.x)/downsize;
    p.z+=sin(iTime*speed/900.0*6.28+p_.y)/downsize;
    //p.w=20000.0;

    vec4 b = floor(p);
    vec4 f = fract(p);
    float res = 1.0;
    
    for (int k = -1; k <= 1; k++) {
        for (int j = -1; j <= 1; j++) {
            for (int i = -1; i <= 1; i++) {
                for (int l = -1; l <= 1; l++) {
                    vec4 neighbour = vec4(float(i), float(j), float(k), float(l));
                    vec4 point = b + neighbour;
                    vec4 r = neighbour - f + hash1(point);
                    float d = dot(r, r);
                    res = min(res, d);
                }
            }
        }
    }
    return sqrt(res);
}

float fbm(vec4 x){
    
    
    
    
    
    
    float res;
    if (voronoitype==0)
        res=noise4d(x);
    else
    {
        vec4 x_=x;
        x_.xyz*=2.1*0.84;
        x_.xyz+=vec3(3000.0,3700.0,16374.0);
        res=voronoi4D(x_);
    }
        //res = cellTiling3D(x.xyz, 56.0, 1.2, 4.0*0.74); // generating cell Tilling    
        //float vor = cellTiling3D(uvw, degree, scale, level); // generating cell Tilling    
    return res;
}

float noisefast( in vec3 x )
{
    ivec3 i = ivec3(floor(x));
    vec3 f = fract(x);
	f = f*f*(3.0-2.0*f);
	ivec2 uv = i.xy + ivec2(37,17)*i.z;
	vec2 rgA = texelFetch( iChannel1, (uv+ivec2(0,0))&255, 0 ).yx;
    vec2 rgB = texelFetch( iChannel1, (uv+ivec2(1,0))&255, 0 ).yx;
    vec2 rgC = texelFetch( iChannel1, (uv+ivec2(0,1))&255, 0 ).yx;
    vec2 rgD = texelFetch( iChannel1, (uv+ivec2(1,1))&255, 0 ).yx;
    vec2 rg = mix( mix( rgA, rgB, f.x ),
                   mix( rgC, rgD, f.x ), f.y );
    return mix( rg.x, rg.y, f.z );
}

float fbmold(vec3 x){
    float res=noisefast(x/4.0);
    return res;
}

/*
float sdBox( vec3 p, vec3 b )
{
    vec3 d = abs(p) - b;
    return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0));
}
*/

float opUnion( float d1, float d2 ) { return min(d1,d2); }

float animate=0.0f;

vec3 pal( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d )
{
    return a + b*cos( 6.28318*(c*t+d) );
}

vec4 map_cloud2(vec3 pos){
    pos*=0.65*1.4;
    if (cloudtype==0) pos*=2.0;
    if (cloudtype==1) pos*=0.32;
    pos.y+=10.0;
    pos.x+=20.0;
    const float slowdown=0.5;
    float time=2.0*iTime*2.5*slowdown*1.5*3.0;
    
    
    
    
    
    

    

    

    
pos*=3.0f;

    vec4 uv;
    
    uv=vec4(pos.xyz,0.0);
    
    
    
    
    
    



		float f,a;
        
        float m=1.0/1.4;
        

        
        
        
        uv/=7.5*0.3/3.33;
        time *= 4.0;
        time *= 2.2*slowdown/2.0/5.0/10.0/3.0*0.45;
        vec4 anim=vec4(0.0,0.0,0.0,time*1.15f);
        
        float anim1=1.0+0.01*0.09*12.5*0.2;
        
		f  = 1.1000*fbm( uv +anim); uv = m*uv; anim*=anim1;
		
       







        a=f; 
    
    


    
    if (f<0) return vec4(0);
    //a/=testvalue;//1.66;
    
    //if (cloudtype==1) a=flevelRange(a,0.21,1.0);
    //if (cloudtype==1) a=flevelRange(a,0.29,1.07);
    if (cloudtype==1){
        //a=1.0-a;
        a/=-0.65;
        a*=1.1*1.07;
        //if (a<testvalue||a>testvalue2) a=0;
        //if (a<-1.8||a>-1.43) a=0;
    }
    float wtime=time*1.7;
    if (cloudtype==0){
        wtime=1.95*2.75;
        } else {
            wtime=2.0*iTime*2.5*slowdown*1.5*1.7;
            wtime *= 4.0;
            wtime *= 2.2*slowdown/2.0/5.0/10.0/3.0*0.45;
            wtime=1.95*2.75;
        }
    
    float a2=texture2D(fxMap,vec2(wtime,a)*0.15).x;
    
    
    
    
    
    
    
    vec2 uf=vec2(a/2.0+0.2,a/2.0+0.2)*p*0.5+0.5+vec2(a2,a);
    uf=vec2(pos.x,pos.z+pos.y)/6.0*testvalue;

    float budz=2.2/1.4;
    /*
    float r=texture2D(iChannel1,uf).r*budz/1.5;
    float g=texture2D(iChannel1,uf).g*budz/1.5;
    float b=texture2D(iChannel1,uf).b*budz*9.0;
    */
    /*
    float r=texture2D(iChannel1,uf).r;
    float g=texture2D(iChannel1,uf).g;
    float b=texture2D(iChannel1,uf).b;
    */
    vec3 col;
    vec3 p=pos.xyz*4.0;
    col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.10,0.20) );
    col *= pal( p.y, vec3(0.8,0.5,0.4),vec3(0.2,0.4,0.2),vec3(2.0,1.0,1.0),vec3(0.0,0.25,0.25) );
    col += pal( p.z, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,0.5),vec3(0.8,0.90,0.30) );
    float r=col.r;
    float g=col.g;
    float b=col.b;

    a2*=10.0;

    if (cloudtype==1) a2*=0.05*5.0*1.5;

    if (cloudtype==0) {
        a2*=0.7;
        /*
        float boostlow=25.0+40.0*4.6;
        float boosthigh=255/0.67;
        #define const_1 (boostlow / 255.0)
        #define const_2 (255.0 / boosthigh)
        a2= ((a2- const_1) * const_2);
        */
    }

    if (cloudtype==0) r=g=b=fbm(vec4(pos.xyz*8.0,time));

    return vec4(r,g,b,1.0)*a2;

    return vec4(a2);
    return vec4(1.0,1.0,1.0,a);
}








#define time iTime*0.25
//#define PI 3.14159265359

#define NOISE_METHOD 1
float noise( in vec3 x )
{

     x.y+=iTime;
     x.x-=iTime*1.2;
     x.z+=iTime*1.3;

    
    
    vec3 p = floor(x);
    vec3 f = fract(x);
	f = f*f*(3.0-2.0*f);

#if NOISE_METHOD==0
    
    
     
     
    return texture2D(iChannel2,(x+0.5)/32.0).y*2.0-1.0;
    return textureLod(iChannel2,(x+0.5)/32.0,0.0).x*2.0-1.0;
#endif
#if NOISE_METHOD==1
    
	vec2 uv = (p.xy+vec2(37.0,239.0)*p.z) + f.xy;
    vec2 rg = texture2D(iChannel1,(uv+0.5)/256.0).yx;
	return mix( rg.x, rg.y, f.z )*2.0-1.0;
#endif    
#if NOISE_METHOD==2
    ivec3 q = ivec3(p);
	ivec2 uv = q.xy + ivec2(37,239)*q.z;
	vec2 rg = mix(mix(texelFetch(iChannel1,(uv           )&255,0),
				      texelFetch(iChannel1,(uv+ivec2(1,0))&255,0),f.x),
				  mix(texelFetch(iChannel1,(uv+ivec2(0,1))&255,0),
				      texelFetch(iChannel1,(uv+ivec2(1,1))&255,0),f.x),f.y).yx;
	return mix( rg.x, rg.y, f.z )*2.0-1.0;
#endif
}

float noise2( in vec3 x )
{
    float iTime_=iTime*4.0;
    x.y+=iTime_*1.1;
     x.x-=iTime_*1.3;
     x.z+=iTime_*1.5;
    
    return noise(x);
}


mat3 rot(vec3 ang)
{
	mat3 x = mat3(1.0,0.0,0.0,0.0,cos(ang.x),-sin(ang.x),0.0,sin(ang.x),cos(ang.x));
	mat3 y = mat3(cos(ang.y),0.0,sin(ang.y),0.0,1.0,0.0,-sin(ang.y),0.0,cos(ang.y));
	mat3 z = mat3(cos(ang.z),-sin(ang.z),0.0,sin(ang.z),cos(ang.z),0.0,0.0,0.0,1.0);
	return x*y*z;
}

float noise3D(vec3 p)
{
	return fract(sin(dot(p ,vec3(12.9898,78.233,128.852))) * 43758.5453)*2.0-1.0;
}

float simplex3D(vec3 p)
{

	
    
     
       p.z+=iTime*2.75;
       p/=1.2;
    
	float f3 = 1.0/3.0;
	float s = (p.x+p.y+p.z)*f3;
	int i = int(floor(p.x+s));
	int j = int(floor(p.y+s));
	int k = int(floor(p.z+s));
	
	float g3 = 1.0/6.0;
	float t = float((i+j+k))*g3;
	float x0 = float(i)-t;
	float y0 = float(j)-t;
	float z0 = float(k)-t;
	x0 = p.x-x0;
	y0 = p.y-y0;
	z0 = p.z-z0;
	
	int i1,j1,k1;
	int i2,j2,k2;
	
	if(x0>=y0)
	{
		if(y0>=z0){ i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } 
		else if(x0>=z0){ i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } 
		else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; }  
	}
	else 
	{ 
		if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } 
		else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } 
		else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } 
	}
	
	float x1 = x0 - float(i1) + g3; 
	float y1 = y0 - float(j1) + g3;
	float z1 = z0 - float(k1) + g3;
	float x2 = x0 - float(i2) + 2.0*g3; 
	float y2 = y0 - float(j2) + 2.0*g3;
	float z2 = z0 - float(k2) + 2.0*g3;
	float x3 = x0 - 1.0 + 3.0*g3; 
	float y3 = y0 - 1.0 + 3.0*g3;
	float z3 = z0 - 1.0 + 3.0*g3;	
				 
	vec3 ijk0 = vec3(i,j,k);
	vec3 ijk1 = vec3(i+i1,j+j1,k+k1);	
	vec3 ijk2 = vec3(i+i2,j+j2,k+k2);
	vec3 ijk3 = vec3(i+1,j+1,k+1);	
            
	vec3 gr0 = normalize(vec3(noise3D(ijk0),noise3D(ijk0*2.01),noise3D(ijk0*2.02)));
	vec3 gr1 = normalize(vec3(noise3D(ijk1),noise3D(ijk1*2.01),noise3D(ijk1*2.02)));
	vec3 gr2 = normalize(vec3(noise3D(ijk2),noise3D(ijk2*2.01),noise3D(ijk2*2.02)));
	vec3 gr3 = normalize(vec3(noise3D(ijk3),noise3D(ijk3*2.01),noise3D(ijk3*2.02)));
	
	float n0 = 0.0;
	float n1 = 0.0;
	float n2 = 0.0;
	float n3 = 0.0;

	float t0 = 0.5 - x0*x0 - y0*y0 - z0*z0;
	if(t0>=0.0)
	{
		t0*=t0;
		n0 = t0 * t0 * dot(gr0, vec3(x0, y0, z0));
	}
	float t1 = 0.5 - x1*x1 - y1*y1 - z1*z1;
	if(t1>=0.0)
	{
		t1*=t1;
		n1 = t1 * t1 * dot(gr1, vec3(x1, y1, z1));
	}
	float t2 = 0.5 - x2*x2 - y2*y2 - z2*z2;
	if(t2>=0.0)
	{
		t2 *= t2;
		n2 = t2 * t2 * dot(gr2, vec3(x2, y2, z2));
	}
	float t3 = 0.5 - x3*x3 - y3*y3 - z3*z3;
	if(t3>=0.0)
	{
		t3 *= t3;
		n3 = t3 * t3 * dot(gr3, vec3(x3, y3, z3));
	}
	return 96.0*(n0+n1+n2+n3);
	
}

float fbm_(vec3 p)
{
    p*=0.75;
    
    
	float f;
    float ff=0.9;
    f  = 0.50000*simplex3D( p ); p = p*2.01*ff;
    f += 0.25000*simplex3D( p ); p = p*2.02*ff;
    f += 0.12500*simplex3D( p ); p = p*2.03*ff;
    f += 0.06250*simplex3D( p ); p = p*2.04*ff;
    f += 0.03125*simplex3D( p );
	return f;
}


float map(vec3 pos){
      float sc=0.8;
      float r=((0.5+(1.0+noise(pos*4.0))/5.0)+(1.0+noise(pos/2.5))/5.0);
      
      r/=7.5;
      r+=0.7;
    vec2 res = vec2( sdEllipsoid(    pos-vec3(-0.0,0.0, 0.0), 
               vec3(1.0*sc,1.0*sc,1.0*sc)*r*2.0), 26.9 );
    return res.x;
}


vec2 map_cube(vec3 pos){
    float res=sdBox(pos.xyz+vec3(0,0,0),vec3(1,1,1));
    return vec2(res,1.0);
}


vec2 castRay( const vec3 ro, vec3 rd )
{
    float scale=1.0;
    vec2 res=vec2(-100,-100);
    float tmin = 0.0000001;
    float t = tmin;
    
    
    int steps_=150/2*0.6;
    float precision_=0.001/64.0*200.0/2.0/100.0*4.7/0.28*83.0;
    float stepper=0.85*0.7*1.2*0.74*0.3/4.0; 

 
    {

        float t = tmin;
        for( int i=0; i<steps_; i++ )
        {
            
            vec3 dest=ro+rd*t;
            /*
            if (dest.x<-2.0*1.9*1.7||dest.x>2.0*1.9*1.7||dest.y<0.0||dest.y>5.0*0.8) {
                res=vec2(100,-120);
                break;
            }
            */
            vec2 a = map_cube(dest);

            vec2 h = a;
            
            if( abs(h.x)<(precision_*t) )
            {
                res = vec2(t,h.y);
                break;
            }
            t += h.x*stepper;
        }
    }

    
    //float m = res.y;
    return res;
}

#define SAMPLE_COUNT 32*7/1.4
#define DIST_MAX 20.0
//128./3.0/7.0/testvalue
#define MOUSEY 0.0
//(3.*iMouse.y/iResolution.y)
#define SAMPLES_ADAPTIVITY 0.2*0.4

// compute desired spacing between samples, modelled as a 1/z curve
float spacing(float t )
{
    // restrict to domain
    t = max(t,0.);
    
    // unnorm pdf - plot this in graphtoy to see shape
    float pdf = 1. / (SAMPLES_ADAPTIVITY*t + 1.);
	// integral of pdf over dist
	float norm = (1. / SAMPLES_ADAPTIVITY)*log(1. + SAMPLES_ADAPTIVITY*DIST_MAX);
    // norm pdf
    pdf /= norm;
    
    // sample spacing for our sample count
    return 1. / (float(SAMPLE_COUNT) * pdf);
}

// mouse toggle
bool useNewApproach = false;

// cam moving in a straight line
vec3 lookDir = vec3(-1.,0.,0.);
vec3 camVel = vec3(-3.,0.,0.);
float zoom = 1.2; // 1.5;

// mod but moves the boundaries to keep them stationary with the camera
float mov_mod( float x, float y )
{
    return mod(x + (useNewApproach ? dot(camVel,lookDir) : 0.), y) ;
    return mod(x + (useNewApproach ? dot(camVel*iTime,lookDir) : 0.), y) ;
}

bool on_boundary( float x, float y )
{
    // the +0.25 solves numerical issues without changing the result
    float numericalFixOffset = y*0.25;
    return mov_mod( x + numericalFixOffset, y ) < y*0.5;
}

// put t on an appropriate sample location and initialise sampling data
void firstT( out float t, out float dt, out float wt, out bool even )
{
    dt = exp2(floor(log2(spacing(0.))));
    t = dt - mov_mod(t,dt);
    even = on_boundary(t,2.*dt);
    wt = 1.;
}
// advance t to next sample location
void nextT( inout float t, inout float dt, inout float wt, inout bool even )
{
/*
    float s = spacing(t); // get desired sample spacing
    if( s < dt ) { dt /= 2.; even = true; } // can immediately move to higher density
    else if( even && s > 2.*dt ) { dt *= 2.; wt = 1.; even = on_boundary(t,2.*dt); } // move to lower density if a sample is there

    if( even ) wt = clamp( 2. - s/dt,0.,1.); // update wt for next odd sample - based on how far this even sample is into its band
*/  
    // next sample
    t += dt;
    even = !even;
}

// wt for blending in/out samples without pops
float sampleWt( float wt, bool even )
{
    return even ? (2.-wt) : wt;
}
// LUT based 3d value noise
float noise3( in vec3 x )
{
    return (noise4d(vec4(x.xyz,1.0))/5.5);

    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 = textureLod( iChannel1, (uv+ 0.5)/4096.0, 0.0 ).yx;
    return mix( rg.x, rg.y, f.z );
}


vec4 map2( in vec3 p )
{
	float d = 0.1 + .8 * sin(0.6*p.z)*sin(0.5*p.x) - p.y;

    vec3 q = p;
    float f;
    float f_=4.7;

    f  = 0.5000*noise3( q ); q = q*2.02*f_;
    f += 0.2500*noise3( q ); 
    //q = q*2.03*f_;
    //f += 0.1250*noise3( q ); q = q*2.01*f_;
    //f += 0.0625*noise3( q );
    d += 2.75 * f;

    d = clamp( d, 0.0, 1.0 );
    
    vec4 res = vec4( d );
    
    vec3 col = 1.15 * vec3(1.0,0.95,0.8);
    col += vec3(1.,0.,0.) * exp2(res.x*10.-10.);
    res.xyz = mix( col, vec3(0.7,0.7,0.7), res.x );
    
    return res;
}

vec3 sundir = normalize(vec3(-1.0,1.0,1.0));

vec4 render( in vec3 ro, in vec3 rd, in vec2 fragCoord){
vec4 col=vec4(0.0);
    if (cloudtype==2){
   vec4 sum = vec4(0, 0, 0, 0);
    
    // setup sampling
    float t, dt, wt; bool even;
    firstT( t, dt, wt, even );
    
    for(int i=0; i<SAMPLE_COUNT; i++)
    {
        if( sum.a > 0.99 ) continue;

        vec3 pos = ro + t*rd;


    vec3 globalpos=pos;
    vec4 globalposscreen=(glmatrix*vec4(globalpos,1.0));


    float depth=globalposscreen.z/200.0;
    float x2=depth*(65536.0*256.0);
    float r2=floor(x2/(65536.0)); x2=x2-r2*(65536.0);
    float g2=floor(x2/(256.0)); x2=x2-g2*(256.0);
    float b2=floor(x2/(1.0)); x2=x2-b2*(1.0);
    float r1=float(r2/256.0);
    float g1=float(g2/256.0);
    float b1=float(b2/256.0);

    

    


    float currdepth=(r1*65536.0+g1*256.0+b1)/(65536.0*256.0)*200.0;
    vec2 coos=gl_FragCoord.xy;
    float xc=coos.x/(1920.0/clscale);
    float yc=coos.y/(1080.0/clscale);
    vec4 f=texture2D(depthMap,vec2(xc,yc));
    float imagedepth=(f.r*65536.0+f.g*256.0+f.b)/(65536.0*256.0)*200.0;

    if (imagedepth<currdepth) col=vec4(0,0,0,0); else{


    vec4 globalposlightmap=(fireLightProjectionMatrix*vec4(globalpos,1.0));
    vec2 coo_=globalposlightmap.xy/globalposlightmap.w;

    float rdepth=texture2D(shadowMap, coo_).r;
    float gdepth=texture2D(shadowMap, coo_).g;
    float bdepth=texture2D(shadowMap, coo_).b;
    float shadowmapdepth=(rdepth*256.0f*256.0f+gdepth*256.0f+bdepth)/65536.0f;
    float biasx = 0.0012*0.8;
    float actualdepth=globalposlightmap.z/200.0-biasx;
    float lightdepth=shadowmapdepth;
        
        
            if (lightdepth<actualdepth) col.rgba=vec4(0.0,0.0,0.1,0.2);
            else {

        vec4 col = map2( pos );

        // iqs goodness
        float dif = clamp((col.w - map2(pos+0.6*sundir*scf*1.7).w)/0.6, 0.0, 1.0 );
        vec3 lin = vec3(0.6, 0.6, 0.9)*1.35 + 0.55*vec3(0.7, 0.7, 0.9)*dif;
        col.xyz *= lin;
        
        col.xyz *= col.xyz;
        
        col.a *= 0.35;
        col.rgb *= col.a;

        // fade samples at far field
        float fadeout = 1.-clamp((t/(DIST_MAX*.3)-.85)/.15,0.,1.); // .3 is an ugly fudge factor due to oversampling
            
        // integrate
        float thisDt = dt * sampleWt( wt, even); // blend in dts
        thisDt = sqrt(thisDt/5. )*5.; // hack to soften and brighten
        sum += thisDt * col * (1.0 - sum.a) * fadeout;

        // next sample
        nextT( t, dt, wt, even );
      }
     }
    }
    sum.xyz /= (0.001+sum.w);

    return clamp( sum, 0.0, 1.0 );
    }
    
    
    vec4 sum = vec4( 0.0 );
    
    
    float t = 0.1*(texture2D(iChannel1, fragCoord.xy/1024.0).r)/4.0;
    
    
    vec3 pos;
    float lighting;
    float su=2.0; 
    for( int i=0; i<1100/su*1.4; i++ )
    {
        if( sum.a > 0.9 ) break;
        pos = ro + t*rd;



    vec3 globalpos=pos;
    vec4 globalposscreen=(glmatrix*vec4(globalpos,1.0));


    float depth=globalposscreen.z/200.0;
    float x2=depth*(65536.0*256.0);
    float r2=floor(x2/(65536.0)); x2=x2-r2*(65536.0);
    float g2=floor(x2/(256.0)); x2=x2-g2*(256.0);
    float b2=floor(x2/(1.0)); x2=x2-b2*(1.0);
    float r1=float(r2/256.0);
    float g1=float(g2/256.0);
    float b1=float(b2/256.0);

    

    


    float currdepth=(r1*65536.0+g1*256.0+b1)/(65536.0*256.0)*200.0;
    vec2 coos=gl_FragCoord.xy;
    float xc=coos.x/(1920.0/clscale);
    float yc=coos.y/(1080.0/clscale);
    vec4 f=texture2D(depthMap,vec2(xc,yc));
    float imagedepth=(f.r*65536.0+f.g*256.0+f.b)/(65536.0*256.0)*200.0;

    if (imagedepth<currdepth) col=vec4(0,0,0,0); else{
    
    
    vec4 globalposlightmap=(fireLightProjectionMatrix*vec4(globalpos,1.0));
    vec2 coo_=globalposlightmap.xy/globalposlightmap.w;

    float rdepth=texture2D(shadowMap, coo_).r;
    float gdepth=texture2D(shadowMap, coo_).g;
    float bdepth=texture2D(shadowMap, coo_).b;
    float shadowmapdepth=(rdepth*256.0f*256.0f+gdepth*256.0f+bdepth)/65536.0f;
    float biasx = 0.0012*0.8;
    float actualdepth=globalposlightmap.z/200.0-biasx;
    float lightdepth=shadowmapdepth;
        
        
            if (lightdepth<actualdepth) col.rgb=vec3(0.0,0.0,0.1);
            else {
                col = map_cloud2( pos.xyz )/1.2;

		        //vec4 col = map( pos );
		        //float dif =  clamp((col.w - map(pos+0.3*sundir).w)/0.6, 0.0, 1.0 );
                if (cloudtype==0){
                    vec3 sundir = vec3(-1.0/5.0,1.0/5.0,0.0);
                    float dif =  clamp((col.w - map_cloud2(pos+0.3*sundir).w)/0.6, 0.0, 1.0 );
                    //vec3 brdf = vec3(0.65,0.68,0.7)*1.35 + 0.45*vec3(0.7, 0.5, 0.3)*dif;
                    vec3 brdf=dif;
                    //if (testvalue<=1.0)
		            col.xyz *= brdf;
                }

                float softcube=cloudshape(pos.xyz/0.2*1.12); // use this value to animate
                if (softcube>0.001) col=vec4(softcube)*10.0*10.0*1.75;
            }
        }
        
        

        
        
        col*=0.005;
        
        
        
        sum = sum + col*(1.0 - sum.a);
        t += 0.002*su;// *1.5;
    }
    

    //vec2 res=castRay(ro,rd);
    //if (res.y>0) sum=vec4(1,1,1,1);
    
    /*
    if (cloudtype==1){
        vec2 uf=vec2(pos.x,pos.z);

        float budz=2.2/1.4;
        float r=texture2D(iChannel1,uf).r*budz;
        float g=texture2D(iChannel1,uf).g*budz;
        float b=texture2D(iChannel1,uf).b*budz;
        col =vec4(r,g,b,sum.a);
        sum=col;
    }
    */

    return sum;

    vec3 cloudcol=vec3(sum.r);
    
    
    col=vec4(cloudcol,sum.a);

    
    
    
    return col.rgba;
}

mat3 setCamera( in vec3 ro, in vec3 ta, float cr )
{

    vec3 cw = normalize(ta-ro);

    
    vec3 cp = upvector;
    

    vec3 cu = normalize( cross(cw,cp) );
    vec3 cv = normalize( cross(cu,cw) );
    return mat3( cu, cv, cw );
}


void main()
{
    
//    cloudtype=0;

    vec2 iResolution = vec2(1920/clscale,1080/clscale);

    vec2 fragCoord=gl_FragCoord;
    vec2 uv = fragCoord/iResolution.xy;
	p = uv*2.0-1.0;
	p.x*=(iResolution.x/iResolution.y);
	vec4 col = vec4(0.05);

    vec3 ro = vec3(0.0,0.0,-1.0);
    vec3 rd = normalize(vec3(p,0.0)-ro);

    
    
    
    

    vec3 rp = ro;
    



















    const float fl = 2.5; 
    ro=rayorigin;
    vec3 ta=raydirection;
    
    
    mat3 ca = setCamera( ro, ta, 0.0 );
    

    float fov_=fov;
    rd = ca * normalize( vec3(p.x,p.y,fov_ ) );


    
    col=render(ro,rd,fragCoord);
    float powf=0.75;
    col.r=pow(col.r,powf);
    col.g=pow(col.g,powf);
    col.b=pow(col.b,powf);
    
	
    gl_FragColor = col;
    
}
