/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ------------------------------------------------------------------------------*/ #ifndef __NBOUNDINGBOX__ #define __NBOUNDINGBOX__ #include "math/matrix3.h" namespace GS { /*! @short AABB. @author Emmanuel Julien (ejulien@nworks.fr) */ class MinMax { protected: enum { ClipNone = 0, ClipRight = 1, ClipLeft = 2, ClipTop = 4, ClipBottom = 8, ClipFront = 16, ClipBack = 32 }; /// Internal use. uint cc_oc(const Vector4 &min, const Vector4 &max, const Vector4 &p) const { uint oc = ClipNone; if (p.x > max.x) oc |= ClipRight; else if (p.x < min.x) oc |= ClipLeft; if (p.y > max.y) oc |= ClipTop; else if (p.y < min.y) oc |= ClipBottom; if (p.z > max.z) oc |= ClipBack; else if (p.z < min.z) oc |= ClipFront; return oc; } /// Internal use. uint ss_oc(const Vector4 &p) const { uint oc = ClipNone; oc |= p.x > 0 ? ClipRight : ClipLeft; oc |= p.y > 0 ? ClipTop : ClipBottom; oc |= p.z > 0 ? ClipBack : ClipFront; return oc; } public: Vector4 mn, mx; /// Return the start of the interval on a given axis. float GetMin(uint axis) const { return mn[axis]; } /// Return the end of the interval on a given axis. float GetMax(uint axis) const { return mx[axis]; } /// Return whether the MinMax object overlap with another one. bool TestAxisOverlap(const MinMax &b, uint axis) const { return (b.mn[axis] > mx[axis]) || (b.mx[axis] < mn[axis]) ? false : true; } /// Intersect ray with this minmax. bool IntersectRay(const Vector4 &o, const Vector4 &d, float &tmin, float &tmax); /// Returns whether a line intersect with the MinMax. bool ClassifyLine(const Vector4 &p, const Vector4 &d, Vector4 &i, Vector4 *n = 0) const; /// Returns whether a segment intersect with the MinMax. bool ClassifySegment(const Vector4 &p0, const Vector4 &p1, Vector4 &i, Vector4 *n = 0) const; /// Return whether two MinMax overlap at a given time. bool TestOverlap(const MinMax &b) const { if (mx.x < b.mn.x) return false; if (mx.y < b.mn.y) return false; if (mx.z < b.mn.z) return false; if (b.mx.x < mn.x) return false; if (b.mx.y < mn.y) return false; if (b.mx.z < mn.z) return false; return true; } /// Test position. inline bool IsInside(const Vector4 &p) const { return (p.x < mn.x) || (p.y < mn.y) || (p.z < mn.z) || (p.x > mx.x) || (p.y > mx.y) || (p.z > mx.z) ? false : true; } /// Grow the min~max boundaries to include another min~max structure. void Grow(const MinMax &b) { mn = Vector4::Minimum(b.mn, mn); mx = Vector4::Maximum(b.mx, mx); } /// Grow the min~max boundaries to include a vector. void Grow(const Vector4 &p) { mn = Vector4::Minimum(p, mn); mx = Vector4::Maximum(p, mx); } /// Get the min-max area. float GetArea() const { return (mx.x - mn.x) * (mx.y - mn.y) * (mx.z - mn.z); } /// Get the min-max center. Vector4 GetCenter() const { return (mn + mx) * 0.5f; } /// Set min-max. void Set(const Vector4 &min, const Vector4 &max) { mn = min; mx = max; } /// Set from position and size. void SetFromPositionSize(const Vector4 &p, const Vector4 &s) { mn = p - s * 0.5f; mx = p + s * 0.5f; } void Reset() { mn.Set(); mx.Set(); } /*! @name Serialization @{ */ bool FromMetaTag(NML::Tag &tag); NML::Tag *AsMetaTag(); /// @} MinMax() : mn(0, 0, 0), mx(0, 0, 0) {} MinMax(const Vector4 &min, const Vector4 &max) : mn(min), mx(max) {} }; /*! @short Oriented bounding box. @author Emmanuel Julien (ejulien@nworks.fr) */ struct OBB { Vector4 bb_position; Vector4 bb_scale; Matrix3 bb_rotation; /// Compute the min/max of the OBB. void ComputeMinMax(MinMax &minmax); /*! @short Transform OBB. @warning Scaling is not supported. */ void Transform(const Matrix4 &mtx); /// OBB from min~max. static OBB FromMinMax(const MinMax &minmax) { return OBB((minmax.mn + minmax.mx) * 0.5f, minmax.mx - minmax.mn); } bool FromMetaTag(NML::Tag &tag); NML::Tag *AsMetaTag(); OBB(const MinMax &minmax) { *this = FromMinMax(minmax); } OBB(const Vector4 &p, const Vector4 &s, const Matrix3 *m = 0) { bb_position = p; bb_scale = s; if (m) bb_rotation = *m; } OBB() {} }; } // GS #endif // __NBOUNDINGBOX__