diff --git a/niflib.cpp b/niflib.cpp index cc6cec6a33769cd985acb090681c774338fb79ce..26454fdffe99876388a07db0f13f1abcf106af78 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -50,14 +50,15 @@ unsigned int blocks_in_memory = 0; //Utility Functions void EnumerateNifTree( NiObjectRef const & root, map<Type,uint> & type_map, map<NiObjectRef, uint> link_map ); -void BuildUpBindPositions( blk_ref const & block ); -blk_ref FindRoot( vector<blk_ref> const & blocks ); +void BuildUpBindPositions( NiObjectRef const & block ); +NiObjectRef FindRoot( vector<NiObjectRef> const & blocks ); void RegisterBlockFactories (); +NiObjectRef GetObjectByType( const NiObjectRef & root, const Type & block_type ); //--Function Bodies--// void SetVerboseMode( bool val ) { verbose = val; } -blk_ref CreateBlock( string block_type ) { +NiObjectRef CreateBlock( string block_type ) { //Initialize the global block list if it hasn't been done yet if ( global_block_map_init == false ) { @@ -79,24 +80,24 @@ blk_ref CreateBlock( string block_type ) { //block = new UnknownBlock( block_type ); } - return blk_ref(block); + return NiObjectRef(block); } //Reads the given file by file name and returns a reference to the root block -blk_ref ReadNifTree( string const & file_name ) { +NiObjectRef ReadNifTree( string const & file_name ) { //Read block list - vector<blk_ref> blocks = ReadNifList( file_name ); + vector<NiObjectRef> blocks = ReadNifList( file_name ); return FindRoot( blocks ); } //Reads the given input stream and returns a reference to the root block -blk_ref ReadNifTree( istream & in ) { +NiObjectRef ReadNifTree( istream & in ) { //Read block list - vector<blk_ref> blocks = ReadNifList( in ); + vector<NiObjectRef> blocks = ReadNifList( in ); return FindRoot( blocks ); } -NiObjectRef FindRoot( vector<blk_ref> const & blocks ) { +NiObjectRef FindRoot( vector<NiObjectRef> const & blocks ) { //--Look for a NiNode that has no parents--// //Find the first NiObjectNET derived object @@ -151,7 +152,7 @@ unsigned int CheckNifHeader( string const & file_name ) { } //Reads the given file by file name and returns a vector of block references -vector<blk_ref> ReadNifList( string const & file_name ) { +vector<NiObjectRef> ReadNifList( string const & file_name ) { //--Open File--// ifstream in( file_name.c_str(), ifstream::binary ); @@ -160,7 +161,7 @@ vector<blk_ref> ReadNifList( string const & file_name ) { } //Reads the given input stream and returns a vector of block references -vector<blk_ref> ReadNifList( istream & in ) { +vector<NiObjectRef> ReadNifList( istream & in ) { //--Read Header--// char header_string[256]; @@ -359,13 +360,13 @@ vector<blk_ref> ReadNifList( istream & in ) { // continue; // } - // blk_ref si_blk = si_attr->asLink(); + // NiObjectRef si_blk = si_attr->asLink(); // if ( si_blk.is_null() == true ) { // continue; // } - // blk_ref sd_blk = si_blk->GetAttr("Data")->asLink(); + // NiObjectRef sd_blk = si_blk->GetAttr("Data")->asLink(); // if ( sd_blk.is_null() == true ) { // continue; @@ -385,7 +386,7 @@ vector<blk_ref> ReadNifList( istream & in ) { } // Writes a valid Nif File given a file name, a pointer to the root block of a file tree -void WriteNifTree( string const & file_name, blk_ref const & root_block, unsigned int version ) { +void WriteNifTree( string const & file_name, NiObjectRef const & root_block, unsigned int version ) { //Open output file ofstream out( file_name.c_str(), ofstream::binary ); @@ -504,25 +505,11 @@ void EnumerateNifTree( NiObjectRef const & root, map<Type,uint> & type_map, map< //Call this function on all links of this object list<NiObjectRef> links = root->GetLinks(); - for ( list<blk_ref>::iterator it = links.begin(); it != links.end(); ++it ) { + for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) { EnumerateNifTree( *it, type_map, link_map ); } } -//int ResetBlockNums( int start_num, blk_ref block ) { -// cout << "Setting " << block << " to " << start_num << endl; -// block->SetBlockNum( start_num ); -// start_num++; -// for (uint i = 0; i < block->LinkCount(); ++i) { -// blk_link l = block->GetLink(i); -// if ( l.block.get_block() != NULL && l.attr->LinkType() == child_link ) { -// start_num = ResetBlockNums( start_num, l.block ); -// } -// } -// return start_num; -// -//} - void BuildUpBindPositions( const NiAVObjectRef av ) { //Get parent if there is one @@ -537,58 +524,61 @@ void BuildUpBindPositions( const NiAVObjectRef av ) { av->SetWorldBindPos( result ); } + //TODO: Implement Child storage and access functions in NiNode ////Call this function for all child nodes if any //attr_ref child_attr = block["Children"]; //if ( child_attr.is_null() == false ) { - // list<blk_ref> children = child_attr->asLinkList(); - // list<blk_ref>::iterator it; + // list<NiObjectRef> children = child_attr->asLinkList(); + // list<NiObjectRef>::iterator it; // for (it = children.begin(); it != children.end(); ++it) { // BuildUpBindPositions( *it ); // } //} } -// Searches for the first object in the hierarchy of type block_type. -NiObjectRef SearchNifTree( const NiObjectRef & root_block, const Type & block_type ) { - if ( root_block->IsSameType( block_type ) ) { - return root_block; +//TODO: Should this be returning an object of a derived type too? +// Searches for the first object in the hierarchy of type. +NiObjectRef GetObjectByType( const NiObjectRef & root, const Type & type ) { + if ( root->IsSameType( type ) ) { + return root; } - //list<blk_ref> links = root_block->GetLinks(); - //for (list <blk_ref>::iterator it = links.begin(); it != links.end(); ++it) { - // // if the link is not null, and if the child's first parent is root_block - // // (this makes sure we only check every child once, even if it is shared by multiple parents), - // // then look for a match in the tree starting from the child. - // if ( it->is_null() == false && (*it)->GetParent() == root_block ) { - // blk_ref result = SearchNifTree( *it, block_type ); - // if ( result.is_null() == false ) return result; - // }; - //}; + + list<NiObjectRef> links = root->GetLinks(); + for (list <NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it) { + // Can no longer guarantee that some objects won't be visited twice. Oh well. + NiObjectRef result = GetObjectByType( *it, type ); + if ( result != NULL ) { + return result; + } + }; + return NULL; // return null reference }; -// Returns all blocks in the tree of type block_name. -list<blk_ref> SearchAllNifTree( blk_ref const & root_block, Type & block_type ) { - list<blk_ref> result; - if ( root_block->IsSameType(block_type) ) { - //result.push_back( root_block ); +//TODO: Should this be returning all objects of a derived type too? +// Returns all in the in the tree of type. +list<NiObjectRef> GetAllObjectsByType( NiObjectRef const & root, const Type & type ) { + list<NiObjectRef> result; + if ( root->IsSameType(type) ) { + result.push_back( root ); } - /*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 ) { - list<blk_ref> childresult = SearchAllNifTree( *it, block_type ); - result.merge( childresult ); - }; - };*/ + list<NiObjectRef> links = root->GetLinks(); + for (list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) { + // Can no longer guarantee that some objects won't be visited twice. Oh well. + list<NiObjectRef> childresult = GetAllObjectsByType( *it, type ); + result.merge( childresult ); + }; return result; }; -//list<blk_ref> GetNifTree( blk_ref const & root_block ) { -// list<blk_ref> result; +//TODO: Is this function used anywhere? Does it need to be re-done? +//list<NiObjectRef> GetNifTree( NiObjectRef const & root_block ) { +// list<NiObjectRef> result; // result.push_back( root_block ); -// list<blk_ref> links = root_block->GetLinks(); -// for (list<blk_ref>::iterator it = links.begin(); it != links.end(); ++it ) { +// list<NiObjectRef> links = root_block->GetLinks(); +// for (list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) { // if ( it->is_null() == false && (*it)->GetParent() == root_block ) { -// list<blk_ref> childresult = GetNifTree( *it ); +// list<NiObjectRef> childresult = GetNifTree( *it ); // result.merge( childresult ); // }; // }; @@ -603,125 +593,130 @@ list<blk_ref> SearchAllNifTree( blk_ref const & root_block, Type & block_type ) * \param kfm The KFM structure (if required by style). * \param kf_type What type of keyframe tree to write (Morrowind style, DAoC style, ...). */ -//void SplitNifTree( blk_ref const & root_block, blk_ref & xnif_root, blk_ref & xkf_root, Kfm & kfm, int kf_type ) { -// // Do we have animation groups (a NiTextKeyExtraData block)? -// // If so, create XNif and XKf trees. -// blk_ref txtkey_block = SearchNifTree( root_block, "NiTextKeyExtraData" ); -// if ( txtkey_block.is_null() == false ) { -// if ( kf_type == KF_MW ) { -// // Construct the XNif file... -// // We are lazy. (TODO: clone & remove keyframe controllers & keyframe data) -// xnif_root = root_block; -// -// // Now the XKf file... -// // Create xkf root header. -// xkf_root = CreateBlock("NiSequenceStreamHelper"); -// -// // Add a copy of the NiTextKeyExtraData block to the XKf header. -// blk_ref xkf_txtkey_block = CreateBlock("NiTextKeyExtraData"); -// xkf_root["Extra Data"] = xkf_txtkey_block; -// -// ITextKeyExtraData const *itxtkey_block = QueryTextKeyExtraData(txtkey_block); -// ITextKeyExtraData *ixkf_txtkey_block = QueryTextKeyExtraData(xkf_txtkey_block); -// ixkf_txtkey_block->SetKeys(itxtkey_block->GetKeys()); -// -// // 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")->asLink().is_null() || (*it)->GetAttr("Controller")->asLink()->GetBlockType() != "NiKeyframeController" ) -// it = nodes.erase( it ); -// else -// it++; -// }; -// -// blk_ref last_block = xkf_txtkey_block; -// for ( list<blk_ref>::const_iterator it = nodes.begin(); it != nodes.end(); ++it ) { -// blk_ref nodextra = CreateBlock("NiStringExtraData"); -// nodextra["String Data"] = (*it)["Name"]->asString(); -// last_block["Next Extra Data"] = nodextra; -// last_block = nodextra; -// }; -// -// // Add controllers & controller data. -// last_block = xkf_root; -// for ( list<blk_ref>::const_iterator it = nodes.begin(); it != nodes.end(); ++it ) { -// blk_ref controller = (*it)->GetAttr("Controller")->asLink(); -// blk_ref xkf_controller = CreateBlock("NiKeyframeController"); -// xkf_controller["Flags"] = controller["Flags"]->asInt(); -// xkf_controller["Frequency"] = controller["Frequency"]->asFloat(); -// xkf_controller["Phase"] = controller["Phase"]->asFloat(); -// xkf_controller["Start Time"] = controller["Start Time"]->asFloat(); -// xkf_controller["Stop Time"] = controller["Stop Time"]->asFloat(); -// -// blk_ref xkf_data = CreateBlock("NiKeyframeData"); -// xkf_controller["Data"] = xkf_data; -// IKeyframeData const *ikfdata = QueryKeyframeData(controller["Data"]->asLink()); -// IKeyframeData *ixkfdata = QueryKeyframeData(xkf_data); -// ixkfdata->SetRotateType(ikfdata->GetRotateType()); -// ixkfdata->SetTranslateType(ikfdata->GetTranslateType()); -// ixkfdata->SetScaleType(ikfdata->GetScaleType()); -// ixkfdata->SetRotateKeys(ikfdata->GetRotateKeys()); -// ixkfdata->SetTranslateKeys(ikfdata->GetTranslateKeys()); -// ixkfdata->SetScaleKeys(ikfdata->GetScaleKeys()); -// -// if ( last_block == xkf_root ) { -// if ( ! last_block["Controller"]->asLink().is_null() ) -// throw runtime_error("Cannot create .kf file for multicontrolled nodes."); // not sure 'bout this one... -// last_block["Controller"] = xkf_controller; -// } else { -// if ( ! last_block["Next Controller"]->asLink().is_null() ) -// throw runtime_error("Cannot create .kf file for multicontrolled nodes."); // not sure 'bout this one... -// last_block["Next Controller"] = xkf_controller; -// }; -// last_block = xkf_controller; -// // note: targets are automatically calculated, we don't need to reset them -// }; -// } else // TODO other games -// throw runtime_error("Not yet implemented."); -// } else { -// // no animation groups: nothing to do -// xnif_root = blk_ref(); -// xkf_root = blk_ref(); -// }; -//} +void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiObjectRef & xkf_root, Kfm & kfm, int kf_type ) { + // Do we have animation groups (a NiTextKeyExtraData block)? + // If so, create XNif and XKf trees. + //TODO: Implement NiTextKeyExtraData so it has a TYPE + NiObjectRef txtkey_block; // = GetObjectByType( root_block, NiTextKeyExtraData::TYPE ); + if ( txtkey_block != NULL ) { + if ( kf_type == KF_MW ) { + // Construct the XNif file... + // We are lazy. (TODO: clone & remove keyframe controllers & keyframe data) + xnif_root = root_block; + + // Now the XKf file... + // Create xkf root header. + xkf_root = CreateBlock("NiSequenceStreamHelper"); + + // Add a copy of the NiTextKeyExtraData block to the XKf header. + NiObjectRef xkf_txtkey_block = CreateBlock("NiTextKeyExtraData"); + //TODO: Implement functions to query extra data + //xkf_root["Extra Data"] = xkf_txtkey_block; + + /*ITextKeyExtraData const *itxtkey_block = QueryTextKeyExtraData(txtkey_block); + ITextKeyExtraData *ixkf_txtkey_block = QueryTextKeyExtraData(xkf_txtkey_block); + ixkf_txtkey_block->SetKeys(itxtkey_block->GetKeys());*/ + + // Append NiNodes with a NiKeyFrameController as NiStringExtraData blocks. + list<NiObjectRef> nodes = GetAllObjectsByType( root_block, NiNode::TYPE ); + for ( list<NiObjectRef>::iterator it = nodes.begin(); it != nodes.end(); ) { + //TODO: Implement functions to add and query controllers + /*if ( (*it)->GetAttr("Controller")->asLink().is_null() || (*it)->GetAttr("Controller")->asLink()->GetBlockType() != "NiKeyframeController" ) + it = nodes.erase( it ); + else + it++;*/ + }; + + NiObjectRef last_block = xkf_txtkey_block; + for ( list<NiObjectRef>::const_iterator it = nodes.begin(); it != nodes.end(); ++it ) { + NiObjectRef nodextra = CreateBlock("NiStringExtraData"); + //TODO: Implement NiStringEtraData along with functions/member variables to cover these data items + //nodextra["String Data"] = (*it)["Name"]->asString(); + //last_block["Next Extra Data"] = nodextra; + last_block = nodextra; + }; + + // Add controllers & controller data. + last_block = xkf_root; + for ( list<NiObjectRef>::const_iterator it = nodes.begin(); it != nodes.end(); ++it ) { + //TODO: Implement NiTimeController class + //NiObjectRef controller = (*it)->GetAttr("Controller")->asLink(); + //NiObjectRef xkf_controller = CreateBlock("NiKeyframeController"); + //xkf_controller["Flags"] = controller["Flags"]->asInt(); + //xkf_controller["Frequency"] = controller["Frequency"]->asFloat(); + //xkf_controller["Phase"] = controller["Phase"]->asFloat(); + //xkf_controller["Start Time"] = controller["Start Time"]->asFloat(); + //xkf_controller["Stop Time"] = controller["Stop Time"]->asFloat(); + // + //NiObjectRef xkf_data = CreateBlock("NiKeyframeData"); + //xkf_controller["Data"] = xkf_data; + //IKeyframeData const *ikfdata = QueryKeyframeData(controller["Data"]->asLink()); + //IKeyframeData *ixkfdata = QueryKeyframeData(xkf_data); + //ixkfdata->SetRotateType(ikfdata->GetRotateType()); + //ixkfdata->SetTranslateType(ikfdata->GetTranslateType()); + //ixkfdata->SetScaleType(ikfdata->GetScaleType()); + //ixkfdata->SetRotateKeys(ikfdata->GetRotateKeys()); + //ixkfdata->SetTranslateKeys(ikfdata->GetTranslateKeys()); + //ixkfdata->SetScaleKeys(ikfdata->GetScaleKeys()); + + //if ( last_block == xkf_root ) { + // if ( ! last_block["Controller"]->asLink().is_null() ) + // throw runtime_error("Cannot create .kf file for multicontrolled nodes."); // not sure 'bout this one... + // last_block["Controller"] = xkf_controller; + //} else { + // if ( ! last_block["Next Controller"]->asLink().is_null() ) + // throw runtime_error("Cannot create .kf file for multicontrolled nodes."); // not sure 'bout this one... + // last_block["Next Controller"] = xkf_controller; + //}; + //last_block = xkf_controller; + //// note: targets are automatically calculated, we don't need to reset them + }; + } else // TODO other games + throw runtime_error("Not yet implemented."); + } else { + // no animation groups: nothing to do + xnif_root = NULL; + xkf_root = NULL; + }; +} /*! * Helper function to split an animation tree into multiple animation trees (one per animation group) and a kfm block. * \param root_block The root block of the full tree. * \param kf Vector of root blocks of the new animation trees. */ -void SplitKfTree( blk_ref const & root_block, vector<blk_ref> & kf ) { +void SplitKfTree( NiObjectRef const & root_block, vector<NiObjectRef> & kf ) { throw runtime_error("Not yet implemented."); }; -void WriteFileGroup( string const & file_name, blk_ref const & root_block, unsigned int version, unsigned int export_files, unsigned int kf_type ) { - //// Get base filename. - //uint file_name_slash = uint(file_name.rfind("\\") + 1); - //string file_name_path = file_name.substr(0, file_name_slash); - //string file_name_base = file_name.substr(file_name_slash, file_name.length()); - //uint file_name_dot = uint(file_name_base.rfind(".")); - //file_name_base = file_name_base.substr(0, file_name_dot); - // - //// Deal with the simple case first - //if ( export_files == EXPORT_NIF ) - // WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file! - //// Now consider all other cases - //else if ( kf_type == KF_MW ) { - // if ( export_files == EXPORT_NIF_KF ) { - // // for Morrowind we must also write the full NIF file - // WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file! - // blk_ref xnif_root; - // blk_ref xkf_root; - // Kfm kfm; // dummy - // SplitNifTree( root_block, xnif_root, xkf_root, kfm, KF_MW ); - // if ( ! xnif_root.is_null() ) { - // WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version ); - // WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_root, version ); - // }; - // } else - // throw runtime_error("Invalid export option."); - //} else - // throw runtime_error("Not yet implemented."); +void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int export_files, unsigned int kf_type ) { + // Get base filename. + uint file_name_slash = uint(file_name.rfind("\\") + 1); + string file_name_path = file_name.substr(0, file_name_slash); + string file_name_base = file_name.substr(file_name_slash, file_name.length()); + uint file_name_dot = uint(file_name_base.rfind(".")); + file_name_base = file_name_base.substr(0, file_name_dot); + + // Deal with the simple case first + if ( export_files == EXPORT_NIF ) + WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file! + // Now consider all other cases + else if ( kf_type == KF_MW ) { + if ( export_files == EXPORT_NIF_KF ) { + // for Morrowind we must also write the full NIF file + WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file! + NiObjectRef xnif_root; + NiObjectRef xkf_root; + Kfm kfm; // dummy + SplitNifTree( root_block, xnif_root, xkf_root, kfm, KF_MW ); + if ( xnif_root != NULL ) { + WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version ); + WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_root, version ); + }; + } else + throw runtime_error("Invalid export option."); + } else + throw runtime_error("Not yet implemented."); }; @@ -730,12 +725,9 @@ unsigned int BlocksInMemory() { return blocks_in_memory; } -void MapParentNodeNames( map<string,blk_ref> & name_map, blk_ref par ) { - ////Check if this block is a scene graph node - //if ( par->QueryInterface( ID_NODE ) == false ) { - // throw runtime_error( "Only trees that have a node as the root can be merged." ); - //} +void MapParentNodeNames( map<string,NiAVObjectRef> & name_map, NiAVObjectRef par ) { + //TODO: Implement functions to get and set children ////Check if this is a parent node //attr_ref children = par->GetAttr("Children"); //if ( children.is_null() == true ) { @@ -743,23 +735,25 @@ void MapParentNodeNames( map<string,blk_ref> & name_map, blk_ref par ) { // return; //} - ////Add the par node to the map, and then call this function for each of its children - //name_map[par->GetAttr("Name")->asString()] = par; + //Add the par node to the map, and then call this function for each of its children + name_map[par->name] = par; - //list<blk_ref> links = par->GetAttr("Children")->asLinkList();; - //for (list <blk_ref>::iterator it = links.begin(); it != links.end(); ++it) { - // if ( it->is_null() == false ) { - // MapParentNodeNames( name_map, *it ); - // }; - //}; + //TODO: Implement functions to get and set children + list<NiAVObjectRef> links;// = par->GetAttr("Children")->asLinkList();; + for (list<NiAVObjectRef>::iterator it = links.begin(); it != links.end(); ++it) { + if ( (*it) != NULL ) { + MapParentNodeNames( name_map, *it ); + }; + }; } -void ReassignTreeCrossRefs( map<string,blk_ref> & name_map, blk_ref par ) { +void ReassignTreeCrossRefs( map<string,NiAVObjectRef> & name_map, NiAVObjectRef par ) { + //TODO: Decide how cross refs are going to work ////Reassign any cross references on this block //((ABlock*)par.get_block())->ReassignCrossRefs( name_map ); - //list<blk_ref> links = par->GetLinks(); - //for (list <blk_ref>::iterator it = links.begin(); it != links.end(); ++it) { + //list<NiObjectRef> links = par->GetLinks(); + //for (list <NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it) { // // if the link is not null, and if the child's first parent is root_block // // (this makes sure we only check every child once, even if it is shared by multiple parents), // // then look for a match in the tree starting from the child. @@ -767,89 +761,87 @@ void ReassignTreeCrossRefs( map<string,blk_ref> & name_map, blk_ref par ) { // ReassignTreeCrossRefs( name_map, *it ); // }; //}; - } //This function will merge two scene graphs by attatching new objects to the correct position //on the existing scene graph. In other words, it deals only with adding new nodes, not altering //existing nodes by changing their data or attatched properties -void MergeSceneGraph( map<string,blk_ref> & name_map, const blk_ref & root, blk_ref par ) { - ////Check if this block is a scene graph node - //if ( par->QueryInterface( ID_NODE ) == false ) { - // throw runtime_error( "Only trees that have a node as the root can be merged." ); - //} - // - ////Check if this block's name exists in the block map - //string name = par->GetAttr("Name")->asString(); - - //if ( name_map.find(name) != name_map.end() ) { - // //This block already exists in the original file, so continue on to its children - - // list<blk_ref> links = par->GetAttr("Children")->asLinkList();; - // for (list <blk_ref>::iterator it = links.begin(); it != links.end(); ++it) { - // if ( it->is_null() == false ) { - // MergeSceneGraph( name_map, root, *it ); - // }; - // }; - // return; - //} +void MergeSceneGraph( map<string,NiAVObjectRef> & name_map, const NiAVObjectRef & root, NiAVObjectRef par ) { + //Check if this block's name exists in the block map + string name = par->name; + + if ( name_map.find(name) != name_map.end() ) { + //This block already exists in the original file, so continue on to its children + + //TODO: Implement children + list<NiAVObjectRef> links;// = par->GetAttr("Children")->asLinkList();; + for (list <NiAVObjectRef>::iterator it = links.begin(); it != links.end(); ++it) { + if ( (*it) != NULL ) { + MergeSceneGraph( name_map, root, *it ); + }; + }; + return; + } - ////This block has a new name and either it has no parent or its parent has a name that is - //// in the list. Attatch it to the block with the same name as its parent - ////all child blocks will follow along. - //blk_ref par_par = par->GetParent(); + //This block has a new name and either it has no parent or its parent has a name that is + // in the list. Attatch it to the block with the same name as its parent + //all child blocks will follow along. + NiAVObjectRef par_par = DynamicCast<NiAVObject>(par->GetParent()); - //if ( par_par.is_null() == true ) { - // //This block has a new name and no parents. That means it is the root block - // //of a disimilar Nif file. - // attr_ref par_children = par->GetAttr("Children"); - // - // //Get the current root child list - // attr_ref root_children = root->GetAttr("Children"); - // - // if ( par_children.is_null() == true ) { - // //This is not a ParentNode class, so simply add it as a new child of the - // //target root node - // root_children->AddLink( par ); - // cout << "Added link to " << par << " in " << root << " block."; - // } else { - // //This is a ParentNode class, so merge its child list with that of the root - // root_children->AddLinks( par_children->asLinkList() ); - // } - //} else { - // //This block has a new name and has a parent with a name that already exists. - // //Attatch it to the block in the target tree that matches the name of its - // //parent + if ( par_par == NULL) { + //TODO: Implement children + ////This block has a new name and no parents. That means it is the root block + ////of a disimilar Nif file. + //attr_ref par_children = par->GetAttr("Children"); + + ////Get the current root child list + //attr_ref root_children = root->GetAttr("Children"); + + //if ( par_children.is_null() == true ) { + // //This is not a ParentNode class, so simply add it as a new child of the + // //target root node + // root_children->AddLink( par ); + // cout << "Added link to " << par << " in " << root << " block."; + //} else { + // //This is a ParentNode class, so merge its child list with that of the root + // root_children->AddLinks( par_children->asLinkList() ); + //} + } else { + //This block has a new name and has a parent with a name that already exists. + //Attatch it to the block in the target tree that matches the name of its + //parent - // //Remove this block from its old parent - // par_par->GetAttr("Children")->RemoveLinks( par ); + //TODO: Implement children + ////Remove this block from its old parent + //par_par->GetAttr("Children")->RemoveLinks( par ); - // //Get the block to attatch to - // blk_ref attatch = name_map[par_par->GetAttr("Name")->asString()]; + //Get the block to attatch to + NiObjectRef attatch = name_map[par_par->name]; - // //Add this block as new child - // attatch->GetAttr("Children")->AddLink( par ); - // //cout << "Added link to " << par << " in " << attatch << " block."; - //} + //TODO: Implement children + ////Add this block as new child + //attatch->GetAttr("Children")->AddLink( par ); + ////cout << "Added link to " << par << " in " << attatch << " block."; + } } -void MergeNifTrees( blk_ref target, blk_ref right, unsigned int version ) { - ////For now assume that both are normal Nif trees just to verify that it works +void MergeNifTrees( NiAVObjectRef target, NiAVObjectRef right, unsigned int version ) { + //For now assume that both are normal Nif trees just to verify that it works - ////Make a clone of the tree to add - //stringstream tmp; - ////WriteNifTree( tmp, right, version ); - //tmp.seekg( 0, ios_base::beg ); - //blk_ref new_tree = right;// ReadNifTree( tmp ); TODO: Figure out why this doesn't work + //Make a clone of the tree to add + stringstream tmp; + //WriteNifTree( tmp, right, version ); + tmp.seekg( 0, ios_base::beg ); + NiAVObjectRef new_tree = right;// ReadNifTree( tmp ); TODO: Figure out why this doesn't work - ////Create a list of names in the target - //map<string,blk_ref> name_map; - //MapParentNodeNames( name_map, target ); + //Create a list of names in the target + map<string,NiAVObjectRef> name_map; + MapParentNodeNames( name_map, target ); - ////Reassign any cross references in the new tree to point to blocks in the - ////target tree with the same names - //ReassignTreeCrossRefs( name_map, new_tree ); + //Reassign any cross references in the new tree to point to blocks in the + //target tree with the same names + ReassignTreeCrossRefs( name_map, new_tree ); - ////Use the name map to merge the Scene Graphs - //MergeSceneGraph( name_map, target, new_tree ); + //Use the name map to merge the Scene Graphs + MergeSceneGraph( name_map, target, new_tree ); } \ No newline at end of file