/*] Copyright (c) 2009-2010, Charles McGarvey [************************** **] All rights reserved. * * vi:ts=4 sw=4 tw=75 * * Distributable under the terms and conditions of the 2-clause BSD license; * see the file COPYING for a complete text of the license. * **************************************************************************/ #ifndef _MOOF_SPHERE_HH_ #define _MOOF_SPHERE_HH_ #include #include #include #include #include #include #include // TODO this needs work namespace Mf { /** * A round object. */ template struct Sphere : public Cullable, public Drawable, public Shape { typedef cml::vector< Scalar, cml::fixed > Vector; Vector point; Scalar radius; Sphere() {} Sphere(const Vector& p, Scalar r) : point(p), radius(r) {} void init(const Vector& p, Scalar r) { point = p; radius = r; } void init(const Vector& p, const Vector& o) { point = p; radius = (o - p).length(); } //void encloseVertices(const Vector vertices[], unsigned count); //void draw(Scalar alpha = 0.0) const; //bool isVisible(const Frustum& frustum) const; void encloseVertices(const Vector vertices[], unsigned count) { // TODO } void draw(Scalar alpha = 0.0) const; bool isVisible(const Frustum& frustum) const { return true; } bool intersect(const Sphere& sphere, Contact& hit) const { Vector n = sphere.point - point; Scalar distance = n.length(); Scalar limit = radius + sphere.radius; if (distance > limit) return false; hit.normal = n.normalize(); hit.distance = limit - distance; hit.point = hit.normal * radius; return true; } bool intersect(const Vector& point2, Contact& hit) const { Vector n = point2 - point; Scalar distance = n.length(); if (distance > radius) return false; hit.normal = n.normalize(); hit.distance = radius - distance; hit.point = point2; return true; } // a ray inside the sphere will not intersect on its way out bool intersect(const Ray& ray, typename Ray::Contact& hit) const { Vector b = point - ray.point; Scalar z = cml::dot(b, ray.direction); // check if the ball is behind the ray if (z < SCALAR(0.0)) return false; Scalar d2 = cml::dot(b, b) - z*z; Scalar r2 = radius * radius; // check for an intersection if (d2 > r2) return false; hit.distance = z - std::sqrt(r2 - d2); if (hit.distance < SCALAR(0.0)) return false; Vector surfacePoint; ray.solve(surfacePoint, hit.distance); hit.normal = surfacePoint - point; return true; } }; template <> inline bool Sphere<3>::isVisible(const Frustum& frustum) const { return frustum.contains(*this); } template <> inline void Sphere<2>::draw(Scalar alpha) const { GLUquadricObj* sphereObj = gluNewQuadric(); gluQuadricDrawStyle(sphereObj, GLU_LINE); glPushMatrix(); glTranslate(promote(point)); gluSphere(sphereObj, GLdouble(radius), 16, 16); glPopMatrix(); gluDeleteQuadric(sphereObj); } template <> inline void Sphere<3>::draw(Scalar alpha) const { GLUquadricObj* sphereObj = gluNewQuadric(); gluQuadricDrawStyle(sphereObj, GLU_LINE); glPushMatrix(); glTranslate(point); gluSphere(sphereObj, GLdouble(radius), 16, 16); glPopMatrix(); gluDeleteQuadric(sphereObj); } template inline bool checkCollision(const Sphere& a, const Sphere& b) { Scalar d = (a.point - b.point).length(); return d < (a.radius + b.radius); } typedef Sphere<2> Sphere2; typedef Sphere2 Circle; typedef Sphere<3> Sphere3; } // namespace Mf #endif // _MOOF_SPHERE_HH_