// Shoutout to easings.net

#define pi 3.1415
#define tr start,dur,x
#define par float start, float dur, float p, float x
// writing start,dur,x everywhere gets annoying
#define xs (x-start)
// same thing with par, just to make things less clutered


// reminder for whenever you touch eases here ever again
// 1 - stop being dumb
// 2 - no the ease function does not have to do anything with the timing
// 3 - when you add x please PLEASE add it as (x - start) (it's "xs" now)
// 4 - stop being a silly little bean

float c(float x){
    return max(0.0, min(1.0, (x - 0.0) / (1.0 - 0.0)));
}

float o(float x){
    return clamp(x, -1.0, 0.0);
}

float o2(float x){
    return clamp(x, 1.0, 0.0);
}

float ease(float easing, float start, float dur, float x){
    start += 1.0;
    if (x >= start - 1.0 && x <= start){
        return easing;
    }else return o(xs) + 1.0;
}

float ease2(float easing, float start, float dur, float x){
    start += 1.0;
    if (x >= start - 1.0 && x <= start){
        return easing;
    }else return o2(xs);
}

float linear(par){
    start /= dur; x /= dur;
    return p*ease(xs,tr);
}

float inSine(par){
    start /= dur; x /= dur;
    return p*ease(1.0 - cos((xs * pi) / 2.0),tr);
}

float outSine(par){
    start /= dur; x /= dur;
    return p*ease(sin((xs * pi) / 2.0),tr);
}

// I am pretty sure doing inEase + outEase would give the same result
// but whatev, I've already wrote everything out

float inOutSine(par){
    start /= dur; x /= dur;
    return p*ease(-(cos(pi * xs) - 1.0) / 2.0, tr);
}

float outInSine(par){
    start /= dur; x /= dur;
    return p*outSine(start, 0.5, 0.5, x) + p*inSine(start + 0.5, 0.5, 0.5, x);
}

float inQuad(par){
    start /= dur; x /= dur;
    return p*ease(pow(xs, 2.0),tr);
}

float outQuad(par){
    start /= dur; x /= dur;
    return p*ease(1.0 - pow(1.0 - xs, 2.0),tr);
}

float inOutQuad(par){
    start /= dur; x /= dur;
    return x - (start - 1.0) < 1.5
    ? p*ease(2.0 * (xs * xs),tr)
    : p*ease(1.0 - pow(-2.0 * xs + 2.0, 2.0) / 2.0,tr);
}

float outInQuad(par){
    start /= dur; x /= dur;
    return p*outQuad(start, 0.5, 0.5, x) + p*inQuad(start + 0.5, 0.5, 0.5, x);
}


float inCubic(par){
    start /= dur; x /= dur;
    return p*ease(pow(xs, 3.0),tr);
}

float outCubic(par){
    start /= dur; x /= dur;
    return p*ease(1.0 - pow( 1.0 - xs, 3.0),tr);
}

float inOutCubic(par){
    start /= dur; x /= dur;
    return x - (start - 1.0) < 1.5
    ? p*ease(4.0 * xs * xs * xs, tr)
    : p*ease(1.0 - pow(-2.0 * xs + 2.0, 3.0) / 2.0, tr);
}

float outInCubic(par){
    start /= dur; x /= dur;
    return p*outCubic(start, 0.5, 0.5, x) + p*inCubic(start+0.5, 0.5, 0.5, x);
}

float inQuart(par){
    start /= dur; x /= dur;
    return p*ease(pow(xs, 4.0),tr);
}

float outQuart(par){
    start /= dur; x /= dur;
    return p*ease(1.0 - pow(1.0 - xs, 4.0), tr);
}

float inOutQuart(par){
    start /= dur; x /= dur;
    return x - (start - 1.0) < 1.5
    ? p*ease(8.0 * pow(xs, 4.0), tr)
    : p*ease(1.0 - pow(-2.0 * xs + 2.0, 4.0) / 2.0, tr);
}

float outInQuart(par){
    start /= dur; x /= dur;
    return p*outQuart(start, 0.5, 0.5, x) + p*inQuart(start + 0.5, 0.5, 0.5, x);
}

float inQuint(par){
    start /= dur; x /= dur;
    return p*ease(pow(xs, 5.0),tr);
}

float outQuint(par){
    start /= dur; x /= dur;
    return p*ease(1.0 - pow(1.0 - xs, 5.0), tr);
}

float inOutQuint(par){
    start /= dur; x /= dur;
    return xs < 0.5
    ? p*ease(16.0 * pow(xs, 5.0), tr)
    : p*ease(1.0 - pow(-2.0 * xs + 2.0, 5.0) / 2.0, tr);
}

float outInQuint(par){
    start /= dur; x /= dur;
    return p*outQuint(start, 0.5, 0.5, x) + p*inQuint(start + 0.5, 0.5, 0.5, x);
}

float inExpo(par){
    start /= dur; x /= dur;
    return p*ease(pow(2.0, 10.0 * xs - 10.0),tr);
}

float outExpo(par){
    start /= dur; x /= dur;
    return p*ease(1.0 - pow(2.0, -10.0 * xs), tr);
}

float inOutExpo(par){
    start /= dur; x /= dur;
    return x - (start - 1.0) < 1.5
    ? p*ease(pow(2.0, 20.0 * xs - 10.0) / 2.0, tr)
    : p*ease((2.0 - pow(2.0, -20.0 * xs + 10.0)) / 2.0, tr);
}

float outInExpo(par){
    start /= dur; x /= dur;
    return p*outExpo(start, 0.5, 0.5, x) + p*inExpo(start + 0.5, 0.5, 0.5, x);
}

float inCirc(par){
    start /= dur; x /= dur;
    return p*ease(c(1.0 - sqrt(1.0 - pow(xs, 2.0))), tr);
}

float outCirc(par){
    start /= dur; x /= dur;
    return p*ease(c(sqrt(1.0 - pow(xs - 1.0, 2.0))), tr);
}

float inOutCirc(par){
    start /= dur; x /= dur;
    return x - (start - 1.0) < 1.5
    ? p*ease((1.0 - sqrt(1.0 - pow(2.0 * xs * 2.0, 1.0))) / 2.0, tr)
    : p*ease((sqrt(1.0 - pow(-2.0 * xs * 2.0 + 2.0, 2.0)) + 1.0) / 2.0, tr);
}

float outInCirc(par){
    start /= dur; x /= dur;
    return p*outCirc(start, 0.5, 0.5, x) + p*inCirc(start + 0.5, 0.5, 0.5, x);
}

float inBack(par, float c1){
    start /= dur; x /= dur;
    if (c1 < 0.0) c1 = 1.70158;
    float c3 = c1 + 1.0;

    return p*ease(c3 * pow(xs, 3.0) - c1 * pow(xs, 2.0), tr);
}

float outBack(par, float c1){
    start /= dur; x /= dur;
    if (c1 < .0) c1 = 1.70158;
    float c2 = c1 + 1.;

    return p*ease(1. + c2 * pow(xs - 1., 3.) + c1 * pow(xs - 1.0, 2.0), tr);
}

float inOutBack(par){
    start /= dur; x /= dur;
    float c1 = 1.70158;
    float c2 = c1 * 1.525;

    return x - (start - 1.0) < 1.5
    ? p*ease((pow(2.0 * xs, 2.0) * ((c2 + 1.0) * 2.0 * xs - c2)) / 2.0, tr)
    : p*ease((pow(2.0 * xs - 2.0, 2.0) * ((c2 + 1.0) * (xs * 2.0 - 2.0) + c2) + 2.0) / 2., tr);
}

float outInBack(par, float c1){
    start /= dur; x /= dur;
    return p*outBack(start, 0.5, 0.5, x, c1) + p*inBack(start + 0.5, 0.5, 0.5, x, c1);
}

float inElastic(par){
    start /= dur; x /= dur;
    float c = (2.0 * pi) / 3.0;

    return p*ease(-pow(2.0, 10.0 * xs - 10.0) * sin((xs * 10.0 - 10.75) * c), tr);
}

float outElastic(par){
    start /= dur; x /= dur;
    float c = (2.0 * pi) / 3.0;

    return p*ease(pow(2.0, -10.0 * xs) * sin((xs * 10.0 - 0.75) * c) + 1.0, tr);
}

float inOutElastic(par){
    start /= dur; x /= dur;
    float c = (2. * pi) / 4.5;

    return xs < 0.5
      ? p*ease(-(pow(2.0, 20.0 * xs - 10.0) * sin((20.0 * xs - 11.125) * c)) / 2.0, tr)
      : p*ease((pow(2.0, -20.0 * xs + 10.0) * sin((20.0 * xs - 11.125) * c)) / 2.0 + 1.0, tr);
}

float outInElastic(par){
    start /= dur; x /= dur;
    return p*outElastic(start, 0.5, 0.5, x) + p*inElastic(start + 0.5, 0.5, 0.5, x);
}

// I can't figure this out,,,
// (^lie^) I FIGURE TI OUTBJkfnlajskbf
float outBounce(par){
    start /= dur; x /= dur;
    float n = 7.5625;
    float d = 2.75;

	if (xs < 1.0 / d){
		return p*ease(n * xs * xs, tr);
	}else if (xs < 2.0 / d){
		x = x - 1.5 / d;
		return p*(n * xs * xs + 0.75);
	}else if (xs < 2.5 / d){
		x = x - 2.25 / d;
		return p*(n * xs * xs + 0.9375);
	}else{
		x = x - 2.625 / d;
		return p*min(n * xs * xs + 0.984375, 1.);
	}
}

float inBounce(par){
    return p*(1.0-outBounce(start, 1.0, 1.0, 1.0-xs));
}

float inOutBounce(par){
    start /= dur; x /= dur;
    return xs < 0.5
    ? p*(1.0 - outBounce(start, 1.0, 1.0, (1.0+start) - 2.0 * xs)) / 2.0
    : p*(1.0 + outBounce(start, 1.0, 1.0, 2.0 * xs - (1.0-start))) / 2.0;
}


// mirin eases

float bounce(par){
    start /= dur; x /= dur;
    return p*ease2(4.0 * xs * (1.0 - xs), tr);
}

float tri(par){
    start /= dur; x /= dur;
    return p*ease2(1.0 - abs(2.0 * xs - 1.0), tr);
}

float bell(par){
    start /= dur; x /= dur;
    return p*inOutQuint(start, 1.0, 1.0, tri(start, 1.0, 1.0, x)+start);
}

float pop(par){
    start /= dur; x /= dur;
    return p*ease2(3.5 * (1.0 - xs) * (1.0 - xs) * sqrt(xs), tr);
}

float tap(par){
    start /= dur; x /= dur;
    return p*ease2(3.5 * xs * xs * sqrt(1.0 - xs), tr);
}

float pulse(par){
    start /= dur; x /= dur;
    return p*tap(start, 0.5, 0.5, x)-pop(start+0.5, 0.5, 0.5, x);
}

float spike(par){
    start /= dur; x /= dur;
    return p*ease2(exp(-10.0 * abs(2.0 * xs - 1.0)), tr);
}

float invert(par){
    start /= dur; x /= dur;
    return p*ease2(xs * xs * (1.0 - xs) * (1.0 - xs) / (0.5 - xs), tr);
}

float flip(float ease){
    return 1.0-ease;
}
#define s smoothstep
#define pi 3.1415
#define res iResolution.xy
#define t iTime
#define rot(a) mat2( cos(a),-sin(a),sin(a),cos(a) )

vec3 tc = vec3(0.345, 0.294, 0.373);
vec3 bc = vec3(0.447, 0.302, 0.424);


float s2(float uv, float a){
    return s(-a, -a+0.005, -uv);
}


vec2 rotate(vec2 v, vec2 o, float a) {
    float s = sin(a);
    float c = cos(a);
    mat2 m = mat2(c, -s, s, c);
    return m * (v-o) + o;
}
// shamelessly yoinked from https://shadertoy.com/view/MlsfRj

vec2 TransformPlane(vec2 uv, vec2 center, float XRot, float YRot) {
    // First Rotate around Y axis
    vec2 RayDirection =  vec2(uv.x, 0.0);
    vec2 A1 = vec2(0.0, -1.0);
    vec2 B1 = RayDirection - A1;
    vec2 C1 = rotate(vec2(-1.0, 0.0), vec2(center.x, 0.0), YRot);
    vec2 D1 = rotate(vec2( 1.0, 0.0), vec2(center.x, 0.0), YRot) - C1;
    // calculate intersection point
    float u = ( (C1.y + 1.0) * D1.x - C1.x * D1.y ) / (D1.x*B1.y-D1.y*B1.x);
    // position on the plane:
    float sx = u * B1.x;
 	float sy = u * uv.y;
    // Now Rotate around X axis
    RayDirection = vec2(sy, .0);
    vec2 B2 = RayDirection - A1;
    vec2 C2 = rotate(vec2(-1.0, 0.00), vec2(center.y, 0.0), XRot);
    vec2 D2 = rotate(vec2( 1.0, 0.0), vec2(center.y, 0.0), XRot) - C2;
    // calculate intersection point
    float v = ( (C2.y + 1.0) * D2.x - C2.x * D2.y ) / (D2.x*B2.y-D2.y*B2.x);
    // final position on the plane:
    return vec2(v * sx, v * B2.x );

}

//uv, pos, arms size, size, bloom size, rotation
float x(vec2 uv, vec2 p, vec2 sz, float si, float bl, float bs, float r){
    uv -= p; uv /= si; uv *= rot(pi*r);
    vec2 uv2 = uv;
    uv.x *= si+sz.y; uv.y /= sz.y;
    uv *= rot(pi*0.25);
    uv2.x /= sz.x; uv2.y *= si+sz.x; uv2 *= rot(-pi*0.25);

    return min((0.0+bs)/(
    (1.0+bs)-s(0.1+bl, 0.1, abs(uv.x))*s(0.1+bl, 0.1, abs(uv.y))
    )+(0.0+bs)/(
    (1.0+bs)-s(0.1+bl, 0.1, abs(uv2.x))*s(0.1+bl, 0.1, abs(uv2.y))
    ),1.0);
}

float box(vec2 uv, float si, float r){
    uv *= rot(pi*r);
    float b = 0.05/((1.0-s(si+0.02, si, abs(uv.x))*s(si+0.02, si, abs(uv.y))))
    ;

    return min(s(.0, 0.5, b), 1.0);
}
float box2(vec2 uv, float si, float r){
    uv *= rot(pi*r);
    float b = 0.05/((s(si+0.02, si, abs(uv.x))*s(si+0.02, si, abs(uv.y))))
    ;

    return min(s(0.0, 0.5, b), 1.0);
}
float boxs(vec2 uv, float si, float r){
    uv *= rot(pi*r);
    float b = s2(abs(uv.x), si)*s2(abs(uv.y), si);

    return b;
}

float circ(vec2 uv, vec2 p, float si){
    uv -= p; uv /= si;
    return s(0.1, 0.09, length(uv))*s(0.07, 0.08, length(uv))+s(0.06, 0.05, length(uv));
}

float rand(float f){
    return fract(sin(f*5321.53126)*351.3637);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 xo = (fragCoord-0.5*res)/res.xy;
    vec2 uv = (fragCoord-0.5*res)/res.y;
    vec2 uv3 = uv;
    vec2 uv4 = uv;
    uv = TransformPlane(uv, vec2(0.0, 0.0), -pi*0.05, 0.0);
    vec2 uv2 = uv;



    vec3 col = vec3(0.0);
    float overlay = s(1.0, 0.2, length(xo));

    float st;

    float st1 = mod(t, 2.);

    float br = outCubic(0.0, 1.0, 0.25, st1);

    br += outCubic(1.0, 1.0, 0.25, st1);


    float st2 = mod(t, 2.0);
    float st3 = mod(t, 3.0);
    float bp1 = inOutExpo(0.0125, 3.0, 1.0, st3);
    float bp2 = inOutExpo(0.0, 3.0, 1.0, st3);
    float bb1 = inOutExpo(0.03, 2.0, 1.0, st2);
    float bb2 = inOutExpo(0.0, 2.0, 1.0, st2);



    float cro = s(0.6, 0.595, length(uv3))*s(0.59, 0.595, length(uv3));

    float bo = clamp(box(uv3, 0.400, br)*
               box2(uv3, 0.38, br), 0.0, 1.0);


    bo = s(0.0, 1.0, bo);

    for (float i=1.0; i < 20.0; i++){
        st += clamp(x(uv,
        vec2((rand(i*5.2)-0.5)*2.0, (rand(i*3.9)-0.5)+sin(2.0*t+i)*0.01),
        vec2(1.25+sin(2.0*t+sin(i*234.12574))*0.25,
        2.0+cos(2.0*t+sin(i*234.12574))*0.25),
        0.15+sin(i)*0.075,
        0.75,
        0.001,
        0.0), 0.0, 1.0-(bo));
        st = min(st, 1.0);
    }


    float po11 = outExpo(0.5, 1.0, 0.2, st3);
    float po12 = outCubic(0.5, 1.0, 0.2, st3);
    float poof1 = flip(linear(1.0+0.5, 0.01, 1.0, st3));



    float st4 = mod(t, 4.0);
    float po21 = outExpo(0.75, 1.0, 0.25, st4);
    float po22 = outCubic(0.75, 1.0, 0.25, st4);
    float po31 = outExpo(0.75, 1.0, 0.15, st4);
    float po32 = outCubic(0.75, 1.0, 0.15, st4);
    float poof2 = flip(linear(0.7+0.75, 0.0001, 1.0, st4));
    float poof13 = linear(0.625+1.5, 0.0001, 10.0, st2);



    uv4.y *= 0.5;

    vec3 dip;

    dip.x += outExpo(1.5, 0.75, 0.075+0.05, st2);
    dip.y += outCubic(1.5, 0.75, 0.075*2.+0.025, st2);
    dip.z -= inOutCubic(0.0, 2.0, 0.015, st2);
    dip.z += outExpo(1.5, 1.0, 0.015, st2);



    float di = box(uv4, 0.075+dip.z, 0.25);
    uv4 += poof13;
    di += box(uv4, 0.05+dip.x, 0.25)*box2(uv4, dip.y, 0.25);
    di = min(di, 1.0);

    float pop1 = s(0.0, 1.0,
          clamp(box(uv-vec2(-0.5, 0.45), po11, 0.0)*
               box2(uv-vec2(-0.5, 0.45), po12, 0.0)
               , 0.0, 1.0-(cro+st+bo)))*poof1;

    float pop21 = s(0.0, 1.0,
          clamp(box(uv-vec2(0.6, 0.0), po21, 0.0)*
               box2(uv-vec2(0.6, 0.0), po22, 0.0)
               , 0.0, 1.0-(cro+st+bo)))*poof2;
    float pop22 = s(0.0, 1.0,
          clamp(box(uv-vec2(0.6, 0.0), po31, 0.0)*
               box2(uv-vec2(0.6, 0.0), po32, 0.0)
               , 0.0, 1.0-(cro+st+bo)))*poof2;

    float st5 = mod(t, 3.35);
    float po41 = outExpo(0.25, 1.0, 0.25+0.2, st5);
    float po42 = outQuart(0.25, 1.0, 0.25+0.175, st5);
    float poof3 = flip(outBounce(1.0, 0.3, 1.0, st5));

    float pop3 = s(0.0, 1.0,
          clamp(box(uv-vec2(-0.65, -0.4), po41, 0.0)*
               box2(uv-vec2(-0.65, -0.4), po42, 0.0)
               , 0.0, 1.0-(cro+st+bo)))*poof3;

    float st6 = mod(t, 3.66);
    float po51 = outExpo(1.75, 1.0, 0.25+0.2, st6);
    float po52 = outQuart(1.75, 1.0, 0.25+0.175, st6);
    float poof4 = flip(outBounce(1.0+1.5, 0.3, 1.0, st6));

    float pop4 = s(0.0, 1.0,
          clamp(box(uv-vec2(0.65, 0.65), po51, 0.0)*
               box2(uv-vec2(0.65, 0.65), po52, 0.0)
               , 0.0, 1.0-(cro+st+bo)))*poof4;


    //
    float bl2 = bo+st+cro+pop1+pop21+pop22+pop3+pop4+di;

    float bi1 = max(clamp(box(uv, 0.50, 0.25+bp1)*
               box2(uv, 0.48, 0.25+bp2), 0.0, 1.0-(bl2)), 0.0);
    float bi2 = clamp(box(uv, 0.70, 0.25+bb1)-
               box(uv, 0.68, 0.25+bb2), 0.0, 1.0-(bl2+bi1));

    st = min(st, 1.0);

    uv2.y += -cos(uv2.x)*0.2+0.2;

    //
    float bl1 = st+bo+bi1+bi2+cro+pop1+pop21+pop22+pop3+pop4+di;
    float bot = clamp(s2(uv2.y, 0.0), 0.0, 1.0-(bl1));
    float top = clamp(s2(-uv2.y, 0.0), 0.0, 1.0-(bl1));


    col += min(bot*bc*s(2.0, 0.0, length(uv))*bc*2.5, 1.0);
    col += min(top*tc*s(1.5, 0.0, length(uv))*tc*2.5, 1.0);
    col += st;
    col += bo*vec3(1.0, 1.0, 0.6);
    col += bi1*vec3(1.0, 0.5, 1.0);
    col += bi2*vec3(0.7, 1.0, 1.0);
    col += cro;
    col += pop1*vec3(1.0, 1.0, 0.6);
    col += pop21*vec3(1.0, 1.0, 0.6);
    col += pop22*vec3(1.0, 1.0, 0.6);
    col += pop3*vec3(1.0, 0.5, 1.0);
    col += pop4*vec3(1.0, 0.5, 1.0);
    col += di*vec3(0.7, 1.0, 1.0);




    col *= overlay;

    fragColor = vec4(col,1.0);
}
