#version 450
layout(location = 0) in vec2 vUV;
layout(std140, binding = 0) uniform Globals {
    vec3 uCamPos;
    vec3 uCamForward;
    vec3 uCamRight;
    vec3 uCamUp;
    vec3 uPlayerPos;
    float uTime;
    float uAspect;
    int uEchoMask;
    int uExitOpen;
};
layout(location = 0) out vec4 FragColor;

float sdBox(vec3 p, vec3 b) { vec3 q=abs(p)-b; return length(max(q,0.0))+min(max(q.x,max(q.y,q.z)),0.0); }
vec2 scene(vec3 p) {
    float cube=sdBox(p-uPlayerPos,vec3(0.55)); vec3 cell=floor((p+5.0)/10.0); vec3 q=mod(p+5.0,10.0)-5.0;
    float phase=dot(cell,vec3(1.73,2.41,3.17))+uTime*0.22;
    float big=length(q)-(1.45+0.48*sin(phase)); vec3 orbit=vec3(sin(phase*1.3),cos(phase*0.9),sin(phase*1.7))*2.65;
    float spheres=min(big,min(length(q-orbit)-0.62,length(q+orbit.zxy)-0.38));
    vec2 result=cube<spheres?vec2(cube,1.0):vec2(spheres,2.0+mod(cell.x+cell.y*2.0+cell.z*3.0,5.0));
    vec3 echoes[5]=vec3[](vec3(8.0,34.0,0.0),vec3(-7.0,29.0,6.0),vec3(3.0,39.0,-8.0),vec3(-9.0,36.0,-7.0),vec3(10.0,28.0,8.0));
    for(int i=0;i<5;++i)if((uEchoMask&(1<<i))==0){float echo=length(p-echoes[i])-(0.72+0.12*sin(uTime*2.1+float(i)));if(echo<result.x)result=vec2(echo,10.0+float(i));}
    if(uExitOpen!=0){float portal=length(p-vec3(0.5,32.0,0.5))-(1.35+0.18*sin(uTime*1.8));if(portal<result.x)result=vec2(portal,20.0);}
    return result;
}
vec3 normalAt(vec3 p) { const float e=0.0025; float d=scene(p).x; return normalize(vec3(scene(p+vec3(e,0,0)).x-d,scene(p+vec3(0,e,0)).x-d,scene(p+vec3(0,0,e)).x-d)); }
vec3 palette(float t) { return 0.56+0.44*cos(6.28318*(vec3(0.02,0.28,0.56)+t)); }
void main() {
    vec2 s=vUV*2.0-1.0; s.x*=uAspect; float r=length(s); float a=atan(s.y,s.x)+0.035*sin(uTime*0.7+r*9.0); s=vec2(cos(a),sin(a))*r;
    vec3 ro=uCamPos; vec3 rd=normalize(uCamForward*1.65+uCamRight*s.x+uCamUp*s.y); float t=0.0,mat=0.0,glow=0.0;
    for(int i=0;i<112;++i){vec3 p=ro+rd*t;vec2 hit=scene(p);glow+=0.004/(0.04+abs(hit.x));if(hit.x<0.0015||t>120.0){mat=hit.y;break;}t+=hit.x*0.68;}
    vec3 col;
    if(t<120.0){vec3 p=ro+rd*t,n=normalAt(p),ld=normalize(vec3(sin(uTime*0.23),0.7,cos(uTime*0.19)));float diff=0.18+0.82*max(dot(n,ld),0.0),rim=pow(1.0-max(dot(n,-rd),0.0),2.5);if(mat<1.5)col=vec3(0.92,0.98,1.0)*diff+palette(uTime*0.06)*rim*1.8;else if(mat>=20.0)col=vec3(1.0,0.96,0.72)*(1.4+rim*2.4)+palette(uTime*0.12)*0.8;else if(mat>=10.0)col=palette(mat*0.17+uTime*0.08)*(1.8+diff+rim*2.2);else col=palette(mat*0.11+t*0.018+uTime*0.025)*(diff+rim*0.8);col*=exp(-t*0.006);}else{float stars=pow(max(0.0,sin(a*12.0+log(r+0.03)*17.0-uTime)),18.0);col=palette(a/6.28318+uTime*0.015)*(0.035+stars*0.75);}
    col+=palette(uTime*0.035+r*0.1)*min(glow,0.32);col*=1.0-0.22*smoothstep(0.3,1.4,r);col=pow(max(col,0.0),vec3(0.82));FragColor=vec4(col,1.0);
}
