// PATTERN 
// 0: fix 
// 1: rotate a mirror box
#define PATTERN 1


#define BOX_ID 1.
#define BOX_ID2 2.
#define OBJ_ID 3.

#define OBJ_R .8
#define EPS 1e-4

const float box_size = 2.;
const vec3 box3 = vec3(box_size, box_size*1.5, box_size);
const vec3 box32 = vec3(box_size, box_size*1.5, box_size)*.95;


mat2 rotate2D(float r){
    float c = cos(r);
    float s = sin(r);
    return mat2(c, s, -s, c);
}

vec3 hsv(float h, float s, float v){
    vec4 t = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
    vec3 p = abs(fract(vec3(h) + t.xyz) * 6.0 - vec3(t.w));
    return v * mix(vec3(t.x), clamp(p - vec3(t.x), 0.0, 1.0), s);
}

float box(vec3 p, vec3 w){
    vec3 q = abs(p) - w;
    return length(max(q, 0.)) + min(max(q.x, max(q.y, q.z)), 0.0);
}

float sphere(vec3 p, float r){
    return length(p) - r;
}

vec2 upU(vec2 d1, vec2 d2) {
    return (d1.x < d2.x) ? d1: d2;
}


vec3 calcNormal(vec3 p, float id){
    vec2 h = vec2(EPS, 0.0);
    vec3 sz = id==OBJ_ID ? vec3(OBJ_R) : id==BOX_ID ? box3 : box32;
    return normalize(vec3(box(p + h.xyy, sz) - box(p - h.xyy, sz),
                        box(p + h.yxy, sz) - box(p - h.yxy, sz),
                        box(p + h.yyx, sz) - box(p - h.yyx, sz)
        )); 
}

mat3 setCamera(vec3 ro, vec3 tg, float cr){
	vec3 cw = normalize(tg-ro);
	vec3 cu = normalize(cross(cw,vec3(sin(cr), cos(cr), 0.0)));
	vec3 cv = cross(cu,cw);
    return mat3(cu, cv, cw);
}

vec3 raymarch(vec3 ro, vec3 rd){
    float td = EPS, td1;
    vec2 d = vec2(100., -1.);
    vec3 p;

    vec3 col = vec3(0);
    
    float col_freq = .1 + sin(iTime*.3)*.2;
    mat2 rot = rotate2D(iTime);
    mat2 rot2 = rotate2D(3.1416*sin(iTime*.2)*.5);
    float offset = sin(iTime)*1.5;

    for(int j=0;j<10;++j){
        d.y = -1.;
        for(int i=0;i<120;++i){
            p = ro + td * rd;

            vec3 q = p;
            q.xy *= rot;
            d = vec2(box(q+offset, vec3(OBJ_R)), OBJ_ID);

            d = upU(d, vec2(-box(p, box3), BOX_ID));
            
            #if PATTERN >= 1
            q=p;
            q.xy *= rot2;
            d = upU(d, vec2(-box(q, box32), BOX_ID2));
            #endif

            if(d.x < EPS){
                break;
            }
            td += d.x;
        }

        p = ro + td * rd;
        if(d.x > EPS) break;
        if(d.y >= OBJ_ID){
            p.xy *= rot;
            p += offset;
        }
        else if(d.y == BOX_ID){
            if(abs(abs(p.y) - box3.y) > EPS){
                col += hsv(p.y*col_freq+iTime*float(j+1)*.1,
                1.,
                1./(abs(abs(p.x) - box3.x) + abs(abs(p.z) - box3.z)+.15) * .08/exp(d.x) * step(-box3.y, -abs(p.y)));
            }
            else{
                p = mod(p*2., 1.) - .5;
                col += smoothstep(.5, 1., .05/length(p.xz));
                break;
            }
        }
        else if(d.y == BOX_ID2){
            p.xy *= rot2;
            if(abs(abs(p.y) - box32.y) > EPS){
                col += hsv(p.y*col_freq+iTime*float(j+1)*.1,
                1.,
                1./(abs(abs(p.x) - box32.x) + abs(abs(p.z) - box32.z)+.15) * .08/exp(d.x));
            }
            else{
                p = mod(p*2., 1.) - .5;
                col += smoothstep(.5, 1., .05/length(p.xz));
                break;
            }
            
        }
        
        vec3 nor = calcNormal(p, d.y);
        vec3 ref = reflect(rd, nor);

        ro = p - nor * EPS;
        rd = ref;
        td = EPS;
    }
    
 

    return col;
}


void mainImage( out vec4 fragColor, in vec2 fragCoord ){

    
    float t = iTime;
    
    vec2 uv = 2.0 * (fragCoord.xy - 0.5 * iResolution.xy) / min(iResolution.y, iResolution.x);
    vec3 col = vec3(0), col2 = vec3(0);
    //---------------------------------------------------------------//

    vec3 ro, tg;
    
    t*=.3;
    ro = vec3(cos(t)*1.8, 0., sin(t)*1.8);
    tg = vec3(0,0,0);

    mat3 ca = setCamera(ro, tg, 0.);
    vec3 rd = ca * normalize(vec3(uv, 1.));

    vec3 p;
    vec2 d;
    float td;
        
    col = raymarch(ro, rd);
    
    
 
    //---------------------------------------------------------------//
    //col = pow(col, vec3(0.4545));
    fragColor = vec4(col, 1);
    
}
