/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2015-2018 Danny Robson <danny@nerdcruft.net>
 */

#ifndef __UTIL_GEOM_SPHERE_HPP
#define __UTIL_GEOM_SPHERE_HPP

#include "../point.hpp"

#include "ray.hpp"


///////////////////////////////////////////////////////////////////////////////
namespace cruft::geom {
    template <size_t S, typename T>
    struct sphere {
        point<S,T> centre;
        T radius;
    };

    typedef sphere<2,float> sphere2f;
    typedef sphere<3,float> sphere3f;


    ///////////////////////////////////////////////////////////////////////////
    /// returns the smallest distance from a ray to a sphere intersection
    ///
    /// returns NaN on miss
    /// returns NaN if behind
    template <size_t S, typename T>
    constexpr T
    distance (const ray<S,T> r, const sphere<S,T> s)
    {
        const T b = dot (r.direction, r.origin - s.centre);
        const T c = dot (r.origin - s.centre, r.origin - s.centre) - s.radius * s.radius;

        const T D = b * b - c;

        // no intersection
        if (D < 0)
            return INFINITY;

        auto t_ = std::sqrt (D);
        auto t0 = -b + t_;
        auto t1 = -b - t_;

        return t1 >= 0 ? t1 :
               t0 >= 0 ? t0 :
               INFINITY;
    }
}

#endif