From 9447d624fa806cdcad604778c8672211417e3f89 Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Wed, 27 Sep 2006 02:01:28 +0000
Subject: [PATCH] Replaced GetSkinInfluencedVertices function with
 GetSkinDeformation function which takes in references to two vectors and
 fills them with the skin deformed vertices and normals Added constructor to
 Matrix44 to convert from Matrix33.

---
 include/nif_math.h       |  6 ++++++
 include/obj/NiGeometry.h |  2 +-
 src/ComplexShape.cpp     |  8 +++++---
 src/nif_math.cpp         |  9 +++++++++
 src/obj/NiGeometry.cpp   | 31 ++++++++++++++++++++++---------
 5 files changed, 43 insertions(+), 13 deletions(-)

diff --git a/include/nif_math.h b/include/nif_math.h
index fed4d26c..2a2b7ce2 100644
--- a/include/nif_math.h
+++ b/include/nif_math.h
@@ -651,6 +651,12 @@ struct Matrix44 {
 	 */
 	NIFLIB_API Matrix44( const Vector3 & translate, const Matrix33 & rotation, float scale );
 
+	/*! This constructor allows a 4x4 transform matrix to be initalized from a
+	 * a 3x3 rotation matrix.
+	 * \param[in] rotation The 3x3 rotation matrix.
+	 */
+	NIFLIB_API Matrix44( const Matrix33 & rotation );
+
 	/*! This function can be used to set all values in this matrix at the same time.
 	 * \param[in] m11 The value to set at row 1, column 1.
 	 * \param[in] m12 The value to set at row 1, column 2.
diff --git a/include/obj/NiGeometry.h b/include/obj/NiGeometry.h
index 65304f29..c1929af1 100644
--- a/include/obj/NiGeometry.h
+++ b/include/obj/NiGeometry.h
@@ -69,7 +69,7 @@ public:
 	string GetShader() const;
 	void SetShader( const string & n );
 
-	vector<Vector3> GetSkinInfluencedVertices() const;
+	void GetSkinDeformation( vector<Vector3> & vertices, vector<Vector3> & normals ) const;
 
 protected:
 	list< Ref<NiNode> > ListAncestors( const Ref<NiNode> & leaf ) const;
diff --git a/src/ComplexShape.cpp b/src/ComplexShape.cpp
index a95d09ca..8f81dbe0 100644
--- a/src/ComplexShape.cpp
+++ b/src/ComplexShape.cpp
@@ -234,15 +234,17 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 
 		//cout << "Get Data" << endl;
 		//Get Data
-		vector<Vector3> shapeVerts;		
+		vector<Vector3> shapeVerts;	
+		vector<Vector3> shapeNorms;
 		//If this is a skin influenced mesh, get vertices from niGeom
 		if ( (*geom)->GetSkinInstance() != NULL ) {
-			shapeVerts = (*geom)->GetSkinInfluencedVertices();
+			(*geom)->GetSkinDeformation( shapeVerts, shapeNorms );
 		} else {
 			shapeVerts = geomData->GetVertices();
+			shapeNorms = geomData->GetNormals();
 		}
 
-		vector<Vector3> shapeNorms = geomData->GetNormals();
+		
 		vector<Color4> shapeColors = geomData->GetColors();
 		vector< vector<TexCoord> > shapeUVs( geomData->GetUVSetCount() );
 		for ( unsigned i = 0; i < shapeUVs.size(); ++i ) {
diff --git a/src/nif_math.cpp b/src/nif_math.cpp
index 7ee458b2..699d57af 100644
--- a/src/nif_math.cpp
+++ b/src/nif_math.cpp
@@ -232,6 +232,15 @@ Matrix44::Matrix44() {
 	*this = Matrix44::IDENTITY;
 }
 
+Matrix44::Matrix44( const Matrix33 & r ) {
+	//Set this matrix with rotate and translate information
+	Matrix44 & m = *this;
+	m[0][0] = r[0][0];  m[0][1] = r[0][1];  m[0][2] = r[0][2];  m[0][3] = 0.0f;
+	m[1][0] = r[1][0];  m[1][1] = r[1][1];  m[1][2] = r[1][2];  m[1][3] = 0.0f;
+	m[2][0] = r[2][0];  m[2][1] = r[2][1];  m[2][2] = r[2][2];  m[2][3] = 0.0f;
+	m[3][0] = 0.0f;     m[3][1] = 0.0f;     m[3][2] = 0.0f;     m[3][3] = 1.0f;
+}
+
 Matrix44::Matrix44( const Vector3 & t, const Matrix33 & r, float scale ) {
 	//Set up a matrix with rotate and translate information
 	Matrix44 rt;
diff --git a/src/obj/NiGeometry.cpp b/src/obj/NiGeometry.cpp
index e13997bf..ced04547 100644
--- a/src/obj/NiGeometry.cpp
+++ b/src/obj/NiGeometry.cpp
@@ -211,7 +211,7 @@ void NiGeometry::UnbindSkin() {
 	skinInstance = NULL;
 }
 
-vector<Vector3> NiGeometry::GetSkinInfluencedVertices() const {
+void NiGeometry::GetSkinDeformation( vector<Vector3> & vertices, vector<Vector3> & normals ) const{
 	//--Get required data & insure validity--//
 
 	NiGeometryDataRef geom_data = GetData();
@@ -245,11 +245,14 @@ vector<Vector3> NiGeometry::GetSkinInfluencedVertices() const {
 	}
 
 	//Get the vertices & bone nodes
-	vector<Vector3> vertices = geom_data->GetVertices();
+	vector<Vector3> in_verts = geom_data->GetVertices();
+	vector<Vector3> in_norms = geom_data->GetNormals();
+
 	vector<NiNodeRef> bone_nodes = skin_inst->GetBones();
 
-	//Set up an aray to hold the transformed vertices
-	vector<Vector3> skin_verts( vertices.size());
+	//Set up output arrays to hold the transformed vertices and normals
+	vertices.resize( in_verts.size() );
+	normals.resize( in_norms.size() );
 
 	//Transform vertices into position based on skin data
 	Matrix44 root_world = skel_root->GetWorldTransform();
@@ -259,19 +262,29 @@ vector<Vector3> NiGeometry::GetSkinInfluencedVertices() const {
 		Matrix44 bone_offset = skin_data->GetBoneTransform(i);
 		vector<SkinWeight> weights = skin_data->GetBoneWeights(i);
 		Matrix44 vert_trans =  bone_offset * bone_world;
+		Matrix44 norm_trans = Matrix44( vert_trans.GetRotation() );
 		for ( uint j = 0; j < weights.size(); ++j ) {
 			uint index = weights[j].index;
 			float weight = weights[j].weight;
-			skin_verts[index] += (vert_trans * vertices[index] ) * weight;
+			if ( index < vertices.size() ) {
+				vertices[index] += (vert_trans * in_verts[index] ) * weight;
+			}
+			if ( index < normals.size() ) {
+				normals[index] += (norm_trans * in_norms[index] ) * weight;
+			}
 		}
 	}
 
 	//Transform all vertices to final position
-	for ( uint i = 0; i < skin_verts.size(); ++i ) {
-		skin_verts[i] = geom_world.Inverse() * skin_verts[i];
+	Matrix44 geom_world_inv = geom_world.Inverse();
+	Matrix44 geom_world_inv_rot = Matrix44( geom_world_inv.GetRotation() );
+	for ( uint i = 0; i < vertices.size(); ++i ) {
+		vertices[i] = geom_world_inv * vertices[i];
+	}
+	for ( uint i = 0; i < normals.size(); ++i ) {
+		normals[i] = geom_world_inv_rot * normals[i];
+		//normals[i] = normals[i].Normalized();
 	}
-
-	return skin_verts;
 }
 
 // Calculate bounding sphere using minimum-volume axis-align bounding box.  Its fast but not a very good fit.
-- 
GitLab