1 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3 * Contains AABB-related code. (axis-aligned bounding box)
5 * \author Pierre Terdiman
6 * \date January, 13, 2000
8 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
10 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
15 inline_ void ComputeMinMax(const Point& p, Point& min, Point& max)
17 if(p.x > max.x) max.x = p.x;
18 if(p.x < min.x) min.x = p.x;
20 if(p.y > max.y) max.y = p.y;
21 if(p.y < min.y) min.y = p.y;
23 if(p.z > max.z) max.z = p.z;
24 if(p.z < min.z) min.z = p.z;
27 // Forward declarations
30 //! Declarations of type-independent methods (most of them implemented in the .cpp)
31 #define AABB_COMMON_METHODS \
32 AABB& Add(const AABB& aabb); \
33 AABB& Sub(const AABB& aabb); \
34 float MakeCube(AABB& cube) const; \
35 void MakeSphere(Sphere& sphere) const; \
36 const sbyte* ComputeOutline(const Point& local_eye, sdword& num) const; \
37 float ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num) const; \
38 bool IsInside(const AABB& box) const; \
39 bool ComputePlanes(Plane* planes) const; \
40 bool ComputePoints(Point* pts) const; \
41 const Point* GetVertexNormals() const; \
42 const udword* GetEdges() const; \
43 const Point* GetEdgeNormals() const; \
44 inline_ BOOL ContainsPoint(const Point& p) const \
46 if(p.x > GetMax(0) || p.x < GetMin(0)) return FALSE; \
47 if(p.y > GetMax(1) || p.y < GetMin(1)) return FALSE; \
48 if(p.z > GetMax(2) || p.z < GetMin(2)) return FALSE; \
54 AABB_RENDER = 0, //!< AABB used for rendering. Not visible == not rendered.
55 AABB_UPDATE = 1, //!< AABB used for dynamic updates. Not visible == not updated.
57 AABB_FORCE_DWORD = 0x7fffffff,
62 struct ICEMATHS_API ShadowAABB
68 class ICEMATHS_API AABB : public Allocateable
76 //! Type-independent methods
79 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
81 * Setups an AABB from min & max vectors.
82 * \param min [in] the min point
83 * \param max [in] the max point
85 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
86 void SetMinMax(const Point& min, const Point& max) { mMin = min; mMax = max; }
88 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
90 * Setups an AABB from center & extents vectors.
91 * \param c [in] the center point
92 * \param e [in] the extents vector
94 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
95 void SetCenterExtents(const Point& c, const Point& e) { mMin = c - e; mMax = c + e; }
97 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
99 * Setups an empty AABB.
101 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
102 void SetEmpty() { Point p(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); mMin = -p; mMax = p;}
104 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
106 * Setups a point AABB.
108 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
109 void SetPoint(const Point& pt) { mMin = mMax = pt; }
111 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
113 * Gets the size of the AABB. The size is defined as the longest extent.
114 * \return the size of the AABB
116 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
117 float GetSize() const { Point e; GetExtents(e); return e.Max(); }
119 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
122 * \param p [in] the next point
124 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
125 inline_ void Extend(const Point& p) { ComputeMinMax(p, mMin, mMax); }
129 //! Get min point of the box
130 inline_ void GetMin(Point& min) const { min = mMin; }
131 //! Get max point of the box
132 inline_ void GetMax(Point& max) const { max = mMax; }
134 //! Get component of the box's min point along a given axis
135 inline_ float GetMin(udword axis) const { return mMin[axis]; }
136 //! Get component of the box's max point along a given axis
137 inline_ float GetMax(udword axis) const { return mMax[axis]; }
140 inline_ void GetCenter(Point& center) const { center = (mMax + mMin)*0.5f; }
142 inline_ void GetExtents(Point& extents) const { extents = (mMax - mMin)*0.5f; }
144 //! Get component of the box's center along a given axis
145 inline_ float GetCenter(udword axis) const { return (mMax[axis] + mMin[axis])*0.5f; }
146 //! Get component of the box's extents along a given axis
147 inline_ float GetExtents(udword axis) const { return (mMax[axis] - mMin[axis])*0.5f; }
150 inline_ void GetDiagonal(Point& diagonal) const { diagonal = mMax - mMin; }
151 inline_ float GetWidth() const { return mMax.x - mMin.x; }
152 inline_ float GetHeight() const { return mMax.y - mMin.y; }
153 inline_ float GetDepth() const { return mMax.z - mMin.z; }
156 inline_ float GetVolume() const { return GetWidth() * GetHeight() * GetDepth(); }
158 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
160 * Computes the intersection between two AABBs.
161 * \param a [in] the other AABB
162 * \return true on intersection
164 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
165 inline_ BOOL Intersect(const AABB& a) const
172 || a.mMax.z < mMin.z) return FALSE;
177 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
179 * Computes the 1D-intersection between two AABBs, on a given axis.
180 * \param a [in] the other AABB
181 * \param axis [in] the axis (0, 1, 2)
182 * \return true on intersection
184 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
185 inline_ BOOL Intersect(const AABB& a, udword axis) const
187 if(mMax[axis] < a.mMin[axis] || a.mMax[axis] < mMin[axis]) return FALSE;
191 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
193 * Recomputes the AABB after an arbitrary transform by a 4x4 matrix.
194 * Original code by Charles Bloom on the GD-Algorithm list. (I slightly modified it)
195 * \param mtx [in] the transform matrix
196 * \param aabb [out] the transformed AABB [can be *this]
198 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
199 inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const
201 // The three edges transformed: you can efficiently transform an X-only vector
202 // by just getting the "X" column of the matrix
204 mtx.GetRow(0, vx); vx *= (mMax.x - mMin.x);
205 mtx.GetRow(1, vy); vy *= (mMax.y - mMin.y);
206 mtx.GetRow(2, vz); vz *= (mMax.z - mMin.z);
208 // Transform the min point
209 aabb.mMin = aabb.mMax = mMin * mtx;
211 // Take the transformed min & axes and find new extents
212 // Using CPU code in the right place is faster...
213 if(IS_NEGATIVE_FLOAT(vx.x)) aabb.mMin.x += vx.x; else aabb.mMax.x += vx.x;
214 if(IS_NEGATIVE_FLOAT(vx.y)) aabb.mMin.y += vx.y; else aabb.mMax.y += vx.y;
215 if(IS_NEGATIVE_FLOAT(vx.z)) aabb.mMin.z += vx.z; else aabb.mMax.z += vx.z;
216 if(IS_NEGATIVE_FLOAT(vy.x)) aabb.mMin.x += vy.x; else aabb.mMax.x += vy.x;
217 if(IS_NEGATIVE_FLOAT(vy.y)) aabb.mMin.y += vy.y; else aabb.mMax.y += vy.y;
218 if(IS_NEGATIVE_FLOAT(vy.z)) aabb.mMin.z += vy.z; else aabb.mMax.z += vy.z;
219 if(IS_NEGATIVE_FLOAT(vz.x)) aabb.mMin.x += vz.x; else aabb.mMax.x += vz.x;
220 if(IS_NEGATIVE_FLOAT(vz.y)) aabb.mMin.y += vz.y; else aabb.mMax.y += vz.y;
221 if(IS_NEGATIVE_FLOAT(vz.z)) aabb.mMin.z += vz.z; else aabb.mMax.z += vz.z;
224 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
226 * Checks the AABB is valid.
227 * \return true if the box is valid
229 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
230 inline_ BOOL IsValid() const
232 // Consistency condition for (Min, Max) boxes: min < max
233 if(mMin.x > mMax.x) return FALSE;
234 if(mMin.y > mMax.y) return FALSE;
235 if(mMin.z > mMax.z) return FALSE;
239 //! Operator for AABB *= float. Scales the extents, keeps same center.
240 inline_ AABB& operator*=(float s)
242 Point Center; GetCenter(Center);
243 Point Extents; GetExtents(Extents);
244 SetCenterExtents(Center, Extents * s);
248 //! Operator for AABB /= float. Scales the extents, keeps same center.
249 inline_ AABB& operator/=(float s)
251 Point Center; GetCenter(Center);
252 Point Extents; GetExtents(Extents);
253 SetCenterExtents(Center, Extents / s);
257 //! Operator for AABB += Point. Translates the box.
258 inline_ AABB& operator+=(const Point& trans)
265 Point mMin; //!< Min point
266 Point mMax; //!< Max point
271 class ICEMATHS_API AABB
279 //! Type-independent methods
282 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
284 * Setups an AABB from min & max vectors.
285 * \param min [in] the min point
286 * \param max [in] the max point
288 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
289 void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; }
291 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
293 * Setups an AABB from center & extents vectors.
294 * \param c [in] the center point
295 * \param e [in] the extents vector
297 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
298 void SetCenterExtents(const Point& c, const Point& e) { mCenter = c; mExtents = e; }
300 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
302 * Setups an empty AABB.
304 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
305 void SetEmpty() { mCenter.Zero(); mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);}
307 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
309 * Setups a point AABB.
311 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
312 void SetPoint(const Point& pt) { mCenter = pt; mExtents.Zero(); }
314 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
316 * Gets the size of the AABB. The size is defined as the longest extent.
317 * \return the size of the AABB
319 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
320 float GetSize() const { return mExtents.Max(); }
322 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
325 * \param p [in] the next point
327 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
328 void Extend(const Point& p)
330 Point Max = mCenter + mExtents;
331 Point Min = mCenter - mExtents;
333 if(p.x > Max.x) Max.x = p.x;
334 if(p.x < Min.x) Min.x = p.x;
336 if(p.y > Max.y) Max.y = p.y;
337 if(p.y < Min.y) Min.y = p.y;
339 if(p.z > Max.z) Max.z = p.z;
340 if(p.z < Min.z) Min.z = p.z;
346 //! Get min point of the box
347 inline_ void GetMin(Point& min) const { min = mCenter - mExtents; }
348 //! Get max point of the box
349 inline_ void GetMax(Point& max) const { max = mCenter + mExtents; }
351 //! Get component of the box's min point along a given axis
352 inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; }
353 //! Get component of the box's max point along a given axis
354 inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; }
357 inline_ void GetCenter(Point& center) const { center = mCenter; }
359 inline_ void GetExtents(Point& extents) const { extents = mExtents; }
361 //! Get component of the box's center along a given axis
362 inline_ float GetCenter(udword axis) const { return mCenter[axis]; }
363 //! Get component of the box's extents along a given axis
364 inline_ float GetExtents(udword axis) const { return mExtents[axis]; }
367 inline_ void GetDiagonal(Point& diagonal) const { diagonal = mExtents * 2.0f; }
368 inline_ float GetWidth() const { return mExtents.x * 2.0f; }
369 inline_ float GetHeight() const { return mExtents.y * 2.0f; }
370 inline_ float GetDepth() const { return mExtents.z * 2.0f; }
373 inline_ float GetVolume() const { return mExtents.x * mExtents.y * mExtents.z * 8.0f; }
375 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
377 * Computes the intersection between two AABBs.
378 * \param a [in] the other AABB
379 * \return true on intersection
381 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
382 inline_ BOOL Intersect(const AABB& a) const
384 float tx = mCenter.x - a.mCenter.x; float ex = a.mExtents.x + mExtents.x; if(AIR(tx) > IR(ex)) return FALSE;
385 float ty = mCenter.y - a.mCenter.y; float ey = a.mExtents.y + mExtents.y; if(AIR(ty) > IR(ey)) return FALSE;
386 float tz = mCenter.z - a.mCenter.z; float ez = a.mExtents.z + mExtents.z; if(AIR(tz) > IR(ez)) return FALSE;
390 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
392 * The standard intersection method from Gamasutra. Just here to check its speed against the one above.
393 * \param a [in] the other AABB
394 * \return true on intersection
396 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
397 inline_ bool GomezIntersect(const AABB& a)
399 Point T = mCenter - a.mCenter; // Vector from A to B
400 return ((fabsf(T.x) <= (a.mExtents.x + mExtents.x))
401 && (fabsf(T.y) <= (a.mExtents.y + mExtents.y))
402 && (fabsf(T.z) <= (a.mExtents.z + mExtents.z)));
405 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
407 * Computes the 1D-intersection between two AABBs, on a given axis.
408 * \param a [in] the other AABB
409 * \param axis [in] the axis (0, 1, 2)
410 * \return true on intersection
412 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
413 inline_ BOOL Intersect(const AABB& a, udword axis) const
415 float t = mCenter[axis] - a.mCenter[axis];
416 float e = a.mExtents[axis] + mExtents[axis];
417 if(AIR(t) > IR(e)) return FALSE;
421 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
423 * Recomputes the AABB after an arbitrary transform by a 4x4 matrix.
424 * \param mtx [in] the transform matrix
425 * \param aabb [out] the transformed AABB [can be *this]
427 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
428 inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const
430 // Compute new center
431 aabb.mCenter = mCenter * mtx;
433 // Compute new extents. FPU code & CPU code have been interleaved for improved performance.
434 Point Ex(mtx.m[0][0] * mExtents.x, mtx.m[0][1] * mExtents.x, mtx.m[0][2] * mExtents.x);
435 IR(Ex.x)&=0x7fffffff; IR(Ex.y)&=0x7fffffff; IR(Ex.z)&=0x7fffffff;
437 Point Ey(mtx.m[1][0] * mExtents.y, mtx.m[1][1] * mExtents.y, mtx.m[1][2] * mExtents.y);
438 IR(Ey.x)&=0x7fffffff; IR(Ey.y)&=0x7fffffff; IR(Ey.z)&=0x7fffffff;
440 Point Ez(mtx.m[2][0] * mExtents.z, mtx.m[2][1] * mExtents.z, mtx.m[2][2] * mExtents.z);
441 IR(Ez.x)&=0x7fffffff; IR(Ez.y)&=0x7fffffff; IR(Ez.z)&=0x7fffffff;
443 aabb.mExtents.x = Ex.x + Ey.x + Ez.x;
444 aabb.mExtents.y = Ex.y + Ey.y + Ez.y;
445 aabb.mExtents.z = Ex.z + Ey.z + Ez.z;
448 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
450 * Checks the AABB is valid.
451 * \return true if the box is valid
453 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
454 inline_ BOOL IsValid() const
456 // Consistency condition for (Center, Extents) boxes: Extents >= 0
457 if(IS_NEGATIVE_FLOAT(mExtents.x)) return FALSE;
458 if(IS_NEGATIVE_FLOAT(mExtents.y)) return FALSE;
459 if(IS_NEGATIVE_FLOAT(mExtents.z)) return FALSE;
463 //! Operator for AABB *= float. Scales the extents, keeps same center.
464 inline_ AABB& operator*=(float s) { mExtents*=s; return *this; }
466 //! Operator for AABB /= float. Scales the extents, keeps same center.
467 inline_ AABB& operator/=(float s) { mExtents/=s; return *this; }
469 //! Operator for AABB += Point. Translates the box.
470 inline_ AABB& operator+=(const Point& trans)
476 Point mCenter; //!< AABB Center
477 Point mExtents; //!< x, y and z extents
482 //! Computes the AABB around a set of vertices
483 inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts)
487 Point Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
488 Point Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT);
491 // _prefetch(list+1); // off by one ?
492 ComputeMinMax(*list++, Mini, Maxi);
494 aabb.SetMinMax(Mini, Maxi);
498 //! Computes the AABB around a set of vertices after transform by a matrix
499 inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts, const Matrix4x4& world)
503 Point Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);
504 Point Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT);
507 // _prefetch(list+1); // off by one ?
508 ComputeMinMax((*list++)*world, Mini, Maxi);
510 aabb.SetMinMax(Mini, Maxi);