From 93f6368ac2bf6db9cbe798951739d50d2ee5e890 Mon Sep 17 00:00:00 2001
From: Shon Ferguson <shonferg@users.sourceforge.net>
Date: Sat, 30 Sep 2006 21:39:44 +0000
Subject: [PATCH] Updated from XML and removed old commented code and cout
 statements.

---
 include/gen/obj_defines.h   |  11 +-
 src/ComplexShape.cpp        |  43 ++------
 src/NIF_IO.cpp              |  69 -------------
 src/gen/obj_impl.cpp        | 197 +++++++++++++++++++++++++++++++++---
 src/kfm.cpp                 |   1 -
 src/nif_math.cpp            |  11 --
 src/niflib.cpp              |  13 +--
 src/obj/NiNode.cpp          |   1 -
 src/obj/NiObject.cpp        |   3 -
 src/obj/NiPixelData.cpp     |   1 -
 src/obj/NiTriStripsData.cpp |   2 -
 11 files changed, 202 insertions(+), 150 deletions(-)

diff --git a/include/gen/obj_defines.h b/include/gen/obj_defines.h
index 474271ec..f8e64779 100644
--- a/include/gen/obj_defines.h
+++ b/include/gen/obj_defines.h
@@ -1063,8 +1063,9 @@ ushort flags; \
 
 #define NI_SPHERICAL_COLLIDER_MEMBERS \
 float unknownFloat1; \
-ushort unknownShort; \
+ushort unknownShort1; \
 float unknownFloat2; \
+ushort unknownShort2; \
 float unknownFloat3; \
 float unknownFloat4; \
 float unknownFloat5; \
@@ -1156,6 +1157,10 @@ bool hasDecal0Texture; \
 TexDesc decal0Texture; \
 bool hasDecal1Texture; \
 TexDesc decal1Texture; \
+bool hasDecal2Texture; \
+TexDesc decal2Texture; \
+bool hasDecal3Texture; \
+TexDesc decal3Texture; \
 mutable uint numShaderTextures; \
 vector<ShaderTexDesc > shaderTextures; \
 
@@ -2548,7 +2553,7 @@ CompareMode function; \
 
 #define NI_SPHERICAL_COLLIDER_PARENT AParticleModifier
 
-#define NI_SPHERICAL_COLLIDER_CONSTRUCT  : unknownFloat1(0.0f), unknownShort((ushort)0), unknownFloat2(0.0f), unknownFloat3(0.0f), unknownFloat4(0.0f), unknownFloat5(0.0f)
+#define NI_SPHERICAL_COLLIDER_CONSTRUCT  : unknownFloat1(0.0f), unknownShort1((ushort)0), unknownFloat2(0.0f), unknownShort2((ushort)0), unknownFloat3(0.0f), unknownFloat4(0.0f), unknownFloat5(0.0f)
 
 #define NI_SPOT_LIGHT_INCLUDE "NiPointLight.h"
 
@@ -2618,7 +2623,7 @@ CompareMode function; \
 
 #define NI_TEXTURING_PROPERTY_PARENT NiProperty
 
-#define NI_TEXTURING_PROPERTY_CONSTRUCT  : flags((ushort)0), applyMode((ApplyMode)2), textureCount((uint)7), hasBaseTexture(false), hasDarkTexture(false), hasDetailTexture(false), hasGlossTexture(false), hasGlowTexture(false), hasBumpMapTexture(false), bumpMapLumaScale(0.0f), bumpMapLumaOffset(0.0f), hasDecal0Texture(false), hasDecal1Texture(false), numShaderTextures((uint)0)
+#define NI_TEXTURING_PROPERTY_CONSTRUCT  : flags((ushort)0), applyMode((ApplyMode)2), textureCount((uint)7), hasBaseTexture(false), hasDarkTexture(false), hasDetailTexture(false), hasGlossTexture(false), hasGlowTexture(false), hasBumpMapTexture(false), bumpMapLumaScale(0.0f), bumpMapLumaOffset(0.0f), hasDecal0Texture(false), hasDecal1Texture(false), hasDecal2Texture(false), hasDecal3Texture(false), numShaderTextures((uint)0)
 
 #define NI_TRANSFORM_CONTROLLER_INCLUDE "NiSingleInterpolatorController.h"
 
diff --git a/src/ComplexShape.cpp b/src/ComplexShape.cpp
index 7e2801ab..978e6734 100644
--- a/src/ComplexShape.cpp
+++ b/src/ComplexShape.cpp
@@ -182,7 +182,7 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 
 	vector<NiTriBasedGeomRef> shapes;
 
-	//cout << "Determine root type" << endl;
+	//Determine root type
 	if ( root->IsDerivedType( NiTriBasedGeom::TypeConst() ) ) {
 		//The function was called on a single shape.
 		//Add it to the list
@@ -209,11 +209,9 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 	//to merge vertices that have different normals.
 	vector<VertNorm> vns;
 
-	//cout << "Clear all existing data" << endl;
 	//Clear all existing data
 	Clear();
 
-	//cout << "Merge in data from each shape" << endl;
 	//Merge in data from each shape
 	bool has_any_verts = false;
 	bool has_any_norms = false;
@@ -221,7 +219,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 	unsigned prop_group_index = 0;
 	for ( vector<NiTriBasedGeomRef>::iterator geom = shapes.begin(); geom != shapes.end(); ++geom ) {
 	
-		//cout << "Merging in " << *geom << endl;
 		//Get properties of this shape
 		propGroups[prop_group_index] = (*geom)->GetProperties();
 		
@@ -232,7 +229,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 			throw runtime_error("One of the NiTriBasedGeom found by ComplexShape::Merge with a NiTriBasedGeom has no NiTriBasedGeomData attached.");
 		}
 
-		//cout << "Get Data" << endl;
 		//Get Data
 		vector<Vector3> shapeVerts;	
 		vector<Vector3> shapeNorms;
@@ -255,7 +251,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 		//Lookup table
 		vector<MergeLookUp> lookUp( geomData->GetVertexCount() );
 
-		//cout << "Vertices and normals" << endl;
 		//Vertices and normals
 		if ( shapeVerts.size() != 0 ) {
 			has_any_verts = true;
@@ -300,7 +295,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 			}
 		}
 
-		//cout << "Colors" << endl;
 		//Colors
 		for ( unsigned c = 0; c < shapeColors.size(); ++c ) {
 			Color4 newColor;
@@ -312,7 +306,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 			for ( unsigned c_index = 0; c_index < colors.size(); ++c_index ) {
 				if ( colors[c_index].r == newColor.r && colors[c_index].g == newColor.g && colors[c_index].b == newColor.b && colors[c_index].a == newColor.a ) {
 					//Match found, use existing index
-					//cout << "Color match found:  " << colors[c_index] << " and " << newColor << " at index " << c_index << endl;
 					lookUp[c].colorIndex = c_index;
 					match_found = true;
 					//Stop searching
@@ -325,11 +318,9 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 				colors.push_back(newColor);
 				//Record new index
 				lookUp[c].colorIndex = unsigned(colors.size()) - 1;
-				//cout << "No Match found.  Placed new color " << newColor << " at lookUp[" << c << "].colorIndex:  " << lookUp[c].colorIndex << endl;
 			}
 		}
 
-		//cout << "Texture Coordinates" << endl;
 		//Texture Coordinates
 
 		//Create UV set list
@@ -351,6 +342,7 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 					TexDesc td = niTexProp->GetTexture(tex);
 					
 					unsigned set = td.uvSet;
+
 					TexType newType = TexType(tex);
 
 					//Search for matching UV set
@@ -358,7 +350,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 					unsigned uvSetIndex;
 					for ( unsigned set_index = 0; set_index < texCoordSets.size(); ++set_index ) {
 						if ( texCoordSets[set_index].texType  == newType ) {
-							////cout << "Match found, use existing texture set index" << endl;
 							//Match found, use existing index
 							uvSetIndex = set_index;
 							match_found = true;
@@ -368,7 +359,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 					}
 
 					if ( match_found == false ) {
-						////cout << "No match found, add this texture set to the list" << endl;
 						//No match found, add this UV set to the list
 						TexCoordSet newTCS;
 						newTCS.texType = newType;
@@ -377,39 +367,31 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 						uvSetIndex = unsigned(texCoordSets.size()) - 1;
 					}
 
-					////cout << "Loop through texture cooridnates in this set" << endl;
+					//Loop through texture cooridnates in this set
+					if ( set >= shapeUVs.size() || set < 0 ) {
+						throw runtime_error("One of the UV sets specified in the NiTexturingProperty did not exist in the NiTriBasedGeomData.");
+					}
 					for ( unsigned v = 0; v < shapeUVs[set].size(); ++v ) {
 						TexCoord newCoord;
 
 						newCoord = shapeUVs[set][v];
 
-						//cout << "Search for matching texture coordinate" << endl;
-						//cout << "uvSetIndex:  " << uvSetIndex << endl;
-						//cout << "set:  " << set << endl;
-						//cout << "texCoordSets.size():  " << unsigned(texCoordSets.size()) << endl;
-						//cout << "v:  " << v << endl;
-						//cout << "lookUp.size():  " << unsigned(lookUp.size()) << endl;
-						//cout << "texCoordSets[uvSetIndex].texCoords.size():  " << unsigned(texCoordSets[uvSetIndex].texCoords.size()) << endl;
 						//Search for matching texture cooridnate
 						bool match_found = false;
 						for ( unsigned tc_index = 0; tc_index < texCoordSets[uvSetIndex].texCoords.size(); ++tc_index ) {
 							if ( texCoordSets[uvSetIndex].texCoords[tc_index]  == newCoord ) {
-								////cout << " Match found, using existing index" << endl;;
 								//Match found, use existing index
 								lookUp[v].uvIndices[uvSetIndex] = tc_index;
 								match_found = true;
-								////cout << "Stop searching" << endl;
 								//Stop searching
 								break;
 							}
 						}
 
-						////cout << "Done with loop, check if match was found" << endl;
+						//Done with loop, check if match was found
 						if ( match_found == false ) {
-							////cout << "No match found" << endl;
 							//No match found, add this texture coordinate to the list
 							texCoordSets[uvSetIndex].texCoords.push_back( newCoord );
-							////cout << "Record new index" << endl;
 							//Record new index
 							lookUp[v].uvIndices[uvSetIndex] = unsigned(texCoordSets[uvSetIndex].texCoords.size()) - 1;
 						}
@@ -418,12 +400,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 			}
 		}
 
-		//cout << "Look up table colors:" << endl;
-		for ( unsigned z = 0; z < lookUp.size(); ++z ) {
-			//cout << z << ":  " << colors[lookUp[z].colorIndex] << endl;
-		}
-
-		//cout << "Use look up table to build list of faces" << endl;
 		//Use look up table to build list of faces
 		for ( unsigned t = 0; t < shapeTris.size(); ++t ) {
 			ComplexFace newFace;
@@ -450,7 +426,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 			faces.push_back(newFace);
 		}
 
-		//cout << "Use look up table to set vertex wights, if any" << endl;
 		//Use look up table to set vertex weights, if any
 		NiSkinInstanceRef skinInst = (*geom)->GetSkinInstance();
 
@@ -481,7 +456,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 		++prop_group_index;
 	}
 
-	//cout << "Finished with all shapes.  Build up a list of influences" << endl;
 	//Finished with all shapes.  Build up a list of influences
 	map<NiNodeRef,unsigned> boneLookUp;
 	for ( unsigned v = 0; v < vns.size(); ++v ) {
@@ -498,7 +472,6 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 		++si_index;
 	}
 	
-	//cout << "Copy vns data to vertices and normals" << endl;
 	//Copy vns data to vertices and normals
 	if ( has_any_verts ) {
 		vertices.resize( vns.size() );
@@ -522,7 +495,7 @@ void ComplexShape::Merge( const Ref<NiAVObject> & root ) {
 			normals[v] = vns[v].normal;
 		}
 	}
-	//cout << "Done Merging" << endl;
+	//Done Merging
 }
 
 //void ComplexShape::CombineTriShapes( list<blk_ref> & tri_shapes ) {
diff --git a/src/NIF_IO.cpp b/src/NIF_IO.cpp
index 06242f11..f1806c36 100644
--- a/src/NIF_IO.cpp
+++ b/src/NIF_IO.cpp
@@ -5,75 +5,6 @@ All rights reserved.  Please see niflib.h for licence. */
 #include "../include/niflib.h"
 namespace Niflib {
 
-//int BlockSearch( istream& in ) {
-//
-//	//Get current file pos
-//	int data_start = in.tellg();
-//
-//	//cout << "Current File Pos: " << data_start << endl;
-//	//cout << "Searching for next block..." << endl;
-//
-//	//Find Next Block
-//	char tmp1 = 0, tmp2 = 0;
-//	uint next_name_len = 0;
-//	while (!in.eof()) {
-//		while (!in.eof() && !((tmp1 == 'N' && tmp2 == 'i') || (tmp1 == 'R' && tmp2 == 'o') || (tmp1 == 'A' && tmp2 == 'v')) ) {
-//			tmp1 = tmp2;
-//			in.read(&tmp2, 1);
-//		}
-//		if (in.eof())
-//			break;
-//		
-//		//Move back to before the uint that holds the length of the string
-//		in.seekg(-6, ios_base::cur);
-//
-//		//Read the length of the string
-//		next_name_len = ReadUInt( in );
-//
-//		//cout << "Matching Data:  " << tmp1 << tmp2 << endl;
-//
-//		//if name length is > 40, then this is unlikley to be a real node. 
-//		if (next_name_len <= 40 && next_name_len >= 5) {
-//			//Read the string
-//			char* next_name = new char[next_name_len];
-//			in.read( next_name, next_name_len );
-//			
-//			//cout << "Found Match:  " << Str(next_name, next_name_len) << endl;
-//
-//			//Move back to where we were before we read anything
-//			in.seekg( -(int(next_name_len) - 2), ios_base::cur);
-//
-//			break;
-//		}
-//		else {
-//			//Move back to where we were before we read anything
-//			in.seekg(2, ios_base::cur);
-//
-//			tmp1 = tmp2 = 0;
-//			//cout << "Found possible block at:  " << int(in.tellg()) - 6 << endl;
-//		}
-//	}
-//
-//	//Note length of data
-//	int data_length = 0;
-//	if (in.eof()) {
-//		//cout << "Reached End of File.  Assuming no more blocks to find." << endl;
-//		in.clear();
-//		in.seekg(-8, ios_base::end);
-//		data_length = int(in.tellg()) - data_start;
-//		in.seekg(data_start, ios_base::beg);
-//	}
-//	else {
-//		in.seekg(-6, ios_base::cur);
-//		data_length = int(in.tellg()) - data_start;
-//		in.seekg(data_start, ios_base::beg);
-//	}
-//
-//	//cout << "Unknown area (" << data_length << " bytes):" << endl;
-//
-//	return data_length;
-//}
-
 //--Read utility functions--//
 
 int ReadInt( istream& in ){
diff --git a/src/gen/obj_impl.cpp b/src/gen/obj_impl.cpp
index 7bed8f02..601f14fd 100644
--- a/src/gen/obj_impl.cpp
+++ b/src/gen/obj_impl.cpp
@@ -11187,9 +11187,14 @@ std::list<NiObjectRef> NiSpecularProperty::InternalGetRefs() const {
 void NiSphericalCollider::InternalRead( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) {
 	AParticleModifier::Read( in, link_stack, version, user_version );
 	NifStream( unknownFloat1, in, version );
-	NifStream( unknownShort, in, version );
+	NifStream( unknownShort1, in, version );
 	NifStream( unknownFloat2, in, version );
-	NifStream( unknownFloat3, in, version );
+	if ( version <= 0x04020002 ) {
+		NifStream( unknownShort2, in, version );
+	};
+	if ( version >= 0x04020100 ) {
+		NifStream( unknownFloat3, in, version );
+	};
 	NifStream( unknownFloat4, in, version );
 	NifStream( unknownFloat5, in, version );
 }
@@ -11197,9 +11202,14 @@ void NiSphericalCollider::InternalRead( istream& in, list<uint> & link_stack, un
 void NiSphericalCollider::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const {
 	AParticleModifier::Write( out, link_map, version, user_version );
 	NifStream( unknownFloat1, out, version );
-	NifStream( unknownShort, out, version );
+	NifStream( unknownShort1, out, version );
 	NifStream( unknownFloat2, out, version );
-	NifStream( unknownFloat3, out, version );
+	if ( version <= 0x04020002 ) {
+		NifStream( unknownShort2, out, version );
+	};
+	if ( version >= 0x04020100 ) {
+		NifStream( unknownFloat3, out, version );
+	};
 	NifStream( unknownFloat4, out, version );
 	NifStream( unknownFloat5, out, version );
 }
@@ -11209,8 +11219,9 @@ std::string NiSphericalCollider::InternalAsString( bool verbose ) const {
 	uint array_output_count = 0;
 	out << AParticleModifier::asString();
 	out << "  Unknown Float 1:  " << unknownFloat1 << endl;
-	out << "  Unknown Short:  " << unknownShort << endl;
+	out << "  Unknown Short 1:  " << unknownShort1 << endl;
 	out << "  Unknown Float 2:  " << unknownFloat2 << endl;
+	out << "  Unknown Short 2:  " << unknownShort2 << endl;
 	out << "  Unknown Float 3:  " << unknownFloat3 << endl;
 	out << "  Unknown Float 4:  " << unknownFloat4 << endl;
 	out << "  Unknown Float 5:  " << unknownFloat5 << endl;
@@ -11933,10 +11944,10 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un
 			};
 		};
 	};
-	if ( (textureCount == 8) ) {
+	if ( (textureCount >= 8) ) {
 		NifStream( hasDecal1Texture, in, version );
 	};
-	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+	if ( (((textureCount >= 8)) && ((hasDecal1Texture != 0))) ) {
 		NifStream( block_num, in, version );
 		link_stack.push_back( block_num );
 		NifStream( decal1Texture.clampMode, in, version );
@@ -11960,6 +11971,60 @@ void NiTexturingProperty::InternalRead( istream& in, list<uint> & link_stack, un
 			};
 		};
 	};
+	if ( (textureCount >= 9) ) {
+		NifStream( hasDecal2Texture, in, version );
+	};
+	if ( (((textureCount >= 9)) && ((hasDecal2Texture != 0))) ) {
+		NifStream( block_num, in, version );
+		link_stack.push_back( block_num );
+		NifStream( decal2Texture.clampMode, in, version );
+		NifStream( decal2Texture.filterMode, in, version );
+		NifStream( decal2Texture.uvSet, in, version );
+		if ( version <= 0x0A020000 ) {
+			NifStream( decal2Texture.ps2L, in, version );
+			NifStream( decal2Texture.ps2K, in, version );
+		};
+		if ( version <= 0x0401000C ) {
+			NifStream( decal2Texture.unknown1, in, version );
+		};
+		if ( version >= 0x0A010000 ) {
+			NifStream( decal2Texture.hasTextureTransform, in, version );
+			if ( (decal2Texture.hasTextureTransform != 0) ) {
+				NifStream( decal2Texture.translation, in, version );
+				NifStream( decal2Texture.tiling, in, version );
+				NifStream( decal2Texture.wRotation, in, version );
+				NifStream( decal2Texture.transformType_, in, version );
+				NifStream( decal2Texture.centerOffset, in, version );
+			};
+		};
+	};
+	if ( (textureCount >= 10) ) {
+		NifStream( hasDecal3Texture, in, version );
+	};
+	if ( (((textureCount >= 10)) && ((hasDecal3Texture != 0))) ) {
+		NifStream( block_num, in, version );
+		link_stack.push_back( block_num );
+		NifStream( decal3Texture.clampMode, in, version );
+		NifStream( decal3Texture.filterMode, in, version );
+		NifStream( decal3Texture.uvSet, in, version );
+		if ( version <= 0x0A020000 ) {
+			NifStream( decal3Texture.ps2L, in, version );
+			NifStream( decal3Texture.ps2K, in, version );
+		};
+		if ( version <= 0x0401000C ) {
+			NifStream( decal3Texture.unknown1, in, version );
+		};
+		if ( version >= 0x0A010000 ) {
+			NifStream( decal3Texture.hasTextureTransform, in, version );
+			if ( (decal3Texture.hasTextureTransform != 0) ) {
+				NifStream( decal3Texture.translation, in, version );
+				NifStream( decal3Texture.tiling, in, version );
+				NifStream( decal3Texture.wRotation, in, version );
+				NifStream( decal3Texture.transformType_, in, version );
+				NifStream( decal3Texture.centerOffset, in, version );
+			};
+		};
+	};
 	if ( version >= 0x0A000100 ) {
 		NifStream( numShaderTextures, in, version );
 		shaderTextures.resize(numShaderTextures);
@@ -12194,10 +12259,10 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin
 			};
 		};
 	};
-	if ( (textureCount == 8) ) {
+	if ( (textureCount >= 8) ) {
 		NifStream( hasDecal1Texture, out, version );
 	};
-	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+	if ( (((textureCount >= 8)) && ((hasDecal1Texture != 0))) ) {
 		if ( decal1Texture.source != NULL )
 			NifStream( link_map[StaticCast<NiObject>(decal1Texture.source)], out, version );
 		else
@@ -12223,6 +12288,64 @@ void NiTexturingProperty::InternalWrite( ostream& out, map<NiObjectRef,uint> lin
 			};
 		};
 	};
+	if ( (textureCount >= 9) ) {
+		NifStream( hasDecal2Texture, out, version );
+	};
+	if ( (((textureCount >= 9)) && ((hasDecal2Texture != 0))) ) {
+		if ( decal2Texture.source != NULL )
+			NifStream( link_map[StaticCast<NiObject>(decal2Texture.source)], out, version );
+		else
+			NifStream( 0xffffffff, out, version );
+		NifStream( decal2Texture.clampMode, out, version );
+		NifStream( decal2Texture.filterMode, out, version );
+		NifStream( decal2Texture.uvSet, out, version );
+		if ( version <= 0x0A020000 ) {
+			NifStream( decal2Texture.ps2L, out, version );
+			NifStream( decal2Texture.ps2K, out, version );
+		};
+		if ( version <= 0x0401000C ) {
+			NifStream( decal2Texture.unknown1, out, version );
+		};
+		if ( version >= 0x0A010000 ) {
+			NifStream( decal2Texture.hasTextureTransform, out, version );
+			if ( (decal2Texture.hasTextureTransform != 0) ) {
+				NifStream( decal2Texture.translation, out, version );
+				NifStream( decal2Texture.tiling, out, version );
+				NifStream( decal2Texture.wRotation, out, version );
+				NifStream( decal2Texture.transformType_, out, version );
+				NifStream( decal2Texture.centerOffset, out, version );
+			};
+		};
+	};
+	if ( (textureCount >= 10) ) {
+		NifStream( hasDecal3Texture, out, version );
+	};
+	if ( (((textureCount >= 10)) && ((hasDecal3Texture != 0))) ) {
+		if ( decal3Texture.source != NULL )
+			NifStream( link_map[StaticCast<NiObject>(decal3Texture.source)], out, version );
+		else
+			NifStream( 0xffffffff, out, version );
+		NifStream( decal3Texture.clampMode, out, version );
+		NifStream( decal3Texture.filterMode, out, version );
+		NifStream( decal3Texture.uvSet, out, version );
+		if ( version <= 0x0A020000 ) {
+			NifStream( decal3Texture.ps2L, out, version );
+			NifStream( decal3Texture.ps2K, out, version );
+		};
+		if ( version <= 0x0401000C ) {
+			NifStream( decal3Texture.unknown1, out, version );
+		};
+		if ( version >= 0x0A010000 ) {
+			NifStream( decal3Texture.hasTextureTransform, out, version );
+			if ( (decal3Texture.hasTextureTransform != 0) ) {
+				NifStream( decal3Texture.translation, out, version );
+				NifStream( decal3Texture.tiling, out, version );
+				NifStream( decal3Texture.wRotation, out, version );
+				NifStream( decal3Texture.transformType_, out, version );
+				NifStream( decal3Texture.centerOffset, out, version );
+			};
+		};
+	};
 	if ( version >= 0x0A000100 ) {
 		NifStream( numShaderTextures, out, version );
 		for (uint i2 = 0; i2 < shaderTextures.size(); i2++) {
@@ -12395,10 +12518,10 @@ std::string NiTexturingProperty::InternalAsString( bool verbose ) const {
 			out << "      Center Offset:  " << decal0Texture.centerOffset << endl;
 		};
 	};
-	if ( (textureCount == 8) ) {
+	if ( (textureCount >= 8) ) {
 		out << "    Has Decal 1 Texture:  " << hasDecal1Texture << endl;
 	};
-	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+	if ( (((textureCount >= 8)) && ((hasDecal1Texture != 0))) ) {
 		out << "    Source:  " << decal1Texture.source << endl;
 		out << "    Clamp Mode:  " << decal1Texture.clampMode << endl;
 		out << "    Filter Mode:  " << decal1Texture.filterMode << endl;
@@ -12415,6 +12538,46 @@ std::string NiTexturingProperty::InternalAsString( bool verbose ) const {
 			out << "      Center Offset:  " << decal1Texture.centerOffset << endl;
 		};
 	};
+	if ( (textureCount >= 9) ) {
+		out << "    Has Decal 2 Texture:  " << hasDecal2Texture << endl;
+	};
+	if ( (((textureCount >= 9)) && ((hasDecal2Texture != 0))) ) {
+		out << "    Source:  " << decal2Texture.source << endl;
+		out << "    Clamp Mode:  " << decal2Texture.clampMode << endl;
+		out << "    Filter Mode:  " << decal2Texture.filterMode << endl;
+		out << "    UV Set:  " << decal2Texture.uvSet << endl;
+		out << "    PS2 L:  " << decal2Texture.ps2L << endl;
+		out << "    PS2 K:  " << decal2Texture.ps2K << endl;
+		out << "    Unknown1:  " << decal2Texture.unknown1 << endl;
+		out << "    Has Texture Transform:  " << decal2Texture.hasTextureTransform << endl;
+		if ( (decal2Texture.hasTextureTransform != 0) ) {
+			out << "      Translation:  " << decal2Texture.translation << endl;
+			out << "      Tiling:  " << decal2Texture.tiling << endl;
+			out << "      W Rotation:  " << decal2Texture.wRotation << endl;
+			out << "      Transform Type?:  " << decal2Texture.transformType_ << endl;
+			out << "      Center Offset:  " << decal2Texture.centerOffset << endl;
+		};
+	};
+	if ( (textureCount >= 10) ) {
+		out << "    Has Decal 3 Texture:  " << hasDecal3Texture << endl;
+	};
+	if ( (((textureCount >= 10)) && ((hasDecal3Texture != 0))) ) {
+		out << "    Source:  " << decal3Texture.source << endl;
+		out << "    Clamp Mode:  " << decal3Texture.clampMode << endl;
+		out << "    Filter Mode:  " << decal3Texture.filterMode << endl;
+		out << "    UV Set:  " << decal3Texture.uvSet << endl;
+		out << "    PS2 L:  " << decal3Texture.ps2L << endl;
+		out << "    PS2 K:  " << decal3Texture.ps2K << endl;
+		out << "    Unknown1:  " << decal3Texture.unknown1 << endl;
+		out << "    Has Texture Transform:  " << decal3Texture.hasTextureTransform << endl;
+		if ( (decal3Texture.hasTextureTransform != 0) ) {
+			out << "      Translation:  " << decal3Texture.translation << endl;
+			out << "      Tiling:  " << decal3Texture.tiling << endl;
+			out << "      W Rotation:  " << decal3Texture.wRotation << endl;
+			out << "      Transform Type?:  " << decal3Texture.transformType_ << endl;
+			out << "      Center Offset:  " << decal3Texture.centerOffset << endl;
+		};
+	};
 	out << "  Num Shader Textures:  " << numShaderTextures << endl;
 	array_output_count = 0;
 	for (uint i1 = 0; i1 < shaderTextures.size(); i1++) {
@@ -12468,9 +12631,15 @@ void NiTexturingProperty::InternalFixLinks( const map<unsigned,NiObjectRef> & ob
 	if ( (hasDecal0Texture != 0) ) {
 		decal0Texture.source = FixLink<NiSourceTexture>( objects, link_stack, version );
 	};
-	if ( (((textureCount == 8)) && ((hasDecal1Texture != 0))) ) {
+	if ( (((textureCount >= 8)) && ((hasDecal1Texture != 0))) ) {
 		decal1Texture.source = FixLink<NiSourceTexture>( objects, link_stack, version );
 	};
+	if ( (((textureCount >= 9)) && ((hasDecal2Texture != 0))) ) {
+		decal2Texture.source = FixLink<NiSourceTexture>( objects, link_stack, version );
+	};
+	if ( (((textureCount >= 10)) && ((hasDecal3Texture != 0))) ) {
+		decal3Texture.source = FixLink<NiSourceTexture>( objects, link_stack, version );
+	};
 	if ( version >= 0x0A000100 ) {
 		for (uint i2 = 0; i2 < shaderTextures.size(); i2++) {
 			if ( (shaderTextures[i2].isUsed != 0) ) {
@@ -12499,6 +12668,10 @@ std::list<NiObjectRef> NiTexturingProperty::InternalGetRefs() const {
 		refs.push_back(StaticCast<NiObject>(decal0Texture.source));
 	if ( decal1Texture.source != NULL )
 		refs.push_back(StaticCast<NiObject>(decal1Texture.source));
+	if ( decal2Texture.source != NULL )
+		refs.push_back(StaticCast<NiObject>(decal2Texture.source));
+	if ( decal3Texture.source != NULL )
+		refs.push_back(StaticCast<NiObject>(decal3Texture.source));
 	for (uint i1 = 0; i1 < shaderTextures.size(); i1++) {
 		if ( shaderTextures[i1].textureData.source != NULL )
 			refs.push_back(StaticCast<NiObject>(shaderTextures[i1].textureData.source));
diff --git a/src/kfm.cpp b/src/kfm.cpp
index 5dcb4cf5..629751df 100644
--- a/src/kfm.cpp
+++ b/src/kfm.cpp
@@ -121,7 +121,6 @@ void Kfm::Write( ostream & out, uint version ) {
 
 Ref<NiObject> Kfm::MergeActions( string const & path ) {
 	// Read NIF file
-	//cout << path + '\\' + nif_filename << endl;
 	NiObjectRef nif = ReadNifTree( path + '\\' + nif_filename);
 	
 	// Read Kf files
diff --git a/src/nif_math.cpp b/src/nif_math.cpp
index 699d57af..f004899a 100644
--- a/src/nif_math.cpp
+++ b/src/nif_math.cpp
@@ -507,17 +507,6 @@ Matrix33 Quaternion::AsMatrix() {
 	m[2][2] = w2 - x2 - y2 + z2;
 
 	return m;
-
-	//out << endl
-	//	<< "         |" << setw(8) << m[0][0] << "," << setw(8) << m[0][1] << "," << setw(8) << m[0][2] << " |" << endl
-	//	<< "         |" << setw(8) << m[1][0] << "," << setw(8) << m[1][1] << "," << setw(8) << m[1][2] << " |" << endl
-	//	<< "         |" << setw(8) << m[2][0] << "," << setw(8) << m[2][1] << "," << setw(8) << m[2][2] << " |" << endl;
-
-	//float pi = 3.141592653589793f;
-	//out << "      Euler Angles:" << endl
-	//	<< "         X:  " << atan2( m[1][2], m[2][2] ) / pi * 180.0 << endl
-	//	<< "         Y:  " << asin( -m[0][2] ) / pi * 180.0 << endl
-	//	<< "         Z:  " << atan2( m[0][1], m[0][0] ) / pi * 180.0 << endl;
 }
 
 /*
diff --git a/src/niflib.cpp b/src/niflib.cpp
index 001f4a18..5a10597d 100644
--- a/src/niflib.cpp
+++ b/src/niflib.cpp
@@ -88,7 +88,6 @@ NiObjectRef CreateObject( string block_type ) {
 
 NiObjectRef ReadNifTree( string const & file_name, NifInfo * info ) {
 	//Read block list
-	//cout << "File name:  " << file_name << endl;
 	vector<NiObjectRef> blocks = ReadNifList( file_name, info );
 	return FindRoot( blocks );
 }
@@ -325,8 +324,6 @@ vector<NiObjectRef> ReadNifList( istream & in, NifInfo * info ) {
 		}
 	}
 
-	//cout << endl;
-
 	//--Read Footer--//
 	Footer footer;
 	footer.Read( in, link_stack, header.version, header.userVersion );
@@ -436,8 +433,7 @@ void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, NifInfo & inf
 #endif
 
 		if (version < 0x05000001) {
-			//cout << i << ":  " << objects[i]->GetType().GetTypeName() << endl;
-			//Write Block Type
+			//Write Object Type
 			WriteString( objects[i]->GetType().GetTypeName() , out );
 		} else if (version >= 0x05000001 && version <= VER_10_1_0_0 ) {
 			WriteUInt( 0, out );
@@ -511,7 +507,6 @@ void EnumerateObjects( NiObjectRef const & root, map<Type*,uint> & type_map, map
 	//Add this object type to the map if it isn't there already
 	if ( type_map.find( (Type*)&(root->GetType()) ) == type_map.end() ) {
 		//The type has not yet been registered, so register it
-		//cout << "Types[" << uint(type_map.size()) << "] = " << root->GetType().GetTypeName() << endl;
 		type_map[ (Type*)&(root->GetType()) ] = uint(type_map.size());
 	}
 
@@ -888,8 +883,6 @@ void MergeSceneGraph( map<string,NiNodeRef> & name_map, const NiNodeRef & root,
 			//This is not a NiNode class, so simply add it as a new child of the
 			//target root node
 			root->AddChild( par );
-
-			//cout << "Added link to " << par << " in " << root << " block.";
 		} else {
 			//This is a NiNode class, so merge its child list with that of the root
 			vector<NiAVObjectRef> children = par_node->GetChildren();
@@ -912,7 +905,6 @@ void MergeSceneGraph( map<string,NiNodeRef> & name_map, const NiNodeRef & root,
 		//TODO:  Implement children
 		////Add this block as new child
 		//attatch->GetAttr("Children")->AddLink( par );
-		////cout << "Added link to " << par << " in " << attatch << " block.";
 	}
 }
 
@@ -991,7 +983,6 @@ void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence>
 				//attach it to the specific type of controller that's
 				//connected to the named node
 				NiNodeRef node = name_map[node_name];
-				//cout << "Attaching interpolator to " << node << endl;
 				list<NiTimeControllerRef> ctlrs = node->GetControllers();
 				NiSingleInterpolatorControllerRef ctlr;
 				for ( list<NiTimeControllerRef>::iterator it = ctlrs.begin(); it != ctlrs.end(); ++it ) {
@@ -1013,8 +1004,6 @@ void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence>
 					node->AddController( StaticCast<NiTimeController>(ctlr) );
 				}
 
-				//cout << "Controller is " << ctlr << endl;
-
 				//Clone the interpolator and attached data and
 				//add it to controller of matching type that was
 				//found
diff --git a/src/obj/NiNode.cpp b/src/obj/NiNode.cpp
index b6e5c052..4250c93d 100644
--- a/src/obj/NiNode.cpp
+++ b/src/obj/NiNode.cpp
@@ -191,7 +191,6 @@ void NiNode::GoToSkeletonBindPosition() {
 			//Loop through all bones again, checking for any that have this bone as a parent
 			for ( uint j = 0; j < bone_nodes.size(); ++j ) {
 				if ( bone_nodes[j]->GetParent() == bone_nodes[i] ) {
-					//cout << "Bone " << bones[j] << " has bone " << bones[i] << " as parent." << endl;
 					//Node 2 has node 1 as a parent
 
 					//Get child offset Matrix33
diff --git a/src/obj/NiObject.cpp b/src/obj/NiObject.cpp
index fa1e6263..1e3ec034 100644
--- a/src/obj/NiObject.cpp
+++ b/src/obj/NiObject.cpp
@@ -41,10 +41,7 @@ void NiObject::AddRef() const {
 void NiObject::SubtractRef() const {
 	_ref_count--;
 	if ( _ref_count < 1 ) {
-		//string id = this->GetIDString();
-		//cout << id << " is being destroyed." << endl;
 		delete this;
-		//cout << "Destruction of " << id << " complete." << endl;
 	}
 }
 
diff --git a/src/obj/NiPixelData.cpp b/src/obj/NiPixelData.cpp
index 3f171c78..c06adca8 100644
--- a/src/obj/NiPixelData.cpp
+++ b/src/obj/NiPixelData.cpp
@@ -211,7 +211,6 @@ void NiPixelData::SetColors( const vector<Color4> & new_pixels, bool generate_mi
 		size = (mipmaps[0].height * mipmaps[0].width * bitsPerPixel) / 8;
 
 		while ( m.width != 1 && m.height != 1 ) {
-			////cout << "Width:  " << m.width << "  Height:  " << m.height << "  Offset:  " << m.offset << endl;
 			m.width /= 2;
 			m.height /= 2;
 			m.offset = size;
diff --git a/src/obj/NiTriStripsData.cpp b/src/obj/NiTriStripsData.cpp
index ffe64391..6423db52 100644
--- a/src/obj/NiTriStripsData.cpp
+++ b/src/obj/NiTriStripsData.cpp
@@ -94,10 +94,8 @@ vector<Triangle> NiTriStripsData::GetTriangles() const {
 		for( uint i = 3; i < it->size(); ++i ) {
 			//Odd numbered triangles need to be reversed to keep the vertices in counter-clockwise order
 			if ( i % 2 == 0 ) {
-				//cout << (*it)[i - 2] << ", " << (*it)[i - 1] << ", " << (*it)[i] << endl;
 				t.Set( (*it)[i - 2], (*it)[i - 1], (*it)[i] );
 			} else {
-				//cout << (*it)[i] << ", " << (*it)[i - 1] << ", " << (*it)[i - 2] << endl;
 				t.Set( (*it)[i], (*it)[i - 1], (*it)[i - 2] );
 			}
 
-- 
GitLab