From 63008f4b2341f2fa436eb7bfde30652eb4be3835 Mon Sep 17 00:00:00 2001
From: Tazpn <tazpn@users.sourceforge.net>
Date: Sat, 22 Sep 2007 16:13:09 +0000
Subject: [PATCH] Fixes for Bound calculations of objects with a morph
 attached.

---
 include/obj/NiGeomMorpherController.h |  5 ++
 include/obj/NiGeometryData.h          |  6 +++
 src/obj/NiGeomMorpherController.cpp   | 67 +++++++++++++++++++++++++++
 src/obj/NiGeometryData.cpp            |  6 +++
 src/obj/bhkBoxShape.cpp               |  1 +
 5 files changed, 85 insertions(+)

diff --git a/include/obj/NiGeomMorpherController.h b/include/obj/NiGeomMorpherController.h
index 38281196..e2233555 100644
--- a/include/obj/NiGeomMorpherController.h
+++ b/include/obj/NiGeomMorpherController.h
@@ -94,6 +94,11 @@ public:
 	 */
 	NIFLIB_API void SetData( NiMorphData * n );
 
+	/*!
+	* Update the Model Bounds
+	*/
+	NIFLIB_API void UpdateModelBound();
+
 	//--END CUSTOM CODE--//
 protected:
 	/*! Unknown. */
diff --git a/include/obj/NiGeometryData.h b/include/obj/NiGeometryData.h
index 381eaad6..86c90cd9 100644
--- a/include/obj/NiGeometryData.h
+++ b/include/obj/NiGeometryData.h
@@ -97,6 +97,12 @@ public:
 	 */
 	NIFLIB_API float GetRadius() const;
 
+	/*! 
+	 * Assigns the center and radius of the spherical bound of this data.
+	 * \remark GeoMorpher controllers will alter the model bound.
+	 */
+	NIFLIB_API void SetBound(Vector3 const & center, float radius);
+
 	/*! 
 	 * Used to retrive the vertices used by this mesh.  The size of the vector will be the same as the vertex count retrieved with the IShapeData::GetVertexCount function.
 	 * \return A vector cntaining the vertices used by this mesh.
diff --git a/src/obj/NiGeomMorpherController.cpp b/src/obj/NiGeomMorpherController.cpp
index 32d23f27..236fdab9 100644
--- a/src/obj/NiGeomMorpherController.cpp
+++ b/src/obj/NiGeomMorpherController.cpp
@@ -9,6 +9,8 @@ All rights reserved.  Please see niflib.h for license. */
 
 //--BEGIN FILE HEAD CUSTOM CODE--//
 #include "../../include/obj/NiKeyBasedInterpolator.h"
+#include "../../include/obj/NiGeometry.h"
+#include "../../include/obj/NiGeometryData.h"
 //--END CUSTOM CODE--//
 
 #include "../../include/FixLink.h"
@@ -248,4 +250,69 @@ void NiGeomMorpherController::SetData( NiMorphData * n ) {
 	data = n;
 }
 
+// Calculate bounding sphere using minimum-volume axis-align bounding box.  Its fast but not a very good fit.
+static void CalcAxisAlignedBox(vector<Vector3> const & vertices, Vector3& center, float& radius)
+{
+	//--Calculate center & radius--//
+
+	//Set lows and highs to first vertex
+	Vector3 lows = vertices[ 0 ];
+	Vector3 highs = vertices[ 0 ];
+
+	if (radius != 0.0f) // Initialize from previous box
+	{
+		lows = Vector3(center.x - radius, center.y - radius, center.z - radius);
+		highs = Vector3(center.x + radius, center.y + radius, center.z + radius);
+	}
+
+	//Iterate through the vertices, adjusting the stored values
+	//if a vertex with lower or higher values is found
+	for ( unsigned int i = 0; i < vertices.size(); ++i ) {
+		const Vector3 & v = vertices[ i ];
+
+		if ( v.x > highs.x ) highs.x = v.x;
+		else if ( v.x < lows.x ) lows.x = v.x;
+
+		if ( v.y > highs.y ) highs.y = v.y;
+		else if ( v.y < lows.y ) lows.y = v.y;
+
+		if ( v.z > highs.z ) highs.z = v.z;
+		else if ( v.z < lows.z ) lows.z = v.z;
+	}
+
+	//Now we know the extent of the shape, so the center will be the average
+	//of the lows and highs
+	center = (highs + lows) / 2.0f;
+
+	//The radius will be the largest distance from the center
+	Vector3 diff;
+	float dist2(0.0f), maxdist2(0.0f);
+	for ( unsigned int i = 0; i < vertices.size(); ++i ) {
+		const Vector3 & v = vertices[ i ];
+
+		diff = center - v;
+		dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
+		if ( dist2 > maxdist2 ) maxdist2 = dist2;
+	};
+	radius = sqrt(maxdist2);
+}
+
+void NiGeomMorpherController::UpdateModelBound() {
+	if (NiGeometryRef geom = DynamicCast<NiGeometry>(target))
+	{
+		if (NiGeometryDataRef gdata = geom->GetData())
+		{
+			Vector3 center = gdata->GetCenter();
+			float radius = gdata->GetRadius();
+			int nmorph = data->GetMorphCount();
+			for (int i=0; i<nmorph; i++)
+			{
+				CalcAxisAlignedBox(data->GetMorphVerts(i), center, radius);
+			}
+			gdata->SetBound(center, radius);
+		}
+	}
+}
+
+
 //--END CUSTOM CODE--//
diff --git a/src/obj/NiGeometryData.cpp b/src/obj/NiGeometryData.cpp
index b8fde880..c3ab2e57 100644
--- a/src/obj/NiGeometryData.cpp
+++ b/src/obj/NiGeometryData.cpp
@@ -516,4 +516,10 @@ void NiGeometryData::SetConsistencyFlags( const ConsistencyType & value ) {
 	consistencyFlags = value;
 }
 
+void NiGeometryData::SetBound(Vector3 const & center, float radius)
+{
+	this->center = center;
+	this->radius = radius;
+}
+
 //--END CUSTOM CODE--//
diff --git a/src/obj/bhkBoxShape.cpp b/src/obj/bhkBoxShape.cpp
index ba8f695d..984f55a8 100644
--- a/src/obj/bhkBoxShape.cpp
+++ b/src/obj/bhkBoxShape.cpp
@@ -103,6 +103,7 @@ Vector3 bhkBoxShape::GetDimensions() const {
 
 void bhkBoxShape::SetDimensions(const Vector3 &value) {
 	dimensions = value;
+	minimumSize = min( min(value.x, value.y), value.z );
 }
 
 //--END CUSTOM CODE--//
-- 
GitLab