From f4c57401f16f876b0d7dbd0b1f50cb48f37ffe18 Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Fri, 29 Sep 2006 16:10:40 +0000
Subject: [PATCH] BindSkin no longer automatically clears transforms between
 the mesh and the root. Instead this can be done with the ApplySkinOffset
 function after all the shapes are in place.

---
 include/obj/NiGeometry.h | 15 ++++++++++
 include/obj/NiSkinData.h |  2 ++
 src/obj/NiGeometry.cpp   | 60 ++++++++++++++++++++++++++++++++++------
 src/obj/NiSkinData.cpp   | 11 +++++++-
 4 files changed, 78 insertions(+), 10 deletions(-)

diff --git a/include/obj/NiGeometry.h b/include/obj/NiGeometry.h
index a1042b24..54ae3313 100644
--- a/include/obj/NiGeometry.h
+++ b/include/obj/NiGeometry.h
@@ -50,7 +50,9 @@ public:
 	 * ancestor in the scenegraph.  This becomes the skeleton root.
 	 */
 	void BindSkin( vector< Ref<NiNode> > bone_nodes );
+
 	void UnbindSkin();
+
 	/*!
 	 * Sets the skin weights in the attached NiSkinData object.
 	 * The version on this class calculates the center and radius of
@@ -83,6 +85,19 @@ public:
 	 */
 	void ApplyTransforms();
 
+	/*
+	 * Propogates the transforms between this skin and the skeleton root,
+	 * and then applies them to the verticies of this skin.  Sets the overall
+	 * skin data transform to the identity.
+	 */
+	void NiGeometry::ApplySkinOffset();
+
+	/*
+	 * Used to determine whether this mesh is influenced by bones as a skin.
+	 * \return true if this mesh is a skin, false otherwise.
+	 */
+	bool IsSkin();
+
 protected:
 	list< Ref<NiNode> > ListAncestors( const Ref<NiNode> & leaf ) const;
 	NI_GEOMETRY_MEMBERS
diff --git a/include/obj/NiSkinData.h b/include/obj/NiSkinData.h
index 5a061aa7..247f26f0 100644
--- a/include/obj/NiSkinData.h
+++ b/include/obj/NiSkinData.h
@@ -47,7 +47,9 @@ public:
 	virtual list<NiObjectRef> GetRefs() const;
 	virtual const Type & GetType() const;
 
+	void ResetOffsets( const Ref<NiGeometry> & owner );
 	Matrix44 GetOverallTransform() const;
+	void SetOverallTransform( const Matrix44 & transform );
 	uint GetBoneCount() const;
 	Matrix44 GetBoneTransform( uint bone_index ) const;
 	vector<SkinWeight> GetBoneWeights( uint bone_index ) const;
diff --git a/src/obj/NiGeometry.cpp b/src/obj/NiGeometry.cpp
index 8ffc6b4d..244df793 100644
--- a/src/obj/NiGeometry.cpp
+++ b/src/obj/NiGeometry.cpp
@@ -166,15 +166,6 @@ void NiGeometry::BindSkin( vector< Ref<NiNode> > bone_nodes ) {
 		throw runtime_error("Failed to find suitable skeleton root.");
 	}
 
-	//Ancestors[bone_nodes.size()] should now hold all nodes between (but not including) the
-	//skeleton root and this mesh.  Cycle through and propogate their transforms
-	for ( list<NiNodeRef>::iterator it = ancestors[bone_nodes.size()].begin(); it != ancestors[bone_nodes.size()].end(); ++it ) {
-		(*it)->PropagateTransform();
-	}
-
-	//Now apply the transforms to the vertices and normals of this mesh
-	this->ApplyTransforms();
-
 	//Create a skin instance using the bone and root data
 	skinInstance = new NiSkinInstance( skeleton_root, bone_nodes );
 
@@ -182,6 +173,57 @@ void NiGeometry::BindSkin( vector< Ref<NiNode> > bone_nodes ) {
 	skinInstance->SetSkinData( new NiSkinData( this ) );
 };
 
+void NiGeometry::ApplySkinOffset() {
+	if ( GetParent() == NULL ) {
+		throw runtime_error("Attempted to apply skin transforms on a shape with no parent.");
+	}
+
+	if ( skinInstance == NULL ) {
+		throw runtime_error("Attempted to apply skin transforms on a shape with no skin instance.");
+	}
+
+	if ( skinInstance->GetSkinData() == NULL ) {
+		throw runtime_error("Attempted to apply skin transforms on a shape with no skin data.");
+	}
+	
+	//Get ancestors
+	list<NiNodeRef> ancestors;
+	ancestors = ListAncestors( GetParent() );
+
+	//Propogate transforms on ancestors below skeleton root
+	bool below_root = false;
+
+	for ( list<NiNodeRef>::iterator it = ancestors.begin(); it != ancestors.end(); ++it ) {
+		if ( *it == skinInstance->GetSkeletonRoot() ) {
+			below_root = true;
+			continue;
+		}
+		if ( below_root ) {
+			cout << "Propogating transform of " << *it << endl;
+			(*it)->PropagateTransform();
+		}
+	}
+
+	//Now apply the transforms to the vertices and normals of this mesh
+	this->ApplyTransforms();
+
+	//Set the skin overall transform to the identity
+	skinInstance->GetSkinData()->SetOverallTransform( Matrix44::IDENTITY );	
+
+	//Reset skin offsets
+	skinInstance->GetSkinData()->ResetOffsets( this );
+}
+
+bool NiGeometry::IsSkin() {
+	//Determine whether this is a skin by looking for a skin instance and
+	//skin data
+	if ( skinInstance != NULL && skinInstance->GetSkinData() != NULL ) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
 list< Ref<NiNode> > NiGeometry::ListAncestors( const Ref<NiNode> & leaf ) const {
 	if ( leaf == NULL ) {
 		throw runtime_error("ListAncestors called with a NULL leaf NiNode Ref");
diff --git a/src/obj/NiSkinData.cpp b/src/obj/NiSkinData.cpp
index 0187143b..a684e3fa 100644
--- a/src/obj/NiSkinData.cpp
+++ b/src/obj/NiSkinData.cpp
@@ -75,7 +75,16 @@ Matrix44 NiSkinData::GetOverallTransform() const {
 	return Matrix44( translation, rotation, scale );
 }
 
+void NiSkinData::SetOverallTransform( const Matrix44 & transform ) {
+	transform.Decompose( translation, rotation, scale );
+}
+
 NiSkinData::NiSkinData( const Ref<NiGeometry> & owner ) NI_SKIN_DATA_CONSTRUCT {
+	ResetOffsets( owner );
+}
+
+void NiSkinData::ResetOffsets( const Ref<NiGeometry> & owner ) {
+
 	//Get skin instance
 	NiSkinInstanceRef skinInst = owner->GetSkinInstance();
 
@@ -85,7 +94,7 @@ NiSkinData::NiSkinData( const Ref<NiGeometry> & owner ) NI_SKIN_DATA_CONSTRUCT {
 
 	boneList.resize( skinInst->GetBoneCount() );
 	vector< Ref<NiNode> > bone_nodes = skinInst->GetBones();
-	
+
 	//--Calculate Overall Offset--//
 
 	//Get TriBasedGeom world transform
-- 
GitLab