#ifndef SPHERE_HXX
#define SPHERE_HXX

#include "Primitive.hxx"
#include "Shader.hxx"
#include "Box.hxx"

class Sphere : public Primitive
{
	Vec3f center, rayorgcenter;
	Box   box;
	float rayorgcenter2, tcenter, radius, radius2, halfway, halfway2, t;
public:
	Sphere(Vec3f center, float radius, Shader *shader)
		: center(center),radius(radius)
	{
		box.min = center - Vec3f(radius + Epsilon);
		box.max = center + Vec3f(radius + Epsilon);

		this->shader = shader;
		// Precompute the radius' square
		radius2 = radius * radius;
	};

	virtual ~Sphere(){};

	virtual bool Intersect(Ray &ray)
	{
		rayorgcenter  = center - ray.org;
		rayorgcenter2 = Dot(rayorgcenter, rayorgcenter);

		// t to point on ray closest to sphere center
		tcenter  = Dot(rayorgcenter, ray.dir);

		// Half way through the sphere, squared
		halfway2 = radius2 - rayorgcenter2 + tcenter * tcenter;

		if (rayorgcenter2 > radius2)
		{
			// Ray origin is outside the sphere
			if (tcenter < 0)
				// The sphere is in our back
				return false;

			if (halfway2 < 0)
				// Ray does not hit the sphere either
				return false;
        
			halfway = sqrt(halfway2);
			t = tcenter - halfway;
		}
		else
		{
			// Ray origin is inside the sphere
			halfway = sqrt(halfway2);
			t = tcenter + halfway;
		}

		if (t < ray.t && t > Epsilon)
		{
			ray.t = t;
			ray.hit = this;
			return true;
		}
		else
			return false;
	};

	virtual Vec3f GetNormal(Ray &ray)
	{
		Vec3f normal = ray.t * ray.dir + ray.org - center;
		Normalize(normal);
		return normal;
	};

	virtual Box CalcBounds()
	{
		return box;
	}
};

#endif
