From 44045539929d831a2cad1520e33c8dbb30034e14 Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Sun, 16 Oct 2005 03:47:20 +0000
Subject: [PATCH] Added IKeyframeData interface. Fixed a bug that was causing
 multiple copies of the same block to be written by WriteNifTree()

---
 NIF_Blocks.cpp | 51 ++++++++++++++++++++++++++++------------------
 NIF_Blocks.h   | 55 +++++++++++++++++++++++++++++++++-----------------
 nif_attrs.h    |  4 ++--
 niflib.cpp     |  4 ++--
 niflib.h       | 35 ++++++++++++++++++++++++++++++++
 5 files changed, 106 insertions(+), 43 deletions(-)

diff --git a/NIF_Blocks.cpp b/NIF_Blocks.cpp
index 53ba8017..7abef842 100644
--- a/NIF_Blocks.cpp
+++ b/NIF_Blocks.cpp
@@ -152,7 +152,7 @@ blk_ref ABlock::GetParent() {
 void ABlock::Read( ifstream& in ) {
 	for (unsigned int i = 0; i < _attr_vect.size(); ++i ) {
 		_attr_vect[i]->Read( in );
-		cout << "   " << _attr_vect[i]->GetName() << endl;
+		//cout << "   " << _attr_vect[i]->GetName() << endl;
 	}
 }
 
@@ -162,7 +162,7 @@ void ABlock::Write( ofstream& out ) {
 
 	//Write Attributes
 	for (unsigned int i = 0; i < _attr_vect.size(); ++i ) {
-		cout << "Writing " << blk_ref(this) << " " << _attr_vect[i]->GetName() << endl;
+		//cout << "Writing " << blk_ref(this) << " " << _attr_vect[i]->GetName() << endl;
 		_attr_vect[i]->Write( out );
 	}
 }
@@ -1416,20 +1416,23 @@ string NiGeomMorpherController::asString() {
 
 void NiKeyframeData::Read( ifstream& in ) {
 
-	scaleType = rotationType = translationType = 0;
+	scaleType = rotationType = translationType = KeyType(0);
 
 	//--Rotation--//
 	uint numRotations = ReadUInt( in );
 
 	if (numRotations > 0) {
-		rotationType = ReadUInt( in );
+		rotationType = KeyType(ReadUInt( in ));
 
 		rotKeys.resize( numRotations );
 		for ( unsigned int i = 0; i < numRotations; ++i ) {
 			rotKeys[i].time = ReadFloat( in );
 
 			if (rotationType != 4) {
-				ReadFVector4(rotKeys[i].data, in );
+				rotKeys[i].data.w = ReadFloat( in );
+				rotKeys[i].data.x = ReadFloat( in );
+				rotKeys[i].data.y = ReadFloat( in );
+				rotKeys[i].data.z = ReadFloat( in );
 			}
 
 			if (rotationType == 3) {
@@ -1467,7 +1470,7 @@ void NiKeyframeData::Read( ifstream& in ) {
 	uint numTranslations = ReadUInt( in );
 
 	if (numTranslations > 0) {
-		translationType = ReadUInt( in );
+		translationType = KeyType(ReadUInt( in ));
 
 		transKeys.resize( numTranslations );
 		for ( unsigned int i = 0; i < numTranslations; ++i ) {
@@ -1488,7 +1491,7 @@ void NiKeyframeData::Read( ifstream& in ) {
 	uint numScalings = ReadUInt( in );
 
 	if (numScalings > 0) {
-		scaleType = ReadUInt( in );
+		scaleType = KeyType(ReadUInt( in ));
 		cout << "Scale Type:  " << scaleType << endl;
 
 		scaleKeys.resize( numScalings );
@@ -1521,7 +1524,10 @@ void NiKeyframeData::Write( ofstream& out ) {
 			WriteFloat( rotKeys[i].time, out );
 
 			if (rotationType != 4) {
-				WriteFVector4(rotKeys[i].data, out );
+				WriteFloat( rotKeys[i].data.w, out );
+				WriteFloat( rotKeys[i].data.x, out );
+				WriteFloat( rotKeys[i].data.y, out );
+				WriteFloat( rotKeys[i].data.z, out );
 			}
 
 			if (rotationType == 3) {
@@ -1590,7 +1596,7 @@ string NiKeyframeData::asString() {
 				out << "Key Time:  " << rotKeys[i].time << "  ";
 
 				if (rotationType != 4) {
-					out << "Rotation:  Q[" << rotKeys[i].data << endl;
+					out << "Rotation:  Q[" << rotKeys[i].data.w << " ( " << rotKeys[i].data.x << ", " << rotKeys[i].data.y << ", " << rotKeys[i].data.z << ")]" << endl;
 					//	<< "   As Matrix:";
 					//QuatToMatrix(rotKeys[i].data, out );
 					//out << "   As Angles:";
@@ -1758,7 +1764,7 @@ void NiStringExtraData::Read( ifstream& in ) {
 	//Read Bytes Remaining but don't bother to store it
 	ReadUInt( in );
 
-	strData = ReadString( in );
+	GetAttr("String Data")->Read( in );
 }
 
 void NiStringExtraData::Write( ofstream& out ) {
@@ -1767,9 +1773,11 @@ void NiStringExtraData::Write( ofstream& out ) {
 	GetAttr("Next Extra Data")->Write( out );
 
 	//Write Bytes Remaining - length of string + 4
-	WriteUInt( uint(strData.length()) + 4, out );
+	attr_ref string_data = GetAttr("String Data");
+	
+	WriteUInt( uint(string_data->asString().length()) + 4, out );
 
-	WriteString( strData, out );
+	string_data->Write( out );
 }
 
 string NiStringExtraData::asString() {
@@ -1777,9 +1785,12 @@ string NiStringExtraData::asString() {
 	out.setf(ios::fixed, ios::floatfield);
 	out << setprecision(1);
 
-	out << "Next Extra Data:  " << GetAttr("Next Extra Data")->asLink() << endl
+	attr_ref next_data = GetAttr("Next Extra Data");
+	attr_ref string_data = GetAttr("String Data");
+
+	out << next_data->GetName() << ":  " << next_data->asLink() << endl
 		<< "Bytes Remaining:  " << uint(strData.length()) + 4 << endl
-		<< "String:  " << strData << endl;
+		<< string_data->GetName() << ":  " << string_data->asString() << endl;
 	
 	return out.str();
 }
@@ -2108,9 +2119,9 @@ void NiRotatingParticlesData::Read( ifstream& in ) {
 void NiTextKeyExtraData::Read( ifstream& in ) {
 
 	GetAttr("Next Extra Data")->Read( in );
+	GetAttr("Unknown Int")->Read( in );
 
-	unknownInt = ReadUInt( in );
-	keyCount = ReadUInt( in );
+	uint keyCount = ReadUInt( in );
 
 	keys.resize(keyCount);
 	for (uint i = 0; i < keys.size(); ++i ) {
@@ -2124,9 +2135,9 @@ void NiTextKeyExtraData::Write( ofstream& out ) {
 	WriteString( "NiTextKeyExtraData", out );
 
 	GetAttr("Next Extra Data")->Write( out );
+	GetAttr("Unknown Int")->Write( out );
 
-	WriteUInt( unknownInt, out );
-	WriteUInt( keyCount, out );
+	WriteUInt( uint(keys.size()), out );
 
 	for (uint i = 0; i < keys.size(); ++i ) {
 		WriteFloat( keys[i].time, out );
@@ -2140,8 +2151,8 @@ string NiTextKeyExtraData::asString() {
 	out << setprecision(1);
 
 	out << "Next Extra Data:  " <<  GetAttr("Next Extra Data")->asLink() << endl
-		<< "Unknown Int (Key Type?):  " << unknownInt << endl
-		<< "Key Count:  " << keyCount << endl;
+		<< "Unknown Int (Key Type?):  " << GetAttr("Unknown Int")->asInt() << endl
+		<< "Key Count:  " << uint(keys.size()) << endl;
 
 	if (verbose) {
 		for (uint i = 0; i < keys.size(); ++i ) {
diff --git a/NIF_Blocks.h b/NIF_Blocks.h
index a0a8a2ca..c2eca2dd 100644
--- a/NIF_Blocks.h
+++ b/NIF_Blocks.h
@@ -908,19 +908,10 @@ public:
 //    float unknown     = 1
 //    float unknown[3]
 
-
-
-template <class T>
-struct Key {
-	float time;
-	T data, forward_tangent, backward_tangent;
-	fVector3 tbc;
-};
-
 /**
  * NiKeyframeData -
  */
-class NiKeyframeData : public ABlock{
+class NiKeyframeData : public ABlock, public IKeyframeData {
 
 	public:
 
@@ -931,15 +922,39 @@ class NiKeyframeData : public ABlock{
 		void Write( ofstream& out );
 		string asString();
 		string GetBlockType() { return "NiKeyframeData"; }
+		
+		void * QueryInterface( int id ) {
+			if ( id == KeyframeData ) {
+				return (void*)static_cast<IKeyframeData*>(this);;
+			} else {
+				return ABlock::QueryInterface( id );
+			}
+		}
+
+		//--IKeyframeData Functions--//
+		KeyType GetRotateType() { return rotationType; }
+		void SetRotateType( KeyType t ) { rotationType = t; }
+		vector< Key<Quaternion> > GetRotateKeys() { return rotKeys; }
+		void SetRotateKeys( vector< Key<Quaternion> > & keys ) { rotKeys = keys; }
+		//Translate
+		KeyType GetTranslateType() { return translationType; }
+		void SetTranslateType( KeyType t ) { translationType = t; }
+		vector< Key<float3> > GetTranslateKeys() { return transKeys; }
+		void SetTranslateKeys( vector< Key<float3> > & keys ) { transKeys = keys; }
+		//Scale
+		KeyType GetScaleType() { return scaleType; }
+		void SetScaleType( KeyType t ) { scaleType = t; }
+		vector< Key<float> > GetScaleKeys() { return scaleKeys; }
+		void SetScaleKeys( vector< Key<float> > & keys ) { scaleKeys = keys; }
 
 	private:
-		uint rotationType;
-		vector< Key<fVector4> > rotKeys;
+		KeyType rotationType;
+		vector< Key<Quaternion> > rotKeys;
 
-		uint translationType;
-		vector< Key<fVector3> >	transKeys;
+		KeyType translationType;
+		vector< Key<float3> >	transKeys;
 
-		uint scaleType;
+		KeyType scaleType;
 		vector< Key<float> > scaleKeys;
 };
 
@@ -1108,7 +1123,9 @@ class NiStringExtraData : public AExtraData{
 
 	public:
 
-		NiStringExtraData(){}
+		NiStringExtraData(){
+			AddAttr( "string", "String Data" );
+		}
 		~NiStringExtraData(){}
 
 		void Read( ifstream& in );
@@ -1184,7 +1201,9 @@ class NiTextKeyExtraData : public AExtraData{
 
 	public:
 
-		NiTextKeyExtraData(){}
+		NiTextKeyExtraData(){
+			AddAttr( "int", "Unknown Int" );	
+		}
 		~NiTextKeyExtraData(){}
 
 		void Read( ifstream& in );
@@ -1193,8 +1212,6 @@ class NiTextKeyExtraData : public AExtraData{
 		string GetBlockType() { return "NiTextKeyExtraData"; }
 
 	private:
-		blk_ref next_index;
-		uint unknownInt, keyCount;
 		vector< Key<string> > keys;
 };
 
diff --git a/nif_attrs.h b/nif_attrs.h
index c4531145..f84f464b 100644
--- a/nif_attrs.h
+++ b/nif_attrs.h
@@ -517,7 +517,7 @@ public:
 	string GetType() const { return "linkgroup"; }
 	void Read( ifstream& in ) {
 		int len = ReadUInt( in );
-		cout << "Link Group Size:  " << len << endl;
+		//cout << "Link Group Size:  " << len << endl;
 
 		if ( len > 30 ) {
 			cout << _owner->asString() << endl;
@@ -533,7 +533,7 @@ public:
 	void Write( ofstream& out ) {
 		//Write the number of links
 		WriteUInt( uint(links.size()), out );
-		cout << "Link Group Size:  " << uint(links.size()) << endl;
+		//cout << "Link Group Size:  " << uint(links.size()) << endl;
 
 		if ( links.size() > 30 ) {
 			cout << "\a" << endl;
diff --git a/niflib.cpp b/niflib.cpp
index 96aaa372..d77bf842 100644
--- a/niflib.cpp
+++ b/niflib.cpp
@@ -254,7 +254,7 @@ vector<blk_ref> ReadNifList( string file_name ) {
 			cin.get();
 		}
 
-		cout << i << " " << blockName << endl;
+		//cout << i << " " << blockName << endl;
 
 		//Create Block of the type that was found
 		blocks[i] = CreateBlock(blockName);
@@ -390,7 +390,7 @@ void ReorderNifTree( vector<blk_ref> & blk_list, blk_ref block ) {
 	list<blk_ref> links = block->GetLinks();
 	list<blk_ref>::iterator it;
 	for (it = links.begin(); it != links.end(); ++it) {
-		if ( it->is_null() == false ) {
+		if ( it->is_null() == false && (*it)->GetParent() == block ) {
 			ReorderNifTree( blk_list, *it );
 		}
 	}
diff --git a/niflib.h b/niflib.h
index 0a7a7a7d..ca5f7017 100644
--- a/niflib.h
+++ b/niflib.h
@@ -71,6 +71,7 @@ const unsigned int HEADER_STRING_LEN = 39;
 const int TriShapeData = 0;
 const int SkinData = 1;
 const int Node = 2;
+const int KeyframeData = 3;
 
 //--Main Functions--//
 
@@ -199,6 +200,19 @@ struct Color {
 	float r, g, b, a;
 };
 
+struct Quaternion {
+	float w, x, y, z;
+};
+
+template <class T>
+struct Key {
+	float time;
+	T data, forward_tangent, backward_tangent;
+	float3 tbc;
+};
+
+enum KeyType { LINEAR_KEY = 1, QUADRATIC_KEY = 2, TBC_KEY = 3 };
+
 class INode {
 public:
 	INode() {}
@@ -248,6 +262,27 @@ public:
 	virtual void RemoveBone( blk_ref bone ) = 0;
 };
 
+class IKeyframeData {
+public:
+	IKeyframeData() {}
+	virtual ~IKeyframeData () {}
+	//Rotate
+	virtual KeyType GetRotateType() = 0;
+	virtual void SetRotateType( KeyType t ) = 0;
+	virtual vector< Key<Quaternion> > GetRotateKeys() = 0;
+	virtual void SetRotateKeys( vector< Key<Quaternion> > & keys ) = 0;
+	//Translate
+	virtual KeyType GetTranslateType() = 0;
+	virtual void SetTranslateType( KeyType t ) = 0;
+	virtual vector< Key<float3> > GetTranslateKeys() = 0;
+	virtual void SetTranslateKeys( vector< Key<float3> > & keys ) = 0;
+	//Scale
+	virtual KeyType GetScaleType() = 0;
+	virtual void SetScaleType( KeyType t ) = 0;
+	virtual vector< Key<float> > GetScaleKeys() = 0;
+	virtual void SetScaleKeys( vector< Key<float> > & keys ) = 0;
+};
+
 //--Attribute Reference--//
 class attr_ref {
 public:
-- 
GitLab