#version 330 core
out vec4 FragColor; 
in vec2 vUV; 
uniform vec2 iResolution; 
uniform float iTime; 
uniform float rotationSpeed; 
uniform float tshift; 
uniform float cameraDistance; 
uniform float cameraTilt; 
uniform vec3 boxDims; 

// Forked from Cube lines Created by Danil (2021+) https://cohost.org/arugl
// boxedStars() and refactoring by iSandRocks (2026)
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported
// License. self https://www.shadertoy.com/view/NslGRN
// using iq's intersectors: https://iquilezles.org/articles/intersectors
// using https://www.shadertoy.com/view/ltKBzG
// using https://www.shadertoy.com/view/tsVXzh
// using https://www.shadertoy.com/view/WlffDn
// using https://www.shadertoy.com/view/WslGz4

#define ANGLE_loops 0
#define FDIST 0.7
#define PI 3.1415926
#define BOXDIMS vec3(0.75, 0.75, 1.25)
#define IOR 1.33

mat3 rotz(float a) {
  float s = sin(a);
  float c = cos(a);
  return mat3(vec3(c, s, 0.0), vec3(-s, c, 0.0), vec3(0.0, 0.0, 1.0));
}

float dot2(in vec3 v) { return dot(v, v); }

float segShadow(in vec3 ro, in vec3 rd, in vec3 pa, float sh) {
  float dm = dot(rd.yz, rd.yz);
  float k1 = (ro.x - pa.x) * dm;
  float k2 = (ro.x + pa.x) * dm;
  vec2 k5 = (ro.yz + pa.yz) * dm;
  float k3 = dot(ro.yz + pa.yz, rd.yz);
  vec2 k4 = (pa.yz + pa.yz) * rd.yz;
  vec2 k6 = (pa.yz + pa.yz) * dm;

  for (int i = 0; i < 4 + ANGLE_loops; i++) {
    vec2 s = vec2(i & 1, i >> 1);
    float t = dot(s, k4) - k3;

    if (t > 0.0)
      sh = min(sh, dot2(vec3(clamp(-rd.x * t, k1, k2), k5 - k6 * s) + rd * t) /
                       (t * t));
  }
  return sh;
}

float boxSoftShadow(in vec3 ro, in vec3 rd, in vec3 rad, in float sk) {
  rd += 0.0001 * (1.0 - abs(sign(rd)));
  vec3 rdd = rd;
  vec3 roo = ro;

  vec3 m = 1.0 / rdd;
  vec3 n = m * roo;
  vec3 k = abs(m) * rad;

  vec3 t1 = -n - k;
  vec3 t2 = -n + k;

  float tN = max(max(t1.x, t1.y), t1.z);
  float tF = min(min(t2.x, t2.y), t2.z);

  if (tN < tF && tF > 0.0)
    return 0.0;

  float sh = 1.0;
  sh = segShadow(roo.xyz, rdd.xyz, rad.xyz, sh);
  sh = segShadow(roo.yzx, rdd.yzx, rad.yzx, sh);
  sh = segShadow(roo.zxy, rdd.zxy, rad.zxy, sh);
  sh = clamp(sk * sqrt(sh), 0.0, 1.0);
  return sh * sh * (3.0 - 2.0 * sh);
}

float box(in vec3 ro, in vec3 rd, in vec3 r, out vec3 nn, bool entering) {
  rd += 0.0001 * (1.0 - abs(sign(rd)));
  vec3 dr = 1.0 / rd;
  vec3 n = ro * dr;
  vec3 k = r * abs(dr);

  vec3 pin = -k - n;
  vec3 pout = k - n;
  float tin = max(pin.x, max(pin.y, pin.z));
  float tout = min(pout.x, min(pout.y, pout.z));
  if (tin > tout)
    return -1.;
  if (entering) {
    nn = -sign(rd) * step(pin.zxy, pin.xyz) * step(pin.yzx, pin.xyz);
  } else {
    nn = sign(rd) * step(pout.xyz, pout.zxy) * step(pout.xyz, pout.yzx);
  }
  return entering ? tin : tout;
}

vec3 bgcol(in vec3 rd) {
  return mix(vec3(0.01), vec3(0.336, 0.458, .668),
             1. - pow(abs(rd.z + 0.25), 1.3));
}

vec3 background(in vec3 ro, in vec3 rd, vec3 l_dir, out float alpha) {
  float t = (-boxDims.z - ro.z) / rd.z;
  alpha = 0.;
  vec3 bgc = bgcol(rd);
  if (t < 0.)
    return bgc;
  vec2 uv = ro.xy + t * rd.xy;
  float shad = boxSoftShadow(
      (ro + t * rd), normalize(l_dir + vec3(0., 0., 1.)) * rotz(PI * 0.65),
      boxDims, 1.5);
  float aofac =
      smoothstep(-0.95, .75, length(abs(uv) - min(abs(uv), vec2(0.45))));
  aofac = min(aofac, smoothstep(-0.65, 1., shad));
  float lght = max(dot(normalize(ro + t * rd + vec3(0., -0., -5.)),
                       normalize(l_dir - vec3(0., 0., 1.)) * rotz(PI * 0.65)),
                   0.0);
  vec3 col =
      mix(vec3(0.4), vec3(.71, .772, 0.895), lght * lght * aofac + 0.05) *
      aofac;
  alpha = 1. - smoothstep(7., 10., length(uv));
  return mix(col * length(col) * 0.8, bgc, smoothstep(7., 10., length(uv)));
}

vec3 hash33(vec3 p3) {
  p3 = fract(p3 * vec3(0.1031, 0.1030, 0.0973));
  p3 += dot(p3, p3.yxz + 33.33);
  return fract((p3.xxy + p3.yxx) * p3.zyx);
}

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);
}

vec3 waveDeform(vec3 pos, float tOffset) {
  vec3 deformed = pos;
  deformed.xz = rotate(deformed.xz, 0.4);
  deformed += cos(deformed.zxy);
  deformed.xz = rotate(deformed.xz, 0.4);
  deformed += cos(deformed.zxy * 2.0 - tOffset * 2.0) * 0.5;
  return deformed;
}

vec3 boxedStars(vec3 ro, vec3 rd) {
  float tmod = mod((iTime + tshift) * 0.33, 1000.);
  float starAccum = 0.0;
  int maxSteps = 150;
  float stepSize = 0.0075;
  float vt = 0.0;
  vec3 pillarAccum = vec3(0.0);
  float pillarWidth = 2.0;
  vec3 ambientBG = vec3(0.0345, 0.036, 0.0915);

  for (int i = 0; i < maxSteps; i++) {
    vec3 vp = ro + rd * vt;
    vp.yz =vp.zy;
    vec3 p = vp * 10.0;
    vec3 id = floor(p);
    vec3 q = fract(p) - 0.5;
    vec3 h = hash33(id);

    vec3 pillarPos = p;
    pillarPos *= 0.3;

    vec3 lightPillar = pillarPos;
    lightPillar = waveDeform(lightPillar + vec3(0.0, tmod, 0.0), tmod);

    vec2 cosPair = cos(lightPillar.xz);
    float innerBeamsDist = length(cosPair);
    float radialBound = length(pillarPos.xz) - pillarWidth;
    float pillarDist = max(innerBeamsDist, radialBound);
    float density = 0.02 / (max(pillarDist, 0.001));
    vec3 pillarGradient = mix(vec3(0.0, 0.1, 1.0), vec3(0.9, 0.0, 1.0),
                              smoothstep(-3.5, 3.5, pillarPos.y));

    if (pillarDist < 1.0) {
      vec3 gradxDens = pillarGradient * density;
      float px = 1.2;
      pillarAccum += clamp(vec3(pow(gradxDens.x, px),
                                pow(gradxDens.y, px),
                                pow(gradxDens.z, px)),
                           0.0, 1.0);
    }

    if (h.z < 0.08) {

      vec3 movement = sin(tmod * (h * 2.0 + 1.0)) * 0.15;
      vec3 offset = (h - 0.5) * 0.3 + movement;
      float d = length(q - offset);
      float glow = pow(clamp(1.0 - d * 10.0, 0.0, 1.0), 4.0) * 2.0;
      float fade = clamp(1.0 - vt * 1.2, 0.0, 1.0);

      starAccum += glow * fade;
    }
    
    vt += stepSize;
  }
  
  vec3 pillarColor = clamp(tanh(pillarAccum * 0.5), 0.0, 1.0);
  vec3 finalColor = ambientBG + (vec3(1.0) * starAccum) + pillarColor;
  
  return clamp(finalColor, 0.0, 1.0);
}

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

  vec3 l_dir = normalize(vec3(0., 1., 0.));
  l_dir *= rotz(0.5);

  float mouseY = cameraTilt;
  float mouseX = -2. * PI - 0.25 * (iTime * rotationSpeed + tshift);

  vec3 eye = cameraDistance * vec3(cos(mouseX) * cos(mouseY), sin(mouseX) * cos(mouseY),
                       sin(mouseY));
  vec3 w = normalize(-eye);
  vec3 up = vec3(0., 0., 1.);
  vec3 u = normalize(cross(w, up));
  vec3 v = cross(u, w);

  vec4 tot = vec4(0.);
  vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.x;
  vec3 rd = normalize(w * FDIST + uv.x * u + uv.y * v);

  vec3 ni;
  float t = box(eye, rd, boxDims, ni, true);
  vec3 ro = eye + t * rd;
  vec2 coords = ro.xy * ni.z / boxDims.xy + ro.yz * ni.x / boxDims.yz +
                ro.zx * ni.y / boxDims.zx;
  float fadeborders = (1. - smoothstep(0.915, 1.05, abs(coords.x))) *
                      (1. - smoothstep(0.915, 1.05, abs(coords.y)));

  if (t > 0.) {
    vec3 col = vec3(0.);
    // Set up glass reflection
    float R0 = (IOR - 1.) / (IOR + 1.);
    R0 *= R0;
    vec3 nr = ni; // simple reflection normal
    vec3 rdr = reflect(rd, nr);
    float talpha;
    vec3 reflcol = background(ro, rdr, l_dir, talpha);

    vec3 interiorCol = boxedStars(ro, rd);

    float fresnel = R0 + (1. - R0) * pow(1. - dot(-rd, nr), 5.);
    col = mix(interiorCol * fadeborders, reflcol, pow(fresnel, 1.5));
    col = clamp(col, 0., 1.);

    float cineshader_alpha = 0.;
    cineshader_alpha = clamp(0.15 * dot(eye, ro), 0., 1.);
    vec4 tcolx = vec4(col, cineshader_alpha);
    tot += tcolx;
  } else {
    vec4 tcolx = vec4(0.);
    float alpha;
    tcolx = vec4(background(eye, rd, l_dir, alpha), 0.15);
    tot += tcolx;
  }
  fragColor = tot;
  fragColor.rgb = clamp(fragColor.rgb, 0., 1.);
}

void main(){ vec2 fragCoord = gl_FragCoord.xy; vec2 uv = fragCoord / iResolution; mainImage(FragColor, fragCoord); }
