Browse Source

Remove BoundingBox::defined_ boolean and instead have min = INF and max = -INF denote the case when a bounding box is degenerate. This helps reduce branching and SSE'ifying BoundingBox. SSE optimize some hot BoundingBox functions.

Jukka Jylänki 10 years ago
parent
commit
fbd07ac39c

+ 1 - 1
Source/Urho3D/AngelScript/MathAPI.cpp

@@ -1001,6 +1001,7 @@ static void RegisterVolumes(asIScriptEngine* engine)
     engine->RegisterObjectMethod("BoundingBox", "void Define(const Frustum&in)", asMETHODPR(BoundingBox, Define, (const Frustum&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void Define(const Polyhedron&in)", asMETHODPR(BoundingBox, Define, (const Polyhedron&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void Define(const Sphere&in)", asMETHODPR(BoundingBox, Define, (const Sphere&), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod("BoundingBox", "bool Defined() const", asMETHOD(BoundingBox, Defined), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void Merge(const Vector3&in)", asMETHODPR(BoundingBox, Merge, (const Vector3&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void Merge(const BoundingBox&in)", asMETHODPR(BoundingBox, Merge, (const BoundingBox&), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("BoundingBox", "void Merge(const Frustum&in)", asMETHODPR(BoundingBox, Merge, (const Frustum&), void), asCALL_THISCALL);
@@ -1024,7 +1025,6 @@ static void RegisterVolumes(asIScriptEngine* engine)
     engine->RegisterObjectMethod("BoundingBox", "Vector3 get_halfSize() const", asMETHOD(BoundingBox, HalfSize), asCALL_THISCALL);
     engine->RegisterObjectProperty("BoundingBox", "Vector3 min", offsetof(BoundingBox, min_));
     engine->RegisterObjectProperty("BoundingBox", "Vector3 max", offsetof(BoundingBox, max_));
-    engine->RegisterObjectProperty("BoundingBox", "bool defined", offsetof(BoundingBox, defined_));
 
     engine->RegisterObjectBehaviour("Frustum", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructFrustum), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectBehaviour("Frustum", asBEHAVE_CONSTRUCT, "void f(const Frustum&in)", asFUNCTION(ConstructFrustumCopy), asCALL_CDECL_OBJLAST);

+ 1 - 1
Source/Urho3D/Graphics/AnimatedModel.cpp

@@ -1183,7 +1183,7 @@ void AnimatedModel::UpdateBoneBoundingBox()
     if (skeleton_.GetNumBones())
     {
         // The bone bounding box is in local space, so need the node's inverse transform
-        boneBoundingBox_.defined_ = false;
+        boneBoundingBox_.Clear();
         Matrix3x4 inverseNodeTransform = node_->GetWorldTransform().Inverse();
 
         const Vector<Bone>& bones = skeleton_.GetBones();

+ 2 - 2
Source/Urho3D/Graphics/View.cpp

@@ -2243,7 +2243,7 @@ void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawabl
     const Matrix4& lightProj = shadowCamera->GetProjection();
     LightType type = light->GetLightType();
 
-    query.shadowCasterBox_[splitIndex].defined_ = false;
+    query.shadowCasterBox_[splitIndex].Clear();
 
     // Transform scene frustum into shadow camera's view space for shadow caster visibility check. For point & spot lights,
     // we can use the whole scene frustum. For directional lights, use the intersection of the scene frustum and the split
@@ -2489,7 +2489,7 @@ void View::SetupDirLightShadowCamera(Camera* shadowCamera, Light* light, float n
                 (GetLightMask(drawable) & light->GetLightMask()))
                 litGeometriesBox.Merge(drawable->GetWorldBoundingBox());
         }
-        if (litGeometriesBox.defined_)
+        if (litGeometriesBox.Defined())
         {
             frustumVolume.Clip(litGeometriesBox);
             // If volume became empty, restore it to avoid zero size

+ 1 - 1
Source/Urho3D/Graphics/Zone.cpp

@@ -336,7 +336,7 @@ void Zone::OnRemoveFromOctree()
 
 void Zone::ClearDrawablesZone()
 {
-    if (octant_ && lastWorldBoundingBox_.defined_)
+    if (octant_ && lastWorldBoundingBox_.Defined())
     {
         PODVector<Drawable*> result;
         BoxOctreeQuery query(result, lastWorldBoundingBox_, DRAWABLE_GEOMETRY | DRAWABLE_ZONE);

+ 2 - 1
Source/Urho3D/LuaScript/pkgs/Math/BoundingBox.pkg

@@ -23,6 +23,8 @@ class BoundingBox
     void Define(const Polyhedron& poly);
     void Define(const Sphere& sphere);
 
+    bool Defined() const;
+
     void Merge(const Vector3& point);
     void Merge(const BoundingBox& box);
     void Merge(const Frustum& frustum);
@@ -52,7 +54,6 @@ class BoundingBox
 
     Vector3 min_ @ min;
     Vector3 max_ @ max;
-    bool defined_ @ defined;
 
     tolua_readonly tolua_property__no_prefix Vector3 center;
     tolua_readonly tolua_property__no_prefix Vector3 size;

+ 8 - 4
Source/Urho3D/Math/BoundingBox.cpp

@@ -32,21 +32,23 @@ namespace Urho3D
 
 void BoundingBox::Define(const Vector3* vertices, unsigned count)
 {
+    Clear();
+
     if (!count)
         return;
 
-    defined_ = false;
     Merge(vertices, count);
 }
 
 void BoundingBox::Define(const Frustum& frustum)
 {
+    Clear();
     Define(frustum.vertices_, NUM_FRUSTUM_VERTICES);
 }
 
 void BoundingBox::Define(const Polyhedron& poly)
 {
-    defined_ = false;
+    Clear();
     Merge(poly);
 }
 
@@ -57,7 +59,6 @@ void BoundingBox::Define(const Sphere& sphere)
 
     min_ = center + Vector3(-radius, -radius, -radius);
     max_ = center + Vector3(radius, radius, radius);
-    defined_ = true;
 }
 
 void BoundingBox::Merge(const Vector3* vertices, unsigned count)
@@ -106,7 +107,10 @@ void BoundingBox::Clip(const BoundingBox& box)
         max_.z_ = box.max_.z_;
 
     if (min_.x_ > max_.x_ || min_.y_ > max_.y_ || min_.z_ > max_.z_)
-        defined_ = false;
+    {
+        min_ = Vector3(M_INFINITY, M_INFINITY, M_INFINITY);
+        max_ = Vector3(-M_INFINITY, -M_INFINITY, -M_INFINITY);
+    }
 }
 
 void BoundingBox::Transform(const Matrix3& transform)

+ 48 - 40
Source/Urho3D/Math/BoundingBox.h

@@ -25,6 +25,10 @@
 #include "../Math/Rect.h"
 #include "../Math/Vector3.h"
 
+#ifdef URHO3D_SSE
+#include <xmmintrin.h>
+#endif
+
 namespace Urho3D
 {
 
@@ -41,68 +45,67 @@ class URHO3D_API BoundingBox
 public:
     /// Construct with zero size.
     BoundingBox() :
-        min_(Vector3::ZERO),
-        max_(Vector3::ZERO),
-        defined_(false)
+        min_(M_INFINITY, M_INFINITY, M_INFINITY),
+        max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
     {
     }
 
     /// Copy-construct from another bounding box.
     BoundingBox(const BoundingBox& box) :
         min_(box.min_),
-        max_(box.max_),
-        defined_(box.defined_)
+        max_(box.max_)
     {
     }
 
     /// Construct from a rect, with the Z dimension left zero.
     BoundingBox(const Rect& rect) :
         min_(Vector3(rect.min_, 0.0f)),
-        max_(Vector3(rect.max_, 0.0f)),
-        defined_(true)
+        max_(Vector3(rect.max_, 0.0f))
     {
     }
 
     /// Construct from minimum and maximum vectors.
     BoundingBox(const Vector3& min, const Vector3& max) :
         min_(min),
-        max_(max),
-        defined_(true)
+        max_(max)
     {
     }
 
     /// Construct from minimum and maximum floats (all dimensions same.)
     BoundingBox(float min, float max) :
         min_(Vector3(min, min, min)),
-        max_(Vector3(max, max, max)),
-        defined_(true)
+        max_(Vector3(max, max, max))
     {
     }
 
     /// Construct from an array of vertices.
     BoundingBox(const Vector3* vertices, unsigned count) :
-        defined_(false)
+        min_(M_INFINITY, M_INFINITY, M_INFINITY),
+        max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
     {
         Define(vertices, count);
     }
 
     /// Construct from a frustum.
     BoundingBox(const Frustum& frustum) :
-        defined_(false)
+        min_(M_INFINITY, M_INFINITY, M_INFINITY),
+        max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
     {
         Define(frustum);
     }
 
     /// Construct from a polyhedron.
     BoundingBox(const Polyhedron& poly) :
-        defined_(false)
+        min_(M_INFINITY, M_INFINITY, M_INFINITY),
+        max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
     {
         Define(poly);
     }
 
     /// Construct from a sphere.
     BoundingBox(const Sphere& sphere) :
-        defined_(false)
+        min_(M_INFINITY, M_INFINITY, M_INFINITY),
+        max_(-M_INFINITY, -M_INFINITY, -M_INFINITY)
     {
         Define(sphere);
     }
@@ -112,7 +115,6 @@ public:
     {
         min_ = rhs.min_;
         max_ = rhs.max_;
-        defined_ = rhs.defined_;
         return *this;
     }
 
@@ -121,7 +123,6 @@ public:
     {
         min_ = Vector3(rhs.min_, 0.0f);
         max_ = Vector3(rhs.max_, 0.0f);
-        defined_ = true;
         return *this;
     }
 
@@ -148,7 +149,6 @@ public:
     {
         min_ = min;
         max_ = max;
-        defined_ = true;
     }
 
     /// Define from minimum and maximum floats (all dimensions same.)
@@ -156,26 +156,28 @@ public:
     {
         min_ = Vector3(min, min, min);
         max_ = Vector3(max, max, max);
-        defined_ = true;
     }
 
     /// Define from a point.
     void Define(const Vector3& point)
     {
         min_ = max_ = point;
-        defined_ = true;
+    }
+
+    /// Returns true if this bounding box is defined via a previous call to Define() or Merge().
+    bool Defined() const
+    {
+        return min_.x_ != M_INFINITY;
     }
 
     /// Merge a point.
     void Merge(const Vector3& point)
     {
-        if (!defined_)
-        {
-            min_ = max_ = point;
-            defined_ = true;
-            return;
-        }
-
+#ifdef URHO3D_SSE
+        __m128 vec = _mm_set_ps(1.f, point.z_, point.y_, point.x_);
+        _mm_storeu_ps(&min_.x_, _mm_min_ps(_mm_loadu_ps(&min_.x_), vec));
+        _mm_storeu_ps(&max_.x_, _mm_max_ps(_mm_loadu_ps(&max_.x_), vec));
+#else
         if (point.x_ < min_.x_)
             min_.x_ = point.x_;
         if (point.y_ < min_.y_)
@@ -188,19 +190,16 @@ public:
             max_.y_ = point.y_;
         if (point.z_ > max_.z_)
             max_.z_ = point.z_;
+#endif
     }
 
     /// Merge another bounding box.
     void Merge(const BoundingBox& box)
     {
-        if (!defined_)
-        {
-            min_ = box.min_;
-            max_ = box.max_;
-            defined_ = true;
-            return;
-        }
-
+#ifdef URHO3D_SSE
+        _mm_storeu_ps(&min_.x_, _mm_min_ps(_mm_loadu_ps(&min_.x_), _mm_loadu_ps(&box.min_.x_)));
+        _mm_storeu_ps(&max_.x_, _mm_max_ps(_mm_loadu_ps(&max_.x_), _mm_loadu_ps(&box.max_.x_)));
+#else
         if (box.min_.x_ < min_.x_)
             min_.x_ = box.min_.x_;
         if (box.min_.y_ < min_.y_)
@@ -213,6 +212,7 @@ public:
             max_.y_ = box.max_.y_;
         if (box.max_.z_ > max_.z_)
             max_.z_ = box.max_.z_;
+#endif
     }
 
     /// Define from an array of vertices.
@@ -241,9 +241,13 @@ public:
     /// Clear to undefined state.
     void Clear()
     {
-        min_ = Vector3::ZERO;
-        max_ = Vector3::ZERO;
-        defined_ = false;
+#ifdef URHO3D_SSE
+        _mm_storeu_ps(&min_.x_, _mm_set1_ps(M_INFINITY));
+        _mm_storeu_ps(&max_.x_, _mm_set1_ps(-M_INFINITY));
+#else
+        min_ = Vector3(M_INFINITY, M_INFINITY, M_INFINITY);
+        max_ = Vector3(-M_INFINITY, -M_INFINITY, -M_INFINITY);
+#endif
     }
 
     /// Return center.
@@ -305,10 +309,14 @@ public:
 
     /// Minimum vector.
     Vector3 min_;
+#ifdef URHO3D_SSE
+    float dummyMin_; // This is never used, but exists to pad the min_ value to four floats.
+#endif
     /// Maximum vector.
     Vector3 max_;
-    /// Defined flag.
-    bool defined_;
+#ifdef URHO3D_SSE
+    float dummyMax_; // This is never used, but exists to pad the max_ value to four floats.
+#endif
 };
 
 }

+ 1 - 1
Source/Urho3D/Math/Ray.cpp

@@ -71,7 +71,7 @@ float Ray::HitDistance(const Plane& plane) const
 float Ray::HitDistance(const BoundingBox& box) const
 {
     // If undefined, no hit (infinite distance)
-    if (!box.defined_)
+    if (!box.Defined())
         return M_INFINITY;
 
     // Check for ray origin being inside the box

+ 1 - 2
Source/Urho3D/Navigation/NavigationMesh.cpp

@@ -1383,8 +1383,7 @@ void NavigationMesh::ReleaseNavigationMesh()
 
     numTilesX_ = 0;
     numTilesZ_ = 0;
-    boundingBox_.min_ = boundingBox_.max_ = Vector3::ZERO;
-    boundingBox_.defined_ = false;
+    boundingBox_.Clear();
 }
 
 void NavigationMesh::SetPartitionType(NavmeshPartitionType ptype)

+ 0 - 1
Source/Urho3D/Resource/XMLElement.cpp

@@ -709,7 +709,6 @@ BoundingBox XMLElement::GetBoundingBox() const
 
     ret.min_ = GetVector3("min");
     ret.max_ = GetVector3("max");
-    ret.defined_ = true;
     return ret;
 }
 

+ 1 - 2
Source/Urho3D/UI/Text3D.cpp

@@ -491,8 +491,7 @@ void Text3D::UpdateTextBatches()
         break;
     }
 
-    boundingBox_.defined_ = false;
-    boundingBox_.min_ = boundingBox_.max_ = Vector3::ZERO;
+    boundingBox_.Clear();
 
     for (unsigned i = 0; i < uiVertexData_.Size(); i += UI_VERTEX_SIZE)
     {