diff --git a/NIF_Blocks.cpp b/NIF_Blocks.cpp index ff488e0970cace6378f11c40eb4e08032d0ed7cc..ac863a8fac82b3ee53bcc808442be4b165d1c2fa 100644 --- a/NIF_Blocks.cpp +++ b/NIF_Blocks.cpp @@ -44,7 +44,9 @@ POSSIBILITY OF SUCH DAMAGE. */ extern bool verbose; extern unsigned int blocks_in_memory; +#ifdef WIN32 #define endl "\r\n" +#endif extern string current_file; @@ -53,13 +55,10 @@ extern string current_file; **********************************************************/ ABlock::ABlock() : _block_num(-1), _ref_count(0) { - //Temporary to test reference counting blocks_in_memory++; } ABlock::~ABlock() { - //Temporary to test reference counting - //cout << "A block has commited suicide." << endl; blocks_in_memory--; // Delete all attributes diff --git a/NIF_Blocks.h b/NIF_Blocks.h index 9925204dba7906aa36dd76d6ca6a6e5fb7c494ed..1957d3a9381a543a078417ea4c825c852cad8421 100644 --- a/NIF_Blocks.h +++ b/NIF_Blocks.h @@ -54,43 +54,11 @@ typedef pair<LinkMapIt,LinkMapIt> LinkMapRange; //--Constants--// //Non-Public Interface IDs -//const int BlockInternal = -1; + const int SkinInstInternal = -2; const int SkinDataInternal = -3; -//const int NodeInternal = -4; - - - - -//void GetBuiltUpTransform(blk_ref block, Matrix & m/*, blk_ref stop*/); -class IBlockInternal { -public: - IBlockInternal() {} - virtual ~IBlockInternal() {} - - //Link Tracking - virtual void AddParent( IBlock * parent ) = 0; - virtual void RemoveParent( IBlock * match ) = 0; - virtual void SetBlockNum( int ) = 0; - virtual void SetBlockTypeNum( int n ) = 0; - virtual int GetBlockTypeNum() = 0; - virtual void FixLinks( const vector<blk_ref> & blocks ) = 0; - virtual void AddChild( IBlock * new_child ) = 0; - virtual void RemoveChild( IBlock * old_child ) = 0; - - //Cross Link Tracking - virtual void RemoveCrossLink( IBlock * block_to_remove ) = 0; - - virtual void IncCrossRef( IBlock * block ) = 0; - virtual void DecCrossRef( IBlock * block ) = 0; - - //File I/O - virtual void Read( istream& in, unsigned int version ) = 0; - virtual void Write( ostream& out, unsigned int version ) const = 0; -}; - -class ABlock : public IBlock/*, public IBlockInternal*/ { +class ABlock : public IBlock { public: ABlock(); ~ABlock(); @@ -157,6 +125,387 @@ protected: list<IBlock*> _cross_refs; }; +//--Link Classes--// + +class Link { +public: + //Constructor + //It is required for a LinkGroup to be aware of the block it is part of + Link ( IBlock * owner) : _owner(owner), index(-1) {} + + //Destructor + ~Link() { KillLink(); } + + void SetIndex( const int new_index ) { + //This function is for the initial file read. It records the index of the block which + //will later be resolved to a link once all the blocks have been read + + //If there is already a link, kill it + if ( link.is_null() == false ) { + KillLink(); + link.nullify(); + } + + index = new_index; + } + + blk_ref GetLink() { return link; } + + + + void SetLink( const blk_ref & new_link ) { + if ( link != new_link ) { + //Kill previous link + KillLink(); + + //Set New Link + link = new_link; + InitLink(); + } + } + + void Fix( const vector<blk_ref> & blocks ) { + //The purpouse of this function is to convert the block index to a link + //to the corresponding block. + + //Ensure that there is an index to convert + if (index == -1 ) { + return; + } + + if ( index < int(blocks.size()) && index >= 0 ) { + link = blocks[index]; + InitLink(); + } + } +private: + IBlock * _owner; + blk_ref link; + int index; + void InitLink() { + //Add parent at new link site + IBlock * target = link.get_block(); + if ( target != NULL ) { + //Get internal interface + ((ABlock*)target)->AddParent( _owner ); + } + } + void KillLink() { + //Remove parent at previous location + IBlock * target = link.get_block(); + if ( target != NULL ) { + ((ABlock*)target)->RemoveParent( _owner ); + } + } +}; + +class LinkGroup { +public: + //Constructor + //It is required for a LinkGroup to be aware of the block it is part of + LinkGroup(IBlock * owner) : _owner(owner) {} + + //Destructor + ~LinkGroup() { + //Remove all links + ClearLinks(); + } + + void SetIndices( const list<int> new_indices ) { + //This function is for the initial file read. It records the indices of the blocks which + //will later be resolved to links once all the blocks have been read + + //If there are already links, kill them + ClearLinks(); + + indices = new_indices; + } + + list<blk_ref> GetLinks() const { + return links; + } + + void AddLink( blk_ref const & block ) { + InitLink( block ); + links.push_back( block ); + } + + void AddLinks( list<blk_ref> const & new_links ) { + //Initiate all of the new links + list<blk_ref>::const_iterator it; + for (it = new_links.begin(); it != new_links.end(); ++it ) { + InitLink( *it ); + links.push_back( *it ); + } + } + + blk_ref FindLink( string const & block_type ) const { + //Find the first link with the requested block type + for ( list<blk_ref>::const_iterator it = links.begin(); it != links.end(); ++it ) { + if ( (*it)->GetBlockType() == block_type ) + return blk_ref(*it); + } + + //No block was found, so return a null one + return blk_ref(-1); + } + + void ClearLinks() { + //Kill all the links + list<blk_ref>::iterator it; + for (it = links.begin(); it != links.end(); ++it ) { + KillLink( *it ); + } + + //Clear the list + links.clear(); + } + + void RemoveLinks( blk_ref const & block ) { + //Remove all links that match this block + //Kill the links first + list<blk_ref>::iterator it; + for (it = links.begin(); it != links.end(); ++it ) { + if ( *it == block ) { + KillLink( *it ); + } + } + + //Now remove them from the list + links.remove( block ); + } + + void Fix( const vector<blk_ref> & blocks ) { + //The purpouse of this function is to convert the block indices to a links + //to the corresponding blocks. + + list<int>::iterator it; + for (it = indices.begin(); it != indices.end(); ++it ) { + if ( *it < int(blocks.size()) && *it >= 0 ) { + blk_ref new_link = blocks[*it]; + InitLink( new_link ); + links.push_back( new_link ); + } + } + + //Clear indices + indices.clear(); + } + +private: + IBlock * _owner; + list<blk_ref> links; + list<int> indices; + void InitLink( const blk_ref & link ) { + //Add parent at new link site + IBlock * target = link.get_block(); + if ( target != NULL ) { + //Get internal interface + ((ABlock*)target)->AddParent( _owner ); + } + } + void KillLink( const blk_ref & link ) { + //Remove parent at previous location + IBlock * target = link.get_block(); + if ( target != NULL ) { + ((ABlock*)target)->RemoveParent( _owner ); + } + } +}; + +//--CrossRef Classes--// + +class CrossRef { +public: + //Constructor + //It is required for a CrossRef to be aware of the block it is part of + CrossRef ( IBlock * owner) : _owner(owner), ref(NULL), index(-1) {} + + //Destructor + ~CrossRef() { KillRef(); } + + void SetIndex( const int new_index ) { + //This function is for the initial file read. It records the index of the block which + //will later be resolved to a reference once all the blocks have been read + + //If there is already a reference, kill it + if ( ref != NULL ) { + KillRef(); + ref = NULL; + } + + index = new_index; + } + + IBlock * GetCrossRef() { return ref; } + + void SetCrossRef( IBlock * new_ref ) { + if ( ref != new_ref ) { + //Kill previous link + KillRef(); + + //Set New Link + ref = new_ref; + InitRef(); + } + } + + void RemoveCrossLink( IBlock * block_to_remove ) { + //This function's purpouse is to inform this CrossRef that the block it is referencing has died + //Simply set it to NULL + ref = NULL; + } + + void Fix( const vector<blk_ref> & blocks ) { + //The purpouse of this function is to convert the block index to a reference + //to the corresponding block. + + if (index < int(blocks.size()) && index >= 0 ) { + ref = blocks[index].get_block(); + index = -1; + InitRef(); + } + } + +private: + IBlock * _owner; + IBlock * ref; + int index; + void InitRef() { + //Inform target block that it is being cross referenced + if ( ref != NULL ) { + //Get internal interface + ((ABlock*)ref)->IncCrossRef( _owner ); + } + } + void KillRef() { + //Inform target block that it is no longer being cross referenced + if ( ref != NULL ) { + ((ABlock*)ref)->IncCrossRef( _owner ); + } + } +}; + +class CrossRefGroup { +public: + //Constructor + //It is required for a LinkGroup to be aware of the block it is part of + CrossRefGroup(IBlock * owner) : _owner(owner) {} + + //Destructor + ~CrossRefGroup() { + //Remove all links + ClearRefs(); + } + + void SetIndices( const list<int> new_indices ) { + //This function is for the initial file read. It records the indices of the blocks which + //will later be resolved to links once all the blocks have been read + + //If there are already links, kill them + ClearRefs(); + + indices = new_indices; + } + + list<IBlock *> GetRefs() const { + return refs; + } + + void AddRef( IBlock * const & new_ref ) { + InitRef( new_ref ); + refs.push_back( new_ref ); + } + + void AddRefs( list<IBlock *> const & new_refs ) { + //Initiate all of the new links + list<IBlock *>::const_iterator it; + for (it = new_refs.begin(); it != new_refs.end(); ++it ) { + InitRef( *it ); + refs.push_back( *it ); + } + } + + IBlock * FindRef( string const & block_type ) const { + //Find the first reference with the requested block type + for ( list<IBlock *>::const_iterator it = refs.begin(); it != refs.end(); ++it ) { + if ( (*it)->GetBlockType() == block_type ) + return *it; + } + + //No block was found, so return NULL + return NULL; + } + + void ClearRefs() { + //Kill all the refs + list<IBlock *>::iterator it; + for (it = refs.begin(); it != refs.end(); ++it ) { + KillRef( *it ); + } + + //Clear the list + refs.clear(); + } + + void RemoveRefs( IBlock * const block ) { + //Remove all refs that match this block + //Kill the refs first + list<IBlock *>::iterator it; + for (it = refs.begin(); it != refs.end(); ++it ) { + if ( *it == block ) { + KillRef( *it ); + } + } + + //Now remove them from the list + refs.remove( block ); + } + + void Fix( const vector<blk_ref> & blocks ) { + //The purpouse of this function is to convert the block indices to a links + //to the corresponding blocks. + + list<int>::iterator it; + for (it = indices.begin(); it != indices.end(); ++it ) { + if ( *it < int(blocks.size()) && *it >= 0 ) { + IBlock * new_ref = blocks[*it].get_block(); + InitRef( new_ref ); + refs.push_back( new_ref ); + } + } + + //Clear indices + indices.clear(); + } + + void RemoveCrossLink( IBlock * block_to_remove ) { + //This function's purpouse is to inform this CrossRefGroup that one of the blocks + //it is referencing has died + + //Remove matching refs + RemoveRefs( block_to_remove ); + } + +private: + IBlock * _owner; + list<IBlock *> refs; + list<int> indices; + void InitRef( IBlock * ref ) { + //Inform target block that it is being cross referenced + if ( ref != NULL ) { + //Get internal interface + ((ABlock*)ref)->IncCrossRef( _owner ); + } + } + void KillRef( IBlock * ref ) { + //Inform target block that it is no longer being cross referenced + if ( ref != NULL ) { + ((ABlock*)ref)->IncCrossRef( _owner ); + } + } +}; + class AControllable : public ABlock { public: AControllable(); @@ -165,13 +514,7 @@ public: ~AControllable() {} }; -//class INodeInternal { -//public: -// virtual void IncSkinRef( IBlock * skin_data ) = 0; -// virtual void DecSkinRef( IBlock * skin_data ) = 0; -//}; - -class ANode : public AControllable, public INode/*, public INodeInternal*/ { +class ANode : public AControllable, public INode { public: ANode(); void Init() { diff --git a/nif_attrs.h b/nif_attrs.h index 92304fb6652f0529bc32b81a47993d4a60bb7395..c45f7b5f7864a1a094e1027c7e1550ec4ccc38ae 100644 --- a/nif_attrs.h +++ b/nif_attrs.h @@ -105,9 +105,9 @@ protected: class lnk_ref : public blk_ref { public: - lnk_ref ( IBlock * owner) : _owner(owner) { /*cout << "Constructor " << endl;*/ InitLink(); } - lnk_ref( IBlock * owner, int index ) : blk_ref(index), _owner(owner) { /*cout << "Constructor " << endl;*/ InitLink(); } - lnk_ref( IBlock * owner, blk_ref block ) : blk_ref(block), _owner(owner) { /*cout << "Constructor " << endl;*/ InitLink(); } + lnk_ref ( IBlock * owner) : _owner(owner) { InitLink(); } + lnk_ref( IBlock * owner, int index ) : blk_ref(index), _owner(owner) { InitLink(); } + lnk_ref( IBlock * owner, blk_ref block ) : blk_ref(block), _owner(owner) { InitLink(); } //Copy Constructors lnk_ref( const lnk_ref & rh ) { @@ -120,7 +120,7 @@ public: InitLink(); } //Destructor - ~lnk_ref() { /*cout << "Destructor " << endl;*/ KillLink(); /*cin.get();*/} + ~lnk_ref() { KillLink(); } //Assignment Operator lnk_ref & operator=(const blk_ref & rh ) { if ( blk_ref(*this)!= rh ) { diff --git a/niflib.h b/niflib.h index af0717a5e7ae3174efccaa01ac970cf00475de09..28955d82205b0be95a9da4fe66c29153f99716de 100644 --- a/niflib.h +++ b/niflib.h @@ -3224,6 +3224,18 @@ public: else return false; } + + /*! + * Makes this reference a null reference, decrimenting the reference count of the block it was pointing to, if any. + */ + void nullify() { + if ( _block != NULL ) { + //Decrement reference count + _block->SubtractRef(); + } + _block = NULL; + _index = -1; + } blk_ref( IBlock * block ) : _index(-1), _block(block) { //Increment reference count