/*originals https://www.shadertoy.com/view/4d3SzX https://www.shadertoy.com/view/lslyRn https://www.shadertoy.com/view/wslcWN*/
#define iterations 17
#define formuparam 0.53

#define volsteps 20
#define stepsize 0.1

#define zoom   0.800
#define tile   0.850
#define speed  0.000

#define brightness 0.0015
#define darkmatter 0.300
#define distfading 0.730
#define saturation 0.850
vec2 computeUV( vec2 uv, float k, float kcube ){

    vec2 t = uv - .5;
    float r2 = t.x * t.x + t.y * t.y;
	float f = 0.;

    if( kcube == 0.0){
        f = 1. + r2 * k;
    }else{
        f = 1. + r2 * ( k + kcube * sqrt( r2 ) );
    }

    vec2 nUv = f * t + .5;
    nUv.y = 1. - nUv.y;

    return nUv;

}


void mainVR( out vec4 fragColor, in vec2 fragCoord, in vec3 ro, in vec3 rd )
{
	//get coords and direction
	vec3 dir=rd;
	vec3 from=ro;

	//volumetric rendering
	float s=0.1,fade=1.;
	vec3 v=vec3(0.);
	for (int r=0; r<volsteps; r++) {
		vec3 p=from+s*dir*.5;
		p = abs(vec3(tile)-mod(p,vec3(tile*2.))); // tiling fold
		float pa,a=pa=0.;
		for (int i=0; i<iterations; i++) {
			p=abs(p)/dot(p,p)-formuparam; // the magic formula
			a+=abs(length(p)-pa); // absolute sum of average change
			pa=length(p);
		}

		a*=a*a;
		if (r>6) fade*=1.1; // dark matter, don't render near
		//v+=vec3(dm,dm*.5,0.);
		v+=fade;
		v+=vec3(s,s*s,s*s*s*s)*a*brightness*fade; // coloring based on distance
		fade*=distfading; // distance fading
		s+=stepsize;
	}
	v=mix(vec3(length(v)),v,saturation); //color adjust
	fragColor = vec4(v*.03,1.);
}


vec2 GetOffsetFromCenter(vec2 screenCoords, vec2 screenSize)
{
    vec2 halfScreenSize = screenSize / 2.0;

	return (screenCoords.xy - halfScreenSize) / min(halfScreenSize.x, halfScreenSize.y);
}


float EffectDuration = 1.0;
float EffectFadeInTimeFactor = 0.5;
float EffectWidth = 0.4;
float EffectMaxTexelOffset = 20.0;

vec2 GetDistortionTexelOffset(vec2 offsetDirection, float offsetDistance, float time)
{
    float progress = mod(time, EffectDuration) / EffectDuration;

    float halfWidth = EffectWidth / 2.0;
    float lower = 1.0 - smoothstep(progress - halfWidth, progress, offsetDistance);
    float upper = smoothstep(progress, progress + halfWidth, offsetDistance);

    float band = 1.0 - (upper + lower);


    float strength = 1.0 - progress;
    float fadeStrength = smoothstep(0.0, EffectFadeInTimeFactor, progress);

    float distortion = band * strength * fadeStrength;


    return distortion * offsetDirection * EffectMaxTexelOffset;
}


vec3 GetTextureOffset(vec2 coords, vec2 textureSize, vec2 texelOffset)
{
    vec2 texelSize = 1.0 / textureSize;
    vec2 offsetCoords = coords + texelSize * texelOffset;

    vec2 halfTexelSize = texelSize / 2.0;
    vec2 clampedOffsetCoords = clamp(offsetCoords, halfTexelSize, 1.0 - halfTexelSize);

    return texture(iChannel0, clampedOffsetCoords).rgb;
}

mat2 rotationMatrix(float angle)
{
angle *= 3.14 / 180.0;
    float s=sin(angle), c=cos(angle);
    return mat2( c, s, -s, c );
}
vec2 rotate(vec2 v, float angle) {
    float s = sin(angle);
    float c = cos(angle);
    return vec2(v.x * c - v.y * s, v.x * s + v.y * c);
}
float cheap_star(vec2 uv, float anim)
{
    uv = abs(uv);
    vec2 pos = min(uv.xy/uv.yx, anim);
    float p = (2.0 - pos.x - pos.y);
    return (2.0+p*(p*p-1.5)) / (uv.x+uv.y);
}

#define NORM_FOCUS (1)

float random(float x)
{
    return fract(sin(x) * 10000.);
}

float noise(vec2 p)
{
    return random(p.x + p.y * 10000.);
}

vec2 sw(vec2 p) { return vec2(floor(p.x), floor(p.y)); }
vec2 se(vec2 p) { return vec2(ceil(p.x), floor(p.y)); }
vec2 nw(vec2 p) { return vec2(floor(p.x), ceil(p.y)); }
vec2 ne(vec2 p) { return vec2(ceil(p.x), ceil(p.y)); }

float smoothNoise(vec2 p)
{
    vec2 interp = smoothstep(0., 1., fract(p));
    float s = mix(noise(sw(p)), noise(se(p)), interp.x);
    float n = mix(noise(nw(p)), noise(ne(p)), interp.x);
    return mix(s, n, interp.y);
}

float fractalNoise(vec2 p)
{
    float x = 0.;
    x += smoothNoise(p      );
    x += smoothNoise(p * 2. ) / 2.;
    x += smoothNoise(p * 4. ) / 4.;
    x += smoothNoise(p * 8. ) / 8.;
    x += smoothNoise(p * 16.) / 16.;
    x /= 1. + 1./2. + 1./4. + 1./8. + 1./16.;
    return x;
}

float movingNoise(vec2 p)
{
    float x = fractalNoise(p + iTime);
    float y = fractalNoise(p - iTime);
    return fractalNoise(p + vec2(x, y));
}

float nestedNoise(vec2 p)
{
    float x = movingNoise(p);
    float y = movingNoise(p + 100.);
    return movingNoise(p + vec2(x, y));
}
#define SPARKS 30
#define FIREWORKS 8.
#define BASE_PAUSE FIREWORKS / 30.
#define PI 3.14
#define PI2 6.28

float n21(vec2 n) {
    return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}

vec2 randomSpark(float noise) {
    vec2 v0 = vec2((noise - .5) * 13., (fract(noise * 123.) - .5) * 15.);
    return v0;
}

vec2 circularSpark(float i, float noiseId, float noiseSpark) {
    noiseId = fract(noiseId * 7897654.45);
    float a = (PI2 / float(SPARKS)) * i;
    float speed2 = 10.*clamp(noiseId, .7, 1.);
    float x = sin(a + iTime*((noiseId-.5)*3.));
    float y = cos(a + iTime*(fract(noiseId*4567.332) - .5)*2.);
    vec2 v0 = vec2(x, y) * speed2;
    return v0;
}


vec2 rocket(vec2 start, float t) {
    float y = t;
    float x = sin(y*10.+cos(t*3.))*.1;
    vec2 p = start + vec2(x, y * 8.);
    return p;
}

vec3 firework(vec2 uv, float index, float pauseTime) {
    vec3 col = vec3(0.);


    float timeScale = 1.;
    vec2 gravity = vec2(0., -9.8);

    float explodeTime = .9;
    float rocketTime = 1.1;
    float episodeTime = rocketTime + explodeTime + pauseTime;

    float ratio = iResolution.x / iResolution.y;

    float timeScaled = (iTime - pauseTime) / timeScale;

    float id = floor(timeScaled / episodeTime);
    float et = mod(timeScaled, episodeTime);

    float noiseId = n21(vec2(id+1., index+1.));

    float scale = clamp(fract(noiseId*567.53)*30., 10., 30.);
    uv *= scale;

    rocketTime -= (fract(noiseId*1234.543) * .5);

    vec2 pRocket = rocket(vec2(0. + ((noiseId - .5)*scale*ratio), 0. - scale/2.), clamp(et, 0., rocketTime));

    if (et < rocketTime) {
        float rd = length(uv - pRocket);
        col += pow(.05/rd , 1.9) * vec3(0.9, .3, .0);
    }


    if (et > rocketTime && et < (rocketTime + explodeTime)) {
        float burst = sign(fract(noiseId*44432.22) - .6);
        for(int i = 0 ; i < SPARKS ; i++) {
                vec2 center = pRocket;
                float fi = float(i);
                float noiseSpark = fract(n21(vec2(id*10.+index*20., float(i+1))) * 332.44);
                float t = et - rocketTime;
                vec2 v0;

                if (fract(noiseId*3532.33) > .5) {
                    v0 = randomSpark(noiseSpark);
                    t -= noiseSpark * (fract(noiseId*543.) * .2);
                } else {
                    v0 = circularSpark(fi, noiseId, noiseSpark);

                    if ( (fract(noiseId*973.22) - .5) > 0.) {
                        float re = mod(fi, 4. + 10. * noiseId);
                        t -= floor(re/2.) * burst * .1;
                    } else {
                        t -= mod(fi, 2.) == 0. ? 0. : burst * .5*clamp(noiseId, .3, 1.);
                    }
                }

                vec2 s = v0*t + (gravity * t * t) / 2.;

                vec2 p = center + s;

                float d = length(uv - p);

                if (t > 0.) {
                    float fade = clamp((1. - t/explodeTime), 0., 1.);
                    vec3 sparkColor = vec3(noiseId*.9, .5*fract(noiseId *456.33), .5*fract(noiseId *1456.33));
                    vec3 c = (.05 / d) * sparkColor;
                    col += c * fade;
                }
            }
    }


    return col;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	//get coords and direction
	vec2 uv=fragCoord.xy/iResolution.xy-0.5;
	    float k = 1.0 * sin( iTime * .9 );
    float kcube = 1.5 * sin( iTime );

    vec2 screenCoords = fragCoord.xy;
    vec2 screenSize = iResolution.xy;
     float time2 = iTime*0.1;
    float offset = .01 * sin( iTime * .05 );
   vec2 offsetFromCenter = GetOffsetFromCenter(screenCoords, screenSize);
    vec2 offsetDirection = normalize(-offsetFromCenter);
    float offsetDistance = length(offsetFromCenter);
  float t = iTime * .1 + ((.25 + .05 * sin(iTime * 1.1))/(length(uv.xy) + .012)) * 2.2;
float si = sin(t);
float co = cos(t);
mat2 ma = mat2(co, si, -si, co);
     vec3 col = vec3(0.);

    for (float i = 0. ; i < FIREWORKS ; i += 1.) {
        col += firework(uv*ma, i + 1., (i * BASE_PAUSE));
    }

    vec2 offset2 = GetDistortionTexelOffset(offsetDirection, offsetDistance, time2);
  uv.x *= iResolution.x / iResolution.y;

        float n = nestedNoise(uv * 2.) * 1.0;
    float lerp = (sin(iTime * 0.05) + 1.1) / 2.0;
    float offset3 = mix(1.0, 3.2, lerp);


    	vec2 offsetVector = normalize(vec2(0.5, 0.5) - uv) * (n * offset3);





uv.xy*=offsetVector*ma;

	vec3 dir=vec3(uv,1.);
	float time=iTime*speed+.25;

  uv.x *= iResolution.x / iResolution.y;

    float dist = sqrt(abs(1.0-dot(uv,uv)));

    //vec3 col = vec3(dist);
    vec3 col2 = texture(iChannel0, iTime/10.0 + dir.xy/dist).rgb*(0.3 + dist*0.7);



    uv *= 2.0 * ( cos(iTime * 2.0) -2.5);

    // anim between 0.9 - 1.1
    float anim = cos(iTime * 2.0) * 0.1 + 1.0;

   dir.xy*=ma;
    vec2 coords = (fragCoord.xy / screenSize);
    coords.y = 1.0 - coords.y;


	vec3 from=vec3(1.,.5,0.5);
	from+=vec3(time*2.,time,-2.);



	mainVR(fragColor, fragCoord, from, dir);
      fragColor*= vec4(cheap_star(uv,anim) * vec3(0.55,0.5,0.55), 1.0);
      fragColor+= vec4(col,1.);


}
