// RTVolume intersection shader (runs in TRACE, per AABB the ray enters).
// Analytic ray-sphere test: the unit box [-1,1]^3 is treated as the
// bounding volume of a sphere of radius 1 centred at the box centre. The
// ray is in object space and is NOT normalised (it is worldToObject *
// worldRay), so the returned t is directly comparable to the world-space
// ray parameter the tracer commits — solve the quadratic with the general
// a = dot(d,d) form rather than assuming |d| == 1.
fn intersection_main(ray: RayDesc, aabbMin: vec3<f32>, aabbMax: vec3<f32>,
                     primitiveId: u32) -> IntersectionResult {
    var r: IntersectionResult;
    r.hit = false;

    let center = (aabbMin + aabbMax) * 0.5;
    let radius = (aabbMax.x - aabbMin.x) * 0.5;

    let oc = ray.origin - center;
    let a  = dot(ray.direction, ray.direction);
    let b  = 2.0 * dot(oc, ray.direction);
    let c  = dot(oc, oc) - radius * radius;
    let disc = b * b - 4.0 * a * c;
    if (disc < 0.0) { return r; }

    let sq = sqrt(disc);
    var t = (-b - sq) / (2.0 * a);   // near root
    if (t < ray.tMin) { t = (-b + sq) / (2.0 * a); }   // fall back to far root
    if (t < ray.tMin || t > ray.tMax) { return r; }

    r.hit     = true;
    r.t       = t;
    r.attribs = vec2<f32>(0.0);
    r.hitKind = 0u;
    return r;
}
