From 8e46bf6ba34d55cb17414ae8b6273a5b888bc45a Mon Sep 17 00:00:00 2001
From: Tazpn <tazpn@users.sourceforge.net>
Date: Sat, 3 Jan 2009 09:57:08 +0000
Subject: [PATCH] niflib:  fix bit unpack routine. Fix tangent space for
 fallout.

---
 include/NIF_IO.h             |  2 +-
 include/obj/NiGeometryData.h | 40 +++++++++++++++-
 src/obj/BSShaderProperty.cpp |  2 +-
 src/obj/NiAVObject.cpp       |  2 +-
 src/obj/NiGeometryData.cpp   | 33 ++++++++++++++
 src/obj/NiTriBasedGeom.cpp   | 88 ++++++++++++++++++++----------------
 6 files changed, 122 insertions(+), 45 deletions(-)

diff --git a/include/NIF_IO.h b/include/NIF_IO.h
index 7593de2a..00cacd3a 100644
--- a/include/NIF_IO.h
+++ b/include/NIF_IO.h
@@ -74,7 +74,7 @@ storage UnpackField( storage src, size_t lshift, size_t num_bits ) {
 		mask |= (1 << i);
 	}
 
-	return (storage)(( src & mask) << lshift);
+	return (storage)(( src & mask) >> lshift);
 }
 
 template <class storage, class T>
diff --git a/include/obj/NiGeometryData.h b/include/obj/NiGeometryData.h
index 9dc5931f..4cab63ce 100644
--- a/include/obj/NiGeometryData.h
+++ b/include/obj/NiGeometryData.h
@@ -197,11 +197,47 @@ public:
 
 	// Consistency Flags
 	// \return The current value.
-	ConsistencyType GetConsistencyFlags() const;
+	NIFLIB_API ConsistencyType GetConsistencyFlags() const;
 
 	// Consistency Flags
 	// \param[in] value The new value.
-	void SetConsistencyFlags( const ConsistencyType & value );
+	NIFLIB_API void SetConsistencyFlags( const ConsistencyType & value );
+
+   // Methods for saving binormals and tangents saved in upper byte.
+   // \return The current value.
+   NIFLIB_API byte GetTspaceFlag() const;
+
+   // Methods for saving binormals and tangents saved in upper byte.
+   // \param[in] value The new value.
+   NIFLIB_API void SetTspaceFlag( byte value );
+
+   // Do we have lighting normals? These are essential for proper lighting: if not
+   // present, the model will only be influenced by ambient light.
+   // \return The current value.
+   NIFLIB_API bool GetHasNormals() const;
+
+   // Do we have lighting normals? These are essential for proper lighting: if not
+   // present, the model will only be influenced by ambient light.
+   // \param[in] value The new value.
+   NIFLIB_API void SetHasNormals( bool value );
+
+   // Unknown. Binormal & tangents? has_normals must be set as well for this field to
+   // be present.
+   // \return The current value.
+   NIFLIB_API vector<Vector3 > GetBinormals() const;
+
+   // Unknown. Binormal & tangents? has_normals must be set as well for this field to
+   // be present.
+   // \param[in] value The new value.
+   NIFLIB_API void SetBinormals( const vector<Vector3 >& value );
+
+   // Unknown. Binormal & tangents?
+   // \return The current value.
+   NIFLIB_API vector<Vector3 > GetTangents() const;
+
+   // Unknown. Binormal & tangents?
+   // \param[in] value The new value.
+   NIFLIB_API void SetTangents( const vector<Vector3 >& value );
 
 	//--END CUSTOM CODE--//
 protected:
diff --git a/src/obj/BSShaderProperty.cpp b/src/obj/BSShaderProperty.cpp
index ee959202..4243ec6e 100644
--- a/src/obj/BSShaderProperty.cpp
+++ b/src/obj/BSShaderProperty.cpp
@@ -20,7 +20,7 @@ using namespace Niflib;
 //Definition of TYPE constant
 const Type BSShaderProperty::TYPE("BSShaderProperty", &NiProperty::TYPE );
 
-BSShaderProperty::BSShaderProperty() : flags((unsigned short)1), shaderType((BSShaderType)1), shaderFlags((BSShaderFlags)0x82000103), unknownInt2((int)1), envmapScale(1.0f) {
+BSShaderProperty::BSShaderProperty() : flags((unsigned short)1), shaderType((BSShaderType)1), shaderFlags((BSShaderFlags)0x82000000), unknownInt2((int)1), envmapScale(1.0f) {
 	//--BEGIN CONSTRUCTOR CUSTOM CODE--//
 
 	//--END CUSTOM CODE--//
diff --git a/src/obj/NiAVObject.cpp b/src/obj/NiAVObject.cpp
index f9570d2e..bc9805c5 100644
--- a/src/obj/NiAVObject.cpp
+++ b/src/obj/NiAVObject.cpp
@@ -23,7 +23,7 @@ using namespace Niflib;
 //Definition of TYPE constant
 const Type NiAVObject::TYPE("NiAVObject", &NiObjectNET::TYPE );
 
-NiAVObject::NiAVObject() : flags((unsigned short)0), unknownShort1((unsigned short)0), scale(1.0f), numProperties((unsigned int)0), unknown2((byte)0), hasBoundingBox(false), collisionObject(NULL) {
+NiAVObject::NiAVObject() : flags((unsigned short)0), unknownShort1((unsigned short)8), scale(1.0f), numProperties((unsigned int)0), unknown2((byte)0), hasBoundingBox(false), collisionObject(NULL) {
 	//--BEGIN CONSTRUCTOR CUSTOM CODE--//
 
 	parent = NULL;
diff --git a/src/obj/NiGeometryData.cpp b/src/obj/NiGeometryData.cpp
index b99c8f14..695773c8 100644
--- a/src/obj/NiGeometryData.cpp
+++ b/src/obj/NiGeometryData.cpp
@@ -565,4 +565,37 @@ void NiGeometryData::SetBound(Vector3 const & center, float radius)
 	this->radius = radius;
 }
 
+
+byte NiGeometryData::GetTspaceFlag() const {
+   return tspaceFlag;
+}
+
+void NiGeometryData::SetTspaceFlag( byte value ) {
+   tspaceFlag = value;
+}
+
+bool NiGeometryData::GetHasNormals() const {
+   return hasNormals;
+}
+
+void NiGeometryData::SetHasNormals( bool value ) {
+   hasNormals = value;
+}
+
+vector<Vector3 > NiGeometryData::GetBinormals() const {
+   return binormals;
+}
+
+void NiGeometryData::SetBinormals( const vector<Vector3 >& value ) {
+   binormals = value;
+}
+
+vector<Vector3 > NiGeometryData::GetTangents() const {
+   return tangents;
+}
+
+void NiGeometryData::SetTangents( const vector<Vector3 >& value ) {
+   tangents = value;
+}
+
 //--END CUSTOM CODE--//
diff --git a/src/obj/NiTriBasedGeom.cpp b/src/obj/NiTriBasedGeom.cpp
index 22bf3400..34081462 100644
--- a/src/obj/NiTriBasedGeom.cpp
+++ b/src/obj/NiTriBasedGeom.cpp
@@ -270,51 +270,59 @@ void NiTriBasedGeom::UpdateTangentSpace(int method) {
 		}
 	}
 
-	// generate the byte data
-	size_t vCount = verts.size();
-	int fSize = sizeof(float[3]);
-	vector<byte> binData( 2 * vCount * fSize );
-
-	for( unsigned i = 0; i < verts.size(); i++ ) {
-		float tan_xyz[3], bin_xyz[3];
-
-		tan_xyz[0] = tangents[i].x;
-		tan_xyz[1] = tangents[i].y;
-		tan_xyz[2] = tangents[i].z;
-
-		bin_xyz[0] = binormals[i].x;
-		bin_xyz[1] = binormals[i].y;
-		bin_xyz[2] = binormals[i].z;
-
-		char * tan_Bytes = (char*)tan_xyz;
-		char * bin_Bytes = (char*)bin_xyz;
-
-		for( int j = 0; j < fSize; j++ ) {
-			binData[ i           * fSize + j] = tan_Bytes[j];
-			binData[(i + vCount) * fSize + j] = bin_Bytes[j];
-		}
-	}
+   if ( !niTriGeomData->GetHasNormals() && (niTriGeomData->GetTspaceFlag() & 0xF0) == 0 )
+   {
+      // generate the byte data
+      size_t vCount = verts.size();
+      int fSize = sizeof(float[3]);
+      vector<byte> binData( 2 * vCount * fSize );
+
+      for( unsigned i = 0; i < verts.size(); i++ ) {
+         float tan_xyz[3], bin_xyz[3];
+
+         tan_xyz[0] = tangents[i].x;
+         tan_xyz[1] = tangents[i].y;
+         tan_xyz[2] = tangents[i].z;
+
+         bin_xyz[0] = binormals[i].x;
+         bin_xyz[1] = binormals[i].y;
+         bin_xyz[2] = binormals[i].z;
+
+         char * tan_Bytes = (char*)tan_xyz;
+         char * bin_Bytes = (char*)bin_xyz;
+
+         for( int j = 0; j < fSize; j++ ) {
+            binData[ i           * fSize + j] = tan_Bytes[j];
+            binData[(i + vCount) * fSize + j] = bin_Bytes[j];
+         }
+      }
 
-	// update or create the tangent space extra data
-	NiBinaryExtraDataRef TSpaceRef;
+      // update or create the tangent space extra data
+      NiBinaryExtraDataRef TSpaceRef;
 
-	std::list<NiExtraDataRef> props = this->GetExtraData();
-	std::list<NiExtraDataRef>::iterator prop;
+      std::list<NiExtraDataRef> props = this->GetExtraData();
+      std::list<NiExtraDataRef>::iterator prop;
 
-	for( prop = props.begin(); prop != props.end(); ++prop ){
-		if((*prop)->GetName() == "Tangent space (binormal & tangent vectors)") {
-			TSpaceRef = DynamicCast<NiBinaryExtraData>(*prop);
-			break;
-		}
-	}
+      for( prop = props.begin(); prop != props.end(); ++prop ){
+         if((*prop)->GetName() == "Tangent space (binormal & tangent vectors)") {
+            TSpaceRef = DynamicCast<NiBinaryExtraData>(*prop);
+            break;
+         }
+      }
 
-	if( TSpaceRef == NULL ) {
-		TSpaceRef = new NiBinaryExtraData();
-		TSpaceRef->SetName( "Tangent space (binormal & tangent vectors)" );
-		this->AddExtraData( StaticCast<NiExtraData>(TSpaceRef) );
-	}
+      if( TSpaceRef == NULL ) {
+         TSpaceRef = new NiBinaryExtraData();
+         TSpaceRef->SetName( "Tangent space (binormal & tangent vectors)" );
+         this->AddExtraData( StaticCast<NiExtraData>(TSpaceRef) );
+      }
 
-	TSpaceRef->SetData(binData);
+      TSpaceRef->SetData(binData);
+   }
+   else
+   {
+      niTriGeomData->SetTangents(tangents);
+      niTriGeomData->SetBinormals(binormals);
+   }
 }
 
 //--END CUSTOM CODE--//
-- 
GitLab