From 534752d76c884e0ee2ce1a5e174db36a92593a07 Mon Sep 17 00:00:00 2001
From: Tazpn <tazpn@users.sourceforge.net>
Date: Sat, 16 Sep 2006 21:53:16 +0000
Subject: [PATCH] 1. Add NiClod and NiClodData. 2. Fix PCH project settings. 3.
 Add NifSkope base partitioning algorithm 4. Add ability to use TriStripper
 instead of NvStripper for tristripdata 5. Sync with XML and equivalent
 changes.

---
 include/gen/obj_defines.h              |  62 +++-
 include/obj/NiClod.h                   |  42 +++
 include/obj/NiClodData.h               |  42 +++
 include/obj/NiControllerManager.h      |  19 +-
 include/obj/NiDefaultAVObjectPalette.h |   6 +
 include/obj/NiDynamicEffect.h          |  24 +-
 include/obj/NiSkinPartition.h          |   1 +
 include/obj/NiTriBasedGeom.h           |   2 +-
 include/obj/NiTriShapeData.h           |   2 +
 include/obj/NiTriStripsData.h          |   5 +
 niflib.vcproj                          | 126 +++++++-
 src/gen/obj_factories.cpp              |   6 +
 src/gen/obj_impl.cpp                   | 186 +++++++++---
 src/obj/NiClod.cpp                     |  37 +++
 src/obj/NiClodData.cpp                 |  37 +++
 src/obj/NiControllerManager.cpp        |  24 ++
 src/obj/NiDefaultAVObjectPalette.cpp   |  18 ++
 src/obj/NiDynamicEffect.cpp            |  24 +-
 src/obj/NiLODNode.cpp                  |   4 +-
 src/obj/NiScreenLODData.cpp            |   4 +-
 src/obj/NiSkinPartition.cpp            | 393 ++++++++++++++++++++++++-
 src/obj/NiTriBasedGeom.cpp             |   8 +-
 src/obj/NiTriShapeData.cpp             |   4 +
 src/obj/NiTriStripsData.cpp            | 105 +++++++
 24 files changed, 1075 insertions(+), 106 deletions(-)
 create mode 100644 include/obj/NiClod.h
 create mode 100644 include/obj/NiClodData.h
 create mode 100644 src/obj/NiClod.cpp
 create mode 100644 src/obj/NiClodData.cpp

diff --git a/include/gen/obj_defines.h b/include/gen/obj_defines.h
index cadeace8..728411a8 100644
--- a/include/gen/obj_defines.h
+++ b/include/gen/obj_defines.h
@@ -533,18 +533,17 @@ InternalFixLinks( objects, link_stack, version, user_version ); \
 return InternalGetRefs(); \
 
 #define NI_DYNAMIC_EFFECT_MEMBERS \
-bool hasAffectedNodeList_; \
-uint affectedNodeList_; \
 bool switchState; \
 mutable uint numAffectedNodes; \
 vector<Ref<NiAVObject > > affectedNodes; \
+vector<uint > affectedNodeListPointers; \
 
 #define NI_DYNAMIC_EFFECT_INCLUDE "NiAVObject.h" \
 
 #define NI_DYNAMIC_EFFECT_PARENT NiAVObject \
 
 #define NI_DYNAMIC_EFFECT_CONSTRUCT \
- : hasAffectedNodeList_(false), affectedNodeList_((uint)0), switchState(false), numAffectedNodes((uint)0) \
+ : switchState(false), numAffectedNodes((uint)0) \
 
 #define NI_DYNAMIC_EFFECT_READ \
 InternalRead( in, link_stack, version, user_version ); \
@@ -3364,14 +3363,14 @@ Vector3 lodCenter; \
 mutable uint numLodLevels; \
 vector<LODRange > lodLevels; \
 ushort unknownShort; \
-Ref<NiLODData > rangeData; \
+Ref<NiLODData > lodLevelData; \
 
 #define NI_L_O_D_NODE_INCLUDE "NiNode.h" \
 
 #define NI_L_O_D_NODE_PARENT NiNode \
 
 #define NI_L_O_D_NODE_CONSTRUCT \
- : numLodLevels((uint)0), unknownShort((ushort)0), rangeData(NULL) \
+ : numLodLevels((uint)0), unknownShort((ushort)0), lodLevelData(NULL) \
 
 #define NI_L_O_D_NODE_READ \
 InternalRead( in, link_stack, version, user_version ); \
@@ -4849,7 +4848,7 @@ float boundRadius; \
 Vector3 worldCenter; \
 float worldRadius; \
 mutable uint proportionCount; \
-vector<float > proportion; \
+vector<float > proportionLevels; \
 
 #define NI_SCREEN_L_O_D_DATA_INCLUDE "NiLODData.h" \
 
@@ -5597,6 +5596,57 @@ InternalFixLinks( objects, link_stack, version, user_version ); \
 #define NI_TRI_STRIPS_DATA_GETREFS \
 return InternalGetRefs(); \
 
+#define NI_CLOD_MEMBERS \
+
+#define NI_CLOD_INCLUDE "NiTriBasedGeom.h" \
+
+#define NI_CLOD_PARENT NiTriBasedGeom \
+
+#define NI_CLOD_CONSTRUCT \
+
+#define NI_CLOD_READ \
+InternalRead( in, link_stack, version, user_version ); \
+
+#define NI_CLOD_WRITE \
+InternalWrite( out, link_map, version, user_version ); \
+
+#define NI_CLOD_STRING \
+return InternalAsString( verbose ); \
+
+#define NI_CLOD_FIXLINKS \
+InternalFixLinks( objects, link_stack, version, user_version ); \
+
+#define NI_CLOD_GETREFS \
+return InternalGetRefs(); \
+
+#define NI_CLOD_DATA_MEMBERS \
+array<ushort,5> unknown5Shorts; \
+float unknownFloat; \
+uint unknownInt; \
+array<ushort,44> unknownClodShorts; \
+
+#define NI_CLOD_DATA_INCLUDE "NiTriBasedGeomData.h" \
+
+#define NI_CLOD_DATA_PARENT NiTriBasedGeomData \
+
+#define NI_CLOD_DATA_CONSTRUCT \
+ : unknownFloat(0.0f), unknownInt((uint)0) \
+
+#define NI_CLOD_DATA_READ \
+InternalRead( in, link_stack, version, user_version ); \
+
+#define NI_CLOD_DATA_WRITE \
+InternalWrite( out, link_map, version, user_version ); \
+
+#define NI_CLOD_DATA_STRING \
+return InternalAsString( verbose ); \
+
+#define NI_CLOD_DATA_FIXLINKS \
+InternalFixLinks( objects, link_stack, version, user_version ); \
+
+#define NI_CLOD_DATA_GETREFS \
+return InternalGetRefs(); \
+
 #define NI_U_V_CONTROLLER_MEMBERS \
 ushort unknownShort; \
 Ref<NiUVData > data; \
diff --git a/include/obj/NiClod.h b/include/obj/NiClod.h
new file mode 100644
index 00000000..98b05419
--- /dev/null
+++ b/include/obj/NiClod.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2006, NIF File Format Library and Tools
+All rights reserved.  Please see niflib.h for licence. */
+
+#ifndef _NICLOD_H_
+#define _NICLOD_H_
+
+#include "NiTriBasedGeom.h"
+namespace Niflib {
+
+
+#include "../gen/obj_defines.h"
+
+class NiClod;
+typedef Ref<NiClod> NiClodRef;
+
+/*!
+ * NiClod - A shape node that refers to singular triangle data.
+ */
+
+class NIFLIB_API NiClod : public NI_CLOD_PARENT {
+public:
+	NiClod();
+	~NiClod();
+	//Run-Time Type Information
+	static const Type & TypeConst() { return TYPE; }
+private:
+	static const Type TYPE;
+public:
+	virtual void Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version );
+	virtual void Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const;
+	virtual string asString( bool verbose = false ) const;
+	virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version );
+	virtual list<NiObjectRef> GetRefs() const;
+	virtual const Type & GetType() const;
+
+protected:
+	NI_CLOD_MEMBERS
+	STANDARD_INTERNAL_METHODS
+};
+
+}
+#endif
diff --git a/include/obj/NiClodData.h b/include/obj/NiClodData.h
new file mode 100644
index 00000000..d78146ee
--- /dev/null
+++ b/include/obj/NiClodData.h
@@ -0,0 +1,42 @@
+/* Copyright (c) 2006, NIF File Format Library and Tools
+All rights reserved.  Please see niflib.h for licence. */
+
+#ifndef _NICLODDATA_H_
+#define _NICLODDATA_H_
+
+#include "NiTriBasedGeomData.h"
+namespace Niflib {
+
+
+#include "../gen/obj_defines.h"
+
+class NiClodData;
+typedef Ref<NiClodData> NiClodDataRef;
+
+/*!
+ * NiClodData - A shape node that refers to singular triangle data.
+ */
+
+class NIFLIB_API NiClodData : public NI_CLOD_DATA_PARENT {
+public:
+	NiClodData();
+	~NiClodData();
+	//Run-Time Type Information
+	static const Type & TypeConst() { return TYPE; }
+private:
+	static const Type TYPE;
+public:
+	virtual void Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version );
+	virtual void Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const;
+	virtual string asString( bool verbose = false ) const;
+	virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version );
+	virtual list<NiObjectRef> GetRefs() const;
+	virtual const Type & GetType() const;
+
+protected:
+	NI_CLOD_DATA_MEMBERS
+	STANDARD_INTERNAL_METHODS
+};
+
+}
+#endif
diff --git a/include/obj/NiControllerManager.h b/include/obj/NiControllerManager.h
index 1fb91e64..9fa69342 100644
--- a/include/obj/NiControllerManager.h
+++ b/include/obj/NiControllerManager.h
@@ -39,7 +39,24 @@ public:
 	virtual list<NiObjectRef> GetRefs() const;
 	virtual const Type & GetType() const;
 
-	//TODO:  This is not a priority but needs to be implemented eventually
+	/*!
+	 * Designates whether animation sequences are cumulative?
+	 */
+	bool GetCumulative() const;
+	void SetCumulative( bool value );
+
+	/*!
+	 * Refers to a list of NiControllerSequence object.
+	 */
+	vector<Ref<NiControllerSequence > > GetControllerSequences() const;
+	void SetControllerSequences( const vector<Ref<NiControllerSequence > >& value );
+
+	/*!
+	 * Refers to a NiDefaultAVObjectPalette.
+	 */
+	Ref<NiDefaultAVObjectPalette > GetObjectPalette() const;
+	void SetObjectPalette( Ref<NiDefaultAVObjectPalette > value );
+
 protected:
 	NI_CONTROLLER_MANAGER_MEMBERS
 	STANDARD_INTERNAL_METHODS
diff --git a/include/obj/NiDefaultAVObjectPalette.h b/include/obj/NiDefaultAVObjectPalette.h
index 1d72351d..5381a6a4 100644
--- a/include/obj/NiDefaultAVObjectPalette.h
+++ b/include/obj/NiDefaultAVObjectPalette.h
@@ -37,6 +37,12 @@ public:
 	virtual list<NiObjectRef> GetRefs() const;
 	virtual const Type & GetType() const;
 
+	/*!
+	 * The objects.
+	 */
+	vector<Ref<NiAVObject> > GetObjs() const;
+	void SetObjs( const vector<Ref<NiAVObject> >& value );
+
 protected:
 	NI_DEFAULT_A_V_OBJECT_PALETTE_MEMBERS
 	STANDARD_INTERNAL_METHODS
diff --git a/include/obj/NiDynamicEffect.h b/include/obj/NiDynamicEffect.h
index 67f8513a..a9af02e2 100644
--- a/include/obj/NiDynamicEffect.h
+++ b/include/obj/NiDynamicEffect.h
@@ -38,21 +38,6 @@ public:
 	virtual list<NiObjectRef> GetRefs() const;
 	virtual const Type & GetType() const;
 
-	/*!
-	 * Determines whether or not an unknown integer follows.
-	 */
-	bool GetHasAffectedNodeList_() const;
-	void SetHasAffectedNodeList_( bool value );
-
-	/*!
-	 * This is probably the list of affected nodes. For some reason i do not
-	 * know the max exporter seems to write pointers instead of links. But it
-	 * doesn't matter because at least in version 4.0.0.2 the list is
-	 * automagically updated by the engine during the load stage.
-	 */
-	uint GetAffectedNodeList_() const;
-	void SetAffectedNodeList_( uint value );
-
 	/*!
 	 * Turns effect on and off?  Switches list to list of unaffected nodes?
 	 */
@@ -65,6 +50,15 @@ public:
 	vector<Ref<NiAVObject > > GetAffectedNodes() const;
 	void SetAffectedNodes( const vector<Ref<NiAVObject > >& value );
 
+	/*!
+	 * This is probably the list of affected nodes. For some reason i do not
+	 * know the max exporter seems to write pointers instead of links. But it
+	 * doesn't matter because at least in version 4.0.0.2 the list is
+	 * automagically updated by the engine during the load stage.
+	 */
+	vector<uint > GetAffectedNodeListPointers() const;
+	void SetAffectedNodeListPointers( const vector<uint >& value );
+
 protected:
 	NI_DYNAMIC_EFFECT_MEMBERS
 	STANDARD_INTERNAL_METHODS
diff --git a/include/obj/NiSkinPartition.h b/include/obj/NiSkinPartition.h
index b9656349..df04b7d0 100644
--- a/include/obj/NiSkinPartition.h
+++ b/include/obj/NiSkinPartition.h
@@ -74,6 +74,7 @@ public:
 protected:
    friend class NiTriBasedGeom;
    NiSkinPartition(Ref<NiTriBasedGeom> shape);
+   NiSkinPartition(Ref<NiTriBasedGeom> shape, int maxBonesPerPartition, int maxBonesPerVertex);
 
    void SetNumPartitions( int value );
    void SetWeightsPerVertex( int partition, ushort value );
diff --git a/include/obj/NiTriBasedGeom.h b/include/obj/NiTriBasedGeom.h
index 5ad3c35e..7c6f56f1 100644
--- a/include/obj/NiTriBasedGeom.h
+++ b/include/obj/NiTriBasedGeom.h
@@ -56,7 +56,7 @@ public:
 	 */
 	void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n );
 
-   void GenHardwareSkinInfo( int max_bones_per_partition = 4 );
+   void GenHardwareSkinInfo( int max_bones_per_partition = 4, int max_bones_per_vertex = 4 );
 
 	Ref<NiSkinInstance> GetSkinInstance() const;
 
diff --git a/include/obj/NiTriShapeData.h b/include/obj/NiTriShapeData.h
index f4b576e6..87d7b973 100644
--- a/include/obj/NiTriShapeData.h
+++ b/include/obj/NiTriShapeData.h
@@ -35,6 +35,8 @@ public:
 	virtual const Type & GetType() const;
 public:
 
+   NiTriShapeData(const vector<Triangle>& verts);
+
 	//--Match Detection--//
 	
 	//Re-implemented only to casue match detection data to be cleared
diff --git a/include/obj/NiTriStripsData.h b/include/obj/NiTriStripsData.h
index 5893de6f..1c9a315f 100644
--- a/include/obj/NiTriStripsData.h
+++ b/include/obj/NiTriStripsData.h
@@ -32,6 +32,9 @@ public:
 	virtual list<NiObjectRef> GetRefs() const;
 	virtual const Type & GetType() const;
 
+
+   NiTriStripsData(const vector<Triangle> &tris, bool nvtristrips = true);
+
 	//--Counts--//
 
 	/*! Used to get the number of triangle strips that this mesh is divided into.
@@ -77,6 +80,8 @@ public:
    virtual void SetTriangles( const vector<Triangle> & in );
 
 private:
+   void SetNvTriangles( const vector<Triangle> & in );
+   void SetTSTriangles( const vector<Triangle> & in );
 	ushort CalcTriangleCount() const;
 
 protected:
diff --git a/niflib.vcproj b/niflib.vcproj
index d43e9283..36174843 100644
--- a/niflib.vcproj
+++ b/niflib.vcproj
@@ -17,8 +17,8 @@
 	<Configurations>
 		<Configuration
 			Name="Debug|Win32"
-			OutputDirectory="$(ProjectDir)../Debug"
-			IntermediateDirectory="$(ProjectDir)../Debug"
+			OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			CharacterSet="2"
@@ -41,6 +41,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
+				AdditionalIncludeDirectories="$(ProjectDir)"
 				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
 				MinimalRebuild="true"
 				BasicRuntimeChecks="3"
@@ -81,8 +82,8 @@
 		</Configuration>
 		<Configuration
 			Name="Release|Win32"
-			OutputDirectory="$(ProjectDir)..\Release"
-			IntermediateDirectory="$(ProjectDir)..\Release"
+			OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			CharacterSet="2"
@@ -107,6 +108,7 @@
 				Name="VCCLCompilerTool"
 				Optimization="0"
 				WholeProgramOptimization="false"
+				AdditionalIncludeDirectories="$(ProjectDir)"
 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
 				RuntimeLibrary="0"
 				UsePrecompiledHeader="0"
@@ -145,8 +147,8 @@
 		</Configuration>
 		<Configuration
 			Name="PyNiflib|Win32"
-			OutputDirectory="$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
+			OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			CharacterSet="2"
@@ -168,6 +170,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="$(ProjectDir)"
 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
 				RuntimeLibrary="0"
 				UsePrecompiledHeader="0"
@@ -205,8 +208,8 @@
 		</Configuration>
 		<Configuration
 			Name="Release - DLL|Win32"
-			OutputDirectory="$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
+			OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)"
 			ConfigurationType="2"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			CharacterSet="2"
@@ -231,6 +234,7 @@
 				Name="VCCLCompilerTool"
 				AdditionalOptions="/FI&quot;pch.h&quot;"
 				Optimization="3"
+				AdditionalIncludeDirectories="$(ProjectDir)"
 				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BUILDING_NIFLIB_DLL;USE_NIFLIB_DLL"
 				RuntimeLibrary="2"
 				UsePrecompiledHeader="0"
@@ -278,8 +282,8 @@
 		</Configuration>
 		<Configuration
 			Name="Debug - PCH|Win32"
-			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
-			IntermediateDirectory="$(ConfigurationName)"
+			OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)"
 			ConfigurationType="4"
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			CharacterSet="2"
@@ -301,16 +305,83 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalOptions="/FI&quot;$(ProjectDir)pch.h&quot;"
+				AdditionalOptions="/FI&quot;$(ProjectDir)include\pch.h&quot;"
 				Optimization="0"
+				AdditionalIncludeDirectories="$(ProjectDir)"
 				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
 				MinimalRebuild="true"
 				BasicRuntimeChecks="3"
 				RuntimeLibrary="1"
-				UsePrecompiledHeader="0"
-				PrecompiledHeaderThrough=""
+				UsePrecompiledHeader="2"
+				PrecompiledHeaderThrough="$(ProjectDir)include\pch.h"
+				WarningLevel="3"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="lib/niflib_debug.lib"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release - PCH|Win32"
+			OutputDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			IntermediateDirectory="$(ProjectDir)obj\$(ConfigurationName)"
+			ConfigurationType="4"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/FI&quot;$(ProjectDir)include\pch.h&quot;"
+				Optimization="0"
+				WholeProgramOptimization="false"
+				AdditionalIncludeDirectories="$(ProjectDir)"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="2"
+				PrecompiledHeaderThrough="$(ProjectDir)include\pch.h"
 				WarningLevel="3"
-				DebugInformationFormat="4"
+				DebugInformationFormat="3"
 			/>
 			<Tool
 				Name="VCManagedResourceCompilerTool"
@@ -323,7 +394,7 @@
 			/>
 			<Tool
 				Name="VCLibrarianTool"
-				OutputFile="$(ProjectDir)../bin/niflibd.lib"
+				OutputFile="lib/niflib.lib"
 			/>
 			<Tool
 				Name="VCALinkTool"
@@ -426,6 +497,15 @@
 						PrecompiledHeaderThrough="$(ProjectDir)include/pch.h"
 					/>
 				</FileConfiguration>
+				<FileConfiguration
+					Name="Release - PCH|Win32"
+					>
+					<Tool
+						Name="VCCLCompilerTool"
+						UsePrecompiledHeader="1"
+						PrecompiledHeaderThrough="$(ProjectDir)include\pch.h"
+					/>
+				</FileConfiguration>
 			</File>
 			<File
 				RelativePath=".\src\Type.cpp"
@@ -750,6 +830,14 @@
 					RelativePath=".\src\obj\NiCamera.cpp"
 					>
 				</File>
+				<File
+					RelativePath=".\src\obj\NiClod.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\src\obj\NiClodData.cpp"
+					>
+				</File>
 				<File
 					RelativePath=".\src\obj\NiCollisionData.cpp"
 					>
@@ -1824,6 +1912,14 @@
 					RelativePath=".\include\obj\NiCamera.h"
 					>
 				</File>
+				<File
+					RelativePath=".\include\obj\NiClod.h"
+					>
+				</File>
+				<File
+					RelativePath=".\include\obj\NiClodData.h"
+					>
+				</File>
 				<File
 					RelativePath=".\include\obj\NiCollisionData.h"
 					>
diff --git a/src/gen/obj_factories.cpp b/src/gen/obj_factories.cpp
index 729c5c5a..bd1a7d9a 100644
--- a/src/gen/obj_factories.cpp
+++ b/src/gen/obj_factories.cpp
@@ -349,6 +349,10 @@ NiObject * CreateNiTriShapeData() { return new NiTriShapeData; }
 NiObject * CreateNiTriStrips() { return new NiTriStrips; }
 #include "../../include/obj/NiTriStripsData.h"
 NiObject * CreateNiTriStripsData() { return new NiTriStripsData; }
+#include "../../include/obj/NiClod.h"
+NiObject * CreateNiClod() { return new NiClod; }
+#include "../../include/obj/NiClodData.h"
+NiObject * CreateNiClodData() { return new NiClodData; }
 #include "../../include/obj/NiUVController.h"
 NiObject * CreateNiUVController() { return new NiUVController; }
 #include "../../include/obj/NiUVData.h"
@@ -543,6 +547,8 @@ void RegisterBlockFactories() {
 	global_block_map["NiTriShapeData"] = CreateNiTriShapeData;
 	global_block_map["NiTriStrips"] = CreateNiTriStrips;
 	global_block_map["NiTriStripsData"] = CreateNiTriStripsData;
+	global_block_map["NiClod"] = CreateNiClod;
+	global_block_map["NiClodData"] = CreateNiClodData;
 	global_block_map["NiUVController"] = CreateNiUVController;
 	global_block_map["NiUVData"] = CreateNiUVData;
 	global_block_map["NiVectorExtraData"] = CreateNiVectorExtraData;
diff --git a/src/gen/obj_impl.cpp b/src/gen/obj_impl.cpp
index e0df54b8..86f2f94b 100644
--- a/src/gen/obj_impl.cpp
+++ b/src/gen/obj_impl.cpp
@@ -175,6 +175,8 @@ using namespace std;
 #include "../../include/obj/NiTriShapeData.h"
 #include "../../include/obj/NiTriStrips.h"
 #include "../../include/obj/NiTriStripsData.h"
+#include "../../include/obj/NiClod.h"
+#include "../../include/obj/NiClodData.h"
 #include "../../include/obj/NiUVController.h"
 #include "../../include/obj/NiUVData.h"
 #include "../../include/obj/NiVectorExtraData.h"
@@ -1146,39 +1148,33 @@ std::list<NiObjectRef> NiAVObject::InternalGetRefs() const {
 void NiDynamicEffect::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
 	uint block_num;
 	NiAVObject::Read( in, link_stack, version, user_version );
-	if ( version <= 0x04000002 ) {
-		NifStream( hasAffectedNodeList_, in, version );
-		if ( (hasAffectedNodeList_ != 0) ) {
-			NifStream( affectedNodeList_, in, version );
-		};
-	};
 	if ( version >= 0x0A020000 ) {
 		NifStream( switchState, in, version );
 	};
-	if ( version >= 0x0A010000 ) {
 		NifStream( numAffectedNodes, in, version );
+	if ( version >= 0x0A010000 ) {
 		affectedNodes.resize(numAffectedNodes);
 		for (uint i2 = 0; i2 < affectedNodes.size(); i2++) {
 			NifStream( block_num, in, version );
 			link_stack.push_back( block_num );
 		};
 	};
+	if ( version <= 0x0A000102 ) {
+		affectedNodeListPointers.resize(numAffectedNodes);
+		for (uint i2 = 0; i2 < affectedNodeListPointers.size(); i2++) {
+			NifStream( affectedNodeListPointers[i2], in, version );
+		};
+	};
 }
 
 void NiDynamicEffect::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
 	NiAVObject::Write( out, link_map, version, user_version );
 	numAffectedNodes = uint(affectedNodes.size());
-	if ( version <= 0x04000002 ) {
-		NifStream( hasAffectedNodeList_, out, version );
-		if ( (hasAffectedNodeList_ != 0) ) {
-			NifStream( affectedNodeList_, out, version );
-		};
-	};
 	if ( version >= 0x0A020000 ) {
 		NifStream( switchState, out, version );
 	};
-	if ( version >= 0x0A010000 ) {
 		NifStream( numAffectedNodes, out, version );
+	if ( version >= 0x0A010000 ) {
 		for (uint i2 = 0; i2 < affectedNodes.size(); i2++) {
 			if ( affectedNodes[i2] != NULL )
 				NifStream( link_map[StaticCast<NiObject>(affectedNodes[i2])], out, version );
@@ -1186,16 +1182,17 @@ void NiDynamicEffect::InternalWrite( ostream& out, map<NiObjectRef,uint> link_ma
 				NifStream( 0xffffffff, out, version );
 		};
 	};
+	if ( version <= 0x0A000102 ) {
+		for (uint i2 = 0; i2 < affectedNodeListPointers.size(); i2++) {
+			NifStream( affectedNodeListPointers[i2], out, version );
+		};
+	};
 }
 
 std::string NiDynamicEffect::InternalAsString( bool verbose ) const {
 	stringstream out;
 	out << NiAVObject::asString();
 	numAffectedNodes = uint(affectedNodes.size());
-	out << "  Has Affected Node List?:  " << hasAffectedNodeList_ << endl;
-	if ( (hasAffectedNodeList_ != 0) ) {
-		out << "    Affected Node List?:  " << affectedNodeList_ << endl;
-	};
 	out << "  Switch State:  " << switchState << endl;
 	out << "  Num Affected Nodes:  " << numAffectedNodes << endl;
 	for (uint i1 = 0; i1 < affectedNodes.size(); i1++) {
@@ -1205,6 +1202,13 @@ std::string NiDynamicEffect::InternalAsString( bool verbose ) const {
 		};
 		out << "    Affected Nodes[" << i1 << "]:  " << affectedNodes[i1] << endl;
 	};
+	for (uint i1 = 0; i1 < affectedNodeListPointers.size(); i1++) {
+		if ( !verbose && ( i1 > MAXARRAYDUMP ) ) {
+			out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl;
+			break;
+		};
+		out << "    Affected Node List Pointers[" << i1 << "]:  " << affectedNodeListPointers[i1] << endl;
+	};
 	return out.str();
 }
 
@@ -7486,8 +7490,8 @@ void NiLODNode::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, uns
 	};
 	if ( version >= 0x0A010000 ) {
 		NifStream( unknownShort, out, version );
-		if ( rangeData != NULL )
-			NifStream( link_map[StaticCast<NiObject>(rangeData)], out, version );
+		if ( lodLevelData != NULL )
+			NifStream( link_map[StaticCast<NiObject>(lodLevelData)], out, version );
 		else
 			NifStream( 0xffffffff, out, version );
 	};
@@ -7511,7 +7515,7 @@ std::string NiLODNode::InternalAsString( bool verbose ) const {
 		out << "    Far Extent:  " << lodLevels[i1].farExtent << endl;
 	};
 	out << "  Unknown Short:  " << unknownShort << endl;
-	out << "  Range Data:  " << rangeData << endl;
+	out << "  LOD Level Data:  " << lodLevelData << endl;
 	return out.str();
 }
 
@@ -7521,11 +7525,11 @@ void NiLODNode::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint
 		if (link_stack.empty())
 			throw runtime_error("Trying to pop a link from empty stack. This is probably a bug.");
 		if (link_stack.front() != 0xffffffff) {
-			rangeData = DynamicCast<NiLODData>(objects[link_stack.front()]);
-			if ( rangeData == NULL )
+			lodLevelData = DynamicCast<NiLODData>(objects[link_stack.front()]);
+			if ( lodLevelData == NULL )
 				throw runtime_error("Link could not be cast to required type during file read. This NIF file may be invalid or improperly understood.");
 		} else
-			rangeData = NULL;
+			lodLevelData = NULL;
 		link_stack.pop_front();
 	};
 }
@@ -7533,8 +7537,8 @@ void NiLODNode::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint
 std::list<NiObjectRef> NiLODNode::InternalGetRefs() const {
 	list<Ref<NiObject> > refs;
 	refs = NiNode::GetRefs();
-	if ( rangeData != NULL )
-		refs.push_back(StaticCast<NiObject>(rangeData));
+	if ( lodLevelData != NULL )
+		refs.push_back(StaticCast<NiObject>(lodLevelData));
 	return refs;
 }
 
@@ -10297,40 +10301,40 @@ void NiScreenLODData::InternalRead( istream& in, list<uint> & link_stack, unsign
 	NifStream( worldCenter, in, version );
 	NifStream( worldRadius, in, version );
 	NifStream( proportionCount, in, version );
-	proportion.resize(proportionCount);
-	for (uint i1 = 0; i1 < proportion.size(); i1++) {
-		NifStream( proportion[i1], in, version );
+	proportionLevels.resize(proportionCount);
+	for (uint i1 = 0; i1 < proportionLevels.size(); i1++) {
+		NifStream( proportionLevels[i1], in, version );
 	};
 }
 
 void NiScreenLODData::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
 	NiLODData::Write( out, link_map, version, user_version );
-	proportionCount = uint(proportion.size());
+	proportionCount = uint(proportionLevels.size());
 	NifStream( boundCenter, out, version );
 	NifStream( boundRadius, out, version );
 	NifStream( worldCenter, out, version );
 	NifStream( worldRadius, out, version );
 	NifStream( proportionCount, out, version );
-	for (uint i1 = 0; i1 < proportion.size(); i1++) {
-		NifStream( proportion[i1], out, version );
+	for (uint i1 = 0; i1 < proportionLevels.size(); i1++) {
+		NifStream( proportionLevels[i1], out, version );
 	};
 }
 
 std::string NiScreenLODData::InternalAsString( bool verbose ) const {
 	stringstream out;
 	out << NiLODData::asString();
-	proportionCount = uint(proportion.size());
+	proportionCount = uint(proportionLevels.size());
 	out << "  Bound Center:  " << boundCenter << endl;
 	out << "  Bound Radius:  " << boundRadius << endl;
 	out << "  World Center:  " << worldCenter << endl;
 	out << "  World Radius:  " << worldRadius << endl;
 	out << "  Proportion Count:  " << proportionCount << endl;
-	for (uint i1 = 0; i1 < proportion.size(); i1++) {
+	for (uint i1 = 0; i1 < proportionLevels.size(); i1++) {
 		if ( !verbose && ( i1 > MAXARRAYDUMP ) ) {
 			out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl;
 			break;
 		};
-		out << "    Proportion[" << i1 << "]:  " << proportion[i1] << endl;
+		out << "    Proportion Levels[" << i1 << "]:  " << proportionLevels[i1] << endl;
 	};
 	return out.str();
 }
@@ -11734,7 +11738,6 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un
 	if ( (textureCount == 8) ) {
 		NifStream( hasDecal1Texture, in, version );
 	};
-	if ( version >= 0x14000004 ) {
 		if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
 			NifStream( block_num, in, version );
 			link_stack.push_back( block_num );
@@ -11759,7 +11762,6 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un
 				};
 			};
 		};
-	};
 	if ( version >= 0x0A000100 ) {
 		NifStream( numShaderTextures, in, version );
 		shaderTextures.resize(numShaderTextures);
@@ -11997,7 +11999,6 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin
 	if ( (textureCount == 8) ) {
 		NifStream( hasDecal1Texture, out, version );
 	};
-	if ( version >= 0x14000004 ) {
 		if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
 			if ( decal1Texture.source != NULL )
 				NifStream( link_map[StaticCast<NiObject>(decal1Texture.source)], out, version );
@@ -12024,7 +12025,6 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin
 				};
 			};
 		};
-	};
 	if ( version >= 0x0A000100 ) {
 		NifStream( numShaderTextures, out, version );
 		for (uint i2 = 0; i2 < shaderTextures.size(); i2++) {
@@ -12320,7 +12320,6 @@ void NiTexturingProperty::InternalFixLinks( const vector<NiObjectRef> & objects,
 			decal0Texture.source = NULL;
 		link_stack.pop_front();
 	};
-	if ( version >= 0x14000004 ) {
 		if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
 			if (link_stack.empty())
 				throw runtime_error("Trying to pop a link from empty stack. This is probably a bug.");
@@ -12332,7 +12331,6 @@ void NiTexturingProperty::InternalFixLinks( const vector<NiObjectRef> & objects,
 				decal1Texture.source = NULL;
 			link_stack.pop_front();
 		};
-	};
 	if ( version >= 0x0A000100 ) {
 		for (uint i2 = 0; i2 < shaderTextures.size(); i2++) {
 			if ( (shaderTextures[i2].isUsed != 0) ) {
@@ -12746,6 +12744,112 @@ std::list<NiObjectRef> NiTriStripsData::InternalGetRefs() const {
 	return refs;
 }
 
+void NiClod::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NiTriBasedGeom::Read( in, link_stack, version, user_version );
+}
+
+void NiClod::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
+	NiTriBasedGeom::Write( out, link_map, version, user_version );
+}
+
+std::string NiClod::InternalAsString( bool verbose ) const {
+	stringstream out;
+	out << NiTriBasedGeom::asString();
+	return out.str();
+}
+
+void NiClod::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NiTriBasedGeom::FixLinks( objects, link_stack, version, user_version );
+}
+
+std::list<NiObjectRef> NiClod::InternalGetRefs() const {
+	list<Ref<NiObject> > refs;
+	refs = NiTriBasedGeom::GetRefs();
+	return refs;
+}
+
+void NiClodData::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NiTriBasedGeomData::Read( in, link_stack, version, user_version );
+	for (uint i1 = 0; i1 < 5; i1++) {
+		NifStream( unknown5Shorts[i1], in, version );
+	};
+	NifStream( unknownFloat, in, version );
+	NifStream( unknownInt, in, version );
+	if ( (unknownInt == 9) ) {
+		for (uint i2 = 0; i2 < 44; i2++) {
+			NifStream( unknownClodShorts[i2], in, version );
+		};
+	};
+	if ( (unknownInt == 199) ) {
+		for (uint i2 = 0; i2 < 233; i2++) {
+			NifStream( unknownClodShorts[i2], in, version );
+		};
+	};
+	if ( (unknownInt == 24) ) {
+		for (uint i2 = 0; i2 < 57; i2++) {
+			NifStream( unknownClodShorts[i2], in, version );
+		};
+	};
+}
+
+void NiClodData::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
+	NiTriBasedGeomData::Write( out, link_map, version, user_version );
+	for (uint i1 = 0; i1 < 5; i1++) {
+		NifStream( unknown5Shorts[i1], out, version );
+	};
+	NifStream( unknownFloat, out, version );
+	NifStream( unknownInt, out, version );
+	if ( (unknownInt == 9) ) {
+		for (uint i2 = 0; i2 < 44; i2++) {
+			NifStream( unknownClodShorts[i2], out, version );
+		};
+	};
+	if ( (unknownInt == 199) ) {
+		for (uint i2 = 0; i2 < 233; i2++) {
+			NifStream( unknownClodShorts[i2], out, version );
+		};
+	};
+	if ( (unknownInt == 24) ) {
+		for (uint i2 = 0; i2 < 57; i2++) {
+			NifStream( unknownClodShorts[i2], out, version );
+		};
+	};
+}
+
+std::string NiClodData::InternalAsString( bool verbose ) const {
+	stringstream out;
+	out << NiTriBasedGeomData::asString();
+	for (uint i1 = 0; i1 < 5; i1++) {
+		if ( !verbose && ( i1 > MAXARRAYDUMP ) ) {
+			out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl;
+			break;
+		};
+		out << "    Unknown 5 Shorts[" << i1 << "]:  " << unknown5Shorts[i1] << endl;
+	};
+	out << "  Unknown Float:  " << unknownFloat << endl;
+	out << "  Unknown Int:  " << unknownInt << endl;
+	if ( (unknownInt == 9) ) {
+		for (uint i2 = 0; i2 < 44; i2++) {
+			if ( !verbose && ( i2 > MAXARRAYDUMP ) ) {
+				out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl;
+				break;
+			};
+			out << "      Unknown Clod Shorts[" << i2 << "]:  " << unknownClodShorts[i2] << endl;
+		};
+	};
+	return out.str();
+}
+
+void NiClodData::InternalFixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NiTriBasedGeomData::FixLinks( objects, link_stack, version, user_version );
+}
+
+std::list<NiObjectRef> NiClodData::InternalGetRefs() const {
+	list<Ref<NiObject> > refs;
+	refs = NiTriBasedGeomData::GetRefs();
+	return refs;
+}
+
 void NiUVController::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
 	uint block_num;
 	NiTimeController::Read( in, link_stack, version, user_version );
diff --git a/src/obj/NiClod.cpp b/src/obj/NiClod.cpp
new file mode 100644
index 00000000..536b1a98
--- /dev/null
+++ b/src/obj/NiClod.cpp
@@ -0,0 +1,37 @@
+/* Copyright (c) 2006, NIF File Format Library and Tools
+All rights reserved.  Please see niflib.h for licence. */
+
+#include "../../include/obj/NiClod.h"
+using namespace Niflib;
+
+//Definition of TYPE constant
+const Type NiClod::TYPE("NiClod", &NI_CLOD_PARENT::TypeConst() );
+
+NiClod::NiClod() NI_CLOD_CONSTRUCT {}
+
+NiClod::~NiClod() {}
+
+void NiClod::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NI_CLOD_READ
+}
+
+void NiClod::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
+	NI_CLOD_WRITE
+}
+
+string NiClod::asString( bool verbose ) const {
+	NI_CLOD_STRING
+}
+
+void NiClod::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NI_CLOD_FIXLINKS
+}
+
+list<NiObjectRef> NiClod::GetRefs() const {
+	NI_CLOD_GETREFS
+}
+
+const Type & NiClod::GetType() const {
+	return TYPE;
+};
+
diff --git a/src/obj/NiClodData.cpp b/src/obj/NiClodData.cpp
new file mode 100644
index 00000000..b7af3368
--- /dev/null
+++ b/src/obj/NiClodData.cpp
@@ -0,0 +1,37 @@
+/* Copyright (c) 2006, NIF File Format Library and Tools
+All rights reserved.  Please see niflib.h for licence. */
+
+#include "../../include/obj/NiClodData.h"
+using namespace Niflib;
+
+//Definition of TYPE constant
+const Type NiClodData::TYPE("NiClodData", &NI_CLOD_DATA_PARENT::TypeConst() );
+
+NiClodData::NiClodData() NI_CLOD_DATA_CONSTRUCT {}
+
+NiClodData::~NiClodData() {}
+
+void NiClodData::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NI_CLOD_DATA_READ
+}
+
+void NiClodData::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
+	NI_CLOD_DATA_WRITE
+}
+
+string NiClodData::asString( bool verbose ) const {
+	NI_CLOD_DATA_STRING
+}
+
+void NiClodData::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
+	NI_CLOD_DATA_FIXLINKS
+}
+
+list<NiObjectRef> NiClodData::GetRefs() const {
+	NI_CLOD_DATA_GETREFS
+}
+
+const Type & NiClodData::GetType() const {
+	return TYPE;
+};
+
diff --git a/src/obj/NiControllerManager.cpp b/src/obj/NiControllerManager.cpp
index b08e6f63..7dfd00cd 100644
--- a/src/obj/NiControllerManager.cpp
+++ b/src/obj/NiControllerManager.cpp
@@ -37,3 +37,27 @@ const Type & NiControllerManager::GetType() const {
 	return TYPE;
 };
 
+bool NiControllerManager::GetCumulative() const {
+	return cumulative;
+}
+
+void NiControllerManager::SetCumulative( bool value ) {
+	cumulative = value;
+}
+
+vector<Ref<NiControllerSequence > > NiControllerManager::GetControllerSequences() const {
+	return controllerSequences;
+}
+
+void NiControllerManager::SetControllerSequences( const vector<Ref<NiControllerSequence > >& value ) {
+	controllerSequences = value;
+}
+
+Ref<NiDefaultAVObjectPalette > NiControllerManager::GetObjectPalette() const {
+	return objectPalette;
+}
+
+void NiControllerManager::SetObjectPalette( Ref<NiDefaultAVObjectPalette > value ) {
+	objectPalette = value;
+}
+
diff --git a/src/obj/NiDefaultAVObjectPalette.cpp b/src/obj/NiDefaultAVObjectPalette.cpp
index 13696c3b..bfbf5b65 100644
--- a/src/obj/NiDefaultAVObjectPalette.cpp
+++ b/src/obj/NiDefaultAVObjectPalette.cpp
@@ -37,3 +37,21 @@ const Type & NiDefaultAVObjectPalette::GetType() const {
 	return TYPE;
 };
 
+vector<Ref<NiAVObject> > NiDefaultAVObjectPalette::GetObjs() const {
+   vector<NiAVObjectRef> objRefs;
+   for (vector<AVObject>::const_iterator itr = objs.begin(); itr != objs.end(); ++itr) {
+      objRefs.push_back(itr->avObject);
+   }
+	return objRefs;
+}
+
+void NiDefaultAVObjectPalette::SetObjs( const vector<Ref<NiAVObject> >& value ) {
+   objs.clear();
+   for (vector<NiAVObjectRef>::const_iterator itr = value.begin(); itr != value.end(); ++itr) {
+      AVObject obj;
+      obj.name = (*itr)->GetName();
+      obj.avObject = (*itr).Ptr();
+      objs.push_back(obj);
+   }
+}
+
diff --git a/src/obj/NiDynamicEffect.cpp b/src/obj/NiDynamicEffect.cpp
index 88c1f157..945237ed 100644
--- a/src/obj/NiDynamicEffect.cpp
+++ b/src/obj/NiDynamicEffect.cpp
@@ -36,22 +36,6 @@ const Type & NiDynamicEffect::GetType() const {
 	return TYPE;
 };
 
-bool NiDynamicEffect::GetHasAffectedNodeList_() const {
-	return hasAffectedNodeList_;
-}
-
-void NiDynamicEffect::SetHasAffectedNodeList_( bool value ) {
-	hasAffectedNodeList_ = value;
-}
-
-uint NiDynamicEffect::GetAffectedNodeList_() const {
-	return affectedNodeList_;
-}
-
-void NiDynamicEffect::SetAffectedNodeList_( uint value ) {
-	affectedNodeList_ = value;
-}
-
 bool NiDynamicEffect::GetSwitchState() const {
 	return switchState;
 }
@@ -68,3 +52,11 @@ void NiDynamicEffect::SetAffectedNodes( const vector<Ref<NiAVObject > >& value )
 	affectedNodes = value;
 }
 
+vector<uint > NiDynamicEffect::GetAffectedNodeListPointers() const {
+	return affectedNodeListPointers;
+}
+
+void NiDynamicEffect::SetAffectedNodeListPointers( const vector<uint >& value ) {
+	affectedNodeListPointers = value;
+}
+
diff --git a/src/obj/NiLODNode.cpp b/src/obj/NiLODNode.cpp
index d02c5ff2..f339e846 100644
--- a/src/obj/NiLODNode.cpp
+++ b/src/obj/NiLODNode.cpp
@@ -54,10 +54,10 @@ void NiLODNode::SetLODLevels( const vector<LODRange >& value ) {
 }
 
 Ref<NiLODData > NiLODNode::GetLODLevelData() const {
-	return rangeData;
+	return lodLevelData;
 }
 
 void NiLODNode::SetLODLevelData( Ref<NiLODData > value ) {
-	rangeData = value;
+	lodLevelData = value;
 }
 
diff --git a/src/obj/NiScreenLODData.cpp b/src/obj/NiScreenLODData.cpp
index 9bcadfc6..7c777080 100644
--- a/src/obj/NiScreenLODData.cpp
+++ b/src/obj/NiScreenLODData.cpp
@@ -68,10 +68,10 @@ void NiScreenLODData::SetWorldRadius( float value ) {
 }
 
 vector<float > NiScreenLODData::GetProportionLevels() const {
-	return proportion;
+	return proportionLevels;
 }
 
 void NiScreenLODData::SetProportionLevels( const vector<float >& value ) {
-	proportion = value;
+	proportionLevels = value;
 }
 
diff --git a/src/obj/NiSkinPartition.cpp b/src/obj/NiSkinPartition.cpp
index 2f1001c6..d68fdf31 100644
--- a/src/obj/NiSkinPartition.cpp
+++ b/src/obj/NiSkinPartition.cpp
@@ -10,16 +10,20 @@ All rights reserved.  Please see niflib.h for licence. */
 #include "../../include/obj/NiTriStripsData.h"
 #include "../../include/gen/SkinWeight.h"
 #include "../../NvTriStrip/NvTriStrip.h"
+#include <algorithm>
 using namespace Niflib;
 
-typedef vector<SkinWeight> SkinWeightList;
-typedef vector<SkinWeightList> BoneWeightList;
 typedef vector<float> WeightList;
 typedef vector<ushort> BoneList;
 typedef vector<ushort> Strip;
 typedef vector<Strip> Strips;
 typedef vector<Triangle> Triangles;
 
+typedef pair<int,float> BoneWeight;
+typedef vector<BoneWeight> BoneWeightList;
+typedef SkinPartition Partition;
+typedef vector<SkinPartition > PartitionList;
+
 //Definition of TYPE constant
 const Type NiSkinPartition::TYPE("NiSkinPartition", &NI_SKIN_PARTITION_PARENT::TypeConst() );
 
@@ -228,7 +232,7 @@ NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) {
       throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." );
    }
 
-   int nWeightsPerVertex = 0;
+   int nWeightsPerVertex = 4;
    vector<WeightList> vertexWeights;
    BoneList boneMap;
    vector<ushort> vertexMap;
@@ -298,7 +302,8 @@ NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) {
       }
    } else {
 
-      SetTriangles(0, geomData->GetTriangles());
+      Triangles triangles = geomData->GetTriangles();
+      SetTriangles(0, triangles);
 
       unsigned short *data = new unsigned short[triangles.size() * 3 * 2];
       for (size_t i=0; i< triangles.size(); i++) {
@@ -331,4 +336,382 @@ NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape) {
       }
    }
   
-}
\ No newline at end of file
+}
+
+
+////////////////////////////////////////////////
+
+static void mergeBones( BoneList &a, BoneList& b ) {
+   for (size_t i=0; i<b.size(); ++i) {
+      int c = b[i];
+      BoneList::iterator it = find(a.begin(), a.end(), c);
+      if ( a.end() == it ) {
+         a.push_back( c );
+      }
+   }
+}
+
+static bool containsBones( BoneList& a, BoneList& b ) {
+   for (size_t i=0; i<b.size(); ++i) {
+      int c = b[i];
+      BoneList::iterator it = find(a.begin(), a.end(), c);
+      if ( a.end() == it ) {
+         return false;
+      }
+   }
+   return true;
+}
+template <typename I, typename V>
+int indexOf(I begin, I end, const V& val) {
+   return std::distance(begin, std::find(begin, end, val));
+}
+
+
+NiSkinPartition::NiSkinPartition(Ref<NiTriBasedGeom> shape, int maxBonesPerPartition, int maxBonesPerVertex ) {
+   NiSkinInstanceRef skinInst = shape->GetSkinInstance();
+   if ( skinInst == NULL ) {
+      throw runtime_error( "You must bind a skin before setting generating skin partitions.  No NiSkinInstance found." );
+   }
+   NiSkinDataRef skinData = skinInst->GetSkinData();
+   if ( skinData == NULL ) {
+      throw runtime_error( "You must bind a skin before setting generating skin partitions.  No NiSkinData found." );
+   }
+   NiTriBasedGeomDataRef geomData = shape->GetData();
+   if ( geomData == NULL ) {
+      throw runtime_error( "Attempted to generate a skin partition on a mesh with no geometry data." );
+   }
+
+      // read in the weights from NiSkinData
+   vector<Vector3> verts = geomData->GetVertices();
+   vector< BoneWeightList > weights;
+   if (verts.empty()){
+      throw runtime_error( "Attempted to generate a skin partition on a mesh with no vertices." );
+   }
+
+   Triangles triangles = geomData->GetTriangles();
+   if (triangles.empty()) {
+      throw runtime_error( "Attempted to generate a skin partition on a mesh with no triangles." );
+   }
+
+   weights.resize( verts.size() );
+   int numBones = skinData->GetBoneCount();
+   for ( int bone = 0; bone < numBones; bone++ )
+   {
+      vector<SkinWeight> vertexWeights = skinData->GetBoneWeights(bone);
+      for (int r = 0; r < int(vertexWeights.size()); ++r ){
+         int vertex = vertexWeights[r].index;
+         float weight = vertexWeights[r].weight;
+         if ( vertex >= int(weights.size()) )
+            throw runtime_error( "bad NiSkinData - vertex count does not match" );
+         weights[vertex].insert( weights[vertex].end(), BoneWeight(bone, weight) );
+      }
+   }
+
+   // count min and max bones per vertex
+   int minBones, maxBones;
+   minBones = maxBones = weights[0].size();
+   for(vector< BoneWeightList >::iterator itr = weights.begin(); itr != weights.end(); ++itr ){
+      int n = (*itr).size();
+      minBones = min(n, minBones);
+      maxBones = max(n, maxBones);
+   }
+
+   if ( minBones <= 0 )
+      throw runtime_error( "bad NiSkinData - some vertices have no weights at all" );
+
+   // reduce vertex influences if necessary
+   if ( maxBones > maxBonesPerVertex )
+   {
+      vector< BoneWeightList >::iterator it = weights.begin();
+      int c = 0;
+      while ( it != weights.end() )
+      {
+         BoneWeightList & lst = *it;
+         if ( int(lst.size()) > maxBonesPerVertex )
+            c++;
+
+         while ( int(lst.size()) > maxBonesPerVertex ) {
+            int j = 0;
+            float weight = lst.front().second;
+            for ( int i = 0; i < int(lst.size()); i++ )
+            {
+               if ( lst[i].second < weight )
+                  j = i;
+            }
+            BoneWeightList::iterator jit = lst.begin() + j;
+            lst.erase( jit );
+         }
+
+         float totalWeight = 0;
+         for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) {
+            totalWeight += (*bw).second;
+         }
+         for (BoneWeightList::iterator bw = lst.begin(); bw != lst.end(); ++bw) {
+            (*bw).second /= totalWeight;
+         }
+      }
+      //qWarning() << "reduced" << c << "vertices to" << maxBonesPerVertex << "bone influences (maximum number of bones per vertex was" << maxBones << ")";
+   }
+
+   maxBones = maxBonesPerVertex;
+
+   // reduces bone weights so that the triangles fit into the partitions
+
+   typedef multimap<int,int> matchmap;
+   typedef pair<matchmap::iterator, matchmap::iterator> matchrange;
+   matchmap match;
+   bool doMatch = true;
+
+   BoneList tribones;
+   int cnt = 0;
+   for (Triangles::iterator itr = triangles.begin(); itr != triangles.end(); ++itr) {
+      Triangle& tri = (*itr);
+      do
+      {
+         tribones.clear();
+         for ( int c = 0; c < 3; c++ ) {
+            BoneWeightList& bwl = weights[tri[c]];
+            for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) {
+               if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) )
+                  tribones.insert(tribones.end(), (*bw).first );
+            }
+         }
+
+         if ( int(tribones.size()) > maxBonesPerPartition )
+         {
+            // sum up the weights for each bone
+            // bones with weight == 1 can't be removed
+
+            map<int, float> sum;
+            vector<int> nono;
+
+            for ( int t = 0; t < 3; t++ ) {
+               BoneWeightList& bwl = weights[tri[t]];
+               if ( bwl.size() == 1 )
+                  nono.insert(nono.end(), bwl.front().first );
+
+               for (BoneWeightList::iterator bw = bwl.begin(); bw != bwl.end(); ++bw) {
+                  sum[ (*bw).first ] += (*bw).second;
+               }                 
+            }
+
+            // select the bone to remove
+
+            float minWeight = 5.0;
+            int minBone = -1;
+
+            for (map<int, float>::iterator sitr = sum.begin(); sitr != sum.end(); ++sitr) {
+               int b = (*sitr).first;
+               if ( (find(nono.begin(), nono.end(), b) == nono.end()) && sum[b] < minWeight) {
+                  minWeight = sum[b];
+                  minBone = b;
+               }
+            }
+
+            if ( minBone < 0 )	// this shouldn't never happen
+               throw runtime_error( "internal error 0x01" );
+
+            // do a vertex match detect
+            if ( doMatch ) {
+               for ( size_t a = 0; a < verts.size(); a++ ) {
+                  match.insert(matchmap::value_type(a, a));
+                  for ( size_t b = a + 1; b < verts.size(); b++ ) {
+                     if ( verts[a] == verts[b] && weights[a] == weights[b] ) {
+                        match.insert(matchmap::value_type(a, b));
+                        match.insert(matchmap::value_type(b, a));
+                     }
+                  }
+               }
+            }
+
+            // now remove that bone from all vertices of this triangle and from all matching vertices too
+            for ( int t = 0; t < 3; t++ ) {
+               bool rem = false;
+
+               matchrange range = match.equal_range(tri[t]);
+               for (matchmap::iterator itr = range.first; itr != range.second; ++itr) {
+                  int v = (*itr).second;
+
+                  BoneWeightList & bws = weights[ v ];
+                  BoneWeightList::iterator it = bws.begin();
+                  while ( it != bws.end() ) {
+                     BoneWeight & bw = *it;
+                     if ( bw.first == minBone ) {
+                        it = bws.erase(it);
+                        rem = true;
+                     } else {
+                        ++it;
+                     }
+                  }
+
+                  float totalWeight = 0;
+
+                  for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) {
+                     totalWeight += (*bw).second;
+                  }
+
+                  if ( totalWeight == 0 )
+                     throw runtime_error( "internal error 0x02" );
+
+                  // normalize
+                  for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) {
+                     (*bw).second /= totalWeight;
+                  }
+               }
+               if ( rem )
+                  cnt++;
+            }
+         }
+      } while ( int(tribones.size()) > maxBonesPerPartition );
+   }
+   //if ( cnt > 0 )
+   //   qWarning() << "removed" << cnt << "bone influences";
+
+   PartitionList& parts = skinPartitionBlocks;
+   // split the triangles into partitions
+   while ( ! triangles.empty() ) {
+
+      SkinPartition part;
+      Triangles::iterator it = triangles.begin();
+      while ( it != triangles.end() ) {
+         Triangle & tri = *it;
+
+         BoneList tribones;
+         for ( int c = 0; c < 3; c++ ) {
+            BoneWeightList& bws = weights[tri[c]];
+            for (BoneWeightList::iterator bw = bws.begin(); bw != bws.end(); ++bw) {
+               if ( tribones.end() == find(tribones.begin(), tribones.end(), (*bw).first ) )
+                  tribones.push_back( (*bw).first );
+            }
+         }
+
+         if ( part.bones.empty() || containsBones( part.bones, tribones ) ) {
+            mergeBones( part.bones, tribones );
+            part.triangles.push_back( tri );
+            it = triangles.erase(it);
+         } else {
+            ++it;
+         }
+      }
+
+      parts.push_back( part );
+   }
+
+   //qWarning() << parts.size() << "small partitions";
+
+   // merge partitions
+
+   bool merged;
+   do
+   {
+      merged = false;
+      // Working backwards through this list minimizes numbers of swaps
+      //for ( int p2 = int(parts.size()-1); p2 >= 0  && ! merged; --p2 )
+      //{
+      //   Partition& part2 = parts[p2];
+      //   for ( int p1 = int(p2-1); p1 >= 0 && ! merged; --p1 )
+      //   {
+      //      Partition& part1 = parts[p1];
+      for ( int p1 = 0; p1 < int(parts.size()) && ! merged; p1++ )
+      {
+         Partition& part1 = parts[p1];
+         for ( int p2 = p1+1; p2 < int(parts.size()) && ! merged; p2++ )
+         {
+            Partition& part2 = parts[p2];
+            BoneList mergedBones = part1.bones;
+            mergeBones( mergedBones, part2.bones );
+            if ( int(mergedBones.size()) <= maxBonesPerPartition )
+            {
+               PartitionList::iterator p2i = parts.begin() + p2;
+               part1.bones = mergedBones;
+               part1.triangles.insert(part1.triangles.end(), (*p2i).triangles.begin(), (*p2i).triangles.end());
+               parts.erase(p2i);
+               merged = true;
+            }
+         }
+      }
+   }
+   while ( merged );
+
+   //qWarning() << parts.size() << "partitions";
+
+   // start writing NiSkinPartition
+
+   for ( int p = 0; p < int(parts.size()); p++ )
+   {
+      Partition& part = parts[p];
+      BoneList& bones = part.bones;
+      sort( bones.begin(), bones.end() );
+
+      Triangles& triangles = part.triangles;
+
+      vector<ushort>& vertices = part.vertexMap;
+      for( Triangles::iterator tri = triangles.begin(); tri !=  triangles.end(); ++tri) {
+         for ( int t = 0; t < 3; t++ ) {
+            if ( vertices.end() == find(vertices.begin(), vertices.end(), (*tri)[t] ) )
+               vertices.push_back( (*tri)[t] );
+         }
+      }
+      sort( vertices.begin(), vertices.end() );
+      part.numVertices = vertices.size();
+      part.hasVertexMap = true;
+
+      // map the vertices
+
+      for ( int tri = 0; tri < int(triangles.size()); tri++ ) {
+         for ( int t = 0; t < 3; t++ ) {
+            triangles[tri][t] = indexOf(vertices.begin(), vertices.end(), triangles[tri][t]);
+         }
+      }
+
+      SetWeightsPerVertex(p, maxBones);
+      EnableVertexWeights(p, true);
+      EnableVertexBoneIndices(p, true);
+
+      // strippify the triangles
+      NiTriStripsDataRef data = new NiTriStripsData(triangles, true);
+      int nstrips = data->GetStripCount();
+      SetStripCount( p, nstrips );
+      for ( int i=0; i<nstrips; ++i ) {
+         SetStrip(p, i, data->GetStrip(i));
+      }
+
+      //// Special case for pre-stripped data
+      //unsigned short *data = new unsigned short[triangles.size() * 3 * 2];
+      //for (size_t i=0; i< triangles.size(); i++) {
+      //   data[i * 3 + 0] = triangles[i][0];
+      //   data[i * 3 + 1] = triangles[i][1];
+      //   data[i * 3 + 2] = triangles[i][2];
+      //}
+      //PrimitiveGroup * groups = 0;
+      //unsigned short numGroups = 0;
+
+      //// GF 3+
+      //SetCacheSize(CACHESIZE_GEFORCE3);
+      //// don't generate hundreds of strips
+      //SetStitchStrips(true);
+      //GenerateStrips(data, triangles.size()*3, &groups, &numGroups);
+      //delete [] data;
+      //if (groups) {
+      //   SetStripCount(p, numGroups);
+      //   for (int g=0; g<numGroups; g++) {
+      //      if (groups[g].type == PT_STRIP) {
+      //         vector<Niflib::ushort> strip(groups[g].numIndices);
+      //         for (size_t s=0; s<groups[g].numIndices; s++)
+      //            strip[s] = groups[g].indices[s];
+      //         SetStrip(p, g, strip);
+      //      }
+      //   }
+      //   delete [] groups;
+      //}
+
+      // fill in vertex weights and bones
+      for (size_t v = 0; v < vertices.size(); ++v) {
+         BoneWeightList& bwl = weights[vertices[v]];
+         for ( int b = 0; b < maxBones; b++ ) {
+            part.boneIndices[v][b] = (int(bwl.size()) > b) ? indexOf(bones.begin(), bones.end(), bwl[b].first) : 0 ;
+            part.vertexWeights[v][b] = (int(bwl.size()) > b ? bwl[b].second : 0.0f);
+         }
+      }
+   }
+}
diff --git a/src/obj/NiTriBasedGeom.cpp b/src/obj/NiTriBasedGeom.cpp
index 242fae93..a35d9c25 100644
--- a/src/obj/NiTriBasedGeom.cpp
+++ b/src/obj/NiTriBasedGeom.cpp
@@ -358,8 +358,12 @@ void NiTriBasedGeom::SetBoneWeights( uint bone_index, const vector<SkinWeight> &
 	skinData->SetBoneWeights( bone_index, n, center, radius );
 }
 
-void NiTriBasedGeom::GenHardwareSkinInfo( int max_bones_per_partition ) {
-   NiSkinPartitionRef skinPart = new NiSkinPartition( this );
+void NiTriBasedGeom::GenHardwareSkinInfo( int max_bones_per_partition /*= 4*/, int max_bones_per_vertex /*= INT_MAX*/ ) {
+   NiSkinPartitionRef skinPart; 
+   if ( max_bones_per_partition == 0 ) //old method
+      skinPart = new NiSkinPartition( this );
+   else
+      skinPart = new NiSkinPartition( this, max_bones_per_partition, max_bones_per_vertex );
 
    // Set the partition info in both places and it will be handled when exported.
    NiSkinInstanceRef skinInst = GetSkinInstance();
diff --git a/src/obj/NiTriShapeData.cpp b/src/obj/NiTriShapeData.cpp
index 090e9bbb..4da709e6 100644
--- a/src/obj/NiTriShapeData.cpp
+++ b/src/obj/NiTriShapeData.cpp
@@ -36,6 +36,10 @@ const Type & NiTriShapeData::GetType() const {
 	return TYPE;
 };
 
+NiTriShapeData::NiTriShapeData(const vector<Triangle> &tris) {
+   SetTriangles(tris);
+}
+
 void NiTriShapeData::SetVertices( const vector<Vector3> & in ) {
 	//Take normal action
 	NiTriBasedGeomData::SetVertices( in );
diff --git a/src/obj/NiTriStripsData.cpp b/src/obj/NiTriStripsData.cpp
index c20deffe..f8dc1289 100644
--- a/src/obj/NiTriStripsData.cpp
+++ b/src/obj/NiTriStripsData.cpp
@@ -3,8 +3,15 @@ All rights reserved.  Please see niflib.h for licence. */
 
 #include "../../include/obj/NiTriStripsData.h"
 #include "../../NvTriStrip/NvTriStrip.h"
+#include "../../TriStripper/tri_stripper.h"
 
 using namespace Niflib;
+using namespace triangle_stripper;
+
+// Helper methods
+typedef vector<unsigned short> TriStrip;
+typedef	list<TriStrip> TriStrips;
+
 
 //Definition of TYPE constant
 const Type NiTriStripsData::TYPE("NiTriStripsData", &NI_TRI_STRIPS_DATA_PARENT::TypeConst() );
@@ -37,6 +44,13 @@ const Type & NiTriStripsData::GetType() const {
 	return TYPE;
 };
 
+NiTriStripsData::NiTriStripsData(const vector<Triangle> &tris, bool nvtristrips) {
+   if (nvtristrips)
+      SetNvTriangles(tris);
+   else
+      SetTSTriangles(tris);
+}
+
 ushort NiTriStripsData::GetStripCount() const {
 	return ushort(points.size());
 }
@@ -121,6 +135,10 @@ ushort NiTriStripsData::CalcTriangleCount() const {
 }
 
 void NiTriStripsData::SetTriangles( const vector<Triangle> & in ) {
+   SetNvTriangles(in);
+}
+
+void NiTriStripsData::SetNvTriangles( const vector<Triangle> & in ) {
    if ( in.size() > 65535 || in.size() < 0 ) {
       throw runtime_error("Invalid Triangle Count: must be between 0 and 65535.");
    }
@@ -163,3 +181,90 @@ void NiTriStripsData::SetTriangles( const vector<Triangle> & in ) {
    numTriangles = CalcTriangleCount();
 }
 
+void NiTriStripsData::SetTSTriangles( const vector<Triangle> & in ) {
+   if ( in.size() > 65535 || in.size() < 0 ) {
+      throw runtime_error("Invalid Triangle Count: must be between 0 and 65535.");
+   }
+
+   points.clear();
+   numTriangles = 0;
+
+   TriStrips strips;
+   vector<unsigned int> idcs(in.size()*3);
+   size_t i, j;
+   for (i=0; i<in.size(); i++)
+   {
+      idcs[i * 3 + 0] = in[i][0];
+      idcs[i * 3 + 1] = in[i][1];
+      idcs[i * 3 + 2] = in[i][2];
+   }
+
+   tri_stripper stripper(idcs);
+
+   primitive_vector groups;
+   stripper.Strip(&groups);
+
+   // triangles left over
+   vector<Triangle> stris;
+
+   for (i=0; i<groups.size(); i++)
+   {
+      if (groups[i].Type == TRIANGLE_STRIP)
+      {			
+         strips.push_back(TriStrip(groups[i].Indices.size()));
+         TriStrip &strip = strips.back();
+
+         for (j=0; j<groups[i].Indices.size(); j++)
+            strip[j] = groups[i].Indices[j];
+      } else
+      {
+         int size = stris.size();
+         stris.resize(size + groups[i].Indices.size()/3);
+         for (j=(size>0)?(size-1):0; j<stris.size(); j++)
+         {
+            stris[j][0] = groups[i].Indices[j*3+0];
+            stris[j][1] = groups[i].Indices[j*3+1];
+            stris[j][2] = groups[i].Indices[j*3+2];
+         }
+      }
+   }
+
+   if (stris.size())
+   {
+      // stitch em
+      TriStrip strip;
+      if (strips.size() > 0)
+      {
+         strip.push_back(strips.back()[strips.back().size()-1]);
+         strip.push_back(stris[0][0]);
+      }
+      for (i=0; i<stris.size(); i++)
+      {
+         if (i > 0)
+         {
+            strip.push_back(stris[i][0]);
+            strip.push_back(stris[i][0]);
+         }
+
+         strip.push_back(stris[i][0]);
+         strip.push_back(stris[i][1]);
+         strip.push_back(stris[i][2]);
+         if (i < stris.size()-1)
+            strip.push_back(stris[i][2]);
+      }
+      strips.push_back(strip);
+   }
+
+   if (strips.size() > 0)
+   {
+      SetStripCount(strips.size());
+
+      int i = 0;
+      TriStrips::const_iterator it;
+      for (it=strips.begin(); it!=strips.end(); ++it)
+         SetStrip(i++, *it);
+   }
+
+   //Recalculate Triangle Count
+   numTriangles = CalcTriangleCount();
+}
-- 
GitLab