From 36ec3e1629ca8f8dc6ac97982ad4bd26687f29be Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Mon, 7 May 2007 08:49:14 +0000
Subject: [PATCH] Updated to the latest XML.  This adds support for
 NiRollController. Fixed several bugs that were preventing support for old 3.1
 and below files from working.  Many of these can now be loaded. Added version
 3.1 to list of "supported" versions.

---
 include/gen/obj_defines.h                |  17 ++-
 include/obj/NiFlipController.h           |   1 +
 include/obj/NiParticleSystemController.h |   1 +
 include/obj/NiRollController.h           |  47 +++++++
 niflib.vcproj                            |   8 ++
 src/NIF_IO.cpp                           |  12 +-
 src/gen/obj_impl.cpp                     | 164 ++++++++++++++++++++---
 src/niflib.cpp                           |  23 ++--
 src/obj/NiFlipController.cpp             |   1 +
 src/obj/NiParticleSystemController.cpp   |   1 +
 src/obj/NiRollController.cpp             |  62 +++++++++
 11 files changed, 296 insertions(+), 41 deletions(-)
 create mode 100644 include/obj/NiRollController.h
 create mode 100644 src/obj/NiRollController.cpp

diff --git a/include/gen/obj_defines.h b/include/gen/obj_defines.h
index 6139a48a..1133d719 100644
--- a/include/gen/obj_defines.h
+++ b/include/gen/obj_defines.h
@@ -483,6 +483,7 @@ float lodAdjust; \
 Ref<NiObject > unknownLink_; \
 unsigned int unknownInt; \
 unsigned int unknownInt2; \
+unsigned int unknownInt3; \
 
 #define NI_COLLISION_DATA_MEMBERS \
 NiNode * targetNode; \
@@ -544,6 +545,10 @@ unsigned int unknownInt2; \
 float delta; \
 mutable unsigned int numSources; \
 vector<Ref<NiSourceTexture > > sources; \
+vector<Ref<NiImage > > image; \
+
+#define NI_ROLL_CONTROLLER_MEMBERS \
+Ref<NiFloatData > data; \
 
 #define NI_FLOAT_DATA_MEMBERS \
 KeyGroup<float > data; \
@@ -802,7 +807,8 @@ Ref<NiObject > unknownLink; \
 Ref<AParticleModifier > particleExtra; \
 Ref<NiObject > unknownLink2; \
 byte trailer; \
-array<3,float > unkownFloats; \
+Ref<NiColorData > colorData; \
+array<2,float > unkownFloats; \
 
 #define NI_B_S_P_ARRAY_CONTROLLER_MEMBERS \
 
@@ -1367,6 +1373,7 @@ vector< vector<ByteColor3 > > imageData; \
 #define NI_DIRECTIONAL_LIGHT_MEMBERS
 #define NI_DITHER_PROPERTY_MEMBERS
 #define NI_FLIP_CONTROLLER_MEMBERS
+#define NI_ROLL_CONTROLLER_MEMBERS
 #define NI_FLOAT_DATA_MEMBERS
 #define NI_FLOAT_EXTRA_DATA_MEMBERS
 #define NI_FLOAT_EXTRA_DATA_CONTROLLER_MEMBERS
@@ -1812,7 +1819,7 @@ vector< vector<ByteColor3 > > imageData; \
 
 #define NI_CAMERA_PARENT NiAVObject
 
-#define NI_CAMERA_CONSTRUCT  : unknownShort((unsigned short)0), frustumLeft(0.0f), frustumRight(0.0f), frustumTop(0.0f), frustumBottom(0.0f), frustumNear(0.0f), frustumFar(0.0f), useOrthographicProjection(false), viewportLeft(0.0f), viewportRight(0.0f), viewportTop(0.0f), viewportBottom(0.0f), lodAdjust(0.0f), unknownLink_(NULL), unknownInt((unsigned int)0), unknownInt2((unsigned int)0)
+#define NI_CAMERA_CONSTRUCT  : unknownShort((unsigned short)0), frustumLeft(0.0f), frustumRight(0.0f), frustumTop(0.0f), frustumBottom(0.0f), frustumNear(0.0f), frustumFar(0.0f), useOrthographicProjection(false), viewportLeft(0.0f), viewportRight(0.0f), viewportTop(0.0f), viewportBottom(0.0f), lodAdjust(0.0f), unknownLink_(NULL), unknownInt((unsigned int)0), unknownInt2((unsigned int)0), unknownInt3((unsigned int)0)
 
 #define NI_COLLISION_DATA_PARENT NiObject
 
@@ -1851,6 +1858,10 @@ vector< vector<ByteColor3 > > imageData; \
 
 #define NI_FLIP_CONTROLLER_CONSTRUCT  : textureSlot((unsigned int)0), unknownInt2((unsigned int)0), delta(0.0f), numSources((unsigned int)0)
 
+#define NI_ROLL_CONTROLLER_PARENT NiSingleInterpolatorController
+
+#define NI_ROLL_CONTROLLER_CONSTRUCT  : data(NULL)
+
 #define NI_FLOAT_DATA_PARENT AKeyedData
 
 #define NI_FLOAT_DATA_CONSTRUCT 
@@ -2019,7 +2030,7 @@ vector< vector<ByteColor3 > > imageData; \
 #define NI_MESH_PARTICLE_SYSTEM_CONSTRUCT 
 #define NI_PARTICLE_SYSTEM_CONTROLLER_PARENT NiTimeController
 
-#define NI_PARTICLE_SYSTEM_CONTROLLER_CONSTRUCT  : speed(0.0f), speedRandom(0.0f), verticalDirection(0.0f), verticalAngle(0.0f), horizontalDirection(0.0f), horizontalAngle(0.0f), unknownFloat5(0.0f), unknownFloat6(0.0f), unknownFloat7(0.0f), unknownFloat8(0.0f), unknownFloat9(0.0f), unknownFloat10(0.0f), unknownFloat11(0.0f), size(0.0f), emitStartTime(0.0f), emitStopTime(0.0f), unknownByte((byte)0), emitRate(0.0f), lifetime(0.0f), lifetimeRandom(0.0f), emitFlags((unsigned short)0), emitter(NULL), unknownShort2_((unsigned short)0), unknownFloat13_(0.0f), unknownInt1_((unsigned int)0), unknownInt2_((unsigned int)0), unknownShort3_((unsigned short)0), numParticles((unsigned short)0), numValid((unsigned short)0), unknownLink(NULL), particleExtra(NULL), unknownLink2(NULL), trailer((byte)0)
+#define NI_PARTICLE_SYSTEM_CONTROLLER_CONSTRUCT  : speed(0.0f), speedRandom(0.0f), verticalDirection(0.0f), verticalAngle(0.0f), horizontalDirection(0.0f), horizontalAngle(0.0f), unknownFloat5(0.0f), unknownFloat6(0.0f), unknownFloat7(0.0f), unknownFloat8(0.0f), unknownFloat9(0.0f), unknownFloat10(0.0f), unknownFloat11(0.0f), size(0.0f), emitStartTime(0.0f), emitStopTime(0.0f), unknownByte((byte)0), emitRate(0.0f), lifetime(0.0f), lifetimeRandom(0.0f), emitFlags((unsigned short)0), emitter(NULL), unknownShort2_((unsigned short)0), unknownFloat13_(0.0f), unknownInt1_((unsigned int)0), unknownInt2_((unsigned int)0), unknownShort3_((unsigned short)0), numParticles((unsigned short)0), numValid((unsigned short)0), unknownLink(NULL), particleExtra(NULL), unknownLink2(NULL), trailer((byte)0), colorData(NULL)
 
 #define NI_B_S_P_ARRAY_CONTROLLER_PARENT NiParticleSystemController
 
diff --git a/include/obj/NiFlipController.h b/include/obj/NiFlipController.h
index 2724fb98..07dabff1 100644
--- a/include/obj/NiFlipController.h
+++ b/include/obj/NiFlipController.h
@@ -12,6 +12,7 @@ namespace Niflib {
 
 // Forward define of referenced NIF objects
 class NiSourceTexture;
+class NiImage;
 
 //#include "../gen/obj_defines.h"
 
diff --git a/include/obj/NiParticleSystemController.h b/include/obj/NiParticleSystemController.h
index 5108364b..4c4f2d66 100644
--- a/include/obj/NiParticleSystemController.h
+++ b/include/obj/NiParticleSystemController.h
@@ -14,6 +14,7 @@ namespace Niflib {
 // Forward define of referenced NIF objects
 class NiObject;
 class AParticleModifier;
+class NiColorData;
 
 //#include "../gen/obj_defines.h"
 
diff --git a/include/obj/NiRollController.h b/include/obj/NiRollController.h
new file mode 100644
index 00000000..a6530620
--- /dev/null
+++ b/include/obj/NiRollController.h
@@ -0,0 +1,47 @@
+/* Copyright (c) 2006, NIF File Format Library and Tools
+All rights reserved.  Please see niflib.h for license. */
+
+#ifndef _NIROLLCONTROLLER_H_
+#define _NIROLLCONTROLLER_H_
+
+#include "NiSingleInterpolatorController.h"
+
+// Include structures
+#include "../Ref.h"
+namespace Niflib {
+
+// Forward define of referenced NIF objects
+class NiFloatData;
+class NiRollController;
+typedef Ref<NiRollController> NiRollControllerRef;
+
+/*!
+ * NiRollController - Unknown.
+ */
+
+class NiRollController : public NI_ROLL_CONTROLLER_PARENT {
+public:
+	NIFLIB_API NiRollController();
+	NIFLIB_API ~NiRollController();
+	//Run-Time Type Information
+	NIFLIB_API static const Type TYPE;
+	NIFLIB_API static NiObject * Create();
+	NIFLIB_API virtual const Type & GetType() const;
+	NIFLIB_HIDDEN virtual void Read( istream& in, list<unsigned int> & link_stack, const NifInfo & info );
+	NIFLIB_HIDDEN virtual void Write( ostream& out, const map<NiObjectRef,unsigned int> & link_map, const NifInfo & info ) const;
+	NIFLIB_API virtual string asString( bool verbose = false ) const;
+	NIFLIB_HIDDEN virtual void FixLinks( const map<unsigned int,NiObjectRef> & objects, list<unsigned int> & link_stack, const NifInfo & info );
+	NIFLIB_HIDDEN virtual list<NiObjectRef> GetRefs() const;
+
+protected:
+	NI_ROLL_CONTROLLER_MEMBERS
+private:
+	void InternalRead( istream& in, list<unsigned int> & link_stack, const NifInfo & info );
+	void InternalWrite( ostream& out, const map<NiObjectRef,unsigned int> & link_map, const NifInfo & info ) const;
+	string InternalAsString( bool verbose ) const;
+	void InternalFixLinks( const map<unsigned int,NiObjectRef> & objects, list<unsigned int> & link_stack, const NifInfo & info );
+	list<NiObjectRef> InternalGetRefs() const;
+};
+
+}
+#endif
diff --git a/niflib.vcproj b/niflib.vcproj
index 3fd4d91c..1e8f3033 100644
--- a/niflib.vcproj
+++ b/niflib.vcproj
@@ -1074,6 +1074,10 @@
 					RelativePath=".\src\obj\NiRawImageData.cpp"
 					>
 				</File>
+				<File
+					RelativePath=".\src\obj\NiRollController.cpp"
+					>
+				</File>
 				<File
 					RelativePath=".\src\obj\NiRotatingParticles.cpp"
 					>
@@ -2200,6 +2204,10 @@
 					RelativePath=".\include\obj\NiRawImageData.h"
 					>
 				</File>
+				<File
+					RelativePath=".\include\obj\NiRollController.h"
+					>
+				</File>
 				<File
 					RelativePath=".\include\obj\NiRotatingParticles.h"
 					>
diff --git a/src/NIF_IO.cpp b/src/NIF_IO.cpp
index 58a46354..fc91ae86 100644
--- a/src/NIF_IO.cpp
+++ b/src/NIF_IO.cpp
@@ -364,12 +364,12 @@ void NifStream( HeaderString & val, istream& in, NifInfo & info ) {
 	//Parse version string and return result.
 	info.version = ParseVersionString( val.header.substr( ver_start ) );
 
-	//Temporarily read the next 3 strings if this is a < 4 file
-	if ( info.version < VER_3_3_0_13 ) {
-		in.getline( tmp, 256 );
-		in.getline( tmp, 256 );
-		in.getline( tmp, 256 );
-	}
+	////Temporarily read the next 3 strings if this is a < 4 file
+	//if ( info.version < VER_3_3_0_13 ) {
+	//	in.getline( tmp, 256 );
+	//	in.getline( tmp, 256 );
+	//	in.getline( tmp, 256 );
+	//}
 
 	//if ( version < VER_4_0_0_0 ) {
 	//	throw runtime_error("NIF Versions below 4.0.0.0 are not yet supported");
diff --git a/src/gen/obj_impl.cpp b/src/gen/obj_impl.cpp
index 5dc6357f..8357429b 100644
--- a/src/gen/obj_impl.cpp
+++ b/src/gen/obj_impl.cpp
@@ -71,6 +71,7 @@ using namespace std;
 #include "../../include/obj/NiDirectionalLight.h"
 #include "../../include/obj/NiDitherProperty.h"
 #include "../../include/obj/NiFlipController.h"
+#include "../../include/obj/NiRollController.h"
 #include "../../include/obj/NiFloatData.h"
 #include "../../include/obj/NiFloatExtraData.h"
 #include "../../include/obj/NiFloatExtraDataController.h"
@@ -213,8 +214,14 @@ Ref<T> FixLink( const map<unsigned,NiObjectRef> & objects, list<unsigned int> &
 	link_stack.pop_front();
 
 	//Check if link is NULL
-	if ( index == 0xFFFFFFFF) {
-		return NULL;
+	if ( info.version > VER_3_3_0_13) {
+		if ( index == 0xFFFFFFFF) {
+			return NULL;
+		}
+	} else {
+		if ( index == 0 ) {
+			return NULL;
+		}
 	}
 
 	map<unsigned int,NiObjectRef>::const_iterator it = objects.find(index);
@@ -224,7 +231,11 @@ Ref<T> FixLink( const map<unsigned,NiObjectRef> & objects, list<unsigned int> &
 		
 	Ref<T> object = DynamicCast<T>(it->second);
 	if ( object == NULL ) {
-		throw runtime_error(FIX_LINK_CAST_ERROR);
+		stringstream ss;
+		ss << FIX_LINK_CAST_ERROR << endl;
+		ss << "Type of object with index " << index << " was:  " << it->second->GetType().GetTypeName() << endl;
+		ss << "Required type was:  " << T::TYPE.GetTypeName() << endl;
+		throw runtime_error( ss.str().c_str() );
 	}
 
 	return object;
@@ -1114,7 +1125,12 @@ void NiDynamicEffect::InternalRead( istream& in, list<unsigned int> & link_stack
 	if ( info.version >= 0x0A020000 ) {
 		NifStream( switchState, in, info );
 	};
-	NifStream( numAffectedNodes, in, info );
+	if ( info.version <= 0x04000002 ) {
+		NifStream( numAffectedNodes, in, info );
+	};
+	if ( info.version >= 0x0A010000 ) {
+		NifStream( numAffectedNodes, in, info );
+	};
 	if ( info.version <= 0x04000002 ) {
 		affectedNodeListPointers.resize(numAffectedNodes);
 		for (unsigned int i2 = 0; i2 < affectedNodeListPointers.size(); i2++) {
@@ -1136,7 +1152,12 @@ void NiDynamicEffect::InternalWrite( ostream& out, const map<NiObjectRef,unsigne
 	if ( info.version >= 0x0A020000 ) {
 		NifStream( switchState, out, info );
 	};
-	NifStream( numAffectedNodes, out, info );
+	if ( info.version <= 0x04000002 ) {
+		NifStream( numAffectedNodes, out, info );
+	};
+	if ( info.version >= 0x0A010000 ) {
+		NifStream( numAffectedNodes, out, info );
+	};
 	if ( info.version <= 0x04000002 ) {
 		for (unsigned int i2 = 0; i2 < affectedNodeListPointers.size(); i2++) {
 			NifStream( affectedNodeListPointers[i2], out, info );
@@ -4961,6 +4982,9 @@ void NiCamera::InternalRead( istream& in, list<unsigned int> & link_stack, const
 	if ( info.version >= 0x04020100 ) {
 		NifStream( unknownInt2, in, info );
 	};
+	if ( info.version <= 0x03010000 ) {
+		NifStream( unknownInt3, in, info );
+	};
 }
 
 void NiCamera::InternalWrite( ostream& out, const map<NiObjectRef,unsigned int> & link_map, const NifInfo & info ) const {
@@ -4990,6 +5014,9 @@ void NiCamera::InternalWrite( ostream& out, const map<NiObjectRef,unsigned int>
 	if ( info.version >= 0x04020100 ) {
 		NifStream( unknownInt2, out, info );
 	};
+	if ( info.version <= 0x03010000 ) {
+		NifStream( unknownInt3, out, info );
+	};
 }
 
 std::string NiCamera::InternalAsString( bool verbose ) const {
@@ -5012,6 +5039,7 @@ std::string NiCamera::InternalAsString( bool verbose ) const {
 	out << "  Unknown Link?:  " << unknownLink_ << endl;
 	out << "  Unknown Int:  " << unknownInt << endl;
 	out << "  Unknown Int 2:  " << unknownInt2 << endl;
+	out << "  Unknown Int 3:  " << unknownInt3 << endl;
 	return out.str();
 }
 
@@ -5764,15 +5792,26 @@ void NiFlipController::InternalRead( istream& in, list<unsigned int> & link_stac
 	unsigned int block_num;
 	NiSingleInterpolatorController::Read( in, link_stack, info );
 	NifStream( textureSlot, in, info );
-	if ( info.version <= 0x0A010000 ) {
+	if ( ( info.version >= 0x04000000 ) && ( info.version <= 0x0A010000 ) ) {
 		NifStream( unknownInt2, in, info );
+	};
+	if ( info.version <= 0x0A010000 ) {
 		NifStream( delta, in, info );
 	};
 	NifStream( numSources, in, info );
-	sources.resize(numSources);
-	for (unsigned int i1 = 0; i1 < sources.size(); i1++) {
-		NifStream( block_num, in, info );
-		link_stack.push_back( block_num );
+	if ( info.version >= 0x04000000 ) {
+		sources.resize(numSources);
+		for (unsigned int i2 = 0; i2 < sources.size(); i2++) {
+			NifStream( block_num, in, info );
+			link_stack.push_back( block_num );
+		};
+	};
+	if ( info.version <= 0x03010000 ) {
+		image.resize(numSources);
+		for (unsigned int i2 = 0; i2 < image.size(); i2++) {
+			NifStream( block_num, in, info );
+			link_stack.push_back( block_num );
+		};
 	};
 }
 
@@ -5780,16 +5819,28 @@ void NiFlipController::InternalWrite( ostream& out, const map<NiObjectRef,unsign
 	NiSingleInterpolatorController::Write( out, link_map, info );
 	numSources = (unsigned int)(sources.size());
 	NifStream( textureSlot, out, info );
-	if ( info.version <= 0x0A010000 ) {
+	if ( ( info.version >= 0x04000000 ) && ( info.version <= 0x0A010000 ) ) {
 		NifStream( unknownInt2, out, info );
+	};
+	if ( info.version <= 0x0A010000 ) {
 		NifStream( delta, out, info );
 	};
 	NifStream( numSources, out, info );
-	for (unsigned int i1 = 0; i1 < sources.size(); i1++) {
-		if ( sources[i1] != NULL )
-			NifStream( link_map.find( StaticCast<NiObject>(sources[i1]) )->second, out, info );
-		else
-			NifStream( 0xffffffff, out, info );
+	if ( info.version >= 0x04000000 ) {
+		for (unsigned int i2 = 0; i2 < sources.size(); i2++) {
+			if ( sources[i2] != NULL )
+				NifStream( link_map.find( StaticCast<NiObject>(sources[i2]) )->second, out, info );
+			else
+				NifStream( 0xffffffff, out, info );
+		};
+	};
+	if ( info.version <= 0x03010000 ) {
+		for (unsigned int i2 = 0; i2 < image.size(); i2++) {
+			if ( image[i2] != NULL )
+				NifStream( link_map.find( StaticCast<NiObject>(image[i2]) )->second, out, info );
+			else
+				NifStream( 0xffffffff, out, info );
+		};
 	};
 }
 
@@ -5814,13 +5865,32 @@ std::string NiFlipController::InternalAsString( bool verbose ) const {
 		out << "    Sources[" << i1 << "]:  " << sources[i1] << endl;
 		array_output_count++;
 	};
+	array_output_count = 0;
+	for (unsigned int i1 = 0; i1 < image.size(); i1++) {
+		if ( !verbose && ( array_output_count > MAXARRAYDUMP ) ) {
+			out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl;
+			break;
+		};
+		if ( !verbose && ( array_output_count > MAXARRAYDUMP ) ) {
+			break;
+		};
+		out << "    Image[" << i1 << "]:  " << image[i1] << endl;
+		array_output_count++;
+	};
 	return out.str();
 }
 
 void NiFlipController::InternalFixLinks( const map<unsigned int,NiObjectRef> & objects, list<unsigned int> & link_stack, const NifInfo & info ) {
 	NiSingleInterpolatorController::FixLinks( objects, link_stack, info );
-	for (unsigned int i1 = 0; i1 < sources.size(); i1++) {
-		sources[i1] = FixLink<NiSourceTexture>( objects, link_stack, info );
+	if ( info.version >= 0x04000000 ) {
+		for (unsigned int i2 = 0; i2 < sources.size(); i2++) {
+			sources[i2] = FixLink<NiSourceTexture>( objects, link_stack, info );
+		};
+	};
+	if ( info.version <= 0x03010000 ) {
+		for (unsigned int i2 = 0; i2 < image.size(); i2++) {
+			image[i2] = FixLink<NiImage>( objects, link_stack, info );
+		};
 	};
 }
 
@@ -5831,6 +5901,46 @@ std::list<NiObjectRef> NiFlipController::InternalGetRefs() const {
 		if ( sources[i1] != NULL )
 			refs.push_back(StaticCast<NiObject>(sources[i1]));
 	};
+	for (unsigned int i1 = 0; i1 < image.size(); i1++) {
+		if ( image[i1] != NULL )
+			refs.push_back(StaticCast<NiObject>(image[i1]));
+	};
+	return refs;
+}
+
+void NiRollController::InternalRead( istream& in, list<unsigned int> & link_stack, const NifInfo & info ) {
+	unsigned int block_num;
+	NiSingleInterpolatorController::Read( in, link_stack, info );
+	NifStream( block_num, in, info );
+	link_stack.push_back( block_num );
+}
+
+void NiRollController::InternalWrite( ostream& out, const map<NiObjectRef,unsigned int> & link_map, const NifInfo & info ) const {
+	NiSingleInterpolatorController::Write( out, link_map, info );
+	if ( data != NULL )
+		NifStream( link_map.find( StaticCast<NiObject>(data) )->second, out, info );
+	else
+		NifStream( 0xffffffff, out, info );
+}
+
+std::string NiRollController::InternalAsString( bool verbose ) const {
+	stringstream out;
+	unsigned int array_output_count = 0;
+	out << NiSingleInterpolatorController::asString();
+	out << "  Data:  " << data << endl;
+	return out.str();
+}
+
+void NiRollController::InternalFixLinks( const map<unsigned int,NiObjectRef> & objects, list<unsigned int> & link_stack, const NifInfo & info ) {
+	NiSingleInterpolatorController::FixLinks( objects, link_stack, info );
+	data = FixLink<NiFloatData>( objects, link_stack, info );
+}
+
+std::list<NiObjectRef> NiRollController::InternalGetRefs() const {
+	list<Ref<NiObject> > refs;
+	refs = NiSingleInterpolatorController::GetRefs();
+	if ( data != NULL )
+		refs.push_back(StaticCast<NiObject>(data));
 	return refs;
 }
 
@@ -8387,7 +8497,9 @@ void NiParticleSystemController::InternalRead( istream& in, list<unsigned int> &
 		NifStream( trailer, in, info );
 	};
 	if ( info.version <= 0x03010000 ) {
-		for (unsigned int i2 = 0; i2 < 3; i2++) {
+		NifStream( block_num, in, info );
+		link_stack.push_back( block_num );
+		for (unsigned int i2 = 0; i2 < 2; i2++) {
 			NifStream( unkownFloats[i2], in, info );
 		};
 	};
@@ -8471,7 +8583,11 @@ void NiParticleSystemController::InternalWrite( ostream& out, const map<NiObject
 		NifStream( trailer, out, info );
 	};
 	if ( info.version <= 0x03010000 ) {
-		for (unsigned int i2 = 0; i2 < 3; i2++) {
+		if ( colorData != NULL )
+			NifStream( link_map.find( StaticCast<NiObject>(colorData) )->second, out, info );
+		else
+			NifStream( 0xffffffff, out, info );
+		for (unsigned int i2 = 0; i2 < 2; i2++) {
 			NifStream( unkownFloats[i2], out, info );
 		};
 	};
@@ -8537,8 +8653,9 @@ std::string NiParticleSystemController::InternalAsString( bool verbose ) const {
 	out << "  Particle Extra:  " << particleExtra << endl;
 	out << "  Unknown Link 2:  " << unknownLink2 << endl;
 	out << "  Trailer:  " << trailer << endl;
+	out << "  Color Data:  " << colorData << endl;
 	array_output_count = 0;
-	for (unsigned int i1 = 0; i1 < 3; i1++) {
+	for (unsigned int i1 = 0; i1 < 2; i1++) {
 		if ( !verbose && ( array_output_count > MAXARRAYDUMP ) ) {
 			out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl;
 			break;
@@ -8560,6 +8677,9 @@ void NiParticleSystemController::InternalFixLinks( const map<unsigned int,NiObje
 	};
 	particleExtra = FixLink<AParticleModifier>( objects, link_stack, info );
 	unknownLink2 = FixLink<NiObject>( objects, link_stack, info );
+	if ( info.version <= 0x03010000 ) {
+		colorData = FixLink<NiColorData>( objects, link_stack, info );
+	};
 }
 
 std::list<NiObjectRef> NiParticleSystemController::InternalGetRefs() const {
@@ -8571,6 +8691,8 @@ std::list<NiObjectRef> NiParticleSystemController::InternalGetRefs() const {
 		refs.push_back(StaticCast<NiObject>(particleExtra));
 	if ( unknownLink2 != NULL )
 		refs.push_back(StaticCast<NiObject>(unknownLink2));
+	if ( colorData != NULL )
+		refs.push_back(StaticCast<NiObject>(colorData));
 	return refs;
 }
 
diff --git a/src/niflib.cpp b/src/niflib.cpp
index 0a96342d..8752e249 100644
--- a/src/niflib.cpp
+++ b/src/niflib.cpp
@@ -170,6 +170,7 @@ vector<NiObjectRef> ReadNifList( istream & in, NifInfo * info ) {
 	//--Read Objects--//
 	size_t numObjects = header.numBlocks;
 	map<unsigned,NiObjectRef> objects; //Map to hold objects by number
+	vector<NiObjectRef> obj_list; //Vector to hold links in the order they were created.
 	list<unsigned int> link_stack; //List to add link values to as they're read in from the file
 	string objectType;
 	stringstream errStream;
@@ -298,7 +299,12 @@ vector<NiObjectRef> ReadNifList( istream & in, NifInfo * info ) {
 
 		//Read new object
 		new_obj->Read( in, link_stack, *info );
+
+		//Add object to map
 		objects[index] = new_obj;
+
+		//Add object to list
+		obj_list.push_back(new_obj);
 			
 #ifdef PRINT_OBJECT_CONTENTS
 		cout << endl << new_obj->asString() << endl;
@@ -335,23 +341,18 @@ vector<NiObjectRef> ReadNifList( istream & in, NifInfo * info ) {
 	for ( it = link_stack.begin(); it != link_stack.end(); ++it ) {
 		cout << *it << endl;
 	}
-#endif
-	
-#ifdef DEBUG_LINK_PHASE
+
 	cout << "Fixing Links:"  << endl;
 #endif
 	//--Now that all objects are read, go back and fix the links--//
-	vector<NiObjectRef> obj_list;
+	
 
-	for ( map<unsigned,NiObjectRef>::iterator it = objects.begin(); it != objects.end(); ++it ) {
+	for ( unsigned int i = 0; i < obj_list.size(); ++i ) {
 #ifdef DEBUG_LINK_PHASE
-		cout << it->first << ":  " << it->second << endl;
+		cout << "   " << i << ":  " << obj_list[i] << endl;
 #endif
 		//Fix links & other pre-processing
-		it->second->FixLinks( objects, link_stack, *info );
-
-		//Add object to list
-		obj_list.push_back(it->second);
+		obj_list[i]->FixLinks( objects, link_stack, *info );
 	}
 
 	//delete info if it was dynamically allocated
@@ -987,7 +988,7 @@ void MergeNifTrees( NiNode * target, NiSequenceStreamHelper * right, unsigned ve
 
 bool IsSupportedVersion( unsigned int version ) {
 	switch (version) {
-		//case VER_3_1:
+		case VER_3_1:
 		case VER_3_3_0_13:
 		case VER_4_0_0_0:
 		case VER_4_0_0_2:
diff --git a/src/obj/NiFlipController.cpp b/src/obj/NiFlipController.cpp
index 2ce75188..434d790d 100644
--- a/src/obj/NiFlipController.cpp
+++ b/src/obj/NiFlipController.cpp
@@ -3,6 +3,7 @@ All rights reserved.  Please see niflib.h for license. */
 
 #include "../../include/obj/NiFlipController.h"
 #include "../../include/obj/NiSourceTexture.h"
+#include "../../include/obj/NiImage.h"
 using namespace Niflib;
 
 //Definition of TYPE constant
diff --git a/src/obj/NiParticleSystemController.cpp b/src/obj/NiParticleSystemController.cpp
index bb840613..dbfafd38 100644
--- a/src/obj/NiParticleSystemController.cpp
+++ b/src/obj/NiParticleSystemController.cpp
@@ -5,6 +5,7 @@ All rights reserved.  Please see niflib.h for license. */
 #include "../../include/gen/Particle.h"
 #include "../../include/obj/NiObject.h"
 #include "../../include/obj/AParticleModifier.h"
+#include "../../include/obj/NiColorData.h"
 using namespace Niflib;
 
 //Definition of TYPE constant
diff --git a/src/obj/NiRollController.cpp b/src/obj/NiRollController.cpp
new file mode 100644
index 00000000..96052ce2
--- /dev/null
+++ b/src/obj/NiRollController.cpp
@@ -0,0 +1,62 @@
+/* Copyright (c) 2006, NIF File Format Library and Tools
+All rights reserved.  Please see niflib.h for license. */
+
+#include "../../include/obj/NiRollController.h"
+#include "../../include/obj/NiFloatData.h"
+using namespace Niflib;
+
+//Definition of TYPE constant
+const Type NiRollController::TYPE("NiRollController", &NI_ROLL_CONTROLLER_PARENT::TYPE );
+
+NiRollController::NiRollController() NI_ROLL_CONTROLLER_CONSTRUCT {}
+
+NiRollController::~NiRollController() {}
+
+void NiRollController::Read( istream& in, list<unsigned int> & link_stack, const NifInfo & info ) {
+	InternalRead( in, link_stack, info );
+}
+
+void NiRollController::Write( ostream& out, const map<NiObjectRef,unsigned int> & link_map, const NifInfo & info ) const {
+	InternalWrite( out, link_map, info );
+}
+
+string NiRollController::asString( bool verbose ) const {
+	return InternalAsString( verbose );
+}
+
+void NiRollController::FixLinks( const map<unsigned int,NiObjectRef> & objects, list<unsigned int> & link_stack, const NifInfo & info ) {
+	InternalFixLinks( objects, link_stack, info );
+}
+
+list<NiObjectRef> NiRollController::GetRefs() const {
+	return InternalGetRefs();
+}
+
+const Type & NiRollController::GetType() const {
+	return TYPE;
+}
+
+namespace Niflib {
+	typedef NiObject*(*obj_factory_func)();
+	extern map<string, obj_factory_func> global_object_map;
+
+	//Initialization function
+	static bool Initialization();
+
+	//A static bool to force the initialization to happen pre-main
+	static bool obj_initialized = Initialization();
+
+	static bool Initialization() {
+		//Add the function to the global object map
+		global_object_map["NiRollController"] = NiRollController::Create;
+
+		//Do this stuff just to make sure the compiler doesn't optimize this function and the static bool away.
+		obj_initialized = true;
+		return obj_initialized;
+	}
+}
+
+NiObject * NiRollController::Create() {
+	return new NiRollController;
+}
+
-- 
GitLab