diff --git a/niflib.cpp b/niflib.cpp index 656a61b863c2fbfbb4098ecc478be69fd4a8df7a..2bbe7c5f3dd69b758986cccd663daf38690bec53 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -322,8 +322,8 @@ vector<blk_ref> ReadNifList( string file_name ) { return blocks; } -//Writes a valid Nif File given a file name, a pointer to the root block of a file tree -void WriteNifTree( string file_name, blk_ref & root_block, unsigned int version ) { +// Writes a valid Nif File given a file name, a pointer to the root block of a file tree +void WriteRawNifTree( string file_name, blk_ref & root_block, unsigned int version ) { // Walk tree, resetting all block numbers //int block_count = ResetBlockNums( 0, root_block ); @@ -377,6 +377,7 @@ void WriteNifTree( string file_name, blk_ref & root_block, unsigned int version //Close file out.close(); } + void ReorderNifTree( vector<blk_ref> & blk_list, blk_ref block ) { //Get internal interface IBlockInternal * bk_intl = (IBlockInternal*)block->QueryInterface( BlockInternal ); @@ -447,6 +448,81 @@ void BuildUpBindPositions( blk_ref block ) { } } +// Searches for the first block in the hierarchy of type block_name. +blk_ref SearchNifTree( blk_ref & root_block, string block_name ) { + if ( root_block->GetBlockType() == block_name ) return root_block; + list<blk_ref> links = root_block->GetLinks(); + for (list <blk_ref>::iterator it = links.begin(); it != links.end(); ++it) { + if ( it->is_null() == false && (*it)->GetParent() == root_block ) { + blk_ref result = SearchNifTree( *it, block_name ); + if ( result.is_null() == false ) return result; + }; + }; + return blk_ref(); // return null block +}; + +// Returns all blocks in the tree of type block_name. +list<blk_ref> SearchAllNifTree( blk_ref & root_block, string block_name ) { + list<blk_ref> result; + if ( root_block->GetBlockType() == block_name ) result.push_back( root_block ); + list<blk_ref> links = root_block->GetLinks(); + for (list<blk_ref>::iterator it = links.begin(); it != links.end(); ++it ) { + if ( it->is_null() == false && (*it)->GetParent() == root_block ) + result.merge( SearchAllNifTree( *it, block_name ) ); + }; + return result; +}; + +// Writes valid XNif & XKf Files given a file name, and a pointer to the root block of the Nif file tree. +// (XNif and XKf file blocks are automatically extracted from the Nif tree if there are animation groups.) +void WriteNifTree( string file_name, blk_ref & root_block, unsigned int version ) { + // Write the full Nif file. + WriteRawNifTree( file_name, root_block, version ); + + // Do we have animation groups (a NiTextKeyExtraData block)? + // If so, write out XNif and XKf files. + blk_ref txtkey_block = SearchNifTree( root_block, "NiTextKeyExtraData" ); + if ( txtkey_block.is_null() == false ) { + // Create file names for the XKf and XNif files. + int file_name_dot = file_name.rfind("."); + string file_name_base; + if ( file_name_dot != string::npos ) + file_name_base = file_name.substr(0, file_name_dot); + else + file_name_base = file_name; + string xkf_name = "x" + file_name + ".kf"; + string xnif_name = "x" + file_name + ".nif"; + + // Create xkf root header. + blk_ref xkf_root = CreateBlock("NiSequenceStreamHelper"); + + // Link the NiTextKeyExtraData block to it. + xkf_root["Extra Data"] = txtkey_block; + + // Append NiNodes with a NiKeyFrameController as NiStringExtraData blocks. + list<blk_ref> nodes = SearchAllNifTree( root_block, "NiNode" ); + for ( list<blk_ref>::iterator it = nodes.begin(); it != nodes.end(); ) + if ( (*it)->GetAttr("Controller").is_null() ) + it = nodes.erase( it ); + else + ++it; + + blk_ref last_block = txtkey_block; + for ( list<blk_ref>::iterator it = nodes.begin(); it != nodes.end(); ++it ) { + blk_ref nodextra = CreateBlock("NiStringExtraData"); + nodextra["String Data"] = (*it)->GetAttr("Name"); + last_block["Next Extra Data"] = nodextra; + }; + + // Now add controllers & controller data... + + // Now write it out... + //WriteRawNifTree( ) + + // Now construct the XNif file... + }; +} + //Returns the total number of blocks in memory unsigned int BlocksInMemory() { return blocks_in_memory;