#define PI 3.1415926
#define TAU 6.2831852
#define sTime 3.
#define sS 1.2
// for less performance device is true
#define smooth true
#define calcUnit 0

const float count = 7.;

float easeOutExpo (float t) {
    // for mac os API pow( x, y )
    // y was smoothly allowed
    return t == 1. ? 1. : 1. - pow( 2., -10. * t );
}

float getTimeline( float t ){
    float tl = ( t >= sTime ) ? ( t - sTime ) : 0.;

    return ( t >= ( sTime + 1. ) ) ? 1. : tl;
}

const mat2 m = mat2(-1.1, -.4, .3, 1.0);

mat2 rotation(float a) {
    float s = sin(a), c = cos(a);
    return mat2(c, s, -s, c);
}

float myNoise( in vec2 f ){
    f *= m;
    return ( cos( f.x + .18975 ) * sin( f.y + .494516 ) + .1615246 );
}


float fbm( in vec2 x, in float H )
{
    float t = 0.0;
    for( int i=0; i<7; i++ )
    {
        float f = pow( 2.0, float(i) );
        x *= rotation( float( i ) );
        float a = pow( f, -H );
        a = smoothstep( 0., .05, a );

        t += a*myNoise(f*x * rotation( float(i) ));

    }
    return t;
}

float deg2Rad( float deg ){
    // return deg * PI / 180.;
    return radians( deg );
}

float axies( vec3 p, float r, float h ){
    return max( length( p.xy ) - r, abs( p.z ) - h );
}

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

// iq
float sdHexPrism( vec3 p, vec2 h )
{
  const vec3 k = vec3(-0.8660254, 0.5, 0.57735);
  p = abs(p);
  p.xy -= 2.0*min(dot(k.xy, p.xy), 0.0)*k.xy;
  vec2 d = vec2(
       length(p.xy-vec2(clamp(p.x,-k.z*h.x,k.z*h.x), h.x))*sign(p.y-h.x),
       p.z-h.y );
  return min(max(d.x,d.y),0.0) + length(max(d,0.0));
}

float bud( vec3 p, vec3 trasf ){

    p.z += 1.6;

    // p.z += pow( dot( p.xz, p.xz ), .5 ) * .2;

    float a = dot( p.xy, p.xy );

    p.z -= pow( a, .35 );

    p.z -= cos( p.x ) * .2;
    p.z -= cos( p.y ) * .2;

    return sdEllipsoid( p, vec3( .05, .05, .15 ) );
}

float p2d( vec2 uv ){

    float ll = ( pow( uv.x + .35, 2. ) + pow( uv.y, 2. ) - .45 );
    float rr = ( pow( uv.x - .35, 2. ) + pow( uv.y, 2. ) - .45 );

    return smoothstep( .095, max( ll, rr ), 0.1 );
}

vec3 calcBg( vec2 uv ){
    vec3 c = vec3( 0. );

    for( float i = 0.; i < 20.; i++ ){
        float x = cos( i / 20. * TAU ) * .4 * ( i / 5. );
        float y = sin( i / 20. * TAU ) * .4 * ( i / 5. );

        vec2 v = uv * rotation( deg2Rad( ( 360. / 20. ) * i ) + ( cos( iTime * -.25 ) * i / 20. ) * .5 );

        v -= .5;
        v *= rotation( i / 20. );


        v *= i / 20.;

        v.x += cos( iTime * .25 ) * .3;
        v.y += sin( iTime * .25 ) * .3;


        //p = mix( p, i / 120., p2d( vec2( v.x + x, v.y + y ) ) );

        c = mix( c, i / 20. * vec3(.83, .3, .43), p2d( vec2( v.x + x, v.y + y ) ) ) * .7;
    }

    return c;
}

float petal( vec3 p, vec3 trasf, float h, float r, float rot, float i ){

    #if calcUnit == 0
    p.z -= .2;
    p.xz *= rotation( PI * ( -.15 - i * .13 ) * ( 1. - getTimeline( iTime * sS ) ) );
    p.z += .2;

    p.z += pow( p.x, 2.8 );

    #else

    p.z -= cos( p.x );
    p.z -= cos( p.y );
    p.z += 2.;

    #endif

    // p.z += pow( p.x, 2.8 );
    // p.z += pow( p.y, 2.8 );

    p += trasf;
    p.xy *= rotation( rot );


    //p.z += .1;
    //p.yz *= rotation( PI );

    //float d = max( length( pow( p.x, 1.6 - i * .05 ) + pow( p.y, 2.0 ) ) - r, abs( p.z ) - h );

    float ll = ( pow( p.x + .16, 2. ) + pow( p.y, 2. ) - r * 1.4 );
    float rr = ( pow( p.x - .16, 2. ) + pow( p.y, 2. ) - r * 1.4 );

    float d = max( max( ll, rr ), abs( p.z ) - h );

    p.y -= .25;
    p.yz *= rotation( PI * .5 );

    d = min( sdEllipsoid( p, vec3( .005 + ( 4. - i ) * .001, .005 + ( 4. - i ) * .001, .04 + ( 4. - i ) * .025 ) ), d );

    return d;
}


float addLayer( float d, vec3 pos, int lI ){
    vec3 p = pos;

    p.z += .8;
    p.z += float( lI ) * .1;

    p.xy *= rotation( float( lI ) / count * PI );

    for( float i = 0.; i < count; i++ ){

        vec3 v = vec3( 0.0, -0.0, -.3 );

        v.x += cos( ( i / count ) * TAU ) * (.6 - ( float( lI ) ) * .055);
        v.y += sin( ( i / count ) * TAU ) * (.6 - ( float( lI ) ) * .055);

        float n = petal( p, v, .01, .11 - float( lI ) * .015, deg2Rad( ( 360. / count ) * i ) + PI * .5, float( lI ) );
        d = min( d, n );
    }

    return d;
}

void repetition(inout vec2 p, float rep)
{

    float an = TAU/count;

    float fa = (atan(p.y,p.x)+an*0.5)/an;
    float ia = floor( fa );

    float sym = an*ia;
    vec2 r = mat2(cos(sym),-sin(sym),
                  sin(sym), cos(sym))*p;

    p = r;
}

float allPetals( float d, vec3 pos, int lI ){
    vec3 p = pos;

    float i = float( lI );

    p.xy *= rotation( PI * ( i - 1. ) + ( 1. - easeOutExpo( getTimeline( iTime * sS - max( 0., i / 4. * .8 ) ) ) ) * 4. );

    p.z += .6;
    p.z += float( lI ) * .1;

    repetition( p.xy, 7. );
    //     float n = petal( p, vec3( -0.58 + ( i * .055 ), 0.0, -.12 ), .01, .11 - i * .015, PI * -.5, i );

    float n = petal( p, vec3( -0.6 + ( i * .07 ), 0.0, -.12 ), .01, .11 - i * .015, PI * -.5, i );
    return n;
}

float eachPetal( vec3 p ){
    float d = 5.;
    vec3 pos = p;


    #if calcUnit==1

    d = min( d, addLayer(d, p, 1) );
    d = min( d, addLayer(d, p, 2) );
    d = min( d, addLayer(d, p, 3) );
    d = min( d, addLayer(d, p, 4) );

    #else

    d = min( d, allPetals(d, p, 1) );
    d = min( d, allPetals(d, p, 2) );
    d = min( d, allPetals(d, p, 3) );
    d = min( d, allPetals(d, p, 4) );

    p = pos;
    p.yz *= rotation( .5 * PI );

    #endif

    // d += pow( d, .999 ) * .001;

    float n = fbm( vec2( fbm( p.xz, .1 ) ), .1 );


    return d;
}

float buud( vec3 p ){
    float d = 5.;
    p.z += .2;
    d = min( d, bud( p, vec3( 0.0, 0.0, 0.0 ) ) );
    p.z -= .2;

    return d;
}



float map(vec3 pos) {

    vec3 p = pos;

    p.yz *= rotation( .5 * PI );

    float d = axies( p, .05, .8 );

    d = max( d, axies( p, .045, .9 ) );

    float n = fbm( vec2( fbm( pos.yz, 1. ) ), .9 );

    p.z -= .4;
    d = min( d, axies( p + n * .005, .05, 1.4 ) );
    p.z += .4;
    p.z += .2;

    d = min( d, axies( p, .02, 1.1 ) );

    p.z -= .2;
    p.yz *= rotation( .0 * PI );

    d = min( d, buud( p ) );

    // bottom
    /*
    p.z += .7;
    d = min( d, max( length( p ) - .15, abs( p.z ) - .02 ) );
    p.z -= .7;

    p.z += .6;
    d = min( d, max( length( p ) - .2, abs( p.z ) - .02 ) );
    p.z -= .6;
    */

    d = min( d, eachPetal( p ) );

    p.z += .875;
    p.xy *= rotation( .58 * PI );
    d = min( d, sdHexPrism( p, vec2( .115, .02 ) ) );

    p.z -= .33 - ( 1. - easeOutExpo( getTimeline( iTime * sS - .7 ) ) ) * .33;

    d = min( d, sdHexPrism( p, vec2( .11 + ( .15 * ( easeOutExpo( getTimeline( iTime * sS - .2 ) ) ) ), .01 ) ) );

    // repair
    p.z += .25;
    d = min( d, sdHexPrism( p, vec2( .115, .08 ) ) );

    return d;
}

// IQ

float calcSoftshadow( in vec3 ro, in vec3 rd, in float mint, in float tmax, int technique )
{
	float res = 1.0;
    float t = mint;
    float ph = 1e10; // big, such that y = 0 on the first iteration

    for( int i=0; i<32; i++ )
    {
		float h = map( ro + rd*t );

        // traditional technique
        if( technique==0 )
        {
        	res = min( res, 10.0*h/t );
        }
        // improved technique
        else
        {
            // use this if you are getting artifact on the first iteration, or unroll the
            // first iteration out of the loop
            //float y = (i==0) ? 0.0 : h*h/(2.0*ph);

            float y = h*h/(2.0*ph);
            float d = sqrt(h*h-y*y);
            res = min( res, 10.0*d/max(0.0,t-y) );
            ph = h;
        }

        t += h;

        if( res<0.0001 || t>tmax ) break;

    }
    res = clamp( res, 0.0, 1.0 );
    return res*res*(3.0-2.0*res);
}

// https://iquilezles.org/articles/normalsSDF
vec3 calcNormal( in vec3 pos) {
    vec2 e = vec2(1.0, -1.0) * 0.5773;
    const float eps = 0.0005;
    return normalize(e.xyy * map(pos + e.xyy * eps) +
        e.yyx * map(pos + e.yyx * eps) +
        e.yxy * map(pos + e.yxy * eps) +
        e.xxx * map(pos + e.xxx * eps));
}

void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord / iResolution.yy;
    uv.x -= ( iResolution.x - iResolution.y ) / iResolution.y * .5;

    // Time varying pixel color
    float tt = iTime * .4;

    uv = (uv - .5) * 2.;


    vec3 origin = vec3(cos(tt) * -2.0, 1.8, sin(tt) * -2.0);
    vec3 ta = vec3(0.3, 0.3, 0.0);

    // origin = vec3(0.0, 0.0, -3.5);

    // camera matrix
    vec3 ww = normalize(ta - origin);
    vec3 uu = normalize(cross(ww, vec3(0.0, 1.0, 0.0)));
    vec3 vv = normalize(cross(uu, ww));

    vec3 tot = vec3(0.0);

    vec3 ray = normalize(uv.x * uu + uv.y * vv + 1.5 * ww);

    float t = 0.0;

    const float tmax = 5.0;


    for (int i = 0; i < ( smooth ? 60 : 256 ); ++i) {
        vec3 p = origin + ray * t;

        float distance = map(p);
        t += distance * .4333;
    }

    vec3 col = calcBg( uv );

    vec3 lig = normalize(vec3(.57703));
    lig.xz *= rotation( iTime * .1 );

    vec3 hal = normalize(lig - ray);
    // vec3 spcol = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

    if (t < tmax) {
        vec3 pos = origin + t * ray;
        vec3 nor = calcNormal(pos);

        float dif = clamp(dot(nor, vec3(.4, 1., -.5)), 0.0, 1.0);

        float spe = pow(clamp(dot(nor, hal), 0.0, 1.0), 50.0) * .6;
        spe *= dif;

        float amb = dot(nor, vec3(0.0, 1.0, 0.0));

        vec3 ap = pos;
        ap.yz *= rotation( .5 * PI );
        float p = fbm( vec2( fbm( nor.xy * .5 - .2, 1. ) ), .9 );

        if( map( pos ) == eachPetal( ap ) ){

            float shadow = calcSoftshadow( pos, lig, 0.1, 3.0, 1 );
            dif *= shadow;

            col = spe + ( vec3(.93, .06, .76) + p * .05 ) * amb + vec3(.5) * dif + vec3(.93, .06, .76) * .5;
        }else if( map( pos ) == buud( ap ) ){
            col = spe + ( vec3(.8, .2, .5) + p * .05 ) * amb + vec3(.8) * dif + vec3(.8, .2, .5) * .5;
        }else{
            col = spe + vec3(.05 + p) * amb + vec3(.1) * dif + vec3(.3, .7, .54) * .15;
            vec3 af = vec3(0.1);
            af += 2.*dif*vec3(1.,.2,.3);
            af += 2.*spe*vec3(1.,2.,3.)*dif;
            col = col*af;
        }

        // af
        col += 0.08 * cos(iTime+uv.xyx+vec3(0,2,4));
    }

    // gamma
    col = sqrt(col);
    tot += col;

    // Output to screen
    fragColor = vec4(tot, 1.0);
}