diff --git a/include/gen/obj_defines.h b/include/gen/obj_defines.h
index cadeace828e8718bb3c339f8c5d641ba08779b04..728411a8613e4d3e78cdba59508f2bd461a7e283 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 0000000000000000000000000000000000000000..98b05419d676688a129ec148853390f90daf7f41
--- /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 0000000000000000000000000000000000000000..d78146eebe416ce7d24077d1628700de0eaba489
--- /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 1fb91e6400fa6ecfab9cd070b26fec0c9c23c6e7..9fa69342d1877eb21b4b115d78610c172413c205 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 1d72351d9ddb5ce372715e3daa29428ad1e9e439..5381a6a45d2fc16c5bba6d8a5417a7fa7dc8ff77 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 67f8513a9ce054a8f17190b2323c5572737de30d..a9af02e29d18c508094639309c1c9beafac40dba 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 b9656349ac3710355a7510e0ddf8bb5af3337407..df04b7d056b3735e4987e8ccb64f22c711bce8c8 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 5ad3c35ed4e93823fc6c0cc88855549d293a56ec..7c6f56f15df16839ea26e1da5b15dccdd73b50e4 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 f4b576e6cddbfbd5cee5fba78198ae15f0772754..87d7b9735cce9c8b0a5bf547335541cd2bad76e9 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 5893de6f1a8359e5b134c44eec530bbe29a80cd5..1c9a315fc1be4bb20b8c4d4441d54ff6bcc88067 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 d43e9283b2bc22f86a5952840f8059c713d06edc..36174843a60089b43aceb61e8ee5b5d171af7c00 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 729c5c5aafe129c2ebe073dcc4c984f3b1b21f9a..bd1a7d9a3e26ea498a7e5c8727b433699bdd8dc8 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 e0df54b8f470f22b05be0db8cdf27c13ea33b029..86f2f94ba33b2d1188aa55b9ee89334a97c5a309 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 0000000000000000000000000000000000000000..536b1a98a98df8034077d879a3e1e136d33e7f9b
--- /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 0000000000000000000000000000000000000000..b7af336893ce2eba64aeaf4a54d5395659549fd5
--- /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 b08e6f6329d691bc2cea6e1ddf432527f19cdbcd..7dfd00cd9dff960370110855b3f69674b0f50745 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 13696c3b4917438a201aa43ce9efef87e3050799..bfbf5b65b84a993574652d3705f94d14463a68dc 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 88c1f15798d40edd16644be3d812e750c8a88746..945237ede3891617778a515170b48aae9f0aa9b9 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 d02c5ff2fa5e047fd4d0700ca6e660c8c134e9a1..f339e8467d25364cfd7bef5695797618f31c1857 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 9bcadfc6402d46a7ffbf289ea9e8b764a3cef74b..7c777080eb431ea6890bc1412f901e512edfae4f 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 2f1001c6a817aa89eabf7764bfc2cfd15c4759d1..d68fdf31c4bed85fdfca8850e945f0d0dc25c669 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 242fae9385ea0bbf2dd3b5640efa7548372f6408..a35d9c2580c27077d431dcb731a2430c5b794526 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 090e9bbb48a730f7208eeca0ef747f9a2fb7bd98..4da709e637ccb95af293eedcf339e19f500a86a4 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 c20deffe461421975b5176fd1710004c213c38fe..f8dc1289a224166be7dbd6dbb2084a03f55df961 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();
+}