diff --git a/NIF_Blocks.cpp b/NIF_Blocks.cpp index d11239bb193c059d7b2d27e251c92b482bee33ff..bd8d26f9351335d1d058f0c1329d6aca44b929d7 100644 --- a/NIF_Blocks.cpp +++ b/NIF_Blocks.cpp @@ -172,6 +172,13 @@ blk_ref ABlock::GetParent() const { return blk_ref(-1); } +list<blk_ref> ABlock::GetParents() const { + list<blk_ref> parents; + for (vector<IBlock *>::const_iterator it = _parents.begin(); it != _parents.end(); it++ ) + parents.push_back(blk_ref(*it)); + return parents; +} + void ABlock::Read( istream& in, unsigned int version ) { //Read Attributes diff --git a/NIF_Blocks.h b/NIF_Blocks.h index f42cdb7487f59639bea585a89e5081d58b664c8e..5111fc9b35e4d7b07bbc7a7a1e4fa4cac0b98c38 100644 --- a/NIF_Blocks.h +++ b/NIF_Blocks.h @@ -104,6 +104,7 @@ public: //Links blk_ref GetParent() const; + list<blk_ref> GetParents() const; list<blk_ref> GetLinks() const; //Reference Counting diff --git a/nif_attrs.h b/nif_attrs.h index f8bd799942f5ae21da1e4591a22f79f65a9ed5af..ec361eec41eac4b4a6acf9223336f396e4461268 100644 --- a/nif_attrs.h +++ b/nif_attrs.h @@ -1218,21 +1218,45 @@ public: // We want to get the closest common ancestor between the _owner and the bones // So start with a list of ancestors of the first bone (this is just a random choice) blk_ref block = bones[0]; - blk_ref par = block->GetParent(); + list<blk_ref> pars = block->GetParents(); + blk_ref nodepar = blk_ref(); + for ( list<blk_ref>::const_iterator it = pars.begin(); it != pars.end(); it++ ) + if ( (*it)->GetBlockType() == "NiNode" ) { + nodepar = *it; + break; + }; list<blk_ref> bone_pars; - while ( par.is_null() == false ) { - bone_pars.push_front(par); - par = par->GetParent(); + while ( nodepar.is_null() == false ) { + bone_pars.push_front(nodepar); + pars = nodepar->GetParents(); + nodepar = blk_ref(); + for ( list<blk_ref>::const_iterator it = pars.begin(); it != pars.end(); it++ ) + if ( (*it)->GetBlockType() == "NiNode" ) { + nodepar = *it; + break; + }; }; // Now do the same with the owner. - block = _owner; - par = block->GetParent(); + block = _owner->GetParent(); // TriShape + pars = block->GetParents(); + nodepar = blk_ref(); + for ( list<blk_ref>::const_iterator it = pars.begin(); it != pars.end(); it++ ) + if ( (*it)->GetBlockType() == "NiNode" ) { + nodepar = *it; + break; + }; list<blk_ref> owner_pars; - while ( par.is_null() == false ) { - owner_pars.push_front(par); - par = par->GetParent(); + while ( nodepar.is_null() == false ) { + owner_pars.push_front(nodepar); + pars = nodepar->GetParents(); + nodepar = blk_ref(); + for ( list<blk_ref>::const_iterator it = pars.begin(); it != pars.end(); it++ ) + if ( (*it)->GetBlockType() == "NiNode" ) { + nodepar = *it; + break; + }; }; - // Now find closest common ancestor. + // Now find closest common NiNode ancestor. if ( owner_pars.empty() || bone_pars.empty() ) throw runtime_error("Skinning instance has no common parent with the bones it refers to (invalid NIF file?). Cannot set skeleton root."); blk_ref skelroot; diff --git a/niflib.h b/niflib.h index 74bc868727f782892347e9d93200d873970fe9a5..db1fb686b302f10c50c85c2145b728f33151de7c 100644 --- a/niflib.h +++ b/niflib.h @@ -1310,6 +1310,26 @@ public: */ virtual blk_ref GetParent() const = 0; + /*! + * Used to retrieve all parents that are linked to this block. + * \return A list of block references to the parents that are linked to this block. + * + * <b>Example:</b> + * \code + * blk_ref my_block = ReadNifTree("test_in.nif"); + * list<blk_ref> parents = my_block->GetParents(); + * \endcode + * + * <b>In Python:</b> + * \code + * my_block = ReadNifTree("test_in.nif") + * parents = block.GetParents() + * \endcode + * + * \sa IAttr::Set(blk_ref const &), IAttr::AddLink, IAttr::AddLinks, IAttr::RemoveLinks, IAttr::ClearLinks + */ + virtual list<blk_ref> GetParents() const = 0; + /*! * Summarizes the information contained in this block in English. * \return A string containing a summary of the information within the block in English. This is the function that Niflyze calls to generate its analysis, so the output is the same.