Sfoglia il codice sorgente

Refactored Plane/Sphere

Marko Pintera 12 anni fa
parent
commit
845c8ea021

+ 1 - 6
BansheeEngine/Source/BsCamera.cpp

@@ -229,11 +229,6 @@ namespace BansheeEngine
 		// Make any pending updates to the calculated frustum planes
 		updateFrustumPlanes();
 
-		// Get centre of the box
-		Vector3 centre = bound.getCenter();
-		// Get the half-size of the box
-		Vector3 halfSize = bound.getHalfSize();
-
 		// For each plane, see if all points are on the negative side
 		// If so, object is not visible
 		for (int plane = 0; plane < 6; ++plane)
@@ -242,7 +237,7 @@ namespace BansheeEngine
 			if (plane == FRUSTUM_PLANE_FAR && mFarDist == 0)
 				continue;
 
-			Plane::Side side = mFrustumPlanes[plane].getSide(centre, halfSize);
+			Plane::Side side = mFrustumPlanes[plane].getSide(bound);
 			if (side == Plane::NEGATIVE_SIDE)
 			{
 				// ALL corners on negative side therefore out of view

+ 0 - 7
CSharpWrap.txt

@@ -108,13 +108,6 @@ For EditorWindow, add a new class in BansheeEditor, which pretty much does the j
 
   Math updates
 
-Plane needs intersection methods for:
- Ray, AABox, Sphere
-
-AABox.cpp is in Include folder
-
-Add "fast*" methods to Math
-
 Rename:
 Int2 -> Vector2I
 FRect -> Rect

+ 1 - 1
CamelotUtility/CamelotUtility.vcxproj

@@ -244,6 +244,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="Source\CmAABox.cpp" />
     <ClCompile Include="Source\CmAsyncOp.cpp" />
     <ClCompile Include="Source\CmBitmapWriter.cpp" />
     <ClCompile Include="Source\CmBox.cpp" />
@@ -333,7 +334,6 @@
     <ClCompile Include="Source\CmHString.cpp" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="Include\CmAABox.cpp" />
     <ClCompile Include="Source\CmColor.cpp" />
     <ClCompile Include="Source\CmDebug.cpp" />
     <ClCompile Include="Source\CmDynLibManager.cpp" />

+ 3 - 3
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -341,9 +341,6 @@
     <ClCompile Include="Source\CmMemStack.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="Include\CmAABox.cpp">
-      <Filter>Source Files\Math</Filter>
-    </ClCompile>
     <ClCompile Include="Source\CmFRect.cpp">
       <Filter>Source Files\Math</Filter>
     </ClCompile>
@@ -371,5 +368,8 @@
     <ClCompile Include="Source\CmRay.cpp">
       <Filter>Source Files\Math</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmAABox.cpp">
+      <Filter>Source Files\Math</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 64 - 102
CamelotUtility/Include/CmPlane.h

@@ -32,51 +32,21 @@ THE SOFTWARE.
 // http://www.boost.org/LICENSE_1_0.txt
 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
 
-
-#ifndef __Plane_H__
-#define __Plane_H__
+#pragma once
 
 #include "CmPrerequisitesUtil.h"
-
 #include "CmVector3.h"
 
-namespace CamelotFramework {
-
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup Math
-	*  @{
-	*/
-	/** Defines a plane in 3D space.
-        @remarks
-            A plane is defined in 3D space by the equation
-            Ax + By + Cz + D = 0
-        @par
-            This equates to a vector (the normal of the plane, whose x, y
-            and z components equate to the coefficients A, B and C
-            respectively), and a constant (D) which is the distance along
-            the normal you have to go to move the plane back to the origin.
-     */
+namespace CamelotFramework 
+{
     class CM_UTILITY_EXPORT Plane
     {
-    public:
-        /** Default constructor - sets everything to 0.
-        */
-        Plane ();
-        Plane (const Plane& rhs);
-        /** Construct a plane through a normal, and a distance to move the plane along the normal.*/
-        Plane (const Vector3& rkNormal, float fConstant);
-		/** Construct a plane using the 4 constants directly **/
-		Plane (float a, float b, float c, float d);
-        Plane (const Vector3& rkNormal, const Vector3& rkPoint);
-        Plane (const Vector3& rkPoint0, const Vector3& rkPoint1,
-            const Vector3& rkPoint2);
-
-        /** The "positive side" of the plane is the half space to which the
-            plane normal points. The "negative side" is the other half
-            space. The flag "no side" indicates the plane itself.
-        */
+	public:
+		/**
+		 * @brief	The "positive side" of the plane is the half space to which the
+		 *			plane normal points. The "negative side" is the other half
+		 *			space. The flag "no side" indicates the plane itself.
+         */
         enum Side
         {
             NO_SIDE,
@@ -85,69 +55,62 @@ namespace CamelotFramework {
             BOTH_SIDE
         };
 
-        Side getSide (const Vector3& rkPoint) const;
+    public:
+        Plane();
+        Plane(const Plane& copy);
+        Plane(const Vector3& normal, float d);
+		Plane(float a, float b, float c, float d);
+        Plane(const Vector3& normal, const Vector3& point);
+        Plane(const Vector3& point0, const Vector3& point1, const Vector3& point2);
+
+        /**
+         * @brief	Returns the side of the plane where the point is located on.
+         * 			
+		 * @note	NO_SIDE signifies the point is on the plane.
+         */
+        Side getSide(const Vector3& point) const;
+
+        /**
+		 * @brief	Returns the side where the alignedBox is. The flag BOTH_SIDE indicates an intersecting box.
+		 *			One corner ON the plane is sufficient to consider the box and the plane intersecting.
+         */
+        Side getSide(const AABox& box) const;
 
         /**
-        Returns the side where the alignedBox is. The flag BOTH_SIDE indicates an intersecting box.
-        One corner ON the plane is sufficient to consider the box and the plane intersecting.
-        */
-        Side getSide (const AABox& rkBox) const;
-
-        /** Returns which side of the plane that the given box lies on.
-            The box is defined as centre/half-size pairs for effectively.
-        @param centre The centre of the box.
-        @param halfSize The half-size of the box.
-        @returns
-            POSITIVE_SIDE if the box complete lies on the "positive side" of the plane,
-            NEGATIVE_SIDE if the box complete lies on the "negative side" of the plane,
-            and BOTH_SIDE if the box intersects the plane.
-        */
-        Side getSide (const Vector3& centre, const Vector3& halfSize) const;
-
-        /** This is a pseudodistance. The sign of the return value is
-            positive if the point is on the positive side of the plane,
-            negative if the point is on the negative side, and zero if the
-            point is on the plane.
-            @par
-            The absolute value of the return value is the true distance only
-            when the plane normal is a unit length vector.
-        */
-        float getDistance (const Vector3& rkPoint) const;
-
-        /** Redefine this plane based on 3 points. */
-        void redefine(const Vector3& rkPoint0, const Vector3& rkPoint1,
-            const Vector3& rkPoint2);
-
-		/** Redefine this plane based on a normal and a point. */
-		void redefine(const Vector3& rkNormal, const Vector3& rkPoint);
-
-		/** Project a vector onto the plane. 
-		@remarks This gives you the element of the input vector that is perpendicular 
-			to the normal of the plane. You can get the element which is parallel
-			to the normal of the plane by subtracting the result of this method
-			from the original vector, since parallel + perpendicular = original.
-		@param v The input vector
-		*/
+         * @brief	Returns a distance from point to plane.
+         *
+		 * @note	The sign of the return value is positive if the point is on the 
+		 * 			positive side of the plane, negative if the point is on the negative 
+		 * 			side, and zero if the point is on the plane.
+         */
+        float getDistance(const Vector3& point) const;
+
+		/**
+		 * @brief	Project a vector onto the plane.
+		 */
 		Vector3 projectVector(const Vector3& v) const;
 
-        /** Normalises the plane.
-            @remarks
-                This method normalises the plane's normal and the length scale of d
-                is as well.
-            @note
-                This function will not crash for zero-sized vectors, but there
-                will be no changes made to their components.
-            @returns The previous length of the plane's normal.
-        */
-        float normalize(void);
-
-		/** Ray / plane intersection, returns boolean result and distance. */
+        /**
+		 * @brief	Normalizes the plane's normal and the length scale of d
+		 *			is as well.
+         */
+        float normalize();
+
+		/**
+		 * @brief	Box/plane intersection.
+		 */
+		bool intersects(const AABox& box) const;
+
+		/**
+		 * @brief	Sphere/plane intersection.
+		 */
+		bool intersects(const Sphere& sphere) const;
+
+		/**
+		 * @brief	Ray/plane intersection, returns boolean result and distance.
+		 */
 		std::pair<bool, float> intersects(const Ray& ray) const;
 
-		Vector3 normal;
-        float d;
-
-        /// Comparison operator
         bool operator==(const Plane& rhs) const
         {
             return (rhs.d == d && rhs.normal == normal);
@@ -156,12 +119,11 @@ namespace CamelotFramework {
         {
             return (rhs.d != d || rhs.normal != normal);
         }
+
+	public:
+		Vector3 normal;
+		float d;
     };
 
     typedef Vector<Plane>::type PlaneList;
-	/** @} */
-	/** @} */
-
-} // namespace CamelotFramework
-
-#endif
+}

+ 44 - 45
CamelotUtility/Include/CmSphere.h

@@ -25,81 +25,80 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 -----------------------------------------------------------------------------
 */
-#ifndef __Sphere_H_
-#define __Sphere_H_
+#pragma once
 
-// Precompiler options
 #include "CmPrerequisitesUtil.h"
-
 #include "CmVector3.h"
 
-namespace CamelotFramework {
-
-
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup Math
-	*  @{
-	*/
-	/** A sphere primitive, mostly used for bounds checking. 
-    @remarks
-        A sphere in math texts is normally represented by the function
-        x^2 + y^2 + z^2 = r^2 (for sphere's centered on the origin). Engine stores spheres
-        simply as a center point and a radius.
-    */
+namespace CamelotFramework 
+{
     class CM_UTILITY_EXPORT Sphere
     {
-    protected:
-        float mRadius;
-        Vector3 mCenter;
     public:
-        /** Standard constructor - creates a unit sphere around the origin.*/
-        Sphere() : mRadius(1.0), mCenter(Vector3::ZERO) {}
-        /** Constructor allowing arbitrary spheres. 
-            @param center The center point of the sphere.
-            @param radius The radius of the sphere.
-        */
+        /**
+         * @brief	Default constructor. Creates a unit sphere around the origin.
+         */
+        Sphere() : mRadius(1.0), mCenter(Vector3::ZERO) 
+		{ }
+
         Sphere(const Vector3& center, float radius)
-            : mRadius(radius), mCenter(center) {}
+            :mRadius(radius), mCenter(center) 
+		{ }
 
-        /** Returns the radius of the sphere. */
+        /**
+         * @brief	Returns the radius of the sphere.
+         */
         float getRadius(void) const { return mRadius; }
 
-        /** Sets the radius of the sphere. */
+        /**
+         * @brief	Sets the radius of the sphere.
+         */
         void setRadius(float radius) { mRadius = radius; }
 
-        /** Returns the center point of the sphere. */
+        /**
+         * @brief	Returns the center point of the sphere.
+         */
         const Vector3& getCenter(void) const { return mCenter; }
 
-        /** Sets the center point of the sphere. */
+        /**
+         * @brief	Sets the center point of the sphere.
+         */
         void setCenter(const Vector3& center) { mCenter = center; }
 
-		/** Returns whether or not this sphere intersects another sphere. */
+		/**
+		 * @brief	Returns whether or not this sphere intersects another sphere.
+		 */
 		bool intersects(const Sphere& s) const
 		{
             return (s.mCenter - mCenter).squaredLength() <=
                 Math::sqr(s.mRadius + mRadius);
 		}
-		/** Returns whether or not this sphere intersects a box. */
+
+		/**
+		 * @brief	Returns whether or not this sphere intersects a box.
+		 */
 		bool intersects(const AABox& box) const;
 
-		/** Returns whether or not this sphere intersects a plane. */
+		/**
+		 * @brief	Returns whether or not this sphere intersects a plane.
+		 */
 		bool intersects(const Plane& plane) const;
 
-		/** Returns whether or not this sphere intersects a point. */
+		/**
+		 * @brief	Returns whether or not this sphere intersects a point.
+		 */
 		bool intersects(const Vector3& v) const
 		{
             return ((v - mCenter).squaredLength() <= Math::sqr(mRadius));
 		}
 
-		/** Ray / sphere intersection, returns boolean result and distance. */
+		/**
+		 * @brief	Ray / sphere intersection, returns boolean result and distance.
+		 */
 		std::pair<bool, float> intersects(const Ray& ray, bool discardInside = true) const;
-    };
-	/** @} */
-	/** @} */
-
-}
-
-#endif
 
+	private:
+		float mRadius;
+		Vector3 mCenter;
+    };
+}

+ 498 - 0
CamelotUtility/Source/CmAABox.cpp

@@ -0,0 +1,498 @@
+#include "CmAABox.h"
+#include "CmRay.h"
+#include "CmPlane.h"
+#include "CmSphere.h"
+
+namespace CamelotFramework
+{
+	const AABox AABox::BOX_EMPTY;
+
+	AABox::AABox() 
+		:mMinimum(Vector3::ZERO), mMaximum(Vector3::ONE)
+	{
+		// Default to a null box 
+		setMin(Vector3(-0.5f, -0.5f, -0.5f));
+		setMax(Vector3(0.5f, 0.5f, 0.5f));
+	}
+
+	AABox::AABox(const AABox& copy)
+		:mMinimum(Vector3::ZERO), mMaximum(Vector3::ONE)
+	{
+		setExtents(copy.mMinimum, copy.mMaximum);
+	}
+
+	AABox::AABox(const Vector3& min, const Vector3& max)
+		:mMinimum(Vector3::ZERO), mMaximum(Vector3::ONE)
+	{
+		setExtents(min, max);
+	}
+
+	AABox& AABox::operator=(const AABox& rhs)
+	{
+		setExtents(rhs.mMinimum, rhs.mMaximum);
+
+		return *this;
+	}
+
+	void AABox::setExtents(const Vector3& min, const Vector3& max)
+	{
+        assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) &&
+            "The minimum corner of the box must be less than or equal to maximum corner" );
+
+		mMinimum = min;
+		mMaximum = max;
+	}
+
+	void AABox::scale(const Vector3& s)
+	{
+		Vector3 center = getCenter();
+		Vector3 min = center + (mMinimum - center) * s;
+		Vector3 max = center + (mMaximum - center) * s;
+
+		setExtents(min, max);
+	}
+
+	Vector3 AABox::getCorner(CornerEnum cornerToGet) const
+	{
+		switch(cornerToGet)
+		{
+		case FAR_LEFT_BOTTOM:
+			return mMinimum;
+		case FAR_LEFT_TOP:
+			return Vector3(mMinimum.x, mMaximum.y, mMinimum.z);
+		case FAR_RIGHT_TOP:
+			return Vector3(mMaximum.x, mMaximum.y, mMinimum.z);
+		case FAR_RIGHT_BOTTOM:
+			return Vector3(mMaximum.x, mMinimum.y, mMinimum.z);
+		case NEAR_RIGHT_BOTTOM:
+			return Vector3(mMaximum.x, mMinimum.y, mMaximum.z);
+		case NEAR_LEFT_BOTTOM:
+			return Vector3(mMinimum.x, mMinimum.y, mMaximum.z);
+		case NEAR_LEFT_TOP:
+			return Vector3(mMinimum.x, mMaximum.y, mMaximum.z);
+		case NEAR_RIGHT_TOP:
+			return mMaximum;
+		default:
+			return Vector3();
+		}
+	}
+
+	void AABox::merge(const AABox& rhs)
+	{
+		Vector3 min = mMinimum;
+		Vector3 max = mMaximum;
+		max.ceil(rhs.mMaximum);
+		min.floor(rhs.mMinimum);
+
+		setExtents(min, max);
+	}
+
+	void AABox::merge(const Vector3& point)
+	{
+		mMaximum.ceil(point);
+		mMinimum.floor(point);
+	}
+
+	void AABox::transform(const Matrix4& matrix)
+	{
+		Vector3 oldMin, oldMax, currentCorner;
+
+		// Getting the old values so that we can use the existing merge method.
+		oldMin = mMinimum;
+		oldMax = mMaximum;
+
+		// We sequentially compute the corners in the following order :
+		// 0, 6, 5, 1, 2, 4 ,7 , 3
+		// This sequence allows us to only change one member at a time to get at all corners.
+
+		// For each one, we transform it using the matrix
+		// Which gives the resulting point and merge the resulting point.
+
+		// First corner 
+		// min min min
+		currentCorner = oldMin;
+		merge(matrix.transform3x4(currentCorner));
+
+		// min,min,max
+		currentCorner.z = oldMax.z;
+		merge(matrix.transform3x4(currentCorner));
+
+		// min max max
+		currentCorner.y = oldMax.y;
+		merge(matrix.transform3x4(currentCorner));
+
+		// min max min
+		currentCorner.z = oldMin.z;
+		merge(matrix.transform3x4(currentCorner));
+
+		// max max min
+		currentCorner.x = oldMax.x;
+		merge(matrix.transform3x4(currentCorner));
+
+		// max max max
+		currentCorner.z = oldMax.z;
+		merge(matrix.transform3x4(currentCorner));
+
+		// max min max
+		currentCorner.y = oldMin.y;
+		merge(matrix.transform3x4(currentCorner));
+
+		// max min min
+		currentCorner.z = oldMin.z;
+		merge(matrix.transform3x4(currentCorner)); 
+	}
+
+	void AABox::transformAffine(const Matrix4& m)
+	{
+		assert(m.isAffine());
+
+		Vector3 centre = getCenter();
+		Vector3 halfSize = getHalfSize();
+
+		Vector3 newCentre = m.transform3x4(centre);
+		Vector3 newHalfSize(
+			Math::abs(m[0][0]) * halfSize.x + Math::abs(m[0][1]) * halfSize.y + Math::abs(m[0][2]) * halfSize.z, 
+			Math::abs(m[1][0]) * halfSize.x + Math::abs(m[1][1]) * halfSize.y + Math::abs(m[1][2]) * halfSize.z,
+			Math::abs(m[2][0]) * halfSize.x + Math::abs(m[2][1]) * halfSize.y + Math::abs(m[2][2]) * halfSize.z);
+
+		setExtents(newCentre - newHalfSize, newCentre + newHalfSize);
+	}
+
+	AABox AABox::intersection(const AABox& b2) const
+	{
+		Vector3 intMin = mMinimum;
+        Vector3 intMax = mMaximum;
+
+        intMin.ceil(b2.getMin());
+        intMax.floor(b2.getMax());
+
+        // Check intersection isn't null
+        if (intMin.x < intMax.x &&
+            intMin.y < intMax.y &&
+            intMin.z < intMax.z)
+        {
+            return AABox(intMin, intMax);
+        }
+
+        return AABox();
+	}
+
+	bool AABox::intersects(const AABox& b2) const
+	{
+		// Use up to 6 separating planes
+		if (mMaximum.x < b2.mMinimum.x)
+			return false;
+		if (mMaximum.y < b2.mMinimum.y)
+			return false;
+		if (mMaximum.z < b2.mMinimum.z)
+			return false;
+
+		if (mMinimum.x > b2.mMaximum.x)
+			return false;
+		if (mMinimum.y > b2.mMaximum.y)
+			return false;
+		if (mMinimum.z > b2.mMaximum.z)
+			return false;
+
+		// Otherwise, must be intersecting
+		return true;
+	}
+
+	bool AABox::intersects(const Sphere& sphere) const
+	{
+		// Use splitting planes
+		const Vector3& center = sphere.getCenter();
+		float radius = sphere.getRadius();
+		const Vector3& min = getMin();
+		const Vector3& max = getMax();
+
+		// Arvo's algorithm
+		float s, d = 0;
+		for (int i = 0; i < 3; ++i)
+		{
+			if (center.ptr()[i] < min.ptr()[i])
+			{
+				s = center.ptr()[i] - min.ptr()[i];
+				d += s * s; 
+			}
+			else if(center.ptr()[i] > max.ptr()[i])
+			{
+				s = center.ptr()[i] - max.ptr()[i];
+				d += s * s; 
+			}
+		}
+		return d <= radius * radius;
+	}
+
+	bool AABox::intersects(const Plane& p) const
+	{
+		return (p.getSide(*this) == Plane::BOTH_SIDE);
+	}
+
+	bool AABox::intersects(const Vector3& v) const
+	{
+		return(v.x >= mMinimum.x  &&  v.x <= mMaximum.x  && 
+			v.y >= mMinimum.y  &&  v.y <= mMaximum.y  && 
+			v.z >= mMinimum.z  &&  v.z <= mMaximum.z);
+	}
+
+	std::pair<bool, float> AABox::intersects(const Ray& ray) const
+	{
+		float lowt = 0.0f;
+		float t;
+		bool hit = false;
+		Vector3 hitpoint;
+		const Vector3& min = getMin();
+		const Vector3& max = getMax();
+		const Vector3& rayorig = ray.getOrigin();
+		const Vector3& raydir = ray.getDirection();
+
+		// Check origin inside first
+		if ((rayorig.x > min.x && rayorig.y > min.y && rayorig.z > min.z) && (rayorig.x < max.x && rayorig.y < max.y && rayorig.z < max.z))
+		{
+			return std::pair<bool, float>(true, 0.0f);
+		}
+
+		// Check each face in turn, only check closest 3
+		// Min x
+		if (rayorig.x <= min.x && raydir.x > 0)
+		{
+			t = (min.x - rayorig.x) / raydir.x;
+			if (t >= 0)
+			{
+				// Substitute t back into ray and check bounds and dist
+				hitpoint = rayorig + raydir * t;
+				if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
+					hitpoint.z >= min.z && hitpoint.z <= max.z &&
+					(!hit || t < lowt))
+				{
+					hit = true;
+					lowt = t;
+				}
+			}
+		}
+		// Max x
+		if (rayorig.x >= max.x && raydir.x < 0)
+		{
+			t = (max.x - rayorig.x) / raydir.x;
+			if (t >= 0)
+			{
+				// Substitute t back into ray and check bounds and dist
+				hitpoint = rayorig + raydir * t;
+				if (hitpoint.y >= min.y && hitpoint.y <= max.y &&
+					hitpoint.z >= min.z && hitpoint.z <= max.z &&
+					(!hit || t < lowt))
+				{
+					hit = true;
+					lowt = t;
+				}
+			}
+		}
+		// Min y
+		if (rayorig.y <= min.y && raydir.y > 0)
+		{
+			t = (min.y - rayorig.y) / raydir.y;
+			if (t >= 0)
+			{
+				// Substitute t back into ray and check bounds and dist
+				hitpoint = rayorig + raydir * t;
+				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
+					hitpoint.z >= min.z && hitpoint.z <= max.z &&
+					(!hit || t < lowt))
+				{
+					hit = true;
+					lowt = t;
+				}
+			}
+		}
+		// Max y
+		if (rayorig.y >= max.y && raydir.y < 0)
+		{
+			t = (max.y - rayorig.y) / raydir.y;
+			if (t >= 0)
+			{
+				// Substitute t back into ray and check bounds and dist
+				hitpoint = rayorig + raydir * t;
+				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
+					hitpoint.z >= min.z && hitpoint.z <= max.z &&
+					(!hit || t < lowt))
+				{
+					hit = true;
+					lowt = t;
+				}
+			}
+		}
+		// Min z
+		if (rayorig.z <= min.z && raydir.z > 0)
+		{
+			t = (min.z - rayorig.z) / raydir.z;
+			if (t >= 0)
+			{
+				// Substitute t back into ray and check bounds and dist
+				hitpoint = rayorig + raydir * t;
+				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
+					hitpoint.y >= min.y && hitpoint.y <= max.y &&
+					(!hit || t < lowt))
+				{
+					hit = true;
+					lowt = t;
+				}
+			}
+		}
+		// Max z
+		if (rayorig.z >= max.z && raydir.z < 0)
+		{
+			t = (max.z - rayorig.z) / raydir.z;
+			if (t >= 0)
+			{
+				// Substitute t back into ray and check bounds and dist
+				hitpoint = rayorig + raydir * t;
+				if (hitpoint.x >= min.x && hitpoint.x <= max.x &&
+					hitpoint.y >= min.y && hitpoint.y <= max.y &&
+					(!hit || t < lowt))
+				{
+					hit = true;
+					lowt = t;
+				}
+			}
+		}
+
+		return std::pair<bool, float>(hit, lowt);
+
+	} 
+
+	bool AABox::intersects(const Ray& ray, float& d1, float& d2) const
+	{
+		const Vector3& min = getMin();
+		const Vector3& max = getMax();
+		const Vector3& rayorig = ray.getOrigin();
+		const Vector3& raydir = ray.getDirection();
+
+		Vector3 absDir;
+		absDir[0] = Math::abs(raydir[0]);
+		absDir[1] = Math::abs(raydir[1]);
+		absDir[2] = Math::abs(raydir[2]);
+
+		// Sort the axis, ensure check minimise floating error axis first
+		int imax = 0, imid = 1, imin = 2;
+		if (absDir[0] < absDir[2])
+		{
+			imax = 2;
+			imin = 0;
+		}
+		if (absDir[1] < absDir[imin])
+		{
+			imid = imin;
+			imin = 1;
+		}
+		else if (absDir[1] > absDir[imax])
+		{
+			imid = imax;
+			imax = 1;
+		}
+
+		float start = 0, end = Math::POS_INFINITY;
+
+#define _CALC_AXIS(i)                                       \
+	do {                                                    \
+	float denom = 1 / raydir[i];                         \
+	float newstart = (min[i] - rayorig[i]) * denom;      \
+	float newend = (max[i] - rayorig[i]) * denom;        \
+	if (newstart > newend) std::swap(newstart, newend); \
+	if (newstart > end || newend < start) return false; \
+	if (newstart > start) start = newstart;             \
+	if (newend < end) end = newend;                     \
+	} while(0)
+
+		// Check each axis in turn
+
+		_CALC_AXIS(imax);
+
+		if (absDir[imid] < std::numeric_limits<float>::epsilon())
+		{
+			// Parallel with middle and minimise axis, check bounds only
+			if (rayorig[imid] < min[imid] || rayorig[imid] > max[imid] ||
+				rayorig[imin] < min[imin] || rayorig[imin] > max[imin])
+				return false;
+		}
+		else
+		{
+			_CALC_AXIS(imid);
+
+			if (absDir[imin] < std::numeric_limits<float>::epsilon())
+			{
+				// Parallel with minimise axis, check bounds only
+				if (rayorig[imin] < min[imin] || rayorig[imin] > max[imin])
+					return false;
+			}
+			else
+			{
+				_CALC_AXIS(imin);
+			}
+		}
+#undef _CALC_AXIS
+
+		d1 = start;
+		d2 = end;
+
+		return true;
+	}
+
+	Vector3 AABox::getCenter() const
+	{
+		return Vector3(
+			(mMaximum.x + mMinimum.x) * 0.5f,
+			(mMaximum.y + mMinimum.y) * 0.5f,
+			(mMaximum.z + mMinimum.z) * 0.5f);
+	}
+
+	Vector3 AABox::getSize() const
+	{
+		return mMaximum - mMinimum;
+	}
+
+	Vector3 AABox::getHalfSize() const
+	{
+		return (mMaximum - mMinimum) * 0.5;
+	}
+
+	float AABox::getRadius() const
+	{
+		return (mMaximum - mMinimum).length();
+	}
+
+	float AABox::getVolume() const
+	{
+		Vector3 diff = mMaximum - mMinimum;
+		return diff.x * diff.y * diff.z;
+	}
+
+    bool AABox::contains(const Vector3& v) const
+    {
+        return mMinimum.x <= v.x && v.x <= mMaximum.x &&
+                mMinimum.y <= v.y && v.y <= mMaximum.y &&
+                mMinimum.z <= v.z && v.z <= mMaximum.z;
+    }
+
+    bool AABox::contains(const AABox& other) const
+    {
+        return this->mMinimum.x <= other.mMinimum.x &&
+                this->mMinimum.y <= other.mMinimum.y &&
+                this->mMinimum.z <= other.mMinimum.z &&
+                other.mMaximum.x <= this->mMaximum.x &&
+                other.mMaximum.y <= this->mMaximum.y &&
+                other.mMaximum.z <= this->mMaximum.z;
+    }
+
+    bool AABox::operator== (const AABox& rhs) const
+    {
+        return this->mMinimum == rhs.mMinimum &&
+                this->mMaximum == rhs.mMaximum;
+    }
+
+    bool AABox::operator!= (const AABox& rhs) const
+    {
+        return !(*this == rhs);
+    }
+}
+

+ 62 - 70
CamelotUtility/Source/CmPlane.cpp

@@ -29,104 +29,86 @@ THE SOFTWARE.
 #include "CmPlane.h"
 #include "CmMatrix3.h"
 #include "CmAABox.h"
+#include "CmSphere.h"
 #include "CmRay.h"
 
-namespace CamelotFramework {
-	//-----------------------------------------------------------------------
-	Plane::Plane ()
+namespace CamelotFramework 
+{
+	Plane::Plane()
 	{
 		normal = Vector3::ZERO;
 		d = 0.0;
 	}
-	//-----------------------------------------------------------------------
-	Plane::Plane (const Plane& rhs)
+
+	Plane::Plane(const Plane& copy)
 	{
-		normal = rhs.normal;
-		d = rhs.d;
+		normal = copy.normal;
+		d = copy.d;
 	}
-	//-----------------------------------------------------------------------
-	Plane::Plane (const Vector3& rkNormal, float fConstant)
+
+	Plane::Plane(const Vector3& normal, float d)
 	{
-		normal = rkNormal;
-		d = -fConstant;
+		this->normal = normal;
+		this->d = -d;
 	}
-	//---------------------------------------------------------------------
-	Plane::Plane (float a, float b, float c, float _d)
+
+	Plane::Plane(float a, float b, float c, float _d)
 		: normal(a, b, c), d(_d)
+	{ }
+
+	Plane::Plane(const Vector3& normal, const Vector3& point)
 	{
+		this->normal = normal;
+		d = -normal.dot(point);
 	}
-	//-----------------------------------------------------------------------
-	Plane::Plane (const Vector3& rkNormal, const Vector3& rkPoint)
-	{
-		redefine(rkNormal, rkPoint);
-	}
-	//-----------------------------------------------------------------------
-	Plane::Plane (const Vector3& rkPoint0, const Vector3& rkPoint1,
-		const Vector3& rkPoint2)
+
+	Plane::Plane(const Vector3& point0, const Vector3& point1, const Vector3& point2)
 	{
-		redefine(rkPoint0, rkPoint1, rkPoint2);
+		Vector3 kEdge1 = point1 - point0;
+		Vector3 kEdge2 = point2 - point0;
+		normal = kEdge1.cross(kEdge2);
+		normal.normalize();
+		d = -normal.dot(point0);
 	}
-	//-----------------------------------------------------------------------
-	float Plane::getDistance (const Vector3& rkPoint) const
+
+	float Plane::getDistance(const Vector3& point) const
 	{
-		return normal.dot(rkPoint) + d;
+		return normal.dot(point) + d;
 	}
-	//-----------------------------------------------------------------------
-	Plane::Side Plane::getSide (const Vector3& rkPoint) const
+
+	Plane::Side Plane::getSide(const Vector3& point) const
 	{
-		float fDistance = getDistance(rkPoint);
+		float dist = getDistance(point);
 
-		if ( fDistance < 0.0 )
+		if (dist < 0.0f)
 			return Plane::NEGATIVE_SIDE;
 
-		if ( fDistance > 0.0 )
+		if (dist > 0.0f)
 			return Plane::POSITIVE_SIDE;
 
 		return Plane::NO_SIDE;
 	}
 
-
-	//-----------------------------------------------------------------------
-	Plane::Side Plane::getSide (const AABox& box) const
+	Plane::Side Plane::getSide(const AABox& box) const
 	{
-        return getSide(box.getCenter(), box.getHalfSize());
-	}
-    //-----------------------------------------------------------------------
-    Plane::Side Plane::getSide (const Vector3& centre, const Vector3& halfSize) const
-    {
-        // Calculate the distance between box centre and the plane
-        float dist = getDistance(centre);
+		// Calculate the distance between box centre and the plane
+		float dist = getDistance(box.getCenter());
 
-        // Calculate the maximise allows absolute distance for
-        // the distance between box centre and plane
-        float maxAbsDist = Math::abs(normal.x * halfSize.x) + Math::abs(normal.y * halfSize.y) + Math::abs(normal.z * halfSize.z);
+		// Calculate the maximize allows absolute distance for
+		// the distance between box centre and plane
+		Vector3 halfSize = box.getHalfSize();
+		float maxAbsDist = Math::abs(normal.x * halfSize.x) + Math::abs(normal.y * halfSize.y) + Math::abs(normal.z * halfSize.z);
 
-        if (dist < -maxAbsDist)
-            return Plane::NEGATIVE_SIDE;
+		if (dist < -maxAbsDist)
+			return Plane::NEGATIVE_SIDE;
 
-        if (dist > +maxAbsDist)
-            return Plane::POSITIVE_SIDE;
+		if (dist > +maxAbsDist)
+			return Plane::POSITIVE_SIDE;
 
-        return Plane::BOTH_SIDE;
-    }
-	//-----------------------------------------------------------------------
-	void Plane::redefine(const Vector3& rkPoint0, const Vector3& rkPoint1,
-		const Vector3& rkPoint2)
-	{
-		Vector3 kEdge1 = rkPoint1 - rkPoint0;
-		Vector3 kEdge2 = rkPoint2 - rkPoint0;
-		normal = kEdge1.cross(kEdge2);
-		normal.normalize();
-		d = -normal.dot(rkPoint0);
-	}
-	//-----------------------------------------------------------------------
-	void Plane::redefine(const Vector3& rkNormal, const Vector3& rkPoint)
-	{
-		normal = rkNormal;
-		d = -rkNormal.dot(rkPoint);
+		return Plane::BOTH_SIDE;
 	}
-	//-----------------------------------------------------------------------
-	Vector3 Plane::projectVector(const Vector3& p) const
+
+	Vector3 Plane::projectVector(const Vector3& point) const
 	{
 		// We know plane normal is unit length, so use simple method
 		Matrix3 xform;
@@ -139,11 +121,11 @@ namespace CamelotFramework {
 		xform[2][0] = -normal.z * normal.x;
 		xform[2][1] = -normal.z * normal.y;
 		xform[2][2] = 1.0f - normal.z * normal.z;
-		return xform.transform(p);
+		return xform.transform(point);
 
 	}
-	//-----------------------------------------------------------------------
-    float Plane::normalize(void)
+
+    float Plane::normalize()
     {
         float fLength = normal.length();
 
@@ -158,6 +140,16 @@ namespace CamelotFramework {
         return fLength;
     }
 
+	bool Plane::intersects(const AABox& box) const
+	{
+		return box.intersects(*this);
+	}
+
+	bool Plane::intersects(const Sphere& sphere) const
+	{
+		return sphere.intersects(*this);
+	}
+
 	std::pair<bool, float> Plane::intersects(const Ray& ray) const
 	{
 		float denom = normal.dot(ray.getDirection());
@@ -170,7 +162,7 @@ namespace CamelotFramework {
 		{
 			float nom = normal.dot(ray.getOrigin()) + d;
 			float t = -(nom/denom);
-			return std::pair<bool, float>(t >= 0, t);
+			return std::pair<bool, float>(t >= 0.0f, t);
 		}
 	}
 }

+ 6 - 8
CamelotUtility/Source/CmSphere.cpp

@@ -8,7 +8,6 @@ namespace CamelotFramework
 	std::pair<bool, float> Sphere::intersects(const Ray& ray, bool discardInside) const
 	{
 		const Vector3& raydir = ray.getDirection();
-		// Adjust ray origin relative to sphere center
 		const Vector3& rayorig = ray.getOrigin() - getCenter();
 		float radius = getRadius();
 
@@ -18,14 +17,12 @@ namespace CamelotFramework
 			return std::pair<bool, float>(true, 0.0f);
 		}
 
-		// Mmm, quadratics
-		// Build coeffs which can be used with std quadratic solver
-		// ie t = (-b +/- sqrt(b*b + 4ac)) / 2a
+		// t = (-b +/- sqrt(b*b + 4ac)) / 2a
 		float a = raydir.dot(raydir);
 		float b = 2 * rayorig.dot(raydir);
 		float c = rayorig.dot(rayorig) - radius*radius;
 
-		// Calc determinant
+		// Determinant
 		float d = (b*b) - (4 * a * c);
 		if (d < 0)
 		{
@@ -34,12 +31,13 @@ namespace CamelotFramework
 		}
 		else
 		{
-			// BTW, if d=0 there is one intersection, if d > 0 there are 2
-			// But we only want the closest one, so that's ok, just use the 
-			// '-' version of the solver
+			// If d == 0 there is one intersection, if d > 0 there are 2.
+			// We only return the first one.
+			
 			float t = ( -b - Math::sqrt(d) ) / (2 * a);
 			if (t < 0)
 				t = ( -b + Math::sqrt(d) ) / (2 * a);
+
 			return std::pair<bool, float>(true, t);
 		}
 	}