diff --git a/NIF_IO.cpp b/NIF_IO.cpp index 09c4bf5780da50e5265ecea3cf333495dc093f7f..4b03566f5494751a21beefa8458c58927e19d413 100644 --- a/NIF_IO.cpp +++ b/NIF_IO.cpp @@ -119,7 +119,7 @@ float ReadFloat( istream &in ){ string ReadString( istream &in ) { uint len = ReadUInt( in ); string out; - if ( len > 3000 ) + if ( len > 4000 ) throw runtime_error("String too long. Not a NIF file or unsupported format?"); if ( len > 0 ) { out.resize(len); diff --git a/gen/Header.cpp b/gen/Header.cpp index 91ef3097a8ec9034127e77bc213a75c9d3e22850..2362ff7fb3e8f5bf316b3bc0ed0a919ba9c748cf 100644 --- a/gen/Header.cpp +++ b/gen/Header.cpp @@ -12,7 +12,7 @@ Header::Header() : version((uint)0x04000002), endianType((byte)1), userVersion(( //Destructor Header::~Header() {}; -void Header::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { +void Header::Read( istream& in ) { NifStream( headerString, in, version ); NifStream( version, in, version ); if ( version >= 0x14000004 ) { @@ -63,7 +63,7 @@ void Header::Read( istream& in, list<uint> & link_stack, unsigned int version, u }; } -void Header::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { +void Header::Write( ostream& out ) const { NifStream( headerString, out, version ); NifStream( version, out, version ); if ( version >= 0x14000004 ) { diff --git a/gen/Header.h b/gen/Header.h index 575863cf453d16a81dc15768f6014f4fda0759d4..478edf28b04765cae433b6e17d7cde2f9372cdb6 100644 --- a/gen/Header.h +++ b/gen/Header.h @@ -83,8 +83,8 @@ struct NIFLIB_API Header { * Unknown. */ uint unknownInt2; - void Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ); - void Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const; + void Read( istream& in ); + void Write( ostream& out ) const; string asString( bool verbose = false ) const; }; diff --git a/nif_math.cpp b/nif_math.cpp index 490268ed6f54efdd4c5bc81c32ba052044e795d3..a348a7fd2acbf8a83b5436d8e03f6d21dda60ddc 100644 --- a/nif_math.cpp +++ b/nif_math.cpp @@ -354,10 +354,8 @@ Matrix44 Matrix44::Inverse() const { Matrix44 result; float det = Determinant(); - cout << "Determinant: " << det << endl; for (int r = 0; r < 4; r++) { for (int c = 0; c < 4; c++) { - //cout << "Adjoint(" << r << "," << c << "): " << Adjunct(r, c) << endl; result[c][r] = Adjoint(r, c) / det; } } diff --git a/niflib.cpp b/niflib.cpp index 154c544b5cf5ba188bb4d60025a04833c4cedeb5..922db60e92e3b27c7c269d362028e5c83cba7613 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -2,8 +2,9 @@ All rights reserved. Please see niflib.h for licence. */ //#define DEBUG // this will produce lots of output -//#define PRINT_BLOCK_NAMES -//#define PRINT_BLOCK_CONTENTS +//#define PRINT_OBJECT_NAMES +//#define PRINT_OBJECT_CONTENTS +#define DEBUG_LINK_PHASE #include "niflib.h" #include "obj/NiAVObject.h" @@ -129,108 +130,113 @@ vector<NiObjectRef> ReadNifList( string const & file_name ) { vector<NiObjectRef> ReadNifList( istream & in ) { //--Read Header--// - char header_string[64]; - in.getline( header_string, 64 ); - string headerstr(header_string); - - // make sure this is a NIF file - if ( ( headerstr.substr(0, 22) != "NetImmerse File Format" ) - && ( headerstr.substr(0, 20) != "Gamebryo File Format" ) ) - throw runtime_error("Not a NIF file."); - - // detect old versions - if ( ( headerstr == "NetImmerse File Format, Version 3.1" ) - || ( headerstr == "NetImmerse File Format, Version 3.03" ) - || ( headerstr == "NetImmerse File Format, Version 3.0" ) - || ( headerstr == "NetImmerse File Format, Version 2.3" ) ) - throw runtime_error("Unsupported: " + headerstr); - - uint version = ReadUInt( in ); - - //There is an unknown Byte here from version 20.0.0.4 on - byte endianType; - if ( version >= VER_20_0_0_4 ) { - endianType = ReadByte( in ); - } - - //There is an Unknown Int here from version 10.1.0.0 on - uint userVersion = 0; - if ( version >= VER_10_1_0_0 ) { - userVersion = ReadUInt( in ); - } - - uint numBlocks = ReadUInt( in ); - - if ( userVersion != 0 ) { - uint len; - ReadUInt( in ); - len = ReadByte( in ); - for (uint i = 0; i < len; i++) ReadByte( in ); - len = ReadByte( in ); - for (uint i = 0; i < len; i++) ReadByte( in ); - len = ReadByte( in ); - for (uint i = 0; i < len; i++) ReadByte( in ); - } - - vector<string> blockTypes; - vector<short> blockTypeIndex; - //New header data exists from version 5.0.0.1 on - if ( version >= 0x05000001 ) { - short numBlockTypes = ReadUShort( in ); - blockTypes.resize(numBlockTypes); - for ( uint i = 0; i < blockTypes.size(); ++i ) { - blockTypes[i] = ReadString( in ); - } - - blockTypeIndex.resize(numBlocks); - for ( uint i = 0; i < blockTypeIndex.size(); ++i ) { - blockTypeIndex[i] = ReadUShort( in ); - } + Header header; - uint unknownInt2 = - ReadUInt( in ); - - //Output -#ifdef DEBUG - cout << endl << endl - << "====[ " << "File Header ]====" << endl - << "Header: " << header_string << endl - << "Version: " << version << endl - << "Endian Type: " << endianType << endl - << "User Version: " << userVersion << endl - << "Number of Blocks: " << numBlocks << endl - << "Block Types: " << uint(blockTypes.size()) << endl; - - for ( uint i = 0; i < blockTypes.size(); ++i ) { - cout << " " << i << ": " << blockTypes[i] << endl; - } - - cout << "Block Type Indices: " << numBlocks << endl; - for ( uint i = 0; i < blockTypeIndex.size(); ++i ) { - cout << " " << i + 1 << ": " << blockTypeIndex[i] << "(" << blockTypes[blockTypeIndex[i]] << ")" << endl; - } + //Read header. + header.Read( in ); - cout << "Unknown Int 2: " << unknownInt2 << endl; -#endif - } else { -#ifdef DEBUG - //Output - cout << endl << endl - << "====[ " << "File Header ]====" << endl - << "Header: " << header_string << endl - << "Version: " << version << endl - << "Number of Blocks: " << numBlocks << endl; -#endif - } - - //TODO: Actually read the user_version from the right place - uint user_version = 0; +// char header_string[64]; +// in.getline( header_string, 64 ); +// string headerstr(header_string); +// +// // make sure this is a NIF file +// if ( ( headerstr.substr(0, 22) != "NetImmerse File Format" ) +// && ( headerstr.substr(0, 20) != "Gamebryo File Format" ) ) +// throw runtime_error("Not a NIF file."); +// +// // detect old versions +// if ( ( headerstr == "NetImmerse File Format, Version 3.1" ) +// || ( headerstr == "NetImmerse File Format, Version 3.03" ) +// || ( headerstr == "NetImmerse File Format, Version 3.0" ) +// || ( headerstr == "NetImmerse File Format, Version 2.3" ) ) +// throw runtime_error("Unsupported: " + headerstr); +// +// uint version = ReadUInt( in ); +// +// //There is an unknown Byte here from version 20.0.0.4 on +// byte endianType; +// if ( version >= VER_20_0_0_4 ) { +// endianType = ReadByte( in ); +// } +// +// //There is an Unknown Int here from version 10.1.0.0 on +// uint userVersion = 0; +// if ( version >= VER_10_1_0_0 ) { +// userVersion = ReadUInt( in ); +// } +// +// uint numBlocks = ReadUInt( in ); +// +// if ( userVersion != 0 ) { +// uint len; +// ReadUInt( in ); +// len = ReadByte( in ); +// for (uint i = 0; i < len; i++) ReadByte( in ); +// len = ReadByte( in ); +// for (uint i = 0; i < len; i++) ReadByte( in ); +// len = ReadByte( in ); +// for (uint i = 0; i < len; i++) ReadByte( in ); +// } +// +// vector<string> blockTypes; +// vector<short> blockTypeIndex; +// //New header data exists from version 5.0.0.1 on +// if ( version >= 0x05000001 ) { +// short numBlockTypes = ReadUShort( in ); +// blockTypes.resize(numBlockTypes); +// for ( uint i = 0; i < blockTypes.size(); ++i ) { +// blockTypes[i] = ReadString( in ); +// } +// +// blockTypeIndex.resize(numBlocks); +// for ( uint i = 0; i < blockTypeIndex.size(); ++i ) { +// blockTypeIndex[i] = ReadUShort( in ); +// } +// +// uint unknownInt2 = +// ReadUInt( in ); +// +// //Output +//#ifdef DEBUG +// cout << endl << endl +// << "====[ " << "File Header ]====" << endl +// << "Header: " << header_string << endl +// << "Version: " << version << endl +// << "Endian Type: " << endianType << endl +// << "User Version: " << userVersion << endl +// << "Number of Blocks: " << numBlocks << endl +// << "Block Types: " << uint(blockTypes.size()) << endl; +// +// for ( uint i = 0; i < blockTypes.size(); ++i ) { +// cout << " " << i << ": " << blockTypes[i] << endl; +// } +// +// cout << "Block Type Indices: " << numBlocks << endl; +// for ( uint i = 0; i < blockTypeIndex.size(); ++i ) { +// cout << " " << i + 1 << ": " << blockTypeIndex[i] << "(" << blockTypes[blockTypeIndex[i]] << ")" << endl; +// } +// +// cout << "Unknown Int 2: " << unknownInt2 << endl; +//#endif +// } else { +//#ifdef DEBUG +// //Output +// cout << endl << endl +// << "====[ " << "File Header ]====" << endl +// << "Header: " << header_string << endl +// << "Version: " << version << endl +// << "Number of Blocks: " << numBlocks << endl; +//#endif +// } +// +// //TODO: Actually read the user_version from the right place +// uint user_version = 0; //--Read Blocks--// - vector<NiObjectRef> blocks( numBlocks ); //List to hold the blocks + vector<NiObjectRef> blocks( header.numBlocks ); //List to hold the blocks list<uint> link_stack; //List to add link values to as they're read in from the file string blockName; - for (uint i = 0; i < numBlocks; i++) { + for (uint i = 0; i < header.numBlocks; i++) { //Check for EOF //if (in.eof() ) { @@ -238,10 +244,10 @@ vector<NiObjectRef> ReadNifList( istream & in ) { //} //There are two ways to read blocks, one before version 5.0.0.1 and one after that - if ( version >= 0x05000001 ) { + if ( header.version >= 0x05000001 ) { //From version 5.0.0.1 to version 10.0.1.0 there is a zero byte at the begining of each block - if ( version <= VER_10_1_0_0 ) { + if ( header.version <= VER_10_1_0_0 ) { uint checkValue = ReadUInt( in ); if ( checkValue != 0 ) { //Throw an exception if it's not zero @@ -253,7 +259,7 @@ vector<NiObjectRef> ReadNifList( istream & in ) { } // Find which block type this is by using the header arrays - blockName = blockTypes[ blockTypeIndex[i] ]; + blockName = header.blockTypes[ header.blockTypeIndex[i] ]; } else { // Find which block type this is by reading the string at this location uint blockNameLength = ReadUInt( in ); @@ -276,7 +282,7 @@ vector<NiObjectRef> ReadNifList( istream & in ) { } } -#ifdef PRINT_BLOCK_NAMES +#ifdef PRINT_OBJECT_NAMES cout << endl << i << ": " << blockName; #endif @@ -297,8 +303,8 @@ vector<NiObjectRef> ReadNifList( istream & in ) { } //blocks[i]->SetBlockNum(i); - blocks[i]->Read( in, link_stack, version, user_version ); -#ifdef PRINT_BLOCK_CONTENTS + blocks[i]->Read( in, link_stack, header.version, header.userVersion ); +#ifdef PRINT_OBJECT_CONTENTS cout << endl << blocks[i]->asString() << endl; #endif } @@ -316,7 +322,7 @@ vector<NiObjectRef> ReadNifList( istream & in ) { if ( ! in.eof() ) throw runtime_error("End of file not reached. This NIF may be corrupt or improperly supported."); -#ifdef DEBUG +#ifdef DEBUG_LINK_PHASE cout << "Link Stack:" << endl; list<uint>::iterator it; for ( it = link_stack.begin(); it != link_stack.end(); ++it ) { @@ -324,16 +330,16 @@ vector<NiObjectRef> ReadNifList( istream & in ) { } #endif -#ifdef DEBUG +#ifdef DEBUG_LINK_PHASE cout << "Fixing Links:" << endl; #endif //--Now that all blocks are read, go back and fix the links--// for (uint i = 0; i < blocks.size(); ++i) { -#ifdef DEBUG - cout << blocks[i]->GetType().GetTypeName() << endl; +#ifdef DEBUG_LINK_PHASE + cout << i << ": " << blocks[i] << endl; #endif //Fix links & other pre-processing - blocks[i]->FixLinks( blocks, link_stack, version, user_version ); + blocks[i]->FixLinks( blocks, link_stack, header.version, header.userVersion ); } diff --git a/obj/NiNode.cpp b/obj/NiNode.cpp index c77a97da2945543e60c669580c73c5339f618977..ba9f6d8ac0c9aed4b4f3d730c273ba27448b5557 100644 --- a/obj/NiNode.cpp +++ b/obj/NiNode.cpp @@ -101,28 +101,6 @@ bool NiNode::IsSkinInfluence() const { } void NiNode::AddSkin( NiSkinInstance * skin_inst ) { - //Ensure that all bones are below this node on the scene graph - vector<NiNodeRef> bones = skin_inst->GetBones(); - for ( uint i = 0; i < bones.size(); ++i ) { - bool is_decended = false; - NiNodeRef node = bones[i]; - while ( node != NULL ) { - if ( node == this ) { - is_decended = true; - break; - } - node = node->GetParent(); - } - if ( is_decended == false ) { - throw runtime_error( "All bones must be lower than the skeleton root in the scene graph." ); - } - } - - //Flag any bones that are part of this skin instance - for ( uint i = 0; i < bones.size(); ++i ) { - bones[i]->SetSkinFlag(true); - } - skins.push_back( skin_inst ); } @@ -194,7 +172,7 @@ void NiNode::GoToSkeletonBindPosition() { //Loop through all bones again, checking for any that have this bone as a parent for ( uint j = 0; j < bones.size(); ++j ) { if ( bones[j]->GetParent() == bones[i] ) { - cout << "Bone " << bones[j] << " has bone " << bones[i] << " as parent." << endl; + //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/obj/NiSkinInstance.cpp b/obj/NiSkinInstance.cpp index 67f46409b440034dd68cf2abf652ea6268a6dca1..862171f41e4ee033e7943ceb508be600c0a80382 100644 --- a/obj/NiSkinInstance.cpp +++ b/obj/NiSkinInstance.cpp @@ -56,13 +56,34 @@ void NiSkinInstance::Bind( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone if ( bones.size() != 0 ) { throw runtime_error("You have attempted to re-bind a skin that is already bound. Unbind it first."); } - + + //Ensure that all bones are below the skeleton root node on the scene graph + for ( uint i = 0; i < bone_nodes.size(); ++i ) { + bool is_decended = false; + NiNodeRef node = bone_nodes[i]; + while ( node != NULL ) { + if ( node == skeleton_root ) { + is_decended = true; + break; + } + node = node->GetParent(); + } + if ( is_decended == false ) { + throw runtime_error( "All bones must be lower than the skeleton root in the scene graph." ); + } + } + //Add the bones to the internal list bones.resize( bone_nodes.size() ); for ( uint i = 0; i < bone_nodes.size(); ++i ) { bones[i] = bone_nodes[i]; } + //Flag any bones that are part of this skin instance + for ( uint i = 0; i < bones.size(); ++i ) { + bones[i]->SetSkinFlag(true); + } + //Store skeleton root and inform it of this attachment skeletonRoot = skeleton_root; skeletonRoot->AddSkin( this );