// Name: Just Another Cube
// Author: mrange
// URL: https://www.shadertoy.com/view/3XdXRr
#version 330 core
precision highp float;

out vec4 FragColor;
in vec2 vUV;
uniform vec2 iResolution;
uniform float iTime;

// CC0: Just another cube
// Glowtracers are great for compact coding, but I wanted to see how much
// I could squeeze a more normal raymarcher in terms of characters used.

// Twigl: https://twigl.app?ol=true&ss=-OW-y9xgRgWubwKcn0Nd

// == Globals ==
// Single-letter variable names are used to save characters (code golfing).
mat2 R;    // A 2D rotation matrix, calculated once per frame in mainImage and used by D.
float d=1. // Stores the most recent distance to the scene from the ray's position.
    , z=0. // Stores the total distance traveled along the ray (initialized to avoid undefined behavior)
    , G=9. // "Glow" variable. Tracks the closest the ray comes to the object (for volumetric glow effect).
    , M=1e-3
    ;
// == Distance Function (SDF - Signed Distance Field) ==
// This function calculates the shortest distance from a given point 'p' to the scene geometry.
// A positive result means the point is outside an object, negative is inside, and zero is on the surface.
// This is the core of "raymarching", as it tells us the largest safe step we can take along a ray.
float D(vec3 p) {
  // Apply two rotations to the point's coordinates. This twists the space the object
  // exists in, making the simple cube shape appear more complex and animated.
  p.xy *= R;
  p.xz *= R;

  // Create a higher-frequency version of the coordinate for detailed surface patterns.
  vec3 S = sin(123.*p);

  // This creates a volumetric glow effect by tracking the minimum distance
  // to either the existing glow value or a glowing shell around the object.
  G = min(
      G
      // The glowing shell
    , max(
        abs(length(p)-.6)
        // The main object distance calculation:
        // 1. A superquadric (rounded cube shape) is created using an L8-norm.
        // The expression `pow(dot(p=p*p*p*p,p),.125)` is a golfed version of
        // `pow(pow(p.x,8)+pow(p.y,8)+pow(p.z,8), 1./8.)`.
        // The `- .5` defines the object's size.
      , d = pow(dot(p*=p*p*p,p),.125) - .5
        // 2. Surface detail subtraction. This creates small surface variations
        // using high-frequency sine waves for more appealing reflections.
        - pow(1.+S.x*S.y*S.z,8.)/1e5
      )
    );

  return d;
}

// == Main Render Function ==
// This function is called for every pixel on the screen to determine its color.
// 'o' is the final output color (rgba). 'C' is the input pixel coordinate (xy).
void mainImage(out vec4 o, vec2 C) {
  // Single-letter variable names are used to save characters (code golfing).
  vec3  p  // The current point in 3D space along the ray.
      , O  // Multi-purpose vector: color accumulator, then normal vector, then final color.
      , r=vec3(iResolution.xy, iResolution.y)  // 'r' holds screen resolution, later re-used for the epsilon vector and reflection.
        // 'I' is the Ray Direction vector. It's calculated once per pixel.
        // This converts the 2D screen coordinate 'C' into a 3D direction, creating the camera perspective.
      , I=normalize(vec3(C-.5*r.xy, r.y))
        // Base glow color (dark bluish tint).
      , B=vec3(1,2,9)*M
      ;

  // == Raymarching Loop ==
  // This loop "marches" a ray from the camera out into the scene to find what it hits.
  // It uses a golfed structure where the body of the loop updates the ray position 'p',
  // and the "advancement" step moves the ray forward.
  for(
        // -- Initializer (runs once before the loop) --
        // Calculate the rotation matrix for this frame based on time.
        R = mat2(cos(.3*iTime+vec4(0,11,33,0)))
    // -- Condition --
    // Loop while total distance 'z' is less than 9 and we are not yet touching a surface (d > 1e-3).
    ; z<9. && d > M
    // -- Advancement --
    // The ray advances by the safe distance 'd' returned by D(p).
    // The result of D(p) is also assigned to the global 'd' inside the function.
    ; z += D(p)
    )
    // -- Loop Body --
    // Calculate the current position 'p' in world space.
    // The camera starts at (0,0,-2) and points forward.
    p = z*I
  , p.z -= 2.
  ;

  // -- Hit Condition --
  // If the loop finished because z exceeded the max distance, we hit nothing. Otherwise, we hit the surface.
  if (z < 9.) {
    // -- Calculate Surface Normal --
    // Estimate the gradient ∇D at the hit point 'p' via central differences on the SDF D.
    // We use ε = 1e-3 and loop over each axis (x, y, z):
    //   • Zero r, then set r[i] = ε.
    //   • Compute O[i] = D(p + r) – D(p – r).
    // After the loop, O holds the unnormalized normal vector.
    for (
        int i=0               // axis index: 0→x, 1→y, 2→z (initialized to avoid warnings)
      ; i < 3
      ; O[i++] = D(p+r) - D(p-r)
      )
        r -= r                // clear r to vec3(0)
      , r[i] = M              // set only the i-th component
      ;

    // -- Lighting and Shading --
    // 'z' is re-purposed to store a fresnel factor (1 - cos(angle)) for edge brightness.
    // `dot(O, I)` calculates how much the surface faces away from the camera.
    // O is also normalized here to become a proper normal vector.
    z = 1.+dot(O = normalize(O),I);

    // 'r' is re-purposed to store the reflection vector.
    r = reflect(I,O);

    // Calculate a point 'C' along the reflection vector 'r' to sample a background color.
    // For upward reflections (r.y > 0), this finds the intersection with the plane y=5.
    C = (p+r*(5.-p.y)/abs(r.y)).xz;

    // Calculate the final color 'O' of the hit point.
    O =
        // Multiply by the fresnel factor squared for stronger edge reflections.
        z*z *
        // Use a ternary operator to decide the color based on where the reflection ray goes.
        (
            // If the reflection vector points upward...
            r.y>0.
            // ...sample a procedural "sky" with a radial gradient and blue tint.
          ? 5e2*smoothstep(5., 4., d = sqrt(length(C*C))+1.)*d*B
            // ...otherwise, sample a "floor" with a deep blue exponential falloff.
          : exp(-2.*length(C))*(B/M-1.)
        )
      // Add rim lighting (brighter on upward-facing surfaces).
      + pow(1.+O.y,5.)*B
      ;
  }

  // == Tonemapping & Output ==
  // Apply final effects and map the High Dynamic Range (HDR) color to a displayable range.
  // Add glow contribution: smaller G values (closer ray passes) create a brighter blue glow.
  o = sqrt(O+B/G).xyzx;
}

void main() {
    vec2 fragCoordPixels = vUV * iResolution;
    vec4 outColor;
    mainImage(outColor, fragCoordPixels);
    FragColor = outColor;
}
